Merge "Rename "service-nearby" to "service-nearby-pre-jarjar"" into tm-dev
diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java
index 7fb14ef..a217677 100644
--- a/nearby/framework/java/android/nearby/NearbyManager.java
+++ b/nearby/framework/java/android/nearby/NearbyManager.java
@@ -24,6 +24,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.os.RemoteException;
+import android.provider.Settings;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -46,7 +47,15 @@
@SystemService(Context.NEARBY_SERVICE)
public class NearbyManager {
- private static final String TAG = "NearbyManager";
+ /**
+ * Whether allows Fast Pair to scan.
+ *
+ * (0 = disabled, 1 = enabled)
+ *
+ * @hide
+ */
+ public static final String FAST_PAIR_SCAN_ENABLED = "fast_pair_scan_enabled";
+
@GuardedBy("sScanListeners")
private static final WeakHashMap<ScanCallback, WeakReference<ScanListenerTransport>>
sScanListeners = new WeakHashMap<>();
@@ -139,7 +148,6 @@
}
}
-
/**
* Start broadcasting the request using nearby specification.
*
@@ -162,6 +170,30 @@
// TODO(b/218187205): implement broadcast.
}
+ /**
+ * Read from {@link Settings} whether Fast Pair scan is enabled.
+ *
+ * @param context the {@link Context} to query the setting.
+ * @param def the default value if no setting value.
+ * @return whether the Fast Pair is enabled.
+ */
+ public static boolean getFastPairScanEnabled(@NonNull Context context, boolean def) {
+ final int enabled = Settings.Secure.getInt(
+ context.getContentResolver(), FAST_PAIR_SCAN_ENABLED, (def ? 1 : 0));
+ return enabled != 0;
+ }
+
+ /**
+ * Write into {@link Settings} whether Fast Pair scan is enabled
+ *
+ * @param context the {@link Context} to set the setting.
+ * @param enable whether the Fast Pair scan should be enabled.
+ */
+ public static void setFastPairScanEnabled(@NonNull Context context, boolean enable) {
+ Settings.Secure.putInt(
+ context.getContentResolver(), FAST_PAIR_SCAN_ENABLED, enable ? 1 : 0);
+ }
+
private static class ScanListenerTransport extends IScanListener.Stub {
private @ScanRequest.ScanType int mScanType;
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 08e98db..4ee16b7 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairAdvHandler.java
@@ -27,17 +27,19 @@
import android.nearby.NearbyDevice;
import android.util.Log;
+import com.android.server.nearby.common.ble.decode.FastPairDecoder;
import com.android.server.nearby.common.bloomfilter.BloomFilter;
import com.android.server.nearby.common.bloomfilter.FastPairBloomFilterHasher;
import com.android.server.nearby.common.locator.Locator;
+import com.android.server.nearby.fastpair.cache.FastPairCacheManager;
import com.android.server.nearby.fastpair.halfsheet.FastPairHalfSheetManager;
import com.android.server.nearby.provider.FastPairDataProvider;
import com.android.server.nearby.util.DataUtils;
-import com.android.server.nearby.util.FastPairDecoder;
import com.android.server.nearby.util.Hex;
import java.util.List;
+import service.proto.Cache;
import service.proto.Data;
import service.proto.Rpcs;
@@ -47,6 +49,7 @@
public class FastPairAdvHandler {
Context mContext;
String mBleAddress;
+
/** The types about how the bloomfilter is processed. */
public enum ProcessBloomFilterType {
IGNORE, // The bloomfilter is not handled. e.g. distance is too far away.
@@ -69,16 +72,18 @@
public void handleBroadcast(NearbyDevice device) {
FastPairDevice fastPairDevice = (FastPairDevice) device;
mBleAddress = fastPairDevice.getBluetoothAddress();
- List<Account> accountList =
- FastPairDataProvider.getInstance().loadFastPairEligibleAccounts();
+ FastPairDataProvider dataProvider = FastPairDataProvider.getInstance();
+ if (dataProvider == null) {
+ return;
+ }
+ List<Account> accountList = dataProvider.loadFastPairEligibleAccounts();
if (FastPairDecoder.checkModelId(fastPairDevice.getData())) {
byte[] model = FastPairDecoder.getModelId(fastPairDevice.getData());
Log.d(TAG, "On discovery model id " + Hex.bytesToStringLowercase(model));
// Use api to get anti spoofing key from model id.
try {
Rpcs.GetObservedDeviceResponse response =
- FastPairDataProvider.getInstance()
- .loadFastPairAntispoofkeyDeviceMetadata(model);
+ dataProvider.loadFastPairAntispoofkeyDeviceMetadata(model);
if (response == null) {
Log.e(TAG, "server does not have model id "
+ Hex.bytesToStringLowercase(model));
@@ -94,26 +99,41 @@
} else {
// Start to process bloom filter
try {
- Log.d(TAG, "account list size " + accountList.size());
byte[] bloomFilterByteArray = FastPairDecoder
.getBloomFilter(fastPairDevice.getData());
byte[] bloomFilterSalt = FastPairDecoder
.getBloomFilterSalt(fastPairDevice.getData());
if (bloomFilterByteArray == null || bloomFilterByteArray.length == 0) {
- Log.d(TAG, "bloom filter byte size is 0");
return;
}
for (Account account : accountList) {
List<Data.FastPairDeviceWithAccountKey> listDevices =
- FastPairDataProvider.getInstance()
- .loadFastPairDeviceWithAccountKey(account);
+ dataProvider.loadFastPairDeviceWithAccountKey(account);
Data.FastPairDeviceWithAccountKey recognizedDevice =
findRecognizedDevice(listDevices,
new BloomFilter(bloomFilterByteArray,
new FastPairBloomFilterHasher()), bloomFilterSalt);
+
if (recognizedDevice != null) {
Log.d(TAG, "find matched device show notification to remind"
+ " user to pair");
+ // Check if the device is already paired
+ List<Cache.StoredFastPairItem> storedFastPairItemList =
+ Locator.get(mContext, FastPairCacheManager.class)
+ .getAllSavedStoredFastPairItem();
+ Cache.StoredFastPairItem recognizedStoredFastPairItem =
+ findRecognizedDeviceFromCachedItem(storedFastPairItemList,
+ new BloomFilter(bloomFilterByteArray,
+ new FastPairBloomFilterHasher()), bloomFilterSalt);
+ if (recognizedStoredFastPairItem != null) {
+ // The bloomfilter is recognized in the cache so the device is paired
+ // before
+ Log.d(TAG, "bloom filter is recognized in the cache");
+ continue;
+ } else {
+ Log.d(TAG, "bloom filter is not recognized not paired before");
+ }
+
return;
}
}
@@ -132,10 +152,27 @@
@Nullable
static Data.FastPairDeviceWithAccountKey findRecognizedDevice(
List<Data.FastPairDeviceWithAccountKey> devices, BloomFilter bloomFilter, byte[] salt) {
+ Log.d(TAG, "saved devices size in the account is " + devices.size());
for (Data.FastPairDeviceWithAccountKey device : devices) {
- if (device.getAccountKey().toByteArray() == null) {
- continue;
+ byte[] rotatedKey = concat(device.getAccountKey().toByteArray(), salt);
+ StringBuilder sb = new StringBuilder();
+ for (byte b : rotatedKey) {
+ sb.append(b);
}
+ if (bloomFilter.possiblyContains(rotatedKey)) {
+ Log.d(TAG, "match " + sb.toString());
+ return device;
+ } else {
+ Log.d(TAG, "not match " + sb.toString());
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ static Cache.StoredFastPairItem findRecognizedDeviceFromCachedItem(
+ List<Cache.StoredFastPairItem> devices, BloomFilter bloomFilter, byte[] salt) {
+ for (Cache.StoredFastPairItem device : devices) {
byte[] rotatedKey = concat(device.getAccountKey().toByteArray(), salt);
if (bloomFilter.possiblyContains(rotatedKey)) {
return device;
@@ -143,4 +180,5 @@
}
return null;
}
+
}
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 1264ade..896056b 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairController.java
@@ -237,12 +237,14 @@
ByteString.copyFrom(hashValue));
// account data place holder here
try {
- List<Account> accountList =
- FastPairDataProvider.getInstance().loadFastPairEligibleAccounts();
+ FastPairDataProvider fastPairDataProvider = FastPairDataProvider.getInstance();
+ if (fastPairDataProvider == null) {
+ return;
+ }
+ List<Account> accountList = fastPairDataProvider.loadFastPairEligibleAccounts();
if (accountList.size() > 0) {
- FastPairDataProvider.getInstance().optIn(accountList.get(0));
- FastPairDataProvider.getInstance().upload(
- accountList.get(0), uploadInfo);
+ fastPairDataProvider.optIn(accountList.get(0));
+ fastPairDataProvider.upload(accountList.get(0), uploadInfo);
}
} catch (IllegalStateException e) {
Log.e(TAG, "OEM does not construct fast pair data proxy correctly");
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 04f72f0..7604771 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/FastPairManager.java
@@ -16,7 +16,6 @@
package com.android.server.nearby.fastpair;
-import static com.android.server.nearby.fastpair.Constant.SETTINGS_TRUE_VALUE;
import static com.android.server.nearby.fastpair.Constant.TAG;
import android.annotation.Nullable;
@@ -41,6 +40,7 @@
import androidx.annotation.NonNull;
+import com.android.server.nearby.common.ble.decode.FastPairDecoder;
import com.android.server.nearby.common.bluetooth.BluetoothException;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairConnection;
import com.android.server.nearby.common.bluetooth.fastpair.FastPairDualConnection;
@@ -48,6 +48,7 @@
import com.android.server.nearby.common.bluetooth.fastpair.Preferences;
import com.android.server.nearby.common.bluetooth.fastpair.ReflectionException;
import com.android.server.nearby.common.bluetooth.fastpair.SimpleBroadcastReceiver;
+import com.android.server.nearby.common.bluetooth.testability.android.bluetooth.BluetoothDevice;
import com.android.server.nearby.common.eventloop.Annotations;
import com.android.server.nearby.common.eventloop.EventLoop;
import com.android.server.nearby.common.eventloop.NamedRunnable;
@@ -58,10 +59,12 @@
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;
import com.android.server.nearby.util.Hex;
+import com.google.common.collect.ImmutableList;
+import com.google.protobuf.ByteString;
+
import java.security.GeneralSecurityException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -71,6 +74,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import service.proto.Cache;
import service.proto.Rpcs;
/**
@@ -147,13 +151,8 @@
.registerReceiver(mScreenBroadcastReceiver, mIntentFilter);
Locator.getFromContextWrapper(mLocatorContextWrapper, FastPairCacheManager.class);
- try {
- mScanEnabled = getScanEnabledFromSettings();
- mScanEnabled = ENFORCED_SCAN_ENABLED_VALUE;
- } catch (Settings.SettingNotFoundException e) {
- Log.w(TAG,
- "initiate: Failed to get initial scan enabled status from Settings.", e);
- }
+ mScanEnabled = NearbyManager.getFastPairScanEnabled(mLocatorContextWrapper, true);
+ mScanEnabled = ENFORCED_SCAN_ENABLED_VALUE;
registerFastPairScanChangeContentObserver(mLocatorContextWrapper.getContentResolver());
}
@@ -180,7 +179,6 @@
@Nullable String companionApp,
FootprintsDeviceManager footprints,
PairingProgressHandlerBase pairingProgressHandlerBase) {
-
return executor.submit(
() -> pairInternal(context, item, companionApp, accountKey, footprints,
pairingProgressHandlerBase), /* result= */ null);
@@ -197,7 +195,8 @@
@Nullable byte[] accountKey,
FootprintsDeviceManager footprints,
PairingProgressHandlerBase pairingProgressHandlerBase) {
- FastPairHalfSheetManager manager = Locator.get(context, FastPairHalfSheetManager.class);
+ FastPairHalfSheetManager fastPairHalfSheetManager =
+ Locator.get(context, FastPairHalfSheetManager.class);
try {
pairingProgressHandlerBase.onPairingStarted();
if (pairingProgressHandlerBase.skipWaitingScreenUnlock()) {
@@ -268,24 +267,17 @@
if (sharedSecret != null) {
Locator.get(context, FastPairController.class).addDeviceToFootprint(
connection.getPublicAddress(), sharedSecret.getKey(), item);
+ cacheFastPairDevice(context, connection.getPublicAddress(),
+ sharedSecret.getKey(), item);
}
}
-
- byte[] key = pairingProgressHandlerBase.getKeyForLocalCache(accountKey,
- connection, sharedSecret);
-
- // We don't cache initial pairing case here but cache it when upload to footprints.
- if (key != null) {
- // CacheManager to save the content here
- }
} else {
// Fast Pair one
connection.pair();
}
-
// TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
// pairingProgressHandlerBase class.
- manager.showPairingSuccessHalfSheet(connection.getPublicAddress());
+ fastPairHalfSheetManager.showPairingSuccessHalfSheet(connection.getPublicAddress());
pairingProgressHandlerBase.onPairingSuccess(connection.getPublicAddress());
} catch (BluetoothException
| InterruptedException
@@ -298,11 +290,38 @@
// TODO(b/213373051): Merge logic with pairingProgressHandlerBase or delete the
// pairingProgressHandlerBase class.
- manager.showPairingFailed();
+ fastPairHalfSheetManager.showPairingFailed();
pairingProgressHandlerBase.onPairingFailed(e);
}
}
+ private static void cacheFastPairDevice(Context context, String publicAddress, byte[] key,
+ DiscoveryItem item) {
+ try {
+ Locator.get(context, EventLoop.class).postAndWait(
+ new NamedRunnable("FastPairCacheDevice") {
+ @Override
+ public void run() {
+ Cache.StoredFastPairItem storedFastPairItem =
+ Cache.StoredFastPairItem.newBuilder()
+ .setMacAddress(publicAddress)
+ .setAccountKey(ByteString.copyFrom(key))
+ .setModelId(item.getTriggerId())
+ .addAllFeatures(item.getFastPairInformation() == null
+ ? ImmutableList.of() :
+ item.getFastPairInformation().getFeaturesList())
+ .setDiscoveryItem(item.getCopyOfStoredItem())
+ .build();
+ Locator.get(context, FastPairCacheManager.class)
+ .putStoredFastPairItem(storedFastPairItem);
+ }
+ }
+ );
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Fail to insert paired device into cache");
+ }
+ }
+
/** Checks if the pairing is initial pairing with fast pair 2.0 design. */
public static boolean isThroughFastPair2InitialPairing(
DiscoveryItem item, @Nullable byte[] accountKey) {
@@ -319,7 +338,7 @@
// regardless.
if (keyguardManager.isKeyguardLocked()) {
Log.v(TAG, "FastPair: Screen is locked, waiting until unlocked "
- + "to show status notifications.");
+ + "to show status notifications.");
try (SimpleBroadcastReceiver isUnlockedReceiver =
SimpleBroadcastReceiver.oneShotReceiver(
context, FlagUtils.getPreferencesBuilder().build(),
@@ -334,19 +353,16 @@
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
- try {
- setScanEnabled(getScanEnabledFromSettings());
- } catch (Settings.SettingNotFoundException e) {
- Log.e(TAG, "Failed to get scan switch updates in Settings page.", e);
- }
+ setScanEnabled(
+ NearbyManager.getFastPairScanEnabled(mLocatorContextWrapper, mScanEnabled));
}
};
try {
resolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.FAST_PAIR_SCAN_ENABLED),
+ Settings.Secure.getUriFor(NearbyManager.FAST_PAIR_SCAN_ENABLED),
/* notifyForDescendants= */ false,
mFastPairScanChangeContentObserver);
- } catch (SecurityException e) {
+ } catch (SecurityException e) {
Log.e(TAG, "Failed to register content observer for fast pair scan.", e);
}
}
@@ -378,13 +394,6 @@
return (NearbyManager) mLocatorContextWrapper
.getApplicationContext().getSystemService(Context.NEARBY_SERVICE);
}
-
- private boolean getScanEnabledFromSettings() throws Settings.SettingNotFoundException {
- return Settings.Secure.getInt(
- mLocatorContextWrapper.getContext().getContentResolver(),
- Settings.Secure.FAST_PAIR_SCAN_ENABLED) == SETTINGS_TRUE_VALUE;
- }
-
private void setScanEnabled(boolean scanEnabled) {
if (mScanEnabled == scanEnabled) {
return;
@@ -395,7 +404,7 @@
}
/**
- * Starts or stops scanning according to mAllowScan value.
+ * Starts or stops scanning according to mAllowScan value.
*/
private void invalidateScan() {
NearbyManager nearbyManager = getNearbyManager();
@@ -415,6 +424,30 @@
}
/**
+ * When certain device is forgotten we need to remove the info from database because the info
+ * is no longer useful.
+ */
+ private void processBluetoothConnectionEvent(Intent intent) {
+ int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.ERROR);
+ if (bondState == BluetoothDevice.BOND_NONE) {
+ BluetoothDevice device =
+ intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+ if (device != null) {
+ Log.d("FastPairService", "Forget device detect");
+ processBackgroundTask(new Runnable() {
+ @Override
+ public void run() {
+ mLocatorContextWrapper.getLocator().get(FastPairCacheManager.class)
+ .removeStoredFastPairItem(device.getAddress());
+ }
+ });
+ }
+
+ }
+ }
+
+ /**
* Helper function to get bluetooth adapter.
*/
@Nullable
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java
deleted file mode 100644
index e171462..0000000
--- a/nearby/service/java/com/android/server/nearby/fastpair/cache/DiscoveryItemDbHelper.java
+++ /dev/null
@@ -1,60 +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.cache;
-
-import android.content.Context;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
-
-/**
- * Discovery db helper
- */
-public class DiscoveryItemDbHelper extends SQLiteOpenHelper {
-
- public static final int DATABASE_VERSION = 1;
- public static final String DATABASE_NAME = "ScanResult.db";
- private static final String SQL_CREATE_DB =
- "CREATE TABLE " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME
- + " (" + DiscoveryItemContract.DiscoveryItemEntry._ID
- + "INTEGER PRIMARY KEY,"
- + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID
- + " TEXT," + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
- + " BLOB)";
- private static final String SQL_DELETE_DB =
- "DROP TABLE IF EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME;
-
- public DiscoveryItemDbHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(SQL_CREATE_DB);
- }
-
- @Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // Since the outdated data has no value so just remove the data.
- db.execSQL(SQL_DELETE_DB);
- onCreate(db);
- }
-
- @Override
- public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- super.onDowngrade(db, oldVersion, newVersion);
- }
-}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
index fb2adb2..b840091 100644
--- a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairCacheManager.java
@@ -39,18 +39,18 @@
*/
public class FastPairCacheManager {
private final Context mContext;
- private final DiscoveryItemDbHelper mDiscoveryItemDbHelper;
+ private final FastPairDbHelper mFastPairDbHelper;
public FastPairCacheManager(Context context) {
mContext = context;
- mDiscoveryItemDbHelper = new DiscoveryItemDbHelper(context);
+ mFastPairDbHelper = new FastPairDbHelper(context);
}
/**
* Clean up function to release db
*/
public void cleanUp() {
- mDiscoveryItemDbHelper.close();
+ mFastPairDbHelper.close();
}
/**
@@ -74,10 +74,12 @@
}
/**
- * Save discovery item into database.
+ * Save discovery item into database. Discovery item is item that discovered through Ble before
+ * pairing success.
*/
public boolean saveDiscoveryItem(DiscoveryItem item) {
- SQLiteDatabase db = mDiscoveryItemDbHelper.getWritableDatabase();
+
+ SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID, item.getTriggerId());
values.put(DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE,
@@ -103,8 +105,7 @@
* Get discovery item from item id.
*/
public Cache.StoredDiscoveryItem getStoredDiscoveryItem(String itemId) {
-
- SQLiteDatabase db = mDiscoveryItemDbHelper.getReadableDatabase();
+ SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
String[] projection = {
DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID,
DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
@@ -140,7 +141,7 @@
*/
public List<Cache.StoredDiscoveryItem> getAllSavedStoreDiscoveryItem() {
List<Cache.StoredDiscoveryItem> storedDiscoveryItemList = new ArrayList<>();
- SQLiteDatabase db = mDiscoveryItemDbHelper.getReadableDatabase();
+ SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
String[] projection = {
DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID,
DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
@@ -169,6 +170,7 @@
cursor.close();
return storedDiscoveryItemList;
}
+
/**
* Get scan result from local database use model id
*/
@@ -176,4 +178,105 @@
return Cache.StoredScanResult.getDefaultInstance();
}
+ /**
+ * Gets the paired Fast Pair item that paired to the phone through mac address.
+ */
+ public Cache.StoredFastPairItem getStoredFastPairItemFromMacAddress(String macAddress) {
+ SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
+ String[] projection = {
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+ };
+ String selection =
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS + " =? ";
+ String[] selectionArgs = {macAddress};
+ Cursor cursor = db.query(
+ StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+ projection,
+ selection,
+ selectionArgs,
+ null,
+ null,
+ null
+ );
+
+ if (cursor.moveToNext()) {
+ byte[] res = cursor.getBlob(cursor.getColumnIndexOrThrow(
+ StoredFastPairItemContract.StoredFastPairItemEntry
+ .COLUMN_STORED_FAST_PAIR_BYTE));
+ try {
+ Cache.StoredFastPairItem item = Cache.StoredFastPairItem.parseFrom(res);
+ return item;
+ } catch (InvalidProtocolBufferException e) {
+ Log.e("FastPairCacheManager", "storediscovery has error");
+ }
+ }
+ cursor.close();
+ return Cache.StoredFastPairItem.getDefaultInstance();
+ }
+
+ /**
+ * Save paired fast pair item into the database.
+ */
+ public boolean putStoredFastPairItem(Cache.StoredFastPairItem storedFastPairItem) {
+ SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+ storedFastPairItem.getMacAddress());
+ values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+ storedFastPairItem.getAccountKey().toString());
+ values.put(StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE,
+ storedFastPairItem.toByteArray());
+ db.insert(StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME, null, values);
+ return true;
+
+ }
+
+ /**
+ * Removes certain storedFastPairItem so that it can update timely.
+ */
+ public void removeStoredFastPairItem(String macAddress) {
+ SQLiteDatabase db = mFastPairDbHelper.getWritableDatabase();
+ int res = db.delete(StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS + "=?",
+ new String[]{macAddress});
+
+ }
+
+ /**
+ * Get all of the store fast pair item related info in the cache.
+ */
+ public List<Cache.StoredFastPairItem> getAllSavedStoredFastPairItem() {
+ List<Cache.StoredFastPairItem> storedFastPairItemList = new ArrayList<>();
+ SQLiteDatabase db = mFastPairDbHelper.getReadableDatabase();
+ String[] projection = {
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS,
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY,
+ StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+ };
+ Cursor cursor = db.query(
+ StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME,
+ projection,
+ null,
+ null,
+ null,
+ null,
+ null
+ );
+
+ while (cursor.moveToNext()) {
+ byte[] res = cursor.getBlob(cursor.getColumnIndexOrThrow(StoredFastPairItemContract
+ .StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE));
+ try {
+ Cache.StoredFastPairItem item = Cache.StoredFastPairItem.parseFrom(res);
+ storedFastPairItemList.add(item);
+ } catch (InvalidProtocolBufferException e) {
+ Log.e("FastPairCacheManager", "storediscovery has error");
+ }
+
+ }
+ cursor.close();
+ return storedFastPairItemList;
+ }
}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java
new file mode 100644
index 0000000..d950d8d
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/FastPairDbHelper.java
@@ -0,0 +1,76 @@
+/*
+ * 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.cache;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Fast Pair db helper handle all of the db actions related Fast Pair.
+ */
+public class FastPairDbHelper extends SQLiteOpenHelper {
+
+ public static final int DATABASE_VERSION = 1;
+ public static final String DATABASE_NAME = "FastPair.db";
+ private static final String SQL_CREATE_DISCOVERY_ITEM_DB =
+ "CREATE TABLE IF NOT EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME
+ + " (" + DiscoveryItemContract.DiscoveryItemEntry._ID
+ + "INTEGER PRIMARY KEY,"
+ + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_MODEL_ID
+ + " TEXT," + DiscoveryItemContract.DiscoveryItemEntry.COLUMN_SCAN_BYTE
+ + " BLOB)";
+ private static final String SQL_DELETE_DISCOVERY_ITEM_DB =
+ "DROP TABLE IF EXISTS " + DiscoveryItemContract.DiscoveryItemEntry.TABLE_NAME;
+ private static final String SQL_CREATE_FAST_PAIR_ITEM_DB =
+ "CREATE TABLE IF NOT EXISTS "
+ + StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME
+ + " (" + StoredFastPairItemContract.StoredFastPairItemEntry._ID
+ + "INTEGER PRIMARY KEY,"
+ + StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_MAC_ADDRESS
+ + " TEXT,"
+ + StoredFastPairItemContract.StoredFastPairItemEntry.COLUMN_ACCOUNT_KEY
+ + " TEXT,"
+ + StoredFastPairItemContract
+ .StoredFastPairItemEntry.COLUMN_STORED_FAST_PAIR_BYTE
+ + " BLOB)";
+ private static final String SQL_DELETE_FAST_PAIR_ITEM_DB =
+ "DROP TABLE IF EXISTS " + StoredFastPairItemContract.StoredFastPairItemEntry.TABLE_NAME;
+
+ public FastPairDbHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(SQL_CREATE_DISCOVERY_ITEM_DB);
+ db.execSQL(SQL_CREATE_FAST_PAIR_ITEM_DB);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // Since the outdated data has no value so just remove the data.
+ db.execSQL(SQL_DELETE_DISCOVERY_ITEM_DB);
+ db.execSQL(SQL_DELETE_FAST_PAIR_ITEM_DB);
+ onCreate(db);
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ super.onDowngrade(db, oldVersion, newVersion);
+ }
+}
diff --git a/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java b/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java
new file mode 100644
index 0000000..9980565
--- /dev/null
+++ b/nearby/service/java/com/android/server/nearby/fastpair/cache/StoredFastPairItemContract.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 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.cache;
+
+import android.provider.BaseColumns;
+
+/**
+ * Defines fast pair item database schema.
+ */
+public class StoredFastPairItemContract {
+ private StoredFastPairItemContract() {}
+
+ /**
+ * StoredFastPairItem entry related info.
+ */
+ public static class StoredFastPairItemEntry implements BaseColumns {
+ public static final String TABLE_NAME = "STORED_FAST_PAIR_ITEM";
+ public static final String COLUMN_MAC_ADDRESS = "MAC_ADDRESS";
+ public static final String COLUMN_ACCOUNT_KEY = "ACCOUNT_KEY";
+
+ public static final String COLUMN_STORED_FAST_PAIR_BYTE = "STORED_FAST_PAIR_BYTE";
+ }
+}
diff --git a/nearby/tests/cts/fastpair/Android.bp b/nearby/tests/cts/fastpair/Android.bp
index 599fe5c..6dc1af8 100644
--- a/nearby/tests/cts/fastpair/Android.bp
+++ b/nearby/tests/cts/fastpair/Android.bp
@@ -37,6 +37,7 @@
"general-tests",
"mts-tethering",
],
+ certificate: "platform",
platform_apis: true,
sdk_version: "module_current",
min_sdk_version: "30",
diff --git a/nearby/tests/cts/fastpair/AndroidManifest.xml b/nearby/tests/cts/fastpair/AndroidManifest.xml
index 463a926..e77d70f 100644
--- a/nearby/tests/cts/fastpair/AndroidManifest.xml
+++ b/nearby/tests/cts/fastpair/AndroidManifest.xml
@@ -18,6 +18,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.nearby.cts">
<uses-sdk android:minSdkVersion="32" android:targetSdkVersion="32" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+
<application>
<uses-library android:name="android.test.runner"/>
</application>
diff --git a/nearby/tests/cts/fastpair/AndroidTest.xml b/nearby/tests/cts/fastpair/AndroidTest.xml
index 59cc779..360bbf3 100644
--- a/nearby/tests/cts/fastpair/AndroidTest.xml
+++ b/nearby/tests/cts/fastpair/AndroidTest.xml
@@ -16,7 +16,8 @@
<configuration description="Config for CTS Nearby Fast Pair test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="location" />
- <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <!-- Instant cannot access NearbyManager. -->
+ <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
<option name="config-descriptor:metadata" key="parameter" value="all_foldable_states" />
@@ -32,4 +33,4 @@
class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
<option name="mainline-module-package-name" value="com.google.android.tethering" />
</object>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
index 370bfe1..cf43cb1 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyFrameworkInitializerTest.java
@@ -16,12 +16,16 @@
package android.nearby.cts;
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
import android.nearby.NearbyFrameworkInitializer;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,15 +35,11 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
public class NearbyFrameworkInitializerTest {
-// // TODO(b/215435710) This test cannot pass now because our test cannot access system API.
-// // run "adb root && adb shell setenforce permissive" and uncomment testServicesRegistered,
-// // test passes.
-// @Test
-// public void testServicesRegistered() {
-// Context ctx = InstrumentationRegistry.getInstrumentation().getContext();
-// assertNotNull( "NearbyManager not registered",
-// ctx.getSystemService(Context.NEARBY_SERVICE));
-// }
+ @Test
+ public void testServicesRegistered() {
+ Context ctx = InstrumentationRegistry.getInstrumentation().getContext();
+ assertThat(ctx.getSystemService(Context.NEARBY_SERVICE)).isNotNull();
+ }
// registerServiceWrappers can only be called during initialization and should throw otherwise
@Test(expected = IllegalStateException.class)
diff --git a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
index 938eab2..eedcce1 100644
--- a/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
+++ b/nearby/tests/cts/fastpair/src/android/nearby/cts/NearbyManagerTest.java
@@ -18,6 +18,8 @@
import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
@@ -36,6 +38,7 @@
import androidx.annotation.RequiresApi;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SdkSuppress;
+import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
@@ -63,7 +66,10 @@
@Before
public void setUp() {
initMocks(this);
+
when(mContext.getSystemService(Context.NEARBY_SERVICE)).thenReturn(mNearbyManager);
+ when(mContext.getContentResolver()).thenReturn(
+ InstrumentationRegistry.getInstrumentation().getContext().getContentResolver());
}
@Test
@@ -110,4 +116,11 @@
callback);
mNearbyManager.stopBroadcast(callback);
}
+
+ @Test
+ @SdkSuppress(minSdkVersion = 32, codeName = "T")
+ public void testSettingsEnable() {
+ NearbyManager.setFastPairScanEnabled(mContext, false);
+ assertThat(NearbyManager.getFastPairScanEnabled(mContext, true)).isFalse();
+ }
}
diff --git a/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/FastPairSettingsProviderTest.kt b/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/FastPairSettingsProviderTest.kt
index 761aaf6..af3f75f 100644
--- a/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/FastPairSettingsProviderTest.kt
+++ b/nearby/tests/integration/privileged/src/android/nearby/integration/privileged/FastPairSettingsProviderTest.kt
@@ -38,10 +38,10 @@
val appContext = ApplicationProvider.getApplicationContext<Context>()
val contentResolver = appContext.contentResolver
- Settings.Secure.putInt(contentResolver, Settings.Secure.FAST_PAIR_SCAN_ENABLED, flag.value)
+ Settings.Secure.putInt(contentResolver, "fast_pair_scan_enabled", flag.value)
val actualValue = Settings.Secure.getInt(
- contentResolver, Settings.Secure.FAST_PAIR_SCAN_ENABLED, /* default value */ -1)
+ contentResolver, "fast_pair_scan_enabled", /* default value */ -1)
assertThat(actualValue).isEqualTo(flag.value)
}
diff --git a/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/FastPairSettingsProviderTest.kt b/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/FastPairSettingsProviderTest.kt
index b73e737..c549073 100644
--- a/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/FastPairSettingsProviderTest.kt
+++ b/nearby/tests/integration/untrusted/src/android/nearby/integration/untrusted/FastPairSettingsProviderTest.kt
@@ -40,14 +40,14 @@
@Test
fun testSettingsFastPairScan_fromUnTrustedApp_readsSucceed() {
Settings.Secure.getInt(contentResolver,
- Settings.Secure.FAST_PAIR_SCAN_ENABLED, /* default value */ -1)
+ "fast_pair_scan_enabled", /* default value */ -1)
}
/** Verify untrusted app can't write Fast Pair scan enabled setting. */
@Test
fun testSettingsFastPairScan_fromUnTrustedApp_writesFailed() {
assertFailsWith<SecurityException> {
- Settings.Secure.putInt(contentResolver, Settings.Secure.FAST_PAIR_SCAN_ENABLED, 1)
+ Settings.Secure.putInt(contentResolver, "fast_pair_scan_enabled", 1)
}
}
}
diff --git a/nearby/tests/multidevices/clients/AndroidManifest.xml b/nearby/tests/multidevices/clients/AndroidManifest.xml
index b6dc5e8..9641756 100644
--- a/nearby/tests/multidevices/clients/AndroidManifest.xml
+++ b/nearby/tests/multidevices/clients/AndroidManifest.xml
@@ -44,7 +44,7 @@
Must stay in the same process as Nearby Discovery Service.
-->
<service
- android:name=".fastpair.seeker.FastPairTestDataProviderService"
+ android:name=".fastpair.seeker.dataprovider.FastPairTestDataProviderService"
android:exported="true"
android:permission="android.permission.WRITE_SECURE_SETTINGS"
android:visibleToInstantApps="true">
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothA2dpSinkService.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothA2dpSinkService.kt
deleted file mode 100644
index f65dfab..0000000
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothA2dpSinkService.kt
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.nearby.multidevices.fastpair.provider
-
-import android.Manifest.permission.BLUETOOTH_CONNECT
-import android.Manifest.permission.BLUETOOTH_SCAN
-import android.annotation.TargetApi
-import android.bluetooth.BluetoothClass
-import android.bluetooth.BluetoothDevice
-import android.bluetooth.BluetoothManager
-import android.bluetooth.BluetoothProfile
-import android.content.Context
-import android.os.Build
-import androidx.annotation.RequiresPermission
-import androidx.annotation.VisibleForTesting
-
-/** Maintains an environment for Bluetooth A2DP sink profile. */
-@TargetApi(Build.VERSION_CODES.LOLLIPOP)
-class BluetoothA2dpSinkService(private val context: Context) {
- private val bluetoothAdapter =
- (context.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager)?.adapter!!
- private var a2dpSinkProxy: BluetoothProfile? = null
-
- /**
- * Starts the Bluetooth A2DP sink profile proxy.
- *
- * @param onServiceConnected the callback for the first time onServiceConnected.
- */
- fun start(onServiceConnected: () -> Unit) {
- // Get the A2DP proxy before continuing with initialization.
- bluetoothAdapter.getProfileProxy(
- context,
- object : BluetoothProfile.ServiceListener {
- override fun onServiceConnected(profile: Int, proxy: BluetoothProfile) {
- // When Bluetooth turns off and then on again, this is called again. But we only care
- // the first time. There doesn't seem to be a way to unregister our listener.
- if (a2dpSinkProxy == null) {
- a2dpSinkProxy = proxy
- onServiceConnected()
- }
- }
-
- override fun onServiceDisconnected(profile: Int) {}
- },
- BLUETOOTH_PROFILE_A2DP_SINK
- )
- }
-
- /**
- * Checks the device is paired or not.
- *
- * @param remoteBluetoothDevice the device to check is paired or not.
- */
- @RequiresPermission(BLUETOOTH_CONNECT)
- fun isPaired(remoteBluetoothDevice: BluetoothDevice?): Boolean =
- bluetoothAdapter.bondedDevices.contains(remoteBluetoothDevice)
-
- /**
- * Gets the current Bluetooth scan mode of the local Bluetooth adapter.
- */
- @RequiresPermission(BLUETOOTH_SCAN)
- fun getScanMode(): Int = bluetoothAdapter.scanMode
-
- /**
- * Clears the bounded devices.
- *
- * @param removeBondDevice the callback to remove bounded devices.
- */
- @RequiresPermission(BLUETOOTH_CONNECT)
- fun clearBoundedDevices(removeBondDevice: (BluetoothDevice) -> Unit) {
- for (device in bluetoothAdapter.bondedDevices) {
- if (device.bluetoothClass.majorDeviceClass == BluetoothClass.Device.Major.PHONE) {
- removeBondDevice(device)
- }
- }
- }
-
- /**
- * Clears the connected but unbounded devices.
- *
- * Sometimes a device will still be connected even though it's not bonded. :( Clear that too.
- *
- * @param disconnectDevice the callback to clear connected but unbounded devices.
- */
- fun clearConnectedUnboundedDevices(
- disconnectDevice: (BluetoothProfile, BluetoothDevice) -> Unit,
- ) {
- for (device in a2dpSinkProxy!!.connectedDevices) {
- disconnectDevice(a2dpSinkProxy!!, device)
- }
- }
-
- companion object {
- /** Hidden SystemApi field in [android.bluetooth.BluetoothProfile] interface. */
- @VisibleForTesting
- const val BLUETOOTH_PROFILE_A2DP_SINK = 11
- }
-}
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiver.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiver.kt
deleted file mode 100644
index f9c77f7..0000000
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiver.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.nearby.multidevices.fastpair.provider
-
-import android.Manifest.permission.BLUETOOTH
-import android.Manifest.permission.BLUETOOTH_CONNECT
-import android.bluetooth.BluetoothAdapter
-import android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE
-import android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
-import android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE
-import android.bluetooth.BluetoothDevice
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
-import android.util.Log
-import androidx.annotation.RequiresPermission
-import androidx.annotation.VisibleForTesting
-
-/** Processes the state of the local Bluetooth adapter. */
-class BluetoothStateChangeReceiver(private val context: Context) : BroadcastReceiver() {
- @VisibleForTesting
- var listener: EventListener? = null
-
- /**
- * Registers this Bluetooth state change receiver.
- *
- * @param listener the listener for Bluetooth state events.
- */
- fun register(listener: EventListener) {
- this.listener = listener
- val bondStateFilter =
- IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED).apply {
- addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)
- addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)
- }
- context.registerReceiver(
- this,
- bondStateFilter,
- /* broadcastPermission= */ null,
- /* scheduler= */ null
- )
- }
-
- /** Unregisters this Bluetooth state change receiver. */
- fun unregister() {
- context.unregisterReceiver(this)
- this.listener = null
- }
-
- /**
- * Callback method for receiving Intent broadcast for Bluetooth state.
- *
- * See [android.content.BroadcastReceiver#onReceive].
- *
- * @param context the Context in which the receiver is running.
- * @param intent the Intent being received.
- */
- @RequiresPermission(allOf = [BLUETOOTH, BLUETOOTH_CONNECT])
- override fun onReceive(context: Context, intent: Intent) {
- Log.i(TAG, "BluetoothStateChangeReceiver received intent, action=${intent.action}")
-
- when (intent.action) {
- BluetoothAdapter.ACTION_SCAN_MODE_CHANGED -> {
- val scanMode =
- intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, SCAN_MODE_NONE)
- val scanModeStr = scanModeToString(scanMode)
- Log.i(TAG, "ACTION_SCAN_MODE_CHANGED, the new scanMode: $scanModeStr")
- listener?.onScanModeChange(scanModeStr)
- }
- BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
- val remoteDevice = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
- val remoteDeviceString =
- if (remoteDevice != null) "${remoteDevice.name}-${remoteDevice.address}" else "none"
- var boundStateString = "ERROR"
- when (intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR)) {
- BluetoothDevice.BOND_NONE -> {
- boundStateString = "BOND_NONE"
- }
- BluetoothDevice.BOND_BONDING -> {
- boundStateString = "BOND_BONDING"
- }
- BluetoothDevice.BOND_BONDED -> {
- boundStateString = "BOND_BONDED"
- }
- }
- Log.i(
- TAG,
- "The bound state of the remote device ($remoteDeviceString) change to $boundStateString."
- )
- }
- else -> {}
- }
- }
-
- private fun scanModeToString(scanMode: Int): String {
- return when (scanMode) {
- SCAN_MODE_CONNECTABLE_DISCOVERABLE -> "DISCOVERABLE"
- SCAN_MODE_CONNECTABLE -> "CONNECTABLE"
- SCAN_MODE_NONE -> "NOT CONNECTABLE"
- else -> "UNKNOWN($scanMode)"
- }
- }
-
- /** Interface for listening the events from Bluetooth adapter. */
- interface EventListener {
- /**
- * Reports the current scan mode of the local Adapter.
- *
- * @param mode the current scan mode in string.
- */
- fun onScanModeChange(mode: String)
- }
-
- companion object {
- private const val TAG = "BluetoothStateReceiver"
- }
-}
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorController.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorController.kt
new file mode 100644
index 0000000..0eacb71
--- /dev/null
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorController.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 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 android.nearby.multidevices.fastpair.provider
+
+import android.bluetooth.le.AdvertiseSettings
+import android.content.Context
+import android.nearby.fastpair.provider.FastPairSimulator
+import android.nearby.fastpair.provider.bluetooth.BluetoothController
+import com.google.android.mobly.snippet.util.Log
+import com.google.common.io.BaseEncoding
+
+class FastPairProviderSimulatorController(
+ private val context: Context,
+ private val modelId: String,
+ private val antiSpoofingKeyString: String,
+ private val eventListener: EventListener,
+) : BluetoothController.EventListener {
+ private lateinit var bluetoothController: BluetoothController
+ lateinit var simulator: FastPairSimulator
+
+ fun startProviderSimulator() {
+ bluetoothController = BluetoothController(context, this)
+ bluetoothController.registerBluetoothStateReceiver()
+ bluetoothController.enableBluetooth()
+ bluetoothController.connectA2DPSinkProfile()
+ }
+
+ fun stopProviderSimulator() {
+ simulator.destroy()
+ bluetoothController.unregisterBluetoothStateReceiver()
+ }
+
+ override fun onA2DPSinkProfileConnected() {
+ createFastPairSimulator()
+ }
+
+ override fun onBondStateChanged(bondState: Int) {
+ }
+
+ override fun onConnectionStateChanged(connectionState: Int) {
+ }
+
+ override fun onScanModeChange(mode: Int) {
+ eventListener.onScanModeChange(FastPairSimulator.scanModeToString(mode))
+ }
+
+ private fun createFastPairSimulator() {
+ val antiSpoofingKey = BaseEncoding.base64().decode(antiSpoofingKeyString)
+ simulator = FastPairSimulator(context, FastPairSimulator.Options.builder(modelId)
+ .setAdvertisingModelId(modelId)
+ .setBluetoothAddress(null)
+ .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
+ .setAdvertisingChangedCallback {
+ val isAdvertising = simulator.isAdvertising
+ Log.i("FastPairSimulator callback(), isAdvertising: $isAdvertising")
+ eventListener.onAdvertisingChange(isAdvertising)
+ }
+ .setAntiSpoofingPrivateKey(antiSpoofingKey)
+ .setUseRandomSaltForAccountKeyRotation(false)
+ .setDataOnlyConnection(false)
+ .setShowsPasskeyConfirmation(false)
+ .setRemoveAllDevicesDuringPairing(true)
+ .build())
+ }
+
+ /** Interface for listening the events from Fast Pair Provider Simulator. */
+ interface EventListener {
+ /**
+ * Reports the current scan mode of the local Adapter.
+ *
+ * @param mode the current scan mode in string.
+ */
+ fun onScanModeChange(mode: String)
+
+ /**
+ * Indicates the advertising state of the Fast Pair provider simulator has changed.
+ *
+ * @param isAdvertising the current advertising state, true if advertising otherwise false.
+ */
+ fun onAdvertisingChange(isAdvertising: Boolean)
+ }
+}
\ No newline at end of file
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorSnippet.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorSnippet.kt
index a03085c..356823e 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorSnippet.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/FastPairProviderSimulatorSnippet.kt
@@ -17,25 +17,18 @@
package android.nearby.multidevices.fastpair.provider
import android.annotation.TargetApi
-import android.bluetooth.le.AdvertiseSettings
import android.content.Context
import android.os.Build
import androidx.test.platform.app.InstrumentationRegistry
-import android.nearby.fastpair.provider.FastPairSimulator
import com.google.android.mobly.snippet.Snippet
import com.google.android.mobly.snippet.rpc.AsyncRpc
import com.google.android.mobly.snippet.rpc.Rpc
-import com.google.android.mobly.snippet.util.Log
-import com.google.common.io.BaseEncoding.base64
/** Expose Mobly RPC methods for Python side to simulate fast pair provider role. */
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class FastPairProviderSimulatorSnippet : Snippet {
private val context: Context = InstrumentationRegistry.getInstrumentation().context
- private val bluetoothA2dpSinkService = BluetoothA2dpSinkService(context)
- private val bluetoothStateChangeReceiver = BluetoothStateChangeReceiver(context)
- private lateinit var fastPairSimulator: FastPairSimulator
- private lateinit var providerStatusEvents: ProviderStatusEvents
+ private lateinit var fastPairProviderSimulatorController: FastPairProviderSimulatorController
/**
* Starts the Fast Pair provider simulator.
@@ -47,47 +40,21 @@
*/
@AsyncRpc(description = "Starts FP provider simulator for seekers to discover.")
fun startProviderSimulator(callbackId: String, modelId: String, antiSpoofingKeyString: String) {
- providerStatusEvents = ProviderStatusEvents(callbackId)
- bluetoothStateChangeReceiver.register(listener = providerStatusEvents)
- bluetoothA2dpSinkService.start { createFastPairSimulator(modelId, antiSpoofingKeyString) }
+ fastPairProviderSimulatorController = FastPairProviderSimulatorController(
+ context, modelId, antiSpoofingKeyString, ProviderStatusEvents(callbackId)
+ )
+ fastPairProviderSimulatorController.startProviderSimulator()
}
/** Stops the Fast Pair provider simulator. */
@Rpc(description = "Stops FP provider simulator.")
fun stopProviderSimulator() {
- fastPairSimulator.destroy()
- bluetoothStateChangeReceiver.unregister()
+ fastPairProviderSimulatorController.stopProviderSimulator()
}
/** Gets BLE mac address of the Fast Pair provider simulator. */
@Rpc(description = "Gets BLE mac address of the Fast Pair provider simulator.")
fun getBluetoothLeAddress(): String {
- return fastPairSimulator.bleAddress!!
- }
-
- private fun createFastPairSimulator(modelId: String, antiSpoofingKeyString: String) {
- val antiSpoofingKey = base64().decode(antiSpoofingKeyString)
- fastPairSimulator =
- FastPairSimulator(
- context,
- FastPairSimulator.Options.builder(
- modelId
- )
- .setAdvertisingModelId(modelId)
- .setBluetoothAddress(null)
- .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
- .setCallback {
- val isAdvertising = fastPairSimulator.isAdvertising
- Log.i("FastPairSimulator callback(), isAdvertising: $isAdvertising")
- providerStatusEvents.onAdvertisingChange(isAdvertising)
- }
- .setAntiSpoofingPrivateKey(antiSpoofingKey)
- .setUseRandomSaltForAccountKeyRotation(false)
- .setDataOnlyConnection(false)
- .setIsMemoryTest(false)
- .setShowsPasskeyConfirmation(false)
- .setRemoveAllDevicesDuringPairing(true)
- .build()
- )
+ return fastPairProviderSimulatorController.simulator.bleAddress!!
}
}
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/ProviderStatusEvents.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/ProviderStatusEvents.kt
index eef4b8b..20983d3 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/ProviderStatusEvents.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/provider/ProviderStatusEvents.kt
@@ -20,7 +20,7 @@
/** The Mobly snippet events to report to the Python side. */
class ProviderStatusEvents(private val callbackId: String) :
- BluetoothStateChangeReceiver.EventListener {
+ FastPairProviderSimulatorController.EventListener {
/**
* Indicates the Bluetooth scan mode of the Fast Pair provider simulator has changed.
@@ -36,7 +36,7 @@
*
* @param isAdvertising the current advertising state, true if advertising otherwise false.
*/
- fun onAdvertisingChange(isAdvertising: Boolean) {
+ override fun onAdvertisingChange(isAdvertising: Boolean) {
postSnippetEvent(callbackId, "onAdvertisingChange") {
putBoolean("isAdvertising", isAdvertising)
}
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/CompanionAppUtils.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/CompanionAppUtils.kt
deleted file mode 100644
index 7ed4372..0000000
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/CompanionAppUtils.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.nearby.multidevices.fastpair.seeker
-
-fun generateCompanionAppLaunchIntentUri(
- companionAppPackageName: String? = null,
- activityName: String? = null,
- action: String? = null
-): String {
- if (companionAppPackageName.isNullOrEmpty() || activityName.isNullOrEmpty()) {
- return ""
- }
- var intentUriString = "intent:#Intent;"
- if (!action.isNullOrEmpty()) {
- intentUriString += "action=$action;"
- }
- intentUriString += "package=$companionAppPackageName;"
- intentUriString += "component=$companionAppPackageName/$activityName;"
- return "${intentUriString}end"
-}
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairSeekerSnippet.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairSeekerSnippet.kt
index 6c28b97..8f5d120 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairSeekerSnippet.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairSeekerSnippet.kt
@@ -21,6 +21,7 @@
import android.nearby.NearbyManager
import android.nearby.ScanCallback
import android.nearby.ScanRequest
+import android.nearby.multidevices.fastpair.seeker.dataprovider.FastPairTestDataCache
import androidx.test.core.app.ApplicationProvider
import com.google.android.mobly.snippet.Snippet
import com.google.android.mobly.snippet.rpc.AsyncRpc
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataCache.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataCache.kt
similarity index 98%
rename from nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataCache.kt
rename to nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataCache.kt
index 28523c1..ad2b40d 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataCache.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataCache.kt
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.nearby.multidevices.fastpair.seeker
+package android.nearby.multidevices.fastpair.seeker.dataprovider
import android.nearby.FastPairAccountKeyDeviceMetadata
import android.nearby.FastPairAntispoofkeyDeviceMetadata
import android.nearby.FastPairDeviceMetadata
import android.nearby.FastPairDiscoveryItem
-import com.google.common.io.BaseEncoding.base64
+import com.google.common.io.BaseEncoding
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
@@ -297,6 +297,6 @@
}
}
- private fun String.base64Decode(): ByteArray = base64().decode(this)
- private fun ByteArray.base64Encode(): String = base64().encode(this)
+ private fun String.base64Decode(): ByteArray = BaseEncoding.base64().decode(this)
+ private fun ByteArray.base64Encode(): String = BaseEncoding.base64().encode(this)
}
\ No newline at end of file
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProvider.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProvider.kt
similarity index 98%
rename from nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProvider.kt
rename to nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProvider.kt
index a1f0369..9ff513a 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProvider.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProvider.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.nearby.multidevices.fastpair.seeker
+package android.nearby.multidevices.fastpair.seeker.dataprovider
import android.accounts.Account
import android.nearby.FastPairDataProviderBase
diff --git a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProviderService.kt b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProviderService.kt
similarity index 95%
rename from nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProviderService.kt
rename to nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProviderService.kt
index 5a1c832..3c0c84c 100644
--- a/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/FastPairTestDataProviderService.kt
+++ b/nearby/tests/multidevices/clients/src/android/nearby/multidevices/fastpair/seeker/dataprovider/FastPairTestDataProviderService.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.nearby.multidevices.fastpair.seeker
+package android.nearby.multidevices.fastpair.seeker.dataprovider
import android.app.Service
import android.content.Intent
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/AppLogger.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/AppLogger.java
deleted file mode 100644
index befc64b..0000000
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/AppLogger.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2022 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 android.nearby.fastpair.provider.simulator.app;
-
-import android.util.Log;
-
-import com.google.errorprone.annotations.FormatMethod;
-
-/** Sends log to logcat with TAG. */
-public class AppLogger {
- private static final String TAG = "FastPairSimulator";
-
- @FormatMethod
- public static void log(String message, Object... objects) {
- Log.i(TAG, String.format(message, objects));
- }
-
- @FormatMethod
- public static void warning(String message, Object... objects) {
- Log.w(TAG, String.format(message, objects));
- }
-
- @FormatMethod
- public static void error(String message, Object... objects) {
- Log.e(TAG, String.format(message, objects));
- }
-
- private AppLogger() {
- }
-}
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
index 9252173..97f3bf4 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
@@ -20,8 +20,6 @@
import static android.nearby.fastpair.provider.simulator.SimulatorStreamProtocol.Event.Code.BLUETOOTH_STATE_BOND;
import static android.nearby.fastpair.provider.simulator.SimulatorStreamProtocol.Event.Code.BLUETOOTH_STATE_CONNECTION;
import static android.nearby.fastpair.provider.simulator.SimulatorStreamProtocol.Event.Code.BLUETOOTH_STATE_SCAN_MODE;
-import static android.nearby.fastpair.provider.simulator.app.AppLogger.log;
-import static android.nearby.fastpair.provider.simulator.app.AppLogger.warning;
import static com.google.common.io.BaseEncoding.base16;
import static com.google.common.io.BaseEncoding.base64;
@@ -41,6 +39,7 @@
import android.nearby.fastpair.provider.FastPairSimulator.BatteryValue;
import android.nearby.fastpair.provider.FastPairSimulator.KeyInputCallback;
import android.nearby.fastpair.provider.FastPairSimulator.PasskeyEventCallback;
+import android.nearby.fastpair.provider.bluetooth.BluetoothController;
import android.nearby.fastpair.provider.simulator.SimulatorStreamProtocol.Event;
import android.nearby.fastpair.provider.simulator.testing.RemoteDevice;
import android.nearby.fastpair.provider.simulator.testing.RemoteDevicesManager;
@@ -96,6 +95,9 @@
*/
@SuppressLint("SetTextI18n")
public class MainActivity extends Activity {
+ public static final String TAG = "FastPairProviderSimulatorApp";
+ private final Logger mLogger = new Logger(TAG);
+
/** Device has a display and the ability to input Yes/No. */
private static final int IO_CAPABILITY_IO = 1;
@@ -213,7 +215,7 @@
return;
}
- log("Send data to output stream: %s", eventBuilder.getCode().getNumber());
+ mLogger.log("Send data to output stream: %s", eventBuilder.getCode().getNumber());
mRemoteDevicesManager.writeDataToRemoteDevice(
mRemoteDeviceId,
eventBuilder.build().toByteString(),
@@ -446,7 +448,7 @@
private void setupRemoteDevices() {
if (Strings.isNullOrEmpty(getIntent().getStringExtra(EXTRA_REMOTE_DEVICE_ID))) {
- log("Can't get remote device id");
+ mLogger.log("Can't get remote device id");
return;
}
mRemoteDeviceId = getIntent().getStringExtra(EXTRA_REMOTE_DEVICE_ID);
@@ -463,7 +465,7 @@
REMOTE_DEVICE_OUTPUT_STREAM_URI),
mInputStreamListener));
} catch (IOException e) {
- warning("Failed to create stream IO handler: %s", e);
+ mLogger.log(e, "Failed to create stream IO handler");
}
}
@@ -503,7 +505,7 @@
private boolean setModelId(String modelId) {
String validModelId = getValidModelId(modelId);
if (TextUtils.isEmpty(validModelId)) {
- log("Can't do setModelId because inputted modelId is invalid!");
+ mLogger.log("Can't do setModelId because inputted modelId is invalid!");
return false;
}
@@ -612,7 +614,7 @@
try {
Preconditions.checkArgument(base16().decode(bluetoothAddress).length == 6);
} catch (IllegalArgumentException e) {
- log("Invalid BLUETOOTH_ADDRESS extra (%s), using default.", bluetoothAddress);
+ mLogger.log("Invalid BLUETOOTH_ADDRESS extra (%s), using default.", bluetoothAddress);
bluetoothAddress = null;
}
final String finalBluetoothAddress = bluetoothAddress;
@@ -669,11 +671,10 @@
mAppLaunchSwitch.isChecked() ? MODEL_ID_APP_LAUNCH : modelId)
.setBluetoothAddress(finalBluetoothAddress)
.setTxPowerLevel(toTxPowerLevel(txPower))
- .setCallback(this::updateStatusView)
+ .setAdvertisingChangedCallback(this::updateStatusView)
.setAntiSpoofingPrivateKey(antiSpoofingKey)
.setUseRandomSaltForAccountKeyRotation(useRandomSaltForAccountKeyRotation)
.setDataOnlyConnection(device != null && device.getDataOnlyConnection())
- .setIsMemoryTest(mInputStreamListener != null)
.setShowsPasskeyConfirmation(
device.getDeviceType().equals(DeviceType.ANDROID_AUTO))
.setRemoveAllDevicesDuringPairing(mRemoveAllDevicesDuringPairing)
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulator.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulator.java
index 931f2e0..aa7daa6 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulator.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulator.java
@@ -163,6 +163,10 @@
public static final String TAG = "FastPairSimulator";
private final Logger mLogger;
+ private static final int BECOME_DISCOVERABLE_TIMEOUT_SEC = 3;
+
+ private static final int SCAN_MODE_REFRESH_SEC = 30;
+
/**
* Headphones. Generated by
* http://bluetooth-pentest.narod.ru/software/bluetooth_class_of_device-service_generator.html
@@ -170,18 +174,16 @@
private static final Value CLASS_OF_DEVICE =
new Value(base16().decode("200418"), ByteOrder.BIG_ENDIAN);
- private static final byte[] SUPPORTED_SERVICES_LTV =
- new Ltv(
- TransportDiscoveryService.SERVICE_UUIDS_16_BIT_LIST_TYPE,
- toBytes(ByteOrder.LITTLE_ENDIAN, A2DP_SINK_SERVICE_UUID))
- .getBytes();
+ private static final byte[] SUPPORTED_SERVICES_LTV = new Ltv(
+ TransportDiscoveryService.SERVICE_UUIDS_16_BIT_LIST_TYPE,
+ toBytes(ByteOrder.LITTLE_ENDIAN, A2DP_SINK_SERVICE_UUID)
+ ).getBytes();
private static final byte[] TDS_CONTROL_POINT_RESPONSE_PARAMETER =
Bytes.concat(new byte[]{BLUETOOTH_SIG_ORGANIZATION_ID}, SUPPORTED_SERVICES_LTV);
private static final String SIMULATOR_FAKE_BLE_ADDRESS = "11:22:33:44:55:66";
private static final long ADVERTISING_REFRESH_DELAY_1_MIN = TimeUnit.MINUTES.toMillis(1);
- private static final long ADVERTISING_REFRESH_DELAY_5_MINS = TimeUnit.MINUTES.toMillis(5);
/** The user will be prompted to accept or deny the incoming pairing request */
public static final int PAIRING_VARIANT_CONSENT = 3;
@@ -250,140 +252,139 @@
private final ScheduledExecutorService mExecutor =
Executors.newSingleThreadScheduledExecutor(); // exempt
private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- private final BroadcastReceiver mBroadcastReceiver =
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mShouldFailPairing) {
- mLogger.log("Pairing disabled by test app switch");
- return;
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mShouldFailPairing) {
+ mLogger.log("Pairing disabled by test app switch");
+ return;
+ }
+ if (mIsDestroyed) {
+ // Sometimes this receiver does not successfully unregister in destroy()
+ // which causes events to occur after the simulator is stopped, so ignore
+ // those events.
+ mLogger.log("Intent received after simulator destroyed, ignoring");
+ return;
+ }
+ BluetoothDevice device = intent.getParcelableExtra(
+ BluetoothDevice.EXTRA_DEVICE);
+ switch (intent.getAction()) {
+ case BluetoothAdapter.ACTION_SCAN_MODE_CHANGED:
+ if (isDiscoverable()) {
+ mIsDiscoverableLatch.countDown();
}
- if (mIsDestroyed) {
- // Sometimes this receiver does not successfully unregister in destroy()
- // which causes events to occur after the simulator is stopped, so ignore
- // those events.
- mLogger.log("Intent received after simulator destroyed, ignoring");
- return;
+ break;
+ case BluetoothDevice.ACTION_PAIRING_REQUEST:
+ int variant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+ ERROR);
+ int key = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, ERROR);
+ mLogger.log(
+ "Pairing request, variant=%d, key=%s", variant,
+ key == ERROR ? "(none)" : key);
+
+ // Prevent Bluetooth Settings from getting the pairing request.
+ abortBroadcast();
+
+ mPairingDevice = device;
+ if (mSecret == null) {
+ // We haven't done the handshake over GATT to agree on the shared
+ // secret. For now, just accept anyway (so we can still simulate
+ // old 1.0 model IDs).
+ mLogger.log("No handshake, auto-accepting anyway.");
+ setPasskeyConfirmation(true);
+ } else if (variant
+ == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
+ // Store the passkey. And check it, since there's a race (see
+ // method for why). Usually this check is a no-op and we'll get
+ // the passkey later over GATT.
+ mLocalPasskey = key;
+ checkPasskey();
+ } else if (variant == PAIRING_VARIANT_DISPLAY_PASSKEY) {
+ if (mPasskeyEventCallback != null) {
+ mPasskeyEventCallback.onPasskeyRequested(
+ FastPairSimulator.this::enterPassKey);
+ } else {
+ mLogger.log("passkeyEventCallback is not set!");
+ enterPassKey(key);
+ }
+ } else if (variant == PAIRING_VARIANT_CONSENT) {
+ setPasskeyConfirmation(true);
+
+ } else if (variant == BluetoothDevice.PAIRING_VARIANT_PIN) {
+ if (mPasskeyEventCallback != null) {
+ mPasskeyEventCallback.onPasskeyRequested(
+ (int pin) -> {
+ byte[] newPin = convertPinToBytes(
+ String.format(Locale.ENGLISH, "%d", pin));
+ mPairingDevice.setPin(newPin);
+ });
+ }
+ } else {
+ // Reject the pairing request if it's not using the Numeric
+ // Comparison (aka Passkey Confirmation) method.
+ setPasskeyConfirmation(false);
}
- BluetoothDevice device = intent.getParcelableExtra(
- BluetoothDevice.EXTRA_DEVICE);
- switch (intent.getAction()) {
- case BluetoothAdapter.ACTION_SCAN_MODE_CHANGED:
- if (isDiscoverable()) {
- mIsDiscoverableLatch.countDown();
+ break;
+ case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
+ int bondState =
+ intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+ BluetoothDevice.BOND_NONE);
+ mLogger.log("Bond state to %s changed to %d", device, bondState);
+ switch (bondState) {
+ case BluetoothDevice.BOND_BONDING:
+ // If we've started bonding, we shouldn't be advertising.
+ mAdvertiser.stopAdvertising();
+ // Not discoverable anymore, but still connectable.
+ setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+ break;
+ case BluetoothDevice.BOND_BONDED:
+ // Once bonded, advertise the account keys.
+ mAdvertiser.startAdvertising(accountKeysServiceData());
+ setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+
+ // If it is subsequent pair, we need to add paired device here.
+ if (mIsSubsequentPair
+ && mSecret != null
+ && mSecret.length == AES_BLOCK_LENGTH) {
+ addAccountKey(mSecret, mPairingDevice);
}
break;
- case BluetoothDevice.ACTION_PAIRING_REQUEST:
- int variant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
- ERROR);
- int key = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, ERROR);
- mLogger.log(
- "Pairing request, variant=%d, key=%s", variant,
- key == ERROR ? "(none)" : key);
-
- // Prevent Bluetooth Settings from getting the pairing request.
- abortBroadcast();
-
- mPairingDevice = device;
- if (mSecret == null) {
- // We haven't done the handshake over GATT to agree on the shared
- // secret. For now, just accept anyway (so we can still simulate
- // old 1.0 model IDs).
- mLogger.log("No handshake, auto-accepting anyway.");
- setPasskeyConfirmation(true);
- } else if (variant
- == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION) {
- // Store the passkey. And check it, since there's a race (see
- // method for why). Usually this check is a no-op and we'll get
- // the passkey later over GATT.
- mLocalPasskey = key;
- checkPasskey();
- } else if (variant == PAIRING_VARIANT_DISPLAY_PASSKEY) {
- if (mPasskeyEventCallback != null) {
- mPasskeyEventCallback.onPasskeyRequested(
- FastPairSimulator.this::enterPassKey);
- } else {
- mLogger.log("passkeyEventCallback is not set!");
- enterPassKey(key);
- }
- } else if (variant == PAIRING_VARIANT_CONSENT) {
- setPasskeyConfirmation(true);
-
- } else if (variant == BluetoothDevice.PAIRING_VARIANT_PIN) {
- if (mPasskeyEventCallback != null) {
- mPasskeyEventCallback.onPasskeyRequested(
- (int pin) -> {
- byte[] newPin = convertPinToBytes(
- String.format(Locale.ENGLISH, "%d", pin));
- mPairingDevice.setPin(newPin);
- });
- }
- } else {
- // Reject the pairing request if it's not using the Numeric
- // Comparison (aka Passkey Confirmation) method.
- setPasskeyConfirmation(false);
- }
- break;
- case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
- int bondState =
- intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
- BluetoothDevice.BOND_NONE);
- mLogger.log("Bond state to %s changed to %d", device, bondState);
- switch (bondState) {
- case BluetoothDevice.BOND_BONDING:
- // If we've started bonding, we shouldn't be advertising.
- mAdvertiser.stopAdvertising();
- // Not discoverable anymore, but still connectable.
- setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
- break;
- case BluetoothDevice.BOND_BONDED:
- // Once bonded, advertise the account keys.
- mAdvertiser.startAdvertising(accountKeysServiceData());
- setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
-
- // If it is subsequent pair, we need to add paired device here.
- if (mIsSubsequentPair
- && mSecret != null
- && mSecret.length == AES_BLOCK_LENGTH) {
- addAccountKey(mSecret, mPairingDevice);
- }
- break;
- case BluetoothDevice.BOND_NONE:
- // If the bonding process fails, we should be advertising again.
- mAdvertiser.startAdvertising(getServiceData());
- break;
- default:
- break;
- }
- break;
- case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:
- mLogger.log(
- "Connection state to %s changed to %d",
- device,
- intent.getIntExtra(
- BluetoothAdapter.EXTRA_CONNECTION_STATE,
- BluetoothAdapter.STATE_DISCONNECTED));
- break;
- case BluetoothAdapter.ACTION_STATE_CHANGED:
- int state = intent.getIntExtra(EXTRA_STATE, -1);
- mLogger.log("Bluetooth adapter state=%s", state);
- switch (state) {
- case STATE_ON:
- startRfcommServer();
- break;
- case STATE_OFF:
- stopRfcommServer();
- break;
- default: // fall out
- }
+ case BluetoothDevice.BOND_NONE:
+ // If the bonding process fails, we should be advertising again.
+ mAdvertiser.startAdvertising(getServiceData());
break;
default:
- mLogger.log(new IllegalArgumentException(intent.toString()),
- "Received unexpected intent");
break;
}
- }
- };
+ break;
+ case BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED:
+ mLogger.log(
+ "Connection state to %s changed to %d",
+ device,
+ intent.getIntExtra(
+ BluetoothAdapter.EXTRA_CONNECTION_STATE,
+ BluetoothAdapter.STATE_DISCONNECTED));
+ break;
+ case BluetoothAdapter.ACTION_STATE_CHANGED:
+ int state = intent.getIntExtra(EXTRA_STATE, -1);
+ mLogger.log("Bluetooth adapter state=%s", state);
+ switch (state) {
+ case STATE_ON:
+ startRfcommServer();
+ break;
+ case STATE_OFF:
+ stopRfcommServer();
+ break;
+ default: // fall out
+ }
+ break;
+ default:
+ mLogger.log(new IllegalArgumentException(intent.toString()),
+ "Received unexpected intent");
+ break;
+ }
+ }
+ };
@Nullable
private byte[] convertPinToBytes(@Nullable String pin) {
@@ -508,7 +509,6 @@
@Nullable
private CountDownLatch mWriteNameCountDown;
private final RfcommServer mRfcommServer = new RfcommServer();
- private final boolean mDataOnlyConnection;
private boolean mSupportDynamicBufferSize = false;
private NotifiableGattServlet mBeaconActionsServlet;
private final FastPairSimulatorDatabase mFastPairSimulatorDatabase;
@@ -570,8 +570,8 @@
this.mUseLogFullEvent = useLogFullEvent;
}
- /** An optional way to get status updates. */
- public interface Callback {
+ /** An optional way to get advertising status updates. */
+ public interface AdvertisingChangedCallback {
/** Called when we change our BLE advertisement. */
void onAdvertisingChanged();
}
@@ -618,7 +618,7 @@
private final boolean mEnableNameCharacteristic;
- private final Callback mCallback;
+ private final AdvertisingChangedCallback mAdvertisingChangedCallback;
private final boolean mIncludeTransportDataDescriptor;
@@ -627,8 +627,6 @@
private final boolean mUseRandomSaltForAccountKeyRotation;
- private final boolean mIsMemoryTest;
-
private final boolean mBecomeDiscoverable;
private final boolean mShowsPasskeyConfirmation;
@@ -648,11 +646,10 @@
boolean dataOnlyConnection,
int txPowerLevel,
boolean enableNameCharacteristic,
- Callback callback,
+ AdvertisingChangedCallback advertisingChangedCallback,
boolean includeTransportDataDescriptor,
@Nullable byte[] antiSpoofingPrivateKey,
boolean useRandomSaltForAccountKeyRotation,
- boolean isMemoryTest,
boolean becomeDiscoverable,
boolean showsPasskeyConfirmation,
boolean enableBeaconActionsCharacteristic,
@@ -665,11 +662,10 @@
this.mDataOnlyConnection = dataOnlyConnection;
this.mTxPowerLevel = txPowerLevel;
this.mEnableNameCharacteristic = enableNameCharacteristic;
- this.mCallback = callback;
+ this.mAdvertisingChangedCallback = advertisingChangedCallback;
this.mIncludeTransportDataDescriptor = includeTransportDataDescriptor;
this.mAntiSpoofingPrivateKey = antiSpoofingPrivateKey;
this.mUseRandomSaltForAccountKeyRotation = useRandomSaltForAccountKeyRotation;
- this.mIsMemoryTest = isMemoryTest;
this.mBecomeDiscoverable = becomeDiscoverable;
this.mShowsPasskeyConfirmation = showsPasskeyConfirmation;
this.mEnableBeaconActionsCharacteristic = enableBeaconActionsCharacteristic;
@@ -708,8 +704,8 @@
return mEnableNameCharacteristic;
}
- public Callback getCallback() {
- return mCallback;
+ public AdvertisingChangedCallback getAdvertisingChangedCallback() {
+ return mAdvertisingChangedCallback;
}
public boolean getIncludeTransportDataDescriptor() {
@@ -725,10 +721,6 @@
return mUseRandomSaltForAccountKeyRotation;
}
- public boolean getIsMemoryTest() {
- return mIsMemoryTest;
- }
-
public boolean getBecomeDiscoverable() {
return mBecomeDiscoverable;
}
@@ -766,13 +758,12 @@
.setModelId(Ascii.toUpperCase(modelId))
.setAdvertisingModelId(Ascii.toUpperCase(modelId))
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
- .setCallback(() -> {
+ .setAdvertisingChangedCallback(() -> {
})
.setIncludeTransportDataDescriptor(true)
.setUseRandomSaltForAccountKeyRotation(false)
.setEnableNameCharacteristic(true)
.setDataOnlyConnection(false)
- .setIsMemoryTest(false)
.setBecomeDiscoverable(true)
.setShowsPasskeyConfirmation(false)
.setEnableBeaconActionsCharacteristic(true)
@@ -799,7 +790,7 @@
private boolean mEnableNameCharacteristic;
- private Callback mCallback;
+ private AdvertisingChangedCallback mAdvertisingChangedCallback;
private boolean mIncludeTransportDataDescriptor;
@@ -808,8 +799,6 @@
private boolean mUseRandomSaltForAccountKeyRotation;
- private boolean mIsMemoryTest;
-
private boolean mBecomeDiscoverable;
private boolean mShowsPasskeyConfirmation;
@@ -832,12 +821,11 @@
this.mDataOnlyConnection = option.mDataOnlyConnection;
this.mTxPowerLevel = option.mTxPowerLevel;
this.mEnableNameCharacteristic = option.mEnableNameCharacteristic;
- this.mCallback = option.mCallback;
+ this.mAdvertisingChangedCallback = option.mAdvertisingChangedCallback;
this.mIncludeTransportDataDescriptor = option.mIncludeTransportDataDescriptor;
this.mAntiSpoofingPrivateKey = option.mAntiSpoofingPrivateKey;
this.mUseRandomSaltForAccountKeyRotation =
option.mUseRandomSaltForAccountKeyRotation;
- this.mIsMemoryTest = option.mIsMemoryTest;
this.mBecomeDiscoverable = option.mBecomeDiscoverable;
this.mShowsPasskeyConfirmation = option.mShowsPasskeyConfirmation;
this.mEnableBeaconActionsCharacteristic = option.mEnableBeaconActionsCharacteristic;
@@ -874,9 +862,10 @@
return this;
}
- /** @see Callback */
- public Builder setCallback(Callback callback) {
- this.mCallback = callback;
+ /** @see AdvertisingChangedCallback */
+ public Builder setAdvertisingChangedCallback(
+ AdvertisingChangedCallback advertisingChangedCallback) {
+ this.mAdvertisingChangedCallback = advertisingChangedCallback;
return this;
}
@@ -913,11 +902,6 @@
return this;
}
- public Builder setIsMemoryTest(boolean isMemoryTest) {
- this.mIsMemoryTest = isMemoryTest;
- return this;
- }
-
public Builder setBecomeDiscoverable(boolean becomeDiscoverable) {
this.mBecomeDiscoverable = becomeDiscoverable;
return this;
@@ -963,11 +947,10 @@
mDataOnlyConnection,
mTxPowerLevel,
mEnableNameCharacteristic,
- mCallback,
+ mAdvertisingChangedCallback,
mIncludeTransportDataDescriptor,
mAntiSpoofingPrivateKey,
mUseRandomSaltForAccountKeyRotation,
- mIsMemoryTest,
mBecomeDiscoverable,
mShowsPasskeyConfirmation,
mEnableBeaconActionsCharacteristic,
@@ -1001,7 +984,6 @@
this.mBluetoothAddress =
new Value(BluetoothAddress.decode(bluetoothAddress), ByteOrder.BIG_ENDIAN);
this.mBleAddress = options.getBleAddress();
- this.mDataOnlyConnection = options.getDataOnlyConnection();
this.mAdvertiser = new OreoFastPairAdvertiser(this);
mFastPairSimulatorDatabase = new FastPairSimulatorDatabase(context);
@@ -1011,7 +993,7 @@
"Provider default device name is %s",
deviceName != null ? new String(deviceName, StandardCharsets.UTF_8) : null);
- if (mDataOnlyConnection) {
+ if (mOptions.getDataOnlyConnection()) {
// To get BLE address, we need to start advertising first, and then
// {@code#setBleAddress} will be called with BLE address.
mAdvertiser.startAdvertising(modelIdServiceData(/* forAdvertising= */ true));
@@ -1055,19 +1037,11 @@
*/
@SuppressWarnings("FutureReturnValueIgnored")
private void scheduleAdvertisingRefresh() {
- mExecutor.scheduleAtFixedRate(
- () -> {
- if (mIsAdvertising) {
- mAdvertiser.startAdvertising(getServiceData());
- }
- },
- mOptions.getIsMemoryTest()
- ? ADVERTISING_REFRESH_DELAY_5_MINS
- : ADVERTISING_REFRESH_DELAY_1_MIN,
- mOptions.getIsMemoryTest()
- ? ADVERTISING_REFRESH_DELAY_5_MINS
- : ADVERTISING_REFRESH_DELAY_1_MIN,
- TimeUnit.MILLISECONDS);
+ mExecutor.scheduleAtFixedRate(() -> {
+ if (mIsAdvertising) {
+ mAdvertiser.startAdvertising(getServiceData());
+ }
+ }, ADVERTISING_REFRESH_DELAY_1_MIN, ADVERTISING_REFRESH_DELAY_1_MIN, TimeUnit.MILLISECONDS);
}
public void destroy() {
@@ -1103,7 +1077,7 @@
public void setIsAdvertising(boolean isAdvertising) {
if (this.mIsAdvertising != isAdvertising) {
this.mIsAdvertising = isAdvertising;
- mOptions.getCallback().onAdvertisingChanged();
+ mOptions.getAdvertisingChangedCallback().onAdvertisingChanged();
}
}
@@ -1113,7 +1087,7 @@
public void setBleAddress(String bleAddress) {
this.mBleAddress = bleAddress;
- if (mDataOnlyConnection) {
+ if (mOptions.getDataOnlyConnection()) {
mBluetoothAddress = new Value(BluetoothAddress.decode(bleAddress),
ByteOrder.BIG_ENDIAN);
start(bleAddress);
@@ -2086,7 +2060,7 @@
if (isDiscoverable()) {
mIsDiscoverableLatch.countDown();
}
- if (mIsDiscoverableLatch.await(3, TimeUnit.SECONDS)) {
+ if (mIsDiscoverableLatch.await(BECOME_DISCOVERABLE_TIMEOUT_SEC, TimeUnit.SECONDS)) {
mLogger.log("Successfully became switched discoverable mode %s", discoverable);
} else {
throw new TimeoutException();
@@ -2105,10 +2079,8 @@
if (scanMode == SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
mRevertDiscoverableFuture =
- mExecutor.schedule(
- () -> setScanMode(SCAN_MODE_CONNECTABLE),
- mOptions.getIsMemoryTest() ? 300 : 30,
- TimeUnit.SECONDS);
+ mExecutor.schedule(() -> setScanMode(SCAN_MODE_CONNECTABLE),
+ SCAN_MODE_REFRESH_SEC, TimeUnit.SECONDS);
}
} catch (Exception e) {
mLogger.log(e, "Error setting scan mode to %d", scanMode);
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulatorDatabase.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulatorDatabase.java
index 254ec51..cbe39ff 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulatorDatabase.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/FastPairSimulatorDatabase.java
@@ -37,7 +37,7 @@
public class FastPairSimulatorDatabase {
private static final String SHARED_PREF_NAME =
- "android.nearby.multidevices.fastpair.provider.fastpairsimulator";
+ "android.nearby.fastpair.provider.fastpairsimulator";
private static final String KEY_DEVICE_NAME = "DEVICE_NAME";
private static final String KEY_ACCOUNT_KEYS = "ACCOUNT_KEYS";
private static final int MAX_NUMBER_OF_ACCOUNT_KEYS = 8;
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/OreoFastPairAdvertiser.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/OreoFastPairAdvertiser.java
index dd664ea..bb77c11 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/OreoFastPairAdvertiser.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/OreoFastPairAdvertiser.java
@@ -54,53 +54,54 @@
public OreoFastPairAdvertiser(FastPairSimulator simulator) {
this.mSimulator = simulator;
this.mAdvertiser = BluetoothAdapter.getDefaultAdapter().getBluetoothLeAdvertiser();
- this.mAdvertisingSetCallback =
- new AdvertisingSetCallback() {
- @Override
- public void onAdvertisingSetStarted(
- AdvertisingSet set, int txPower, int status) {
- if (status == AdvertisingSetCallback.ADVERTISE_SUCCESS) {
- mLogger.log("Advertising succeeded, advertising at %s dBm", txPower);
- simulator.setIsAdvertising(true);
- mAdvertisingSet = set;
+ this.mAdvertisingSetCallback = new AdvertisingSetCallback() {
- try {
- // Requires custom Android build, see callback below.
- Reflect.on(set).withMethod("getOwnAddress").invoke();
- } catch (ReflectionException e) {
- mLogger.log(e, "Error calling getOwnAddress for AdvertisingSet");
- }
- } else {
- mLogger.log(
- new IllegalStateException(),
- "Advertising failed, error code=%d", status);
- }
- }
+ @Override
+ public void onAdvertisingSetStarted(
+ AdvertisingSet set, int txPower, int status) {
+ if (status == AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+ mLogger.log("Advertising succeeded, advertising at %s dBm", txPower);
+ simulator.setIsAdvertising(true);
+ mAdvertisingSet = set;
- @Override
- public void onAdvertisingDataSet(AdvertisingSet set, int status) {
- if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
- mLogger.log(
- new IllegalStateException(),
- "Updating advertisement failed, error code=%d",
- status);
- stopAdvertising();
- }
+ try {
+ // Requires custom Android build, see callback below.
+ Reflect.on(set).withMethod("getOwnAddress").invoke();
+ } catch (ReflectionException e) {
+ mLogger.log(e, "Error calling getOwnAddress for AdvertisingSet");
}
+ } else {
+ mLogger.log(
+ new IllegalStateException(),
+ "Advertising failed, error code=%d", status);
+ }
+ }
- // Called via reflection with AdvertisingSet.getOwnAddress().
- public void onOwnAddressRead(
- AdvertisingSet set, int addressType, String address) {
- if (!address.equals(simulator.getBleAddress())) {
- mLogger.log(
- "Read own BLE address=%s at %s",
- address,
- new SimpleDateFormat("HH:mm:ss:SSS", Locale.US)
- .format(Calendar.getInstance().getTime()));
- simulator.setBleAddress(address);
- }
- }
- };
+ @Override
+ public void onAdvertisingDataSet(AdvertisingSet set, int status) {
+ if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
+ mLogger.log(
+ new IllegalStateException(),
+ "Updating advertisement failed, error code=%d",
+ status);
+ stopAdvertising();
+ }
+ }
+
+ // Called via reflection with AdvertisingSet.getOwnAddress().
+ public void onOwnAddressRead(
+ AdvertisingSet set, int addressType, String address) {
+ if (!address.equals(simulator.getBleAddress())) {
+ mLogger.log(
+ "Read own BLE address=%s at %s",
+ address,
+ new SimpleDateFormat("HH:mm:ss:SSS", Locale.US)
+ .format(Calendar.getInstance().getTime()));
+ // Implicitly start the advertising once BLE address callback arrived.
+ simulator.setBleAddress(address);
+ }
+ }
+ };
}
@Override
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/BluetoothController.kt b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
similarity index 92%
rename from nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/BluetoothController.kt
rename to nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
index ed04eae..6a3e59e 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/BluetoothController.kt
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.nearby.fastpair.provider.simulator.app
+package android.nearby.fastpair.provider.bluetooth
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
@@ -25,9 +25,9 @@
import android.content.Intent
import android.content.IntentFilter
import android.nearby.fastpair.provider.FastPairSimulator
-import android.nearby.fastpair.provider.simulator.app.AppLogger.*
-import android.nearby.fastpair.provider.simulator.testing.Reflect
-import android.nearby.fastpair.provider.simulator.testing.ReflectionException
+import android.nearby.fastpair.provider.utils.Logger
+import android.nearby.fastpair.provider.utils.Reflect
+import android.nearby.fastpair.provider.utils.ReflectionException
import android.os.SystemClock
import android.provider.Settings
@@ -36,6 +36,7 @@
private val context: Context,
private val listener: EventListener,
) : BroadcastReceiver() {
+ private val mLogger = Logger(TAG)
private val bluetoothAdapter: BluetoothAdapter =
(context.getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager)?.adapter!!
private var remoteDevice: BluetoothDevice? = null
@@ -71,14 +72,14 @@
.withMethod("setIoCapability", Int::class.javaPrimitiveType)[
ioCapabilityClassic]
} catch (e: ReflectionException) {
- warning("Error setIoCapability to %s: %s", ioCapabilityClassic, e)
+ mLogger.log(e, "Error setIoCapability to %s: %s", ioCapabilityClassic)
}
try {
Reflect.on(bluetoothAdapter)
.withMethod("setLeIoCapability", Int::class.javaPrimitiveType)[
ioCapabilityBLE]
} catch (e: ReflectionException) {
- warning("Error setLeIoCapability to %s: %s", ioCapabilityBLE, e)
+ mLogger.log(e, "Error setLeIoCapability to %s: %s", ioCapabilityBLE)
}
// Toggling airplane mode on/off to restart Bluetooth stack and reset the BLE.
@@ -90,7 +91,10 @@
TURN_AIRPLANE_MODE_ON
)
} catch (expectedOnNonCustomAndroid: SecurityException) {
- warning("Requires custom Android to toggle airplane mode")
+ mLogger.log(
+ expectedOnNonCustomAndroid,
+ "Requires custom Android to toggle airplane mode"
+ )
// Fall back to turn off Bluetooth.
bluetoothAdapter.disable()
}
@@ -102,7 +106,10 @@
TURN_AIRPLANE_MODE_OFF
)
} catch (expectedOnNonCustomAndroid: SecurityException) {
- error("SecurityException while toggled airplane mode.")
+ mLogger.log(
+ expectedOnNonCustomAndroid,
+ "SecurityException while toggled airplane mode."
+ )
} finally {
// Double confirm that Bluetooth is turned on.
bluetoothAdapter.enable()
@@ -183,8 +190,6 @@
* @param intent the Intent being received.
*/
override fun onReceive(context: Context, intent: Intent) {
- log("BluetoothController received intent, action=%s", intent.action)
-
when (intent.action) {
BluetoothDevice.ACTION_BOND_STATE_CHANGED -> {
// After a device starts bonding, we only pay attention to intents about that device.
@@ -198,7 +203,7 @@
BluetoothDevice.BOND_NONE -> null
else -> remoteDevice
}
- log(
+ mLogger.log(
"ACTION_BOND_STATE_CHANGED, the bound state of the remote device (%s) change to %s.",
remoteDevice?.remoteDeviceToString(),
bondState.bondStateToString()
@@ -211,7 +216,7 @@
BluetoothAdapter.EXTRA_CONNECTION_STATE,
BluetoothAdapter.STATE_DISCONNECTED
)
- log(
+ mLogger.log(
"ACTION_CONNECTION_STATE_CHANGED, the new connectionState: %s",
remoteDeviceConnectionState
)
@@ -223,7 +228,7 @@
BluetoothAdapter.EXTRA_SCAN_MODE,
BluetoothAdapter.SCAN_MODE_NONE
)
- log(
+ mLogger.log(
"ACTION_SCAN_MODE_CHANGED, the new scanMode: %s",
FastPairSimulator.scanModeToString(scanMode)
)
@@ -277,10 +282,12 @@
}
companion object {
+ private const val TAG = "BluetoothController"
+
/** Hidden SystemApi field in [BluetoothProfile] interface. */
private const val BLUETOOTH_PROFILE_A2DP_SINK = 11
private const val TURN_AIRPLANE_MODE_OFF = 0
private const val TURN_AIRPLANE_MODE_ON = 1
}
-}
+}
\ No newline at end of file
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/Reflect.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/Reflect.java
similarity index 98%
rename from nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/Reflect.java
rename to nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/Reflect.java
index 16fbc71..5ae5310 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/Reflect.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/Reflect.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.nearby.fastpair.provider.simulator.testing;
+package android.nearby.fastpair.provider.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/ReflectionException.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/ReflectionException.java
similarity index 93%
rename from nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/ReflectionException.java
rename to nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/ReflectionException.java
index 2a65f39..959fd11 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/testing/ReflectionException.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/utils/ReflectionException.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.nearby.fastpair.provider.simulator.testing;
+package android.nearby.fastpair.provider.utils;
/**
* An exception thrown during a reflection operation. Like ReflectiveOperationException, except
diff --git a/nearby/tests/multidevices/clients/tests/Android.bp b/nearby/tests/multidevices/clients/tests/Android.bp
deleted file mode 100644
index a29a298..0000000
--- a/nearby/tests/multidevices/clients/tests/Android.bp
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (C) 2022 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 {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-// Run the tests: atest --host NearbyMultiDevicesClientsRoboTest
-android_robolectric_test {
- name: "NearbyMultiDevicesClientsRoboTest",
- srcs: ["src/**/*.kt"],
- instrumentation_for: "NearbyMultiDevicesClientsSnippets",
- java_resources: ["robolectric.properties"],
-
- static_libs: [
- "NearbyMultiDevicesClientsLib",
- "androidx.test.ext.junit",
- "androidx.test.rules",
- "junit",
- "mobly-snippet-lib",
- "platform-test-annotations",
- "truth-prebuilt",
- ],
- test_options: {
- // timeout in seconds.
- timeout: 36000,
- },
-}
\ No newline at end of file
diff --git a/nearby/tests/multidevices/clients/tests/AndroidManifest.xml b/nearby/tests/multidevices/clients/tests/AndroidManifest.xml
deleted file mode 100644
index c8e17e8..0000000
--- a/nearby/tests/multidevices/clients/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.nearby.multidevices"/>
diff --git a/nearby/tests/multidevices/clients/tests/robolectric.properties b/nearby/tests/multidevices/clients/tests/robolectric.properties
deleted file mode 100644
index 2ea03bb..0000000
--- a/nearby/tests/multidevices/clients/tests/robolectric.properties
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright (C) 2022 Google Inc.
-#
-# 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.
-#
-sdk=NEWEST_SDK
\ No newline at end of file
diff --git a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/common/Mockotlin.kt b/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/common/Mockotlin.kt
deleted file mode 100644
index 8e70d9f..0000000
--- a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/common/Mockotlin.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2022 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.nearby.multidevices.common
-
-import org.mockito.ArgumentCaptor
-import org.mockito.Mockito
-import org.mockito.MockitoAnnotations
-
-/**
- * Helper methods to wrap common Mockito functions that don't do quite what you would expect in
- * Kotlin. The returned null values need to be recast to their original type in Kotlin otherwise it
- * breaks.
- */
-object Mockotlin {
-
- /**
- * Delegates to [Mockito.any].
- * @return null as T
- */
- fun <T> any() = Mockito.any<T>() as T
-
- /**
- * Delegates to [Mockito.eq].
- * @return null as T
- */
- fun <T> eq(match: T) = Mockito.eq(match) as T
-
- /**
- * Delegates to [Mockito.isA].
- * @return null as T
- */
- fun <T> isA(match: Class<T>): T = Mockito.isA(match) as T
-
- /** Delegates to [Mockito.when ], uses the same API as the mockitokotlin2 library. */
- fun <T> whenever(methodCall: T) = Mockito.`when`(methodCall)!!
-
- /**
- * Delegates to [Mockito.any] and calls it with Class<T>.
- * @return Class<T>
- */
- inline fun <reified T> anyClass(): Class<T> {
- Mockito.any(T::class.java)
- return T::class.java
- }
-
- /**
- * Delegates to [Mockito.anyListOf] and calls it with Class<T>.
- * @return List<T>
- */
- fun <T> anyListOf(): List<T> = Mockito.anyList<T>()
-
- /**
- * Delegates to [Mockito.mock].
- * @return T
- */
- inline fun <reified T> mock() = Mockito.mock(T::class.java)!!
-
- /** This is the same as calling `MockitoAnnotations.initMocks(this)` */
- fun Any.initMocks() {
- MockitoAnnotations.initMocks(this)
- }
-
- /**
- * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
- * when null is returned.
- */
- fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
-}
diff --git a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiverTest.kt b/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiverTest.kt
deleted file mode 100644
index f23ccbb..0000000
--- a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/provider/BluetoothStateChangeReceiverTest.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2022 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.nearby.multidevices.fastpair.provider
-
-import android.Manifest
-import android.bluetooth.BluetoothAdapter
-import android.content.Context
-import android.content.Intent
-import android.nearby.multidevices.fastpair.provider.BluetoothStateChangeReceiver
-import androidx.annotation.RequiresPermission
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.google.android.mobly.snippet.util.Log
-import com.google.common.truth.Truth.assertThat
-import com.android.nearby.multidevices.common.Mockotlin.mock
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.verify
-
-/** Robolectric tests for [BluetoothStateChangeReceiver]. */
-@RunWith(AndroidJUnit4::class)
-class BluetoothStateChangeReceiverTest {
- private lateinit var bluetoothStateChangeReceiver: BluetoothStateChangeReceiver
- private lateinit var context: Context
- private val mockListener = mock<BluetoothStateChangeReceiver.EventListener>()
-
- @Before
- fun setUp() {
- context = InstrumentationRegistry.getInstrumentation().context
- bluetoothStateChangeReceiver = BluetoothStateChangeReceiver(context)
- Log.apkLogTag = "BluetoothStateChangeReceiverTest"
- }
-
- @Test
- fun testRegister_setsListener() {
- bluetoothStateChangeReceiver.register(mockListener)
-
- assertThat(bluetoothStateChangeReceiver.listener).isNotNull()
- }
-
- @Test
- fun testUnregister_clearListener() {
- bluetoothStateChangeReceiver.register(mockListener)
-
- bluetoothStateChangeReceiver.unregister()
-
- assertThat(bluetoothStateChangeReceiver.listener).isNull()
- }
-
- @Test
- @RequiresPermission(Manifest.permission.BLUETOOTH)
- fun testOnReceive_actionScanModeChanged_reportsOnScanModeChange() {
- val intent =
- Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)
- .putExtra(
- BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
- )
- bluetoothStateChangeReceiver.register(mockListener)
-
- bluetoothStateChangeReceiver.onReceive(context, intent)
-
- verify(mockListener).onScanModeChange("DISCOVERABLE")
- }
-}
diff --git a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/seeker/CompanionAppUtilsTest.kt b/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/seeker/CompanionAppUtilsTest.kt
deleted file mode 100644
index 94c0952..0000000
--- a/nearby/tests/multidevices/clients/tests/src/com/android/nearby/multidevices/fastpair/seeker/CompanionAppUtilsTest.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2022 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.nearby.multidevices.fastpair.seeker
-
-import android.nearby.multidevices.fastpair.seeker.generateCompanionAppLaunchIntentUri
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-
-/** Robolectric tests for CompanionAppUtils.kt. */
-@RunWith(RobolectricTestRunner::class)
-class CompanionAppUtilsTest {
-
- @Test
- fun testGenerateCompanionAppLaunchIntentUri_defaultNullPackage_returnsEmptyString() {
- assertThat(generateCompanionAppLaunchIntentUri()).isEmpty()
- }
-
- @Test
- fun testGenerateCompanionAppLaunchIntentUri_emptyPackageName_returnsEmptyString() {
- assertThat(generateCompanionAppLaunchIntentUri(companionAppPackageName = "")).isEmpty()
- }
-
- @Test
- fun testGenerateCompanionAppLaunchIntentUri_emptyActivityName_returnsEmptyString() {
- val uriString = generateCompanionAppLaunchIntentUri(
- companionAppPackageName = COMPANION_APP_PACKAGE_TEST_CONSTANT, activityName = "")
-
- assertThat(uriString).isEmpty()
- }
-
- @Test
- fun testGenerateCompanionAppLaunchIntentUri_emptyAction_returnsNoActionUriString() {
- val uriString = generateCompanionAppLaunchIntentUri(
- companionAppPackageName = COMPANION_APP_PACKAGE_TEST_CONSTANT,
- activityName = COMPANION_APP_ACTIVITY_TEST_CONSTANT,
- action = "")
-
- assertThat(uriString).doesNotContain("action=")
- assertThat(uriString).contains("package=$COMPANION_APP_PACKAGE_TEST_CONSTANT")
- assertThat(uriString).contains(COMPANION_APP_ACTIVITY_TEST_CONSTANT)
- }
-
- @Test
- fun testGenerateCompanionAppLaunchIntentUri_nonNullArgs_returnsUriString() {
- val uriString = generateCompanionAppLaunchIntentUri(
- companionAppPackageName = COMPANION_APP_PACKAGE_TEST_CONSTANT,
- activityName = COMPANION_APP_ACTIVITY_TEST_CONSTANT,
- action = COMPANION_APP_ACTION_TEST_CONSTANT)
-
- assertThat(uriString).isEqualTo("intent:#Intent;" +
- "action=android.nearby.SHOW_WELCOME;" +
- "package=android.nearby.companion;" +
- "component=android.nearby.companion/android.nearby.companion.MainActivity;" +
- "end")
- }
-
- companion object {
- private const val COMPANION_APP_PACKAGE_TEST_CONSTANT = "android.nearby.companion"
- private const val COMPANION_APP_ACTIVITY_TEST_CONSTANT =
- "android.nearby.companion.MainActivity"
- private const val COMPANION_APP_ACTION_TEST_CONSTANT = "android.nearby.SHOW_WELCOME"
- }
-}
diff --git a/nearby/tests/multidevices/host/seeker_discover_provider_test.py b/nearby/tests/multidevices/host/seeker_discover_provider_test.py
index f875250..a52ca15 100644
--- a/nearby/tests/multidevices/host/seeker_discover_provider_test.py
+++ b/nearby/tests/multidevices/host/seeker_discover_provider_test.py
@@ -16,8 +16,10 @@
DEFAULT_MODEL_ID = '00000C'
# Default public key to simulate as registered headsets.
DEFAULT_ANTI_SPOOFING_KEY = 'Cbj9eCJrTdDgSYxLkqtfADQi86vIaMvxJsQ298sZYWE='
-# Default time in seconds for events waiting.
-DEFAULT_TIMEOUT_SEC = 60
+# Time in seconds for events waiting.
+BECOME_DISCOVERABLE_TIMEOUT_SEC = 10
+START_ADVERTISING_TIMEOUT_SEC = 5
+SCAN_TIMEOUT_SEC = 30
# Abbreviations for common use type.
FastPairProviderSimulator = fast_pair_provider_simulator.FastPairProviderSimulator
@@ -47,8 +49,8 @@
super().setup_test()
self._provider.start_provider_simulator(DEFAULT_MODEL_ID,
DEFAULT_ANTI_SPOOFING_KEY)
- self._provider.wait_for_discoverable_mode(DEFAULT_TIMEOUT_SEC)
- self._provider.wait_for_advertising_start(DEFAULT_TIMEOUT_SEC)
+ self._provider.wait_for_discoverable_mode(BECOME_DISCOVERABLE_TIMEOUT_SEC)
+ self._provider.wait_for_advertising_start(START_ADVERTISING_TIMEOUT_SEC)
self._seeker.start_scan()
def teardown_test(self) -> None:
@@ -62,7 +64,7 @@
def test_seeker_start_scanning_find_provider(self) -> None:
provider_ble_mac_address = self._provider.get_ble_mac_address()
self._seeker.wait_and_assert_provider_found(
- timeout_seconds=DEFAULT_TIMEOUT_SEC,
+ timeout_seconds=SCAN_TIMEOUT_SEC,
expected_model_id=DEFAULT_MODEL_ID,
expected_ble_mac_address=provider_ble_mac_address)
diff --git a/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
index b8233ec..adae97d 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/fastpair/cache/FastPairCacheManagerTest.java
@@ -25,6 +25,8 @@
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.SdkSuppress;
+import com.google.protobuf.ByteString;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -37,9 +39,17 @@
private static final String MODEL_ID = "001";
private static final String MODEL_ID2 = "002";
private static final String APP_NAME = "APP_NAME";
+ private static final String MAC_ADDRESS = "00:11:22:33";
+ private static final ByteString ACCOUNT_KEY = ByteString.copyFromUtf8("axgs");
+ private static final String MAC_ADDRESS_B = "00:11:22:44";
+ private static final ByteString ACCOUNT_KEY_B = ByteString.copyFromUtf8("axgb");
+
@Mock
DiscoveryItem mDiscoveryItem;
- @Mock DiscoveryItem mDiscoveryItem2;
+ @Mock
+ DiscoveryItem mDiscoveryItem2;
+ @Mock
+ Cache.StoredFastPairItem mStoredFastPairItem;
Cache.StoredDiscoveryItem mStoredDiscoveryItem = Cache.StoredDiscoveryItem.newBuilder()
.setTriggerId(MODEL_ID)
.setAppName(APP_NAME).build();
@@ -97,4 +107,47 @@
assertThat(fastPairCacheManager.getAllSavedStoreDiscoveryItem()).hasSize(3);
}
+ @Test
+ @SdkSuppress(minSdkVersion = 32, codeName = "T")
+ public void saveRetrieveInfoStoredFastPairItem() {
+ Context mContext = ApplicationProvider.getApplicationContext();
+ Cache.StoredFastPairItem storedFastPairItem = Cache.StoredFastPairItem.newBuilder()
+ .setMacAddress(MAC_ADDRESS)
+ .setAccountKey(ACCOUNT_KEY)
+ .build();
+
+
+ FastPairCacheManager fastPairCacheManager = new FastPairCacheManager(mContext);
+ fastPairCacheManager.putStoredFastPairItem(storedFastPairItem);
+
+ assertThat(fastPairCacheManager.getStoredFastPairItemFromMacAddress(
+ MAC_ADDRESS).getAccountKey())
+ .isEqualTo(ACCOUNT_KEY);
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = 32, codeName = "T")
+ public void checkGetAllFastPairItems() {
+ Context mContext = ApplicationProvider.getApplicationContext();
+ Cache.StoredFastPairItem storedFastPairItem = Cache.StoredFastPairItem.newBuilder()
+ .setMacAddress(MAC_ADDRESS)
+ .setAccountKey(ACCOUNT_KEY)
+ .build();
+ Cache.StoredFastPairItem storedFastPairItemB = Cache.StoredFastPairItem.newBuilder()
+ .setMacAddress(MAC_ADDRESS_B)
+ .setAccountKey(ACCOUNT_KEY_B)
+ .build();
+
+ FastPairCacheManager fastPairCacheManager = new FastPairCacheManager(mContext);
+ fastPairCacheManager.putStoredFastPairItem(storedFastPairItem);
+ fastPairCacheManager.putStoredFastPairItem(storedFastPairItemB);
+
+ assertThat(fastPairCacheManager.getAllSavedStoredFastPairItem().size())
+ .isEqualTo(2);
+
+ fastPairCacheManager.removeStoredFastPairItem(MAC_ADDRESS_B);
+
+ assertThat(fastPairCacheManager.getAllSavedStoredFastPairItem().size())
+ .isEqualTo(1);
+ }
}