Add half sheet apk to nearby
Test: start activity show avaiable device to pairing click connect to
start pairing process pair success
Bug: 202335820
Change-Id: I454527f11a396ecf8acd55649dc740ed2d09c6fc
diff --git a/nearby/service/Android.bp b/nearby/service/Android.bp
index 63e2748..b80d677 100644
--- a/nearby/service/Android.bp
+++ b/nearby/service/Android.bp
@@ -27,6 +27,9 @@
name: "nearby-service-string-res",
srcs: [
"java/**/Constant.java",
+ "java/**/UserActionHandlerBase.java",
+ "java/**/UserActionHandler.java",
+ "java/**/FastPairConstants.java",
],
}
@@ -55,6 +58,7 @@
static_libs: [
"androidx.annotation_annotation",
"androidx.core_core",
+ "androidx.localbroadcastmanager_localbroadcastmanager",
"guava",
"libprotobuf-java-lite",
"fast-pair-lite-protos",
diff --git a/nearby/service/java/com/android/server/nearby/common/fastpair/service/UserActionHandlerBase.java b/nearby/service/java/com/android/server/nearby/common/fastpair/service/UserActionHandlerBase.java
index c50e219..67d87e3 100644
--- a/nearby/service/java/com/android/server/nearby/common/fastpair/service/UserActionHandlerBase.java
+++ b/nearby/service/java/com/android/server/nearby/common/fastpair/service/UserActionHandlerBase.java
@@ -23,6 +23,7 @@
public static final String EXTRA_ITEM_ID = PREFIX + "EXTRA_ITEM_ID";
public static final String EXTRA_COMPANION_APP = ACTION_PREFIX + "EXTRA_COMPANION_APP";
+ public static final String EXTRA_MAC_ADDRESS = PREFIX + "EXTRA_MAC_ADDRESS";
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
index bf73360..1477d95 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
@@ -22,4 +22,22 @@
public class Constant {
public static final String EXTRA_BINDER = "com.android.server.nearby.fastpair.BINDER";
public static final String EXTRA_BUNDLE = "com.android.server.nearby.fastpair.BUNDLE_EXTRA";
+ public static final String SUCCESS_STATE = "SUCCESS";
+ public static final String FAIL_STATE = "FAIL";
+ public static final String DISMISS = "DISMISS";
+ public static final String NEED_CONFIRM_PASSKEY = "NEED CONFIRM PASSKEY";
+ // device support assistant additional setup
+ public static final String NEED_ADDITIONAL_SETUP = "NEED ADDITIONAL SETUP";
+ public static final String SHOW_PAIRING_WITHOUT_INTERACTION =
+ "SHOW_PAIRING_WITHOUT_INTERACTION";
+ public static final String ACTION_FAST_PAIR_HALF_SHEET_CANCEL =
+ "com.android.nearby.ACTION_FAST_PAIR_HALF_SHEET_CANCEL";
+ public static final String ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET =
+ "com.android.nearby.ACTION_FAST_PAIR_BAN_STATE_RESET";
+ public static final String EXTRA_HALF_SHEET_INFO =
+ "com.android.nearby.halfsheet.HALF_SHEET";
+ public static final String EXTRA_HALF_SHEET_TYPE =
+ "com.android.nearby.halfsheet.HALF_SHEET_TYPE";
+ public static final String DEVICE_PAIRING_FRAGMENT_TYPE = "DEVICE_PAIRING";
+
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
index 56650ce..247339e 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -16,8 +16,12 @@
package com.android.server.nearby.fastpair;
+
+import static com.android.server.nearby.fastpair.Constant.DEVICE_PAIRING_FRAGMENT_TYPE;
import static com.android.server.nearby.fastpair.Constant.EXTRA_BINDER;
import static com.android.server.nearby.fastpair.Constant.EXTRA_BUNDLE;
+import static com.android.server.nearby.fastpair.Constant.EXTRA_HALF_SHEET_INFO;
+import static com.android.server.nearby.fastpair.Constant.EXTRA_HALF_SHEET_TYPE;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
@@ -35,6 +39,7 @@
import android.nearby.ScanCallback;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.Base64;
import android.util.Log;
import androidx.annotation.NonNull;
@@ -58,6 +63,8 @@
import com.android.server.nearby.fastpair.pairinghandler.PairingProgressHandlerBase;
import com.android.server.nearby.util.Environment;
+import com.google.protobuf.ByteString;
+
import java.security.GeneralSecurityException;
import java.util.List;
import java.util.concurrent.ExecutionException;
@@ -69,6 +76,7 @@
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
+import service.proto.Cache;
import service.proto.Rpcs;
/**
@@ -80,9 +88,12 @@
private static final String ACTION_PREFIX = UserActionHandler.PREFIX;
private static final int WAIT_FOR_UNLOCK_MILLIS = 5000;
private static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
- /** A notification ID which should be dismissed*/
+ /** A notification ID which should be dismissed */
public static final String EXTRA_NOTIFICATION_ID = ACTION_PREFIX + "EXTRA_NOTIFICATION_ID";
public static final String ACTION_RESOURCES_APK = "android.nearby.SHOW_HALFSHEET";
+ // Temp action deleted when the scanner is ready
+ public static final String ACTION_START_PAIRING = "NEARBY_START_PAIRING";
+ public static final String EXTRA_ADDRESS = "ADDRESS";
private static Executor sFastPairExecutor;
@@ -96,6 +107,17 @@
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.d("FastPairService", " screen on");
+ } else if (intent.getAction().equals(ACTION_START_PAIRING)) {
+ String address = intent.getStringExtra(EXTRA_ADDRESS);
+ String testPublicKey =
+ "E4kxROcAj2SPlqrxHgXOm_yF-XIMSS91pFrfmeLcxULWyn0nK8i52PPkoC4r"
+ + "LKRM2kZzNgT8bhDwK5njJAjiOg";
+ showHalfSheet(Cache.ScanFastPairStoreItem.newBuilder().setAddress(address)
+ .setAntiSpoofingPublicKey(ByteString.copyFrom(
+ Base64.decode(testPublicKey, Base64.URL_SAFE
+ | Base64.NO_WRAP | Base64.NO_PADDING)))
+ .build());
+ Log.d("FastPairService", "start pair " + address);
} else {
Log.d("FastPairService", " screen off");
}
@@ -128,12 +150,14 @@
}
};
+
/**
* Function called when nearby service start.
*/
public void initiate() {
mIntentFilter.addAction(Intent.ACTION_SCREEN_ON);
mIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
+ mIntentFilter.addAction("NEARBY_START_PAIRING");
mLocatorContextWrapper.getContext()
.registerReceiver(mScreenBroadcastReceiver, mIntentFilter);
@@ -228,7 +252,9 @@
item.getFastPairInformation().getDataOnlyConnection());
}
FastPairConnection connection = new FastPairDualConnection(
- context, item.getMacAddress(), prefsBuilder.build(), null);
+ context, item.getMacAddress(),
+ // Change to prefsBuilder.build when the api integration complete
+ Preferences.builderFromGmsLog().build(), null);
pairingProgressHandlerBase.onPairingSetupCompleted();
FastPairConnection.SharedSecret sharedSecret;
@@ -239,7 +265,7 @@
: item.getAuthenticationPublicKeySecp256R1());
byte[] key = pairingProgressHandlerBase.getKeyForLocalCache(accountKey,
- connection, sharedSecret);
+ connection, sharedSecret);
// We don't cache initial pairing case here but cache it when upload to footprints.
if (key != null) {
@@ -308,7 +334,8 @@
return manager == null ? null : manager.getAdapter();
}
- /** Gets the package name of HalfSheet.apk
+ /**
+ * Gets the package name of HalfSheet.apk
* getHalfSheetApkPkgName may invoke PackageManager multiple times and it does not have
* race condition check. Since there is no lock for mHalfSheetApkPkgName.
*/
@@ -318,8 +345,8 @@
}
List<ResolveInfo> resolveInfos = mLocatorContextWrapper.getContext()
.getPackageManager().queryIntentActivities(
- new Intent(ACTION_RESOURCES_APK),
- PackageManager.MATCH_SYSTEM_ONLY);
+ new Intent(ACTION_RESOURCES_APK),
+ PackageManager.MATCH_SYSTEM_ONLY);
// remove apps that don't live in the nearby apex
resolveInfos.removeIf(info ->
@@ -352,14 +379,19 @@
* Invokes half sheet in the other apk. This function can only be called in Nearby because other
* app can't get the correct component name.
*/
- void showHalfSheet() {
+ void showHalfSheet(Cache.ScanFastPairStoreItem scanFastPairStoreItem) {
if (mLocatorContextWrapper != null) {
String packageName = getHalfSheetApkPkgName();
HalfSheetCallback callback = new HalfSheetCallback();
+ callback.setmFastPairController(Locator
+ .getFromContextWrapper(mLocatorContextWrapper, FastPairController.class));
Bundle bundle = new Bundle();
bundle.putBinder(EXTRA_BINDER, callback);
mLocatorContextWrapper.getContext()
.startActivityAsUser(new Intent(ACTIVITY_INTENT_ACTION)
+ .putExtra(EXTRA_HALF_SHEET_INFO,
+ scanFastPairStoreItem.toByteArray())
+ .putExtra(EXTRA_HALF_SHEET_TYPE, DEVICE_PAIRING_FRAGMENT_TYPE)
.putExtra(EXTRA_BUNDLE, bundle)
.setComponent(new ComponentName(packageName,
packageName + ".HalfSheetActivity")),
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java
index 5444e82..e92bb8a 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java
@@ -18,9 +18,12 @@
import android.content.Context;
+import com.android.server.nearby.common.eventloop.EventLoop;
import com.android.server.nearby.common.locator.Locator;
import com.android.server.nearby.common.locator.Module;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
+import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
+import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
import java.time.Clock;
import java.time.Instant;
@@ -37,10 +40,16 @@
public void configure(Context context, Class<?> type, Locator locator) {
if (type.equals(FastPairCacheManager.class)) {
locator.bind(FastPairCacheManager.class, new FastPairCacheManager(context));
+ } else if (type.equals(FootprintsDeviceManager.class)) {
+ locator.bind(FootprintsDeviceManager.class, new FootprintsDeviceManager());
+ } else if (type.equals(EventLoop.class)) {
+ locator.bind(EventLoop.class, EventLoop.newInstance("NearbyFastPair"));
} else if (type.equals(FastPairController.class)) {
locator.bind(FastPairController.class, new FastPairController(context));
} else if (type.equals(FastPairCacheManager.class)) {
locator.bind(FastPairCacheManager.class, new FastPairCacheManager(context));
+ } else if (type.equals(FastPairHalfSheetManager.class)) {
+ locator.bind(FastPairHalfSheetManager.class, new FastPairHalfSheetManager());
} else if (type.equals(Clock.class)) {
locator.bind(Clock.class, new Clock() {
@Override
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/UserActionHandler.java b/nearby/service/java/com/android/server/nearby/fastpair/UserActionHandler.java
index f2b0d59..674633d 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/UserActionHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/UserActionHandler.java
@@ -25,4 +25,7 @@
public static final String EXTRA_DISCOVERY_ITEM = PREFIX + "EXTRA_DISCOVERY_ITEM";
public static final String EXTRA_FAST_PAIR_SECRET = PREFIX + "EXTRA_FAST_PAIR_SECRET";
+ public static final String ACTION_FAST_PAIR = ACTION_PREFIX + "ACTION_FAST_PAIR";
+ public static final String EXTRA_PRIVATE_BLE_ADDRESS =
+ ACTION_PREFIX + "EXTRA_PRIVATE_BLE_ADDRESS";
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
index d59305b..4c43965 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManager.java
@@ -17,6 +17,7 @@
package com.android.server.nearby.fastpair.halfsheet;
import android.bluetooth.BluetoothDevice;
+import android.util.Log;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
@@ -29,7 +30,7 @@
* Shows pairing fail half sheet.
*/
public void showPairingFailed() {
-
+ Log.d("FastPairHalfSheetManager", "show fail half sheet");
}
/**
@@ -42,30 +43,38 @@
/**
* Show passkey confirmation info on half sheet
*/
- public void showPasskeyConfirmation(BluetoothDevice device, int passkey) {}
+ public void showPasskeyConfirmation(BluetoothDevice device, int passkey) {
+ }
/**
* This function will handle pairing steps for half sheet.
*/
- public void showPairingHalfSheet(DiscoveryItem item) {}
+ public void showPairingHalfSheet(DiscoveryItem item) {
+ Log.d("FastPairHalfSheetManager", "show pairing half sheet");
+ }
/**
* Shows pairing success info.
*/
- public void showPairingSuccessHalfSheet(String address){}
+ public void showPairingSuccessHalfSheet(String address) {
+ Log.d("FastPairHalfSheetManager", "show success half sheet");
+ }
/**
* Removes dismiss runnable.
*/
- public void disableDismissRunnable(){}
+ public void disableDismissRunnable() {
+ }
/**
* Destroys the bluetooth pairing controller.
*/
- public void destroyBluetoothPairController(){}
+ public void destroyBluetoothPairController() {
+ }
/**
* Notify manager the pairing has finished.
*/
- public void notifyPairingProcessDone(boolean success, String address, DiscoveryItem item) {}
+ public void notifyPairingProcessDone(boolean success, String address, DiscoveryItem item) {
+ }
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
index fd9e460..2c792ed 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
@@ -16,15 +16,37 @@
package com.android.server.nearby.fastpair.halfsheet;
+import android.content.Intent;
import android.nearby.IFastPairHalfSheetCallback;
import android.util.Log;
+import com.android.server.nearby.fastpair.FastPairController;
+
+
/**
* Callback to send ux action back to nearby service.
*/
-public class HalfSheetCallback extends IFastPairHalfSheetCallback.Stub {
+public class HalfSheetCallback extends IFastPairHalfSheetCallback.Stub {
+ private FastPairController mFastPairController;
+
+ public HalfSheetCallback() {
+ }
+
+ /**
+ * Set function for Fast Pair controller.
+ */
+ public void setmFastPairController(FastPairController fastPairController) {
+ mFastPairController = fastPairController;
+ }
+
+ /**
+ * Half Sheet connection button clicked.
+ */
@Override
- public void onHalfSheetConnectionConfirm() {
+ public void onHalfSheetConnectionConfirm(Intent intent) {
Log.d("FastPairHalfSheet", "Call back receiver");
+ if (mFastPairController != null) {
+ mFastPairController.pair(intent);
+ }
}
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBase.java b/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBase.java
index 760b4e0..ccd7e5e 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBase.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBase.java
@@ -76,7 +76,8 @@
Log.v("PairingHandler",
- "PairingProgressHandler:Create %s for pairing");
+ "PairingProgressHandler:Create "
+ + item.getMacAddress() + " for pairing");
return pairingProgressHandlerBase;
}
@@ -134,7 +135,7 @@
* <li>1, optIn footprint for initial pairing.
* <li>2, write the device name to provider
* <li>2.1, generate default personalized name for initial pairing or get the personalized name
- * from footprint for subsequent pairing.
+ * from footprint for subsequent pairing.
* <li>2.2, set alias name for the bluetooth device.
* <li>2.3, update the device name for connection to write into provider for initial pair.
* <li>3, suppress battery notifications until oobe finishes.
@@ -180,7 +181,7 @@
*/
public void onPairingSuccess(String address) {
Log.v("PairingHandler", "PairingProgressHandler:onPairingSuccess with address: "
- + maskBluetoothAddress(address));
+ + maskBluetoothAddress(address));
}
private static void optInFootprintsForInitialPairing(
diff --git a/nearby/service/proto/src/fastpair/cache.proto b/nearby/service/proto/src/fastpair/cache.proto
index bf80b58..12731fb 100644
--- a/nearby/service/proto/src/fastpair/cache.proto
+++ b/nearby/service/proto/src/fastpair/cache.proto
@@ -304,3 +304,158 @@
reserved 5;
}
+
+// A locally cached Fast Pair device associating an account key with the
+// bluetooth address of the device.
+message StoredFastPairItem {
+ // The device's public mac address.
+ string mac_address = 1;
+
+ // The account key written to the device.
+ bytes account_key = 2;
+
+ // When user need to update provider name, enable this value to trigger
+ // writing new name to provider.
+ bool need_to_update_provider_name = 3;
+
+ // The retry times to update name into provider.
+ int32 update_name_retries = 4;
+
+ // Latest firmware version from the server.
+ string latest_firmware_version = 5;
+
+ // The firmware version that is on the device.
+ string device_firmware_version = 6;
+
+ // The timestamp from the last time we fetched the firmware version from the
+ // device.
+ int64 last_check_firmware_timestamp_millis = 7;
+
+ // The timestamp from the last time we fetched the firmware version from
+ // server.
+ int64 last_server_query_timestamp_millis = 8;
+
+ // Only allows one bloom filter check process to create gatt connection and
+ // try to read the firmware version value.
+ bool can_read_firmware = 9;
+
+ // Device's model id.
+ string model_id = 10;
+
+ // Features that this Fast Pair device supports.
+ repeated FastPairFeature features = 11;
+
+ // Keeps the stored discovery item in local cache, we can have most
+ // information of fast pair device locally without through footprints, i.e. we
+ // can have most fast pair features locally.
+ StoredDiscoveryItem discovery_item = 12;
+
+ // When true, the latest uploaded event to FMA is connected. We use
+ // it as the previous ACL state when getting the BluetoothAdapter STATE_OFF to
+ // determine if need to upload the disconnect event to FMA.
+ bool fma_state_is_connected = 13;
+
+ // Device's buffer size range.
+ repeated BufferSizeRange buffer_size_range = 18;
+
+ // The additional account key if this device could be associated with multiple
+ // accounts. Notes that for this device, the account_key field is the basic
+ // one which will not be associated with the accounts.
+ repeated bytes additional_account_key = 19;
+
+ // Deprecated fields.
+ reserved 14, 15, 16, 17;
+}
+
+// Contains information about Fast Pair devices stored through our scanner.
+// Next ID: 29
+message ScanFastPairStoreItem {
+ // Device's model id.
+ string model_id = 1;
+
+ // Device's RSSI value
+ int32 rssi = 2;
+
+ // Device's tx power
+ int32 tx_power = 3;
+
+ // Bytes of item icon in PNG format displayed in Discovery item list.
+ bytes icon_png = 4;
+
+ // A FIFE URL of the item icon displayed in Discovery item list.
+ string icon_fife_url = 28;
+
+ // Device name like "Bose QC 35".
+ string device_name = 5;
+
+ // Client timestamp when user last saw Fast Pair device.
+ int64 last_observation_timestamp_millis = 6;
+
+ // Action url after user click the notification.
+ string action_url = 7;
+
+ // Device's bluetooth address.
+ string address = 8;
+
+ // The computed threshold rssi value that would trigger FastPair notifications
+ int32 threshold_rssi = 9;
+
+ // Populated with the contents of the bloom filter in the event that
+ // the scanned device is advertising a bloom filter instead of a model id
+ bytes bloom_filter = 10;
+
+ // Device name from the BLE scan record
+ string ble_device_name = 11;
+
+ // Strings used for the FastPair UI
+ FastPairStrings fast_pair_strings = 12;
+
+ // A key used to authenticate advertising device.
+ // See NearbyItem.authentication_public_key_secp256r1 for more information.
+ bytes anti_spoofing_public_key = 13;
+
+ // When true, Fast Pair will only create a bond with the device and not
+ // attempt to connect any profiles (for example, A2DP or HFP).
+ bool data_only_connection = 14;
+
+ // The type of the manufacturer (first party, third party, etc).
+ int32 manufacturer_type_num = 15;
+
+ // Additional images that are attached specifically for true wireless Fast
+ // Pair devices.
+ TrueWirelessHeadsetImages true_wireless_images = 16;
+
+ // When true, this device can support assistant function.
+ bool assistant_supported = 17;
+
+ // Optional, the name of the company producing this Fast Pair device.
+ string company_name = 18;
+
+ // Features supported by the Fast Pair device.
+ FastPairFeature features = 19;
+
+ // The interaction type that this scan should trigger
+ InteractionType interaction_type = 20;
+
+ // The copy of the advertisement bytes, used to pass along to other
+ // apps that use Fast Pair as the discovery vehicle.
+ bytes full_ble_record = 21;
+
+ // Companion app related information
+ CompanionAppDetails companion_detail = 22;
+
+ // Client timestamp when user first saw Fast Pair device.
+ int64 first_observation_timestamp_millis = 23;
+
+ // The type of the device (wearable, headphones, etc).
+ int32 device_type_num = 24;
+
+ // The type of notification (app launch smart setup, etc).
+ NotificationType notification_type = 25;
+
+ // The customized title.
+ string customized_title = 26;
+
+ // The customized description.
+ string customized_description = 27;
+}
diff --git a/nearby/service/proto/src/fastpair/rpcs.proto b/nearby/service/proto/src/fastpair/rpcs.proto
index 384d471..0399d09 100644
--- a/nearby/service/proto/src/fastpair/rpcs.proto
+++ b/nearby/service/proto/src/fastpair/rpcs.proto
@@ -313,3 +313,17 @@
string fast_pair_tv_connect_device_no_account_description = 24;
}
+// The buffer size range of a Fast Pair devices support dynamic buffer size.
+message BufferSizeRange {
+ // The max buffer size in ms.
+ int32 max_size = 1;
+
+ // The min buffer size in ms.
+ int32 min_size = 2;
+
+ // The default buffer size in ms.
+ int32 default_size = 3;
+
+ // The codec of this buffer size range.
+ int32 codec = 4;
+}