[Fast Pair] Add FastpairNotificationManager logic for subsequent pairing
e2e video: https://photos.app.goo.gl/WawkcRm9eND3HfBb7
Test: -m
Fix: 247152236
Ignore-AOSP-First: nearby_not_in_aosp_yet
Change-Id: If2913e5072f130425315d203eb7eb03236968a68
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
index 7564716..412b738 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
@@ -36,6 +36,7 @@
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
+import com.android.server.nearby.fastpair.notification.FastPairNotificationManager;
import com.android.server.nearby.provider.FastPairDataProvider;
import com.android.server.nearby.util.ArrayUtils;
import com.android.server.nearby.util.DataUtils;
@@ -215,15 +216,11 @@
Log.d(TAG, "bloom filter is recognized in the cache");
continue;
}
-
- if (mIsFirst) {
- mIsFirst = false;
- pair(account, scannedDevice, recognizedDevice);
- }
+ showSubsequentNotification(account, scannedDevice, recognizedDevice);
}
}
- private void pair(Account account, FastPairDevice scannedDevice,
+ private void showSubsequentNotification(Account account, FastPairDevice scannedDevice,
Data.FastPairDeviceWithAccountKey recognizedDevice) {
// Get full info from api the initial request will only return
// part of the info due to size limit.
@@ -242,12 +239,13 @@
.setMacAddress(
scannedDevice.getBluetoothAddress())
.build();
-
- // Connect and show notification
- Locator.get(mContext, FastPairController.class).pair(
- new DiscoveryItem(mContext, storedDiscoveryItem),
- devicesWithAccountKeys.get(0).getAccountKey().toByteArray(),
- /* companionApp= */ null);
+ // Show notification
+ FastPairNotificationManager fastPairNotificationManager =
+ Locator.get(mContext, FastPairNotificationManager.class);
+ DiscoveryItem item = new DiscoveryItem(mContext, storedDiscoveryItem);
+ Locator.get(mContext, FastPairCacheManager.class).saveDiscoveryItem(item);
+ fastPairNotificationManager.showDiscoveryNotification(item,
+ devicesWithAccountKeys.get(0).getAccountKey().toByteArray());
}
// Battery advertisement format:
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 e1db7e5..447d199 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -129,11 +129,8 @@
Log.d(TAG, "Incorrect state, ignore pairing");
return;
}
- boolean useLargeNotifications =
- item.getAuthenticationPublicKeySecp256R1() != null;
FastPairNotificationManager fastPairNotificationManager =
- new FastPairNotificationManager(mContext, item,
- useLargeNotifications);
+ Locator.get(mContext, FastPairNotificationManager.class);
FastPairHalfSheetManager fastPairHalfSheetManager =
Locator.get(mContext, FastPairHalfSheetManager.class);
mFastPairCacheManager.saveDiscoveryItem(item);
@@ -169,7 +166,7 @@
@Nullable byte[] accountKey,
@Nullable String companionApp) {
FastPairNotificationManager fastPairNotificationManager =
- new FastPairNotificationManager(mContext, item, false);
+ Locator.get(mContext, FastPairNotificationManager.class);
FastPairHalfSheetManager fastPairHalfSheetManager =
Locator.get(mContext, FastPairHalfSheetManager.class);
PairingProgressHandlerBase pairingProgressHandlerBase =
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 ea8c386..1ef98e5 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -16,6 +16,7 @@
package com.android.server.nearby.fastpair;
+import static com.android.nearby.halfsheet.constants.Constant.ACTION_FAST_PAIR;
import static com.android.nearby.halfsheet.constants.Constant.ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET;
import static com.android.nearby.halfsheet.constants.Constant.ACTION_FAST_PAIR_HALF_SHEET_CANCEL;
import static com.android.nearby.halfsheet.constants.Constant.ACTION_HALF_SHEET_FOREGROUND_STATE;
@@ -23,6 +24,8 @@
import static com.android.nearby.halfsheet.constants.FastPairConstants.EXTRA_MODEL_ID;
import static com.android.server.nearby.fastpair.Constant.TAG;
+import static com.google.common.io.BaseEncoding.base16;
+
import android.annotation.Nullable;
import android.annotation.WorkerThread;
import android.app.KeyguardManager;
@@ -103,6 +106,7 @@
final IntentFilter mIntentFilter;
final Locator mLocator;
private boolean mScanEnabled;
+ private final FastPairCacheManager mFastPairCacheManager;
private final BroadcastReceiver mScreenBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -147,9 +151,29 @@
}
Locator.get(mLocatorContextWrapper, FastPairHalfSheetManager.class)
.dismiss(modelId);
-
+ break;
+ case ACTION_FAST_PAIR:
+ Log.d(TAG, "onReceive: ACTION_FAST_PAIR");
+ String itemId = intent.getStringExtra(UserActionHandler.EXTRA_ITEM_ID);
+ String accountKeyString = intent
+ .getStringExtra(UserActionHandler.EXTRA_FAST_PAIR_SECRET);
+ if (itemId == null || accountKeyString == null) {
+ Log.d(TAG, "skip pair action, item id "
+ + "or fast pair account key not found");
+ break;
+ }
+ try {
+ FastPairController controller =
+ Locator.getFromContextWrapper(mLocatorContextWrapper,
+ FastPairController.class);
+ if (mFastPairCacheManager != null) {
+ controller.pair(mFastPairCacheManager.getDiscoveryItem(itemId),
+ base16().decode(accountKeyString), /* companionApp= */ null);
+ }
+ } catch (IllegalStateException e) {
+ Log.e(TAG, "Cannot find FastPairController class", e);
+ }
}
-
}
};
@@ -160,6 +184,8 @@
mLocator.bind(new FastPairModule());
Rpcs.GetObservedDeviceResponse getObservedDeviceResponse =
Rpcs.GetObservedDeviceResponse.newBuilder().build();
+ mFastPairCacheManager =
+ Locator.getFromContextWrapper(mLocatorContextWrapper, FastPairCacheManager.class);
}
final ScanCallback mScanCallback = new ScanCallback() {
@@ -199,11 +225,11 @@
mIntentFilter.addAction(ACTION_FAST_PAIR_HALF_SHEET_CANCEL);
mIntentFilter.addAction(ACTION_FAST_PAIR_HALF_SHEET_BAN_STATE_RESET);
mIntentFilter.addAction(ACTION_HALF_SHEET_FOREGROUND_STATE);
+ mIntentFilter.addAction(ACTION_FAST_PAIR);
mLocatorContextWrapper.getContext().registerReceiver(mScreenBroadcastReceiver,
mIntentFilter, Context.RECEIVER_EXPORTED);
- Locator.getFromContextWrapper(mLocatorContextWrapper, FastPairCacheManager.class);
// Default false for now.
mScanEnabled = NearbyManager.isFastPairScanEnabled(mLocatorContextWrapper.getContext());
registerFastPairScanChangeContentObserver(mLocatorContextWrapper.getContentResolver());
@@ -307,6 +333,13 @@
context, item.getMacAddress(),
prefsBuilder.build(),
null);
+ connection.setOnPairedCallback(
+ address -> {
+ Log.v(TAG, "connection on paired callback;");
+ // TODO(b/259150992) add fill Bluetooth metadata values logic
+ pairingProgressHandlerBase.onPairedCallbackCalled(
+ connection, accountKey, footprints, address);
+ });
pairingProgressHandlerBase.onPairingSetupCompleted();
FastPairConnection.SharedSecret sharedSecret;
@@ -474,7 +507,7 @@
NearbyManager nearbyManager = getNearbyManager();
if (nearbyManager == null) {
Log.w(TAG, "invalidateScan: "
- + "failed to start or stop scannning because NearbyManager is null.");
+ + "failed to start or stop scanning because NearbyManager is null.");
return;
}
if (mScanEnabled) {
@@ -504,8 +537,7 @@
processBackgroundTask(new Runnable() {
@Override
public void run() {
- mLocatorContextWrapper.getLocator().get(FastPairCacheManager.class)
- .removeStoredFastPairItem(device.getAddress());
+ mFastPairCacheManager.removeStoredFastPairItem(device.getAddress());
}
});
}
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 d7946d1..1df4723 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairModule.java
@@ -24,6 +24,7 @@
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.notification.FastPairNotificationManager;
import java.time.Clock;
import java.time.Instant;
@@ -52,6 +53,9 @@
locator.bind(FastPairHalfSheetManager.class, new FastPairHalfSheetManager(context));
} else if (type.equals(FastPairAdvHandler.class)) {
locator.bind(FastPairAdvHandler.class, new FastPairAdvHandler(context));
+ } else if (type.equals(FastPairNotificationManager.class)) {
+ locator.bind(FastPairNotificationManager.class,
+ new FastPairNotificationManager(context));
} else if (type.equals(Clock.class)) {
locator.bind(Clock.class, new Clock() {
@Override
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/notification/FastPairNotificationManager.java b/nearby/service/java/com/android/server/nearby/fastpair/notification/FastPairNotificationManager.java
index 65ad05e..c74249c 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/notification/FastPairNotificationManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/notification/FastPairNotificationManager.java
@@ -16,56 +16,166 @@
package com.android.server.nearby.fastpair.notification;
+import static com.android.server.nearby.fastpair.Constant.TAG;
import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
import android.content.Context;
+import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.nearby.halfsheet.R;
+import com.android.server.nearby.fastpair.HalfSheetResources;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
+import com.google.common.base.Objects;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
+import java.util.concurrent.TimeUnit;
+
/**
* Responsible for show notification logic.
*/
public class FastPairNotificationManager {
+ private static int sInstanceId = 0;
+ // Notification channel group ID for Devices notification channels.
+ private static final String DEVICES_CHANNEL_GROUP_ID = "DEVICES_CHANNEL_GROUP_ID";
// These channels are rebranded string because they are migrated from different channel ID they
// should not be changed.
// Channel ID for channel "Devices within reach".
static final String DEVICES_WITHIN_REACH_CHANNEL_ID = "DEVICES_WITHIN_REACH_REBRANDED";
+ // Channel ID for channel "Devices".
+ static final String DEVICES_CHANNEL_ID = "DEVICES_REBRANDED";
+ // Channel ID for channel "Devices with your account".
+ public static final String DEVICES_WITH_YOUR_ACCOUNT_CHANNEL_ID = "DEVICES_WITH_YOUR_ACCOUNT";
+
+ // Default channel importance for channel "Devices within reach".
+ private static final int DEFAULT_DEVICES_WITHIN_REACH_CHANNEL_IMPORTANCE =
+ NotificationManager.IMPORTANCE_HIGH;
+ // Default channel importance for channel "Devices".
+ private static final int DEFAULT_DEVICES_CHANNEL_IMPORTANCE =
+ NotificationManager.IMPORTANCE_LOW;
+ // Default channel importance for channel "Devices with your account".
+ private static final int DEFAULT_DEVICES_WITH_YOUR_ACCOUNT_CHANNEL_IMPORTANCE =
+ NotificationManager.IMPORTANCE_MIN;
+
+ /** Fixed notification ID that won't duplicated with {@code notificationId}. */
+ private static final int MAGIC_PAIR_NOTIFICATION_ID = "magic_pair_notification_id".hashCode();
+ /** Fixed notification ID that won't duplicated with {@code mNotificationId}. */
+ @VisibleForTesting
+ static final int PAIR_SUCCESS_NOTIFICATION_ID = MAGIC_PAIR_NOTIFICATION_ID - 1;
+ /** Fixed notification ID for showing the pairing failure notification. */
+ @VisibleForTesting static final int PAIR_FAILURE_NOTIFICATION_ID =
+ MAGIC_PAIR_NOTIFICATION_ID - 3;
+
+ /**
+ * The amount of delay enforced between notifications. The system only allows 10 notifications /
+ * second, but delays in the binder IPC can cause overlap.
+ */
+ private static final long MIN_NOTIFICATION_DELAY_MILLIS = 300;
+
+ // To avoid a (really unlikely) race where the user pairs and succeeds quickly more than once,
+ // use a unique ID per session, so we can delay cancellation without worrying.
+ // This is for connecting related notifications only. Discovery notification will use item id
+ // as notification id.
+ @VisibleForTesting
+ final int mNotificationId;
+ private HalfSheetResources mResources;
+ private final FastPairNotifications mNotifications;
+ private boolean mDiscoveryNotificationEnable = true;
+ // A static cache that remembers all recently shown notifications. We use this to throttle
+ // ourselves from showing notifications too rapidly. If we attempt to show a notification faster
+ // than once every 100ms, the later notifications will be dropped and we'll show stale state.
+ // Maps from Key -> Uptime Millis
+ private final Cache<Key, Long> mNotificationCache =
+ CacheBuilder.newBuilder()
+ .maximumSize(100)
+ .expireAfterWrite(MIN_NOTIFICATION_DELAY_MILLIS, TimeUnit.MILLISECONDS)
+ .build();
+ private NotificationManager mNotificationManager;
/**
* FastPair notification manager that handle notification ui for fast pair.
*/
- public FastPairNotificationManager(Context context, DiscoveryItem item, boolean useLargeIcon,
- int notificationId) {
+ @VisibleForTesting
+ public FastPairNotificationManager(Context context, int notificationId,
+ NotificationManager notificationManager, HalfSheetResources resources) {
+ mNotificationId = notificationId;
+ mNotificationManager = notificationManager;
+ mResources = resources;
+ mNotifications = new FastPairNotifications(context, mResources);
+
+ configureDevicesNotificationChannels();
}
+
/**
* FastPair notification manager that handle notification ui for fast pair.
*/
- public FastPairNotificationManager(Context context, DiscoveryItem item, boolean useLargeIcon) {
+ public FastPairNotificationManager(Context context, int notificationId) {
+ this(context, notificationId, context.getSystemService(NotificationManager.class),
+ new HalfSheetResources(context));
+ }
+ /**
+ * FastPair notification manager that handle notification ui for fast pair.
+ */
+ public FastPairNotificationManager(Context context) {
+ this(context, /* notificationId= */ MAGIC_PAIR_NOTIFICATION_ID + sInstanceId);
+
+ sInstanceId++;
+ }
+
+ /**
+ * Shows the notification when found saved device. A notification will be like
+ * "Your saved device is available."
+ * This uses item id as notification Id. This should be disabled when connecting starts.
+ */
+ public void showDiscoveryNotification(DiscoveryItem item, byte[] accountKey) {
+ if (mDiscoveryNotificationEnable) {
+ Log.v(TAG, "the discovery notification is disabled");
+ return;
+ }
+
+ show(item.getId().hashCode(), mNotifications.discoveryNotification(item, accountKey));
}
/**
* Shows pairing in progress notification.
*/
- public void showConnectingNotification() {}
+ public void showConnectingNotification(DiscoveryItem item) {
+ disableShowDiscoveryNotification();
+ cancel(PAIR_FAILURE_NOTIFICATION_ID);
+ show(mNotificationId, mNotifications.progressNotification(item));
+ }
/**
- * Shows success notification
+ * Shows when Fast Pair successfully pairs the headset.
*/
public void showPairingSucceededNotification(
- @Nullable String companionApp,
+ DiscoveryItem item,
int batteryLevel,
- @Nullable String deviceName,
- String address) {
-
+ @Nullable String deviceName) {
+ enableShowDiscoveryNotification();
+ cancel(mNotificationId);
+ show(PAIR_SUCCESS_NOTIFICATION_ID,
+ mNotifications
+ .pairingSucceededNotification(
+ batteryLevel, deviceName, item.getTitle(), item));
}
/**
* Shows failed notification.
*/
- public void showPairingFailedNotification(byte[] accountKey) {
-
+ public synchronized void showPairingFailedNotification(DiscoveryItem item, byte[] accountKey) {
+ enableShowDiscoveryNotification();
+ cancel(mNotificationId);
+ show(PAIR_FAILURE_NOTIFICATION_ID,
+ mNotifications.showPairingFailedNotification(item, accountKey));
}
/**
@@ -73,4 +183,98 @@
*/
public void notifyPairingProcessDone(boolean success, boolean forceNotify,
String privateAddress, String publicAddress) {}
+
+ /** Enables the discovery notification when pairing is in progress */
+ public void enableShowDiscoveryNotification() {
+ Log.v(TAG, "enabling discovery notification");
+ mDiscoveryNotificationEnable = true;
+ }
+
+ /** Disables the discovery notification when pairing is in progress */
+ public synchronized void disableShowDiscoveryNotification() {
+ Log.v(TAG, "disabling discovery notification");
+ mDiscoveryNotificationEnable = false;
+ }
+
+ private void show(int id, Notification notification) {
+ mNotificationManager.notify(id, notification);
+ }
+
+ /**
+ * Configures devices related notification channels, including "Devices" and "Devices within
+ * reach" channels.
+ */
+ private void configureDevicesNotificationChannels() {
+ mNotificationManager.createNotificationChannelGroup(
+ new NotificationChannelGroup(
+ DEVICES_CHANNEL_GROUP_ID,
+ mResources.get().getString(R.string.common_devices)));
+ mNotificationManager.createNotificationChannel(
+ createNotificationChannel(
+ DEVICES_WITHIN_REACH_CHANNEL_ID,
+ mResources.get().getString(R.string.devices_within_reach_channel_name),
+ DEFAULT_DEVICES_WITHIN_REACH_CHANNEL_IMPORTANCE,
+ DEVICES_CHANNEL_GROUP_ID));
+ mNotificationManager.createNotificationChannel(
+ createNotificationChannel(
+ DEVICES_CHANNEL_ID,
+ mResources.get().getString(R.string.common_devices),
+ DEFAULT_DEVICES_CHANNEL_IMPORTANCE,
+ DEVICES_CHANNEL_GROUP_ID));
+ mNotificationManager.createNotificationChannel(
+ createNotificationChannel(
+ DEVICES_WITH_YOUR_ACCOUNT_CHANNEL_ID,
+ mResources.get().getString(R.string.devices_with_your_account_channel_name),
+ DEFAULT_DEVICES_WITH_YOUR_ACCOUNT_CHANNEL_IMPORTANCE,
+ DEVICES_CHANNEL_GROUP_ID));
+ }
+
+ private NotificationChannel createNotificationChannel(
+ String channelId, String channelName, int channelImportance, String channelGroupId) {
+ NotificationChannel channel =
+ new NotificationChannel(channelId, channelName, channelImportance);
+ channel.setGroup(channelGroupId);
+ if (channelImportance >= NotificationManager.IMPORTANCE_HIGH) {
+ channel.setSound(/* sound= */ null, /* audioAttributes= */ null);
+ // Disable vibration. Otherwise, the silent sound triggers a vibration if your
+ // ring volume is set to vibrate (aka turned down all the way).
+ channel.enableVibration(false);
+ }
+
+ return channel;
+ }
+
+ /** Cancel a previously shown notification. */
+ public void cancel(int id) {
+ try {
+ mNotificationManager.cancel(id);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Failed to cancel notification " + id, e);
+ }
+ mNotificationCache.invalidate(new Key(id));
+ }
+
+ private static final class Key {
+ @Nullable final String mTag;
+ final int mId;
+
+ Key(int id) {
+ this.mTag = null;
+ this.mId = id;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o instanceof Key) {
+ Key that = (Key) o;
+ return Objects.equal(mTag, that.mTag) && (mId == that.mId);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(mTag == null ? 0 : mTag, mId);
+ }
+ }
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandler.java b/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandler.java
index d469c45..5317673 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandler.java
@@ -20,7 +20,6 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.content.Context;
-import android.text.TextUtils;
import android.util.Log;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
@@ -68,7 +67,7 @@
@Override
public void onReadyToPair() {
super.onReadyToPair();
- mFastPairNotificationManager.showConnectingNotification();
+ mFastPairNotificationManager.showConnectingNotification(mItem);
}
@Override
@@ -79,32 +78,24 @@
String address) {
String deviceName = super.onPairedCallbackCalled(connection, accountKey, footprints,
address);
-
int batteryLevel = -1;
BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
- if (bluetoothAdapter != null) {
- // Need to check battery level here set that to -1 for now
- batteryLevel = -1;
+ if (address != null && bluetoothAdapter != null) {
+ batteryLevel = bluetoothAdapter.getRemoteDevice(address).getBatteryLevel();
} else {
- Log.v(
- "NotificationPairingProgressHandler",
- "onPairedCallbackCalled getBatteryLevel failed,"
- + " adapter is null");
+ Log.v(TAG, "onPairedCallbackCalled getBatteryLevel failed");
}
- mFastPairNotificationManager.showPairingSucceededNotification(
- !TextUtils.isEmpty(mCompanionApp) ? mCompanionApp : null,
- batteryLevel,
- deviceName,
- address);
+ mFastPairNotificationManager
+ .showPairingSucceededNotification(mItem, batteryLevel, deviceName);
return deviceName;
}
@Override
public void onPairingFailed(Throwable throwable) {
super.onPairingFailed(throwable);
- mFastPairNotificationManager.showPairingFailedNotification(mAccountKey);
+ mFastPairNotificationManager.showPairingFailedNotification(mItem, mAccountKey);
mFastPairNotificationManager.notifyPairingProcessDone(
/* success= */ false,
/* forceNotify= */ false,
@@ -115,6 +106,19 @@
@Override
public void onPairingSuccess(String address) {
super.onPairingSuccess(address);
+ int batteryLevel = -1;
+
+ BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
+ BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
+ String deviceName = null;
+ if (address != null && bluetoothAdapter != null) {
+ deviceName = bluetoothAdapter.getRemoteDevice(address).getName();
+ batteryLevel = bluetoothAdapter.getRemoteDevice(address).getBatteryLevel();
+ } else {
+ Log.v(TAG, "onPairedCallbackCalled getBatteryLevel failed");
+ }
+ mFastPairNotificationManager
+ .showPairingSucceededNotification(mItem, batteryLevel, deviceName);
mFastPairNotificationManager.notifyPairingProcessDone(
/* success= */ true,
/* forceNotify= */ false,
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairAdvHandlerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairAdvHandlerTest.java
index 0544efc..900b618 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairAdvHandlerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/FastPairAdvHandlerTest.java
@@ -177,7 +177,8 @@
DiscoveryItem discoveryItem =
new DiscoveryItem(mLocatorContextWrapper, STORED_DISCOVERY_ITEM);
- verify(mFastPairController).pair(eq(discoveryItem), eq(ACCOUNT_KEY), eq(null));
+ verify(mFastPairNotificationManager).showDiscoveryNotification(eq(discoveryItem),
+ eq(ACCOUNT_KEY));
verify(mFastPairHalfSheetManager, never()).showHalfSheet(any());
}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationBuilderTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationBuilderTest.java
index b644c91..d995969 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationBuilderTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationBuilderTest.java
@@ -23,7 +23,6 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -69,7 +68,6 @@
mResolveInfoList = new ArrayList<>();
mResolveInfo.activityInfo = new ActivityInfo();
mApplicationInfo = new ApplicationInfo();
- mPackageManager = mock(PackageManager.class);
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo())
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationManagerTest.java
index 4fb6b37..9670a3f 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/notification/FastPairNotificationManagerTest.java
@@ -18,38 +18,62 @@
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.content.Context;
+import android.content.res.Resources;
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.server.nearby.common.locator.Locator;
import com.android.server.nearby.common.locator.LocatorContextWrapper;
+import com.android.server.nearby.fastpair.HalfSheetResources;
+import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import service.proto.Cache;
+
public class FastPairNotificationManagerTest {
- @Mock private Context mContext;
- private static final boolean USE_LARGE_ICON = true;
+ @Mock
+ private Context mContext;
+ @Mock
+ NotificationManager mNotificationManager;
+ @Mock
+ Resources mResources;
+ @Mock
+ private LocatorContextWrapper mLocatorContextWrapper;
+ @Mock
+ private Locator mLocator;
+
private static final int NOTIFICATION_ID = 1;
- private static final String COMPANION_APP = "companionApp";
private static final int BATTERY_LEVEL = 1;
private static final String DEVICE_NAME = "deviceName";
- private static final String ADDRESS = "address";
private FastPairNotificationManager mFastPairNotificationManager;
- private LocatorContextWrapper mLocatorContextWrapper;
+ private DiscoveryItem mItem;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mLocatorContextWrapper = new LocatorContextWrapper(mContext);
when(mContext.getContentResolver()).thenReturn(
InstrumentationRegistry.getInstrumentation().getContext().getContentResolver());
+ when(mLocatorContextWrapper.getResources()).thenReturn(mResources);
+ when(mLocatorContextWrapper.getLocator()).thenReturn(mLocator);
+ HalfSheetResources.setResourcesContextForTest(mLocatorContextWrapper);
+ // Real context is needed
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ FastPairNotificationManager fastPairNotificationManager =
mFastPairNotificationManager =
- new FastPairNotificationManager(mLocatorContextWrapper, null,
- USE_LARGE_ICON, NOTIFICATION_ID);
+ new FastPairNotificationManager(context, NOTIFICATION_ID, mNotificationManager,
+ new HalfSheetResources(mLocatorContextWrapper));
+ mLocator.overrideBindingForTest(FastPairNotificationManager.class,
+ fastPairNotificationManager);
+
+ mItem = new DiscoveryItem(mLocatorContextWrapper,
+ Cache.StoredDiscoveryItem.newBuilder().setTitle("Device Name").build());
}
@Test
@@ -60,17 +84,18 @@
@Test
public void showConnectingNotification() {
- mFastPairNotificationManager.showConnectingNotification();
+ mFastPairNotificationManager.showConnectingNotification(mItem);
}
@Test
public void showPairingFailedNotification() {
- mFastPairNotificationManager.showPairingFailedNotification(new byte[]{1});
+ mFastPairNotificationManager
+ .showPairingFailedNotification(mItem, new byte[]{1});
}
@Test
public void showPairingSucceededNotification() {
- mFastPairNotificationManager.showPairingSucceededNotification(COMPANION_APP,
- BATTERY_LEVEL, DEVICE_NAME, ADDRESS);
+ mFastPairNotificationManager
+ .showPairingSucceededNotification(mItem, BATTERY_LEVEL, DEVICE_NAME);
}
}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandlerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandlerTest.java
index 24f296c..5c61ddb 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandlerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/NotificationPairingProgressHandlerTest.java
@@ -20,13 +20,18 @@
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.bluetooth.BluetoothManager;
+import android.content.Context;
+import android.content.res.Resources;
import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
import com.android.server.nearby.common.locator.Locator;
import com.android.server.nearby.common.locator.LocatorContextWrapper;
+import com.android.server.nearby.fastpair.HalfSheetResources;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
@@ -62,6 +67,10 @@
FootprintsDeviceManager mFootprintsDeviceManager;
@Mock
android.bluetooth.BluetoothManager mBluetoothManager;
+ @Mock
+ NotificationManager mNotificationManager;
+ @Mock
+ Resources mResources;
private static final String MAC_ADDRESS = "00:11:22:33:44:55";
private static final byte[] ACCOUNT_KEY = new byte[]{0x01, 0x02};
@@ -76,6 +85,9 @@
when(mContextWrapper.getSystemService(BluetoothManager.class))
.thenReturn(mBluetoothManager);
when(mContextWrapper.getLocator()).thenReturn(mLocator);
+ when(mContextWrapper.getResources()).thenReturn(mResources);
+ HalfSheetResources.setResourcesContextForTest(mContextWrapper);
+
mLocator.overrideBindingForTest(FastPairCacheManager.class,
mFastPairCacheManager);
mLocator.overrideBindingForTest(Clock.class, mClock);
@@ -126,11 +138,17 @@
private NotificationPairingProgressHandler createProgressHandler(
@Nullable byte[] accountKey, DiscoveryItem fastPairItem) {
- FastPairNotificationManager fastPairNotificationManager =
- new FastPairNotificationManager(mContextWrapper, fastPairItem, true);
FastPairHalfSheetManager fastPairHalfSheetManager =
new FastPairHalfSheetManager(mContextWrapper);
+ // Real context is needed
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ FastPairNotificationManager fastPairNotificationManager =
+ new FastPairNotificationManager(context, 1234, mNotificationManager,
+ new HalfSheetResources(mContextWrapper));
mLocator.overrideBindingForTest(FastPairHalfSheetManager.class, fastPairHalfSheetManager);
+ mLocator.overrideBindingForTest(FastPairNotificationManager.class,
+ fastPairNotificationManager);
+
NotificationPairingProgressHandler mNotificationPairingProgressHandler =
new NotificationPairingProgressHandler(
mContextWrapper,
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBaseTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBaseTest.java
index a3eb50c..6d769df 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBaseTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/pairinghandler/PairingProgressHandlerBaseTest.java
@@ -20,16 +20,21 @@
import static org.mockito.Mockito.when;
+import android.app.NotificationManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
+import android.content.Context;
+import android.content.res.Resources;
import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
import com.android.server.nearby.common.bluetooth.fastpair.Preferences;
import com.android.server.nearby.common.locator.Locator;
import com.android.server.nearby.common.locator.LocatorContextWrapper;
+import com.android.server.nearby.fastpair.HalfSheetResources;
import com.android.server.nearby.fastpair.cache.DiscoveryItem;
import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.footprint.FootprintsDeviceManager;
@@ -64,6 +69,10 @@
FastPairConnection mFastPairConnection;
@Mock
BluetoothManager mBluetoothManager;
+ @Mock
+ Resources mResources;
+ @Mock
+ NotificationManager mNotificationManager;
private static final String MAC_ADDRESS = "00:11:22:33:44:55";
private static final byte[] ACCOUNT_KEY = new byte[]{0x01, 0x02};
@@ -81,6 +90,9 @@
mLocator.overrideBindingForTest(FastPairCacheManager.class,
mFastPairCacheManager);
mLocator.overrideBindingForTest(Clock.class, mClock);
+ when(mContextWrapper.getResources()).thenReturn(mResources);
+ HalfSheetResources.setResourcesContextForTest(mContextWrapper);
+
sBluetoothDevice =
BluetoothAdapter.getDefaultAdapter().getRemoteDevice("00:11:22:33:44:55");
sDiscoveryItem = FakeDiscoveryItems.newFastPairDiscoveryItem(mContextWrapper);
@@ -205,10 +217,17 @@
private PairingProgressHandlerBase createProgressHandler(
@Nullable byte[] accountKey, DiscoveryItem fastPairItem, boolean isRetroactivePair) {
- FastPairNotificationManager fastPairNotificationManager =
- new FastPairNotificationManager(mContextWrapper, fastPairItem, true);
+
FastPairHalfSheetManager fastPairHalfSheetManager =
new FastPairHalfSheetManager(mContextWrapper);
+ // Real context is needed
+ Context context = InstrumentationRegistry.getInstrumentation().getContext();
+ FastPairNotificationManager fastPairNotificationManager =
+ new FastPairNotificationManager(context, 1234, mNotificationManager,
+ new HalfSheetResources(mContextWrapper));
+
+ mLocator.overrideBindingForTest(FastPairNotificationManager.class,
+ fastPairNotificationManager);
mLocator.overrideBindingForTest(FastPairHalfSheetManager.class, fastPairHalfSheetManager);
PairingProgressHandlerBase pairingProgressHandlerBase =
PairingProgressHandlerBase.create(