[DO NOT MERGE] Fast Pair Half Sheet server side implementation
Refactor doc: go/fp-halfsheet-aosp
Bug: 196262706
Bug: 196644352
Bug: 218771606
Test: Built band verified flow manually
Change-Id: I86d81cd582482889946185a86399ebca21c84e56
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 5958007..0695b5f 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/Constant.java
@@ -33,22 +33,11 @@
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/FastPairController.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
index 793e126..1264ade 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -16,21 +16,15 @@
package com.android.server.nearby.fastpair;
-import static com.android.server.nearby.common.bluetooth.fastpair.BroadcastConstants.EXTRA_RETROACTIVE_PAIR;
-import static com.android.server.nearby.common.fastpair.service.UserActionHandlerBase.EXTRA_COMPANION_APP;
-import static com.android.server.nearby.fastpair.FastPairManager.EXTRA_NOTIFICATION_ID;
-
-import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.primitives.Bytes.concat;
import android.accounts.Account;
import android.annotation.Nullable;
import android.content.Context;
-import android.content.Intent;
+import android.nearby.FastPairDevice;
import android.text.TextUtils;
import android.util.Log;
-import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
import com.android.server.nearby.common.bluetooth.fastpair.BluetoothAddress;
@@ -110,73 +104,60 @@
/**
* Pairing function.
*/
- @UiThread
- public void pair(Intent intent) {
- String itemId = intent.getStringExtra(UserActionHandler.EXTRA_ITEM_ID);
- int notificationId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
- byte[] discoveryItem = intent.getByteArrayExtra(UserActionHandler.EXTRA_DISCOVERY_ITEM);
- String accountKeyString = intent.getStringExtra(UserActionHandler.EXTRA_FAST_PAIR_SECRET);
- String companionApp = trimCompanionApp(intent.getStringExtra(EXTRA_COMPANION_APP));
- byte[] accountKey = accountKeyString != null ? base16().decode(accountKeyString) : null;
- boolean isRetroactivePair = intent.getBooleanExtra(EXTRA_RETROACTIVE_PAIR, false);
+ public void pair(FastPairDevice fastPairDevice) {
+ byte[] discoveryItem = fastPairDevice.getData();
+ String modelId = fastPairDevice.getModelId();
+ Log.v(TAG, "pair: fastPairDevice " + fastPairDevice);
mEventLoop.postRunnable(
- new NamedRunnable("fastPairWith=" + itemId) {
+ new NamedRunnable("fastPairWith=" + modelId) {
@Override
public void run() {
- DiscoveryItem item = null;
- if (discoveryItem != null) {
- try {
- item = new DiscoveryItem(mContext,
- Cache.StoredDiscoveryItem.parseFrom(discoveryItem));
- } catch (InvalidProtocolBufferException e) {
- Log.w(TAG,
- "Error parsing serialized discovery item with size "
- + discoveryItem.length);
+ try {
+ DiscoveryItem item = new DiscoveryItem(mContext,
+ Cache.StoredDiscoveryItem.parseFrom(discoveryItem));
+ if (TextUtils.isEmpty(item.getMacAddress())) {
+ Log.w(TAG, "There is no mac address in the DiscoveryItem,"
+ + " ignore pairing");
return;
}
+ // Check enabled state to prevent multiple pair attempts if we get the
+ // intent more than once (this can happen due to an Android platform
+ // bug - b/31459521).
+ if (item.getState()
+ != Cache.StoredDiscoveryItem.State.STATE_ENABLED) {
+ Log.d(TAG, "Incorrect state, ignore pairing");
+ return;
+ }
+ boolean useLargeNotifications =
+ item.getAuthenticationPublicKeySecp256R1() != null;
+ FastPairNotificationManager fastPairNotificationManager =
+ new FastPairNotificationManager(mContext, item,
+ useLargeNotifications);
+ FastPairHalfSheetManager fastPairHalfSheetManager =
+ Locator.get(mContext, FastPairHalfSheetManager.class);
+ mFastPairCacheManager.saveDiscoveryItem(item);
+
+ PairingProgressHandlerBase pairingProgressHandlerBase =
+ PairingProgressHandlerBase.create(
+ mContext,
+ item,
+ /* companionApp= */ null,
+ /* accountKey= */ null,
+ mFootprintsDeviceManager,
+ fastPairNotificationManager,
+ fastPairHalfSheetManager,
+ /* isRetroactivePair= */ false);
+
+ pair(item,
+ /* accountKey= */ null,
+ /* companionApp= */ null,
+ pairingProgressHandlerBase);
+ } catch (InvalidProtocolBufferException e) {
+ Log.w(TAG,
+ "Error parsing serialized discovery item with size "
+ + discoveryItem.length);
}
-
-
- if (item == null || TextUtils.isEmpty(item.getMacAddress())) {
- Log.w(TAG, "Invalid DiscoveryItem, ignore pairing");
- return;
- }
-
- // Check enabled state to prevent multiple pair attempts if we get the
- // intent more than once (this can happen due to an Android platform
- // bug - b/31459521).
- if (item.getState() != Cache.StoredDiscoveryItem.State.STATE_ENABLED
- && !isRetroactivePair) {
- Log.d(TAG, "Incorrect state, ignore pairing");
- return;
- }
-
- boolean useLargeNotifications = accountKey != null
- || item.getAuthenticationPublicKeySecp256R1() != null;
- FastPairNotificationManager fastPairNotificationManager =
- notificationId == -1
- ? new FastPairNotificationManager(mContext, item,
- useLargeNotifications)
- : new FastPairNotificationManager(mContext, item,
- useLargeNotifications, notificationId);
- FastPairHalfSheetManager fastPairHalfSheetManager =
- Locator.get(mContext, FastPairHalfSheetManager.class);
-
- mFastPairCacheManager.saveDiscoveryItem(item);
-
- PairingProgressHandlerBase pairingProgressHandlerBase =
- PairingProgressHandlerBase.create(
- mContext,
- item,
- companionApp,
- accountKey,
- mFootprintsDeviceManager,
- fastPairNotificationManager,
- fastPairHalfSheetManager,
- isRetroactivePair);
-
- pair(item, accountKey, companionApp, pairingProgressHandlerBase);
}
});
}
@@ -315,4 +296,4 @@
interface Callback {
void fastPairUpdateDeviceItemsEnabled(boolean enabled);
}
-}
+}
\ No newline at end of file
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 9e1a718..3a3c962 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -56,6 +56,7 @@
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
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 com.android.server.nearby.fastpair.pairinghandler.PairingProgressHandlerBase;
import com.android.server.nearby.util.FastPairDecoder;
import com.android.server.nearby.util.ForegroundThread;
@@ -194,7 +195,7 @@
@Nullable byte[] accountKey,
FootprintsDeviceManager footprints,
PairingProgressHandlerBase pairingProgressHandlerBase) {
-
+ FastPairHalfSheetManager manager = Locator.get(context, FastPairHalfSheetManager.class);
try {
pairingProgressHandlerBase.onPairingStarted();
if (pairingProgressHandlerBase.skipWaitingScreenUnlock()) {
@@ -279,6 +280,10 @@
// Fast Pair one
connection.pair();
}
+
+ // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
+ // pairingProgressHandlerBase class.
+ manager.showPairingSuccessHalfSheet(connection.getPublicAddress());
pairingProgressHandlerBase.onPairingSuccess(connection.getPublicAddress());
} catch (BluetoothException
| InterruptedException
@@ -287,7 +292,11 @@
| ExecutionException
| PairingException
| GeneralSecurityException e) {
- Log.e(TAG, "FastPair: Error");
+ Log.e(TAG, "Failed to pair.", e);
+
+ // TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
+ // pairingProgressHandlerBase class.
+ manager.showPairingFailed();
pairingProgressHandlerBase.onPairingFailed(e);
}
}
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 42839b2..6f79e6e 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
@@ -29,10 +29,14 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.nearby.FastPairDevice;
+import android.nearby.FastPairStatusCallback;
+import android.nearby.PairStatusMetadata;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.nearby.common.locator.LocatorContextWrapper;
import com.android.server.nearby.fastpair.FastPairController;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
@@ -47,27 +51,24 @@
* Fast Pair ux manager for half sheet.
*/
public class FastPairHalfSheetManager {
- static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
+ private static final String ACTIVITY_INTENT_ACTION = "android.nearby.SHOW_HALFSHEET";
private static final String HALF_SHEET_CLASS_NAME =
"com.android.nearby.halfsheet.HalfSheetActivity";
+ private static final String TAG = "FPHalfSheetManager";
private String mHalfSheetApkPkgName;
- private Context mContext;
- private LocatorContextWrapper mLocatorContextWrapper;
+ private final LocatorContextWrapper mLocatorContextWrapper;
- /**
- * Construct function
- */
+ FastPairService mFastPairService;
+
public FastPairHalfSheetManager(Context context) {
- mContext = context;
- mLocatorContextWrapper = new LocatorContextWrapper(context);
+ this(new LocatorContextWrapper(context));
}
- /**
- * Construct function for test
- */
- public FastPairHalfSheetManager(LocatorContextWrapper locatorContextWrapper) {
+ @VisibleForTesting
+ FastPairHalfSheetManager(LocatorContextWrapper locatorContextWrapper) {
mLocatorContextWrapper = locatorContextWrapper;
+ mFastPairService = new FastPairService();
}
/**
@@ -79,14 +80,13 @@
if (mLocatorContextWrapper != null) {
String packageName = getHalfSheetApkPkgName();
if (packageName == null) {
- Log.e("FastPairHalfSheetManager", "package name is null");
+ Log.e(TAG, "package name is null");
return;
}
- HalfSheetCallback callback = new HalfSheetCallback();
- callback.setmFastPairController(
+ mFastPairService.setFastPairController(
mLocatorContextWrapper.getLocator().get(FastPairController.class));
Bundle bundle = new Bundle();
- bundle.putBinder(EXTRA_BINDER, callback);
+ bundle.putBinder(EXTRA_BINDER, mFastPairService);
mLocatorContextWrapper
.startActivityAsUser(new Intent(ACTIVITY_INTENT_ACTION)
.putExtra(EXTRA_HALF_SHEET_INFO,
@@ -97,11 +97,9 @@
.setComponent(new ComponentName(packageName,
HALF_SHEET_CLASS_NAME)),
UserHandle.CURRENT);
-
}
} catch (IllegalStateException e) {
- Log.e("FastPairHalfSheetManager",
- "Can't resolve package that contains half sheet");
+ Log.e(TAG, "Can't resolve package that contains half sheet");
}
}
@@ -109,7 +107,15 @@
* Shows pairing fail half sheet.
*/
public void showPairingFailed() {
- Log.d("FastPairHalfSheetManager", "show fail half sheet");
+ FastPairStatusCallback pairStatusCallback = mFastPairService.getPairStatusCallback();
+ if (pairStatusCallback != null) {
+ Log.v(TAG, "showPairingFailed: pairStatusCallback not NULL");
+ pairStatusCallback.onPairUpdate(new FastPairDevice.Builder().build(),
+ new PairStatusMetadata(PairStatusMetadata.Status.FAIL));
+ } else {
+ Log.w(TAG, "FastPairHalfSheetManager failed to show success half sheet because "
+ + "the pairStatusCallback is null");
+ }
}
/**
@@ -129,14 +135,22 @@
* This function will handle pairing steps for half sheet.
*/
public void showPairingHalfSheet(DiscoveryItem item) {
- Log.d("FastPairHalfSheetManager", "show pairing half sheet");
+ Log.d(TAG, "show pairing half sheet");
}
/**
* Shows pairing success info.
*/
public void showPairingSuccessHalfSheet(String address) {
- Log.d("FastPairHalfSheetManager", "show success half sheet");
+ FastPairStatusCallback pairStatusCallback = mFastPairService.getPairStatusCallback();
+ if (pairStatusCallback != null) {
+ pairStatusCallback.onPairUpdate(
+ new FastPairDevice.Builder().setBluetoothAddress(address).build(),
+ new PairStatusMetadata(PairStatusMetadata.Status.SUCCESS));
+ } else {
+ Log.w(TAG, "FastPairHalfSheetManager failed to show success half sheet because "
+ + "the pairStatusCallback is null");
+ }
}
/**
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
index 53c2c12..8c0d572 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/FastPairService.java
@@ -73,7 +73,13 @@
* Asks the Fast Pair service to pair the device.
*/
@Override
- public void connect(FastPairDevice fastPairDevice) {}
+ public void connect(FastPairDevice fastPairDevice) {
+ if (mFastPairController != null) {
+ mFastPairController.pair(fastPairDevice);
+ } else {
+ Log.w(TAG, "Failed to connect because there is no FastPairController.");
+ }
+ }
public FastPairStatusCallback getPairStatusCallback() {
return mFastPairStatusCallback;
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
deleted file mode 100644
index 2c792ed..0000000
--- a/nearby/service/java/com/android/server/nearby/fastpair/halfsheet/HalfSheetCallback.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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 {
- 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(Intent intent) {
- Log.d("FastPairHalfSheet", "Call back receiver");
- if (mFastPairController != null) {
- mFastPairController.pair(intent);
- }
- }
-}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
index ab18f54..58e4c47 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/halfsheet/FastPairHalfSheetManagerTest.java
@@ -16,11 +16,6 @@
package com.android.server.nearby.fastpair.halfsheet;
-
-import static com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager.ACTIVITY_INTENT_ACTION;
-
-import static com.google.common.truth.Truth.assertThat;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -72,7 +67,6 @@
public void setup() {
MockitoAnnotations.initMocks(this);
-
mScanFastPairStoreItem = Cache.ScanFastPairStoreItem.newBuilder()
.setAddress(BLEADDRESS)
.setDeviceName(NAME)
@@ -85,7 +79,6 @@
ResolveInfo resolveInfo = new ResolveInfo();
List<ResolveInfo> resolveInfoList = new ArrayList<>();
-
mPackageManager = mock(PackageManager.class);
when(mContextWrapper.getPackageManager()).thenReturn(mPackageManager);
resolveInfo.activityInfo = new ActivityInfo();
@@ -108,8 +101,6 @@
verify(mContextWrapper, atLeastOnce())
.startActivityAsUser(intentArgumentCaptor.capture(), eq(UserHandle.CURRENT));
- Intent launchIntent = intentArgumentCaptor.getValue();
- assertThat(launchIntent.getAction()).isEqualTo(ACTIVITY_INTENT_ACTION);
}
@Test
@@ -118,7 +109,6 @@
ResolveInfo resolveInfo = new ResolveInfo();
List<ResolveInfo> resolveInfoList = new ArrayList<>();
-
mPackageManager = mock(PackageManager.class);
when(mContextWrapper.getPackageManager()).thenReturn(mPackageManager);
resolveInfo.activityInfo = new ActivityInfo();
@@ -142,6 +132,5 @@
verify(mContextWrapper, never())
.startActivityAsUser(intentArgumentCaptor.capture(), eq(UserHandle.CURRENT));
-
}
}