diff --git a/nearby/README.md b/nearby/README.md index 2731b3e220..0d265638ba 100644 --- a/nearby/README.md +++ b/nearby/README.md @@ -49,6 +49,7 @@ Then, add the jar in IDE as below. ```sh Build unbundled module using banchan +$ source build/envsetup.sh $ banchan com.google.android.tethering mainline_modules_arm64 $ m apps_only dist $ adb install out/dist/com.google.android.tethering.apex diff --git a/nearby/framework/java/android/nearby/NearbyManager.java b/nearby/framework/java/android/nearby/NearbyManager.java index 070a2b66cb..00f1c38923 100644 --- a/nearby/framework/java/android/nearby/NearbyManager.java +++ b/nearby/framework/java/android/nearby/NearbyManager.java @@ -284,6 +284,8 @@ public class NearbyManager { */ public void queryOffloadCapability(@NonNull @CallbackExecutor Executor executor, @NonNull Consumer callback) { + Objects.requireNonNull(executor); + Objects.requireNonNull(callback); try { mService.queryOffloadCapability(new OffloadTransport(executor, callback)); } catch (RemoteException e) { diff --git a/nearby/service/java/com/android/server/nearby/NearbyConfiguration.java b/nearby/service/java/com/android/server/nearby/NearbyConfiguration.java index 9b32d699bb..9ef905d90e 100644 --- a/nearby/service/java/com/android/server/nearby/NearbyConfiguration.java +++ b/nearby/service/java/com/android/server/nearby/NearbyConfiguration.java @@ -54,6 +54,11 @@ public class NearbyConfiguration { public static final String NEARBY_REFACTOR_DISCOVERY_MANAGER = "nearby_refactor_discovery_manager"; + /** + * Flag to guard enable BLE during Nearby Service init time. + */ + public static final String NEARBY_ENABLE_BLE_IN_INIT = "nearby_enable_ble_in_init"; + private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE); private final DeviceConfigListener mDeviceConfigListener = new DeviceConfigListener(); @@ -67,6 +72,8 @@ public class NearbyConfiguration { private boolean mSupportTestApp; @GuardedBy("mDeviceConfigLock") private boolean mRefactorDiscoveryManager; + @GuardedBy("mDeviceConfigLock") + private boolean mEnableBleInInit; public NearbyConfiguration() { mDeviceConfigListener.start(); @@ -131,6 +138,15 @@ public class NearbyConfiguration { } } + /** + * @return {@code true} if enableBLE() is called during NearbyService init time. + */ + public boolean enableBleInInit() { + synchronized (mDeviceConfigLock) { + return mEnableBleInInit; + } + } + private class DeviceConfigListener implements DeviceConfig.OnPropertiesChangedListener { public void start() { DeviceConfig.addOnPropertiesChangedListener(getNamespace(), @@ -149,6 +165,8 @@ public class NearbyConfiguration { NEARBY_SUPPORT_TEST_APP, false /* defaultValue */); mRefactorDiscoveryManager = getDeviceConfigBoolean( NEARBY_REFACTOR_DISCOVERY_MANAGER, false /* defaultValue */); + mEnableBleInInit = getDeviceConfigBoolean( + NEARBY_ENABLE_BLE_IN_INIT, true /* defaultValue */); } } } diff --git a/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManager.java b/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManager.java index 0c4142657c..8995232025 100644 --- a/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManager.java +++ b/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManager.java @@ -21,6 +21,7 @@ import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; import static com.android.server.nearby.NearbyService.TAG; import android.annotation.Nullable; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.nearby.DataElement; import android.nearby.IScanListener; @@ -35,6 +36,7 @@ import android.util.Log; import androidx.annotation.NonNull; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.nearby.NearbyConfiguration; import com.android.server.nearby.injector.Injector; import com.android.server.nearby.managers.registration.DiscoveryRegistration; import com.android.server.nearby.provider.AbstractDiscoveryProvider; @@ -66,6 +68,7 @@ public class DiscoveryProviderManager extends private final BleDiscoveryProvider mBleDiscoveryProvider; private final Injector mInjector; private final Executor mExecutor; + private final NearbyConfiguration mNearbyConfiguration; public DiscoveryProviderManager(Context context, Injector injector) { Log.v(TAG, "DiscoveryProviderManager: "); @@ -75,6 +78,7 @@ public class DiscoveryProviderManager extends mChreDiscoveryProvider = new ChreDiscoveryProvider(mContext, new ChreCommunication(injector, mContext, mExecutor), mExecutor); mInjector = injector; + mNearbyConfiguration = new NearbyConfiguration(); } @VisibleForTesting @@ -86,6 +90,7 @@ public class DiscoveryProviderManager extends mInjector = injector; mBleDiscoveryProvider = bleDiscoveryProvider; mChreDiscoveryProvider = chreDiscoveryProvider; + mNearbyConfiguration = new NearbyConfiguration(); } private static boolean isChreOnly(Set scanFilters) { @@ -141,6 +146,10 @@ public class DiscoveryProviderManager extends /** Called after boot completed. */ public void init() { + // Register BLE only scan when Bluetooth is turned off + if (mNearbyConfiguration.enableBleInInit()) { + setBleScanEnabled(); + } if (mInjector.getContextHubManager() != null) { mChreDiscoveryProvider.init(); } @@ -242,7 +251,7 @@ public class DiscoveryProviderManager extends @GuardedBy("mMultiplexerLock") private void startBleProvider(Set scanFilters) { if (!mBleDiscoveryProvider.getController().isStarted()) { - Log.d(TAG, "DiscoveryProviderManager starts Ble scanning."); + Log.d(TAG, "DiscoveryProviderManager starts BLE scanning."); mBleDiscoveryProvider.getController().setListener(this); mBleDiscoveryProvider.getController().setProviderScanMode(mMerged.getScanMode()); mBleDiscoveryProvider.getController().setProviderScanFilters( @@ -313,4 +322,29 @@ public class DiscoveryProviderManager extends public void onMergedRegistrationsUpdated() { invalidateProviderScanMode(); } + + /** + * Registers Nearby service to Ble scan if Bluetooth is off. (Even when Bluetooth is off) + * @return {@code true} when Nearby currently can scan through Bluetooth or Ble or successfully + * registers Nearby service to Ble scan when Blutooth is off. + */ + public boolean setBleScanEnabled() { + BluetoothAdapter adapter = mInjector.getBluetoothAdapter(); + if (adapter == null) { + Log.e(TAG, "BluetoothAdapter is null."); + return false; + } + if (adapter.isEnabled() || adapter.isLeEnabled()) { + return true; + } + if (!adapter.isBleScanAlwaysAvailable()) { + Log.v(TAG, "Ble always on scan is disabled."); + return false; + } + if (!adapter.enableBLE()) { + Log.e(TAG, "Failed to register Ble scan."); + return false; + } + return true; + } } diff --git a/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManagerLegacy.java b/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManagerLegacy.java index 4b76eba888..3ef8fb79e0 100644 --- a/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManagerLegacy.java +++ b/nearby/service/java/com/android/server/nearby/managers/DiscoveryProviderManagerLegacy.java @@ -22,6 +22,7 @@ import static com.android.server.nearby.NearbyService.TAG; import android.annotation.Nullable; import android.app.AppOpsManager; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.nearby.DataElement; import android.nearby.IScanListener; @@ -38,6 +39,7 @@ import android.util.Log; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.nearby.NearbyConfiguration; import com.android.server.nearby.injector.Injector; import com.android.server.nearby.metrics.NearbyMetrics; import com.android.server.nearby.presence.PresenceDiscoveryResult; @@ -69,6 +71,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider private final Context mContext; private final BleDiscoveryProvider mBleDiscoveryProvider; private final Injector mInjector; + private final NearbyConfiguration mNearbyConfiguration; @ScanRequest.ScanMode private int mScanMode; @GuardedBy("mLock") @@ -83,6 +86,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider mContext, new ChreCommunication(injector, mContext, executor), executor); mScanTypeScanListenerRecordMap = new HashMap<>(); mInjector = injector; + mNearbyConfiguration = new NearbyConfiguration(); Log.v(TAG, "DiscoveryProviderManagerLegacy: "); } @@ -96,6 +100,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider mBleDiscoveryProvider = bleDiscoveryProvider; mChreDiscoveryProvider = chreDiscoveryProvider; mScanTypeScanListenerRecordMap = scanTypeScanListenerRecordMap; + mNearbyConfiguration = new NearbyConfiguration(); } private static boolean isChreOnly(List scanFilters) { @@ -142,18 +147,18 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) { ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder); if (record == null) { - Log.w(TAG, "DiscoveryProviderManager cannot find the scan record."); + Log.w(TAG, "DiscoveryProviderManagerLegacy cannot find the scan record."); continue; } CallerIdentity callerIdentity = record.getCallerIdentity(); if (!DiscoveryPermissions.noteDiscoveryResultDelivery( appOpsManager, callerIdentity)) { - Log.w(TAG, "[DiscoveryProviderManager] scan permission revoked " + Log.w(TAG, "[DiscoveryProviderManagerLegacy] scan permission revoked " + "- not forwarding results"); try { record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED); } catch (RemoteException e) { - Log.w(TAG, "DiscoveryProviderManager failed to report error.", e); + Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report error.", e); } return; } @@ -180,7 +185,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider NearbyMetrics.logScanDeviceDiscovered( record.hashCode(), record.getScanRequest(), nearbyDevice); } catch (RemoteException e) { - Log.w(TAG, "DiscoveryProviderManager failed to report onDiscovered.", e); + Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report onDiscovered.", e); } } } @@ -193,18 +198,18 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider for (IBinder listenerBinder : mScanTypeScanListenerRecordMap.keySet()) { ScanListenerRecord record = mScanTypeScanListenerRecordMap.get(listenerBinder); if (record == null) { - Log.w(TAG, "DiscoveryProviderManager cannot find the scan record."); + Log.w(TAG, "DiscoveryProviderManagerLegacy cannot find the scan record."); continue; } CallerIdentity callerIdentity = record.getCallerIdentity(); if (!DiscoveryPermissions.noteDiscoveryResultDelivery( appOpsManager, callerIdentity)) { - Log.w(TAG, "[DiscoveryProviderManager] scan permission revoked " + Log.w(TAG, "[DiscoveryProviderManagerLegacy] scan permission revoked " + "- not forwarding results"); try { record.getScanListener().onError(ScanCallback.ERROR_PERMISSION_DENIED); } catch (RemoteException e) { - Log.w(TAG, "DiscoveryProviderManager failed to report error.", e); + Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report error.", e); } return; } @@ -212,7 +217,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider try { record.getScanListener().onError(errorCode); } catch (RemoteException e) { - Log.w(TAG, "DiscoveryProviderManager failed to report onError.", e); + Log.w(TAG, "DiscoveryProviderManagerLegacy failed to report onError.", e); } } } @@ -220,6 +225,10 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider /** Called after boot completed. */ public void init() { + // Register BLE only scan when Bluetooth is turned off + if (mNearbyConfiguration.enableBleInInit()) { + setBleScanEnabled(); + } if (mInjector.getContextHubManager() != null) { mChreDiscoveryProvider.init(); } @@ -293,10 +302,10 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider if (listenerBinder != null && deathRecipient != null) { listenerBinder.unlinkToDeath(removedRecord.getDeathRecipient(), 0); } - Log.v(TAG, "DiscoveryProviderManager unregistered scan listener."); + Log.v(TAG, "DiscoveryProviderManagerLegacy unregistered scan listener."); NearbyMetrics.logScanStopped(removedRecord.hashCode(), removedRecord.getScanRequest()); if (mScanTypeScanListenerRecordMap.isEmpty()) { - Log.v(TAG, "DiscoveryProviderManager stops provider because there is no " + Log.v(TAG, "DiscoveryProviderManagerLegacy stops provider because there is no " + "scan listener registered."); stopProviders(); return; @@ -306,8 +315,8 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider // Removes current highest scan mode requested and sets the next highest scan mode. if (removedRecord.getScanRequest().getScanMode() == mScanMode) { - Log.v(TAG, "DiscoveryProviderManager starts to find the new highest scan mode " - + "because the highest scan mode listener was unregistered."); + Log.v(TAG, "DiscoveryProviderManagerLegacy starts to find the new highest " + + "scan mode because the highest scan mode listener was unregistered."); @ScanRequest.ScanMode int highestScanModeRequested = ScanRequest.SCAN_MODE_NO_POWER; // find the next highest scan mode; for (ScanListenerRecord record : mScanTypeScanListenerRecordMap.values()) { @@ -377,7 +386,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider private void startBleProvider(List scanFilters) { if (!mBleDiscoveryProvider.getController().isStarted()) { - Log.d(TAG, "DiscoveryProviderManager starts Ble scanning."); + Log.d(TAG, "DiscoveryProviderManagerLegacy starts BLE scanning."); mBleDiscoveryProvider.getController().setListener(this); mBleDiscoveryProvider.getController().setProviderScanMode(mScanMode); mBleDiscoveryProvider.getController().setProviderScanFilters(scanFilters); @@ -387,7 +396,7 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider @VisibleForTesting void startChreProvider(List scanFilters) { - Log.d(TAG, "DiscoveryProviderManager starts CHRE scanning."); + Log.d(TAG, "DiscoveryProviderManagerLegacy starts CHRE scanning."); mChreDiscoveryProvider.getController().setProviderScanFilters(scanFilters); mChreDiscoveryProvider.getController().setProviderScanMode(mScanMode); mChreDiscoveryProvider.getController().start(); @@ -503,4 +512,29 @@ public class DiscoveryProviderManagerLegacy implements AbstractDiscoveryProvider unregisterScanListener(listener); } } + + /** + * Registers Nearby service to Ble scan if Bluetooth is off. (Even when Bluetooth is off) + * @return {@code true} when Nearby currently can scan through Bluetooth or Ble or successfully + * registers Nearby service to Ble scan when Blutooth is off. + */ + public boolean setBleScanEnabled() { + BluetoothAdapter adapter = mInjector.getBluetoothAdapter(); + if (adapter == null) { + Log.e(TAG, "BluetoothAdapter is null."); + return false; + } + if (adapter.isEnabled() || adapter.isLeEnabled()) { + return true; + } + if (!adapter.isBleScanAlwaysAvailable()) { + Log.v(TAG, "Ble always on scan is disabled."); + return false; + } + if (!adapter.enableBLE()) { + Log.e(TAG, "Failed to register Ble scan."); + return false; + } + return true; + } } diff --git a/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java b/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java index 72edad0326..66ae79c567 100644 --- a/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java +++ b/nearby/service/java/com/android/server/nearby/provider/BleBroadcastProvider.java @@ -85,6 +85,7 @@ public class BleBroadcastProvider extends AdvertiseCallback { case BroadcastRequest.PRESENCE_VERSION_V0: bluetoothLeAdvertiser.startAdvertising(getAdvertiseSettings(), advertiseData, this); + Log.v(TAG, "Start to broadcast V0 advertisement."); break; case BroadcastRequest.PRESENCE_VERSION_V1: if (adapter.isLeExtendedAdvertisingSupported()) { @@ -92,6 +93,7 @@ public class BleBroadcastProvider extends AdvertiseCallback { getAdvertisingSetParameters(), advertiseData, null, null, null, mAdvertisingSetCallback); + Log.v(TAG, "Start to broadcast V1 advertisement."); } else { Log.w(TAG, "Failed to start advertising set because the chipset" + " does not supports LE Extended Advertising feature."); diff --git a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java index 9dd07a4d9f..e4651b791b 100644 --- a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java +++ b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java @@ -68,15 +68,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider { @GuardedBy("mLock") @Nullable private List mScanFilters; - private android.bluetooth.le.ScanCallback mScanCallbackLegacy = - new android.bluetooth.le.ScanCallback() { - @Override - public void onScanResult(int callbackType, ScanResult scanResult) { - } - @Override - public void onScanFailed(int errorCode) { - } - }; private android.bluetooth.le.ScanCallback mScanCallback = new android.bluetooth.le.ScanCallback() { @Override @@ -170,7 +161,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider { if (isBleAvailable()) { Log.d(TAG, "BleDiscoveryProvider started"); startScan(getScanFilters(), getScanSettings(/* legacy= */ false), mScanCallback); - startScan(getScanFilters(), getScanSettings(/* legacy= */ true), mScanCallbackLegacy); return; } Log.w(TAG, "Cannot start BleDiscoveryProvider because Ble is not available."); @@ -187,7 +177,6 @@ public class BleDiscoveryProvider extends AbstractDiscoveryProvider { } Log.v(TAG, "Ble scan stopped."); bluetoothLeScanner.stopScan(mScanCallback); - bluetoothLeScanner.stopScan(mScanCallbackLegacy); synchronized (mLock) { if (mScanFilters != null) { mScanFilters = null; diff --git a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java index d69d42d44d..21ec2520d3 100644 --- a/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java +++ b/nearby/service/java/com/android/server/nearby/provider/ChreDiscoveryProvider.java @@ -20,6 +20,9 @@ import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; import static com.android.server.nearby.NearbyService.TAG; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; + import android.annotation.Nullable; import android.content.BroadcastReceiver; import android.content.Context; @@ -155,7 +158,7 @@ public class ChreDiscoveryProvider extends AbstractDiscoveryProvider { builder.setFastPairSupported(version != ChreCommunication.INVALID_NANO_APP_VERSION); try { callback.onQueryComplete(builder.build()); - } catch (RemoteException e) { + } catch (RemoteException | NullPointerException e) { e.printStackTrace(); } }); @@ -350,7 +353,11 @@ public class ChreDiscoveryProvider extends AbstractDiscoveryProvider { DataElement.DataType.ACTION, new byte[]{(byte) filterResult.getIntent()})); } - + if (filterResult.hasTimestampNs()) { + presenceDeviceBuilder + .setDiscoveryTimestampMillis(MILLISECONDS.convert( + filterResult.getTimestampNs(), NANOSECONDS)); + } PublicCredential publicCredential = new PublicCredential.Builder( secretId, diff --git a/nearby/service/proto/src/presence/blefilter.proto b/nearby/service/proto/src/presence/blefilter.proto index e1bf45595a..bf9357b286 100644 --- a/nearby/service/proto/src/presence/blefilter.proto +++ b/nearby/service/proto/src/presence/blefilter.proto @@ -115,6 +115,9 @@ message BleFilterResult { repeated DataElement data_element = 7; optional bytes ble_service_data = 8; optional ResultType result_type = 9; + // Timestamp when the device is discovered, in nanoseconds, + // relative to Android SystemClock.elapsedRealtimeNanos(). + optional uint64 timestamp_ns = 10; } message BleFilterResults { diff --git a/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerLegacyTest.java b/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerLegacyTest.java index aa0dad328c..0ca571a8dc 100644 --- a/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerLegacyTest.java +++ b/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerLegacyTest.java @@ -16,6 +16,7 @@ package com.android.server.nearby.managers; +import static android.Manifest.permission.READ_DEVICE_CONFIG; import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE; import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; @@ -23,10 +24,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.nearby.DataElement; import android.nearby.IScanListener; @@ -36,6 +39,8 @@ import android.nearby.PublicCredential; import android.nearby.ScanRequest; import android.os.IBinder; +import androidx.test.platform.app.InstrumentationRegistry; + import com.android.server.nearby.injector.Injector; import com.android.server.nearby.provider.BleDiscoveryProvider; import com.android.server.nearby.provider.ChreCommunication; @@ -86,6 +91,8 @@ public class DiscoveryProviderManagerLegacyTest { DiscoveryProviderManagerLegacy.ScanListenerDeathRecipient mScanListenerDeathRecipient; @Mock IBinder mIBinder; + @Mock + BluetoothAdapter mBluetoothAdapter; private DiscoveryProviderManagerLegacy mDiscoveryProviderManager; private Map mScanTypeScanListenerRecordMap; @@ -135,10 +142,15 @@ public class DiscoveryProviderManagerLegacyTest { @Before public void setup() { + InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( + READ_DEVICE_CONFIG); MockitoAnnotations.initMocks(this); when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager); + when(mInjector.getBluetoothAdapter()).thenReturn(mBluetoothAdapter); when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController); when(mChreDiscoveryProvider.getController()).thenReturn(mChreController); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.isEnabled()).thenReturn(true); mScanTypeScanListenerRecordMap = new HashMap<>(); mDiscoveryProviderManager = @@ -163,6 +175,13 @@ public class DiscoveryProviderManagerLegacyTest { mDiscoveryProviderManager.invalidateProviderScanMode(); } + @Test + public void test_enableBleWhenBleOff() throws Exception { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + mDiscoveryProviderManager.init(); + verify(mBluetoothAdapter, times(1)).enableBLE(); + } + @Test public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() { when(mChreDiscoveryProvider.available()).thenReturn(true); @@ -375,4 +394,62 @@ public class DiscoveryProviderManagerLegacyTest { .isTrue(); assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull(); } + + @Test + public void isBluetoothEnabledTest_bluetoothEnabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void isBluetoothEnabledTest_bleEnabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(true); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_enabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_enableFailed() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse(); + } + + @Test + public void enabledTest_scanIsOn() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_failed() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse(); + } } diff --git a/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerTest.java index 7ecf631df3..7cea34a5f6 100644 --- a/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerTest.java +++ b/nearby/tests/unit/src/com/android/server/nearby/managers/DiscoveryProviderManagerTest.java @@ -16,6 +16,7 @@ package com.android.server.nearby.managers; +import static android.Manifest.permission.READ_DEVICE_CONFIG; import static android.nearby.PresenceCredential.IDENTITY_TYPE_PRIVATE; import static android.nearby.ScanRequest.SCAN_TYPE_NEARBY_PRESENCE; @@ -24,10 +25,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.AppOpsManager; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.nearby.DataElement; import android.nearby.IScanListener; @@ -37,6 +40,8 @@ import android.nearby.PublicCredential; import android.nearby.ScanRequest; import android.os.IBinder; +import androidx.test.platform.app.InstrumentationRegistry; + import com.android.server.nearby.injector.Injector; import com.android.server.nearby.provider.BleDiscoveryProvider; import com.android.server.nearby.provider.ChreCommunication; @@ -80,6 +85,8 @@ public class DiscoveryProviderManagerTest { CallerIdentity mCallerIdentity; @Mock IBinder mIBinder; + @Mock + BluetoothAdapter mBluetoothAdapter; private Executor mExecutor; private DiscoveryProviderManager mDiscoveryProviderManager; @@ -128,12 +135,17 @@ public class DiscoveryProviderManagerTest { @Before public void setup() { + InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( + READ_DEVICE_CONFIG); MockitoAnnotations.initMocks(this); mExecutor = Executors.newSingleThreadExecutor(); when(mInjector.getAppOpsManager()).thenReturn(mAppOpsManager); when(mBleDiscoveryProvider.getController()).thenReturn(mBluetoothController); when(mChreDiscoveryProvider.getController()).thenReturn(mChreController); when(mScanListener.asBinder()).thenReturn(mIBinder); + when(mInjector.getBluetoothAdapter()).thenReturn(mBluetoothAdapter); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.isEnabled()).thenReturn(true); mDiscoveryProviderManager = new DiscoveryProviderManager(mContext, mExecutor, mInjector, @@ -156,6 +168,13 @@ public class DiscoveryProviderManagerTest { mDiscoveryProviderManager.invalidateProviderScanMode(); } + @Test + public void test_enableBleWhenBleOff() throws Exception { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + mDiscoveryProviderManager.init(); + verify(mBluetoothAdapter, times(1)).enableBLE(); + } + @Test public void testStartProviders_chreOnlyChreAvailable_bleProviderNotStarted() { reset(mBluetoothController); @@ -336,4 +355,62 @@ public class DiscoveryProviderManagerTest { .isTrue(); assertThat(manager.mChreDiscoveryProvider.getFiltersLocked()).isNotNull(); } + + @Test + public void isBluetoothEnabledTest_bluetoothEnabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void isBluetoothEnabledTest_bleEnabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(true); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_enabled() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(true); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_enableFailed() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(true); + when(mBluetoothAdapter.enableBLE()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse(); + } + + @Test + public void enabledTest_scanIsOn() { + when(mBluetoothAdapter.isEnabled()).thenReturn(true); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isTrue(); + } + + @Test + public void enabledTest_failed() { + when(mBluetoothAdapter.isEnabled()).thenReturn(false); + when(mBluetoothAdapter.isLeEnabled()).thenReturn(false); + when(mBluetoothAdapter.isBleScanAlwaysAvailable()).thenReturn(false); + + assertThat(mDiscoveryProviderManager.setBleScanEnabled()).isFalse(); + } } diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java index 05b556b098..c064844055 100644 --- a/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java +++ b/nearby/tests/unit/src/com/android/server/nearby/provider/BleBroadcastProviderTest.java @@ -16,6 +16,7 @@ package com.android.server.nearby.provider; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; @@ -69,7 +70,7 @@ public class BleBroadcastProviderTest { AdvertiseSettings settings = new AdvertiseSettings.Builder().build(); mBleBroadcastProvider.onStartSuccess(settings); - verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); + verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); } @Test @@ -81,7 +82,7 @@ public class BleBroadcastProviderTest { // advertising set can not be mocked, so we will allow nulls mBleBroadcastProvider.mAdvertisingSetCallback.onAdvertisingSetStarted(null, -30, AdvertisingSetCallback.ADVERTISE_SUCCESS); - verify(mBroadcastListener).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); + verify(mBroadcastListener, times(any())).onStatusChanged(eq(BroadcastCallback.STATUS_OK)); } @Test diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java index 154441b537..8ee661f300 100644 --- a/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java +++ b/nearby/tests/unit/src/com/android/server/nearby/provider/ChreDiscoveryProviderTest.java @@ -192,7 +192,7 @@ public class ChreDiscoveryProviderTest { @Test @SdkSuppress(minSdkVersion = 32, codeName = "T") - public void testOnNearbyDeviceDiscoveredWithDataElements() { + public void testOnNearbyDeviceDiscoveredWithDataElements_TIME() { // Disables the setting of test app support boolean isSupportedTestApp = getDeviceConfigBoolean( NEARBY_SUPPORT_TEST_APP, false /* defaultValue */); @@ -209,6 +209,7 @@ public class ChreDiscoveryProviderTest { // First byte is length of service data, padding zeros should be thrown away. final byte [] bleServiceData = new byte[] {5, 1, 2, 3, 4, 5, 0, 0, 0, 0}; final byte [] testData = new byte[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + final long timestampNs = 1697765417070000000L; final List expectedExtendedProperties = new ArrayList<>(); expectedExtendedProperties.add(new DataElement(DATA_TYPE_CONNECTION_STATUS_KEY, @@ -262,6 +263,7 @@ public class ChreDiscoveryProviderTest { .setValue(ByteString.copyFrom(testData)) .setValueLength(testData.length) ) + .setTimestampNs(timestampNs) .build(); Blefilter.BleFilterResults results = Blefilter.BleFilterResults.newBuilder().addResult(result).build(); @@ -285,11 +287,18 @@ public class ChreDiscoveryProviderTest { DeviceConfig.setProperty(NAMESPACE, NEARBY_SUPPORT_TEST_APP, "true", false); assertThat(new NearbyConfiguration().isTestAppSupported()).isTrue(); } + // Nanoseconds to Milliseconds + assertThat((mNearbyDevice.getValue().getPresenceDevice()) + .getDiscoveryTimestampMillis()).isEqualTo(timestampNs / 1000000); } @Test - @SdkSuppress(minSdkVersion = 32, codeName = "T") + @SdkSuppress(minSdkVersion = 33, codeName = "T") public void testOnNearbyDeviceDiscoveredWithTestDataElements() { + // The feature only supports user-debug builds. + if (!Build.isDebuggable()) { + return; + } // Enables the setting of test app support boolean isSupportedTestApp = getDeviceConfigBoolean( NEARBY_SUPPORT_TEST_APP, false /* defaultValue */);