Merge "Introduce BLE advertiser wrapper for unit tests." into main
This commit is contained in:
commit
da69a84220
6 changed files with 218 additions and 79 deletions
|
|
@ -41,6 +41,7 @@ import android.nearby.aidl.IOffloadCallback;
|
|||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.nearby.injector.BluetoothLeAdvertiserWrapper;
|
||||
import com.android.server.nearby.injector.Injector;
|
||||
import com.android.server.nearby.managers.BluetoothFinderManager;
|
||||
import com.android.server.nearby.managers.BroadcastProviderManager;
|
||||
|
|
@ -195,6 +196,7 @@ public class NearbyService extends INearbyManager.Stub {
|
|||
if (mInjector instanceof SystemInjector) {
|
||||
// The nearby service must be functioning after this boot phase.
|
||||
((SystemInjector) mInjector).initializeBluetoothAdapter();
|
||||
((SystemInjector) mInjector).initializeBluetoothLeAdvertiserWrapper();
|
||||
// Initialize ContextManager for CHRE scan.
|
||||
((SystemInjector) mInjector).initializeContextHubManager();
|
||||
}
|
||||
|
|
@ -227,6 +229,8 @@ public class NearbyService extends INearbyManager.Stub {
|
|||
private static final class SystemInjector implements Injector {
|
||||
private final Context mContext;
|
||||
@Nullable private BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
@Nullable private BluetoothLeAdvertiserWrapper mBluetoothLeAdvertiserWrapper;
|
||||
@Nullable private ContextHubManager mContextHubManager;
|
||||
@Nullable private AppOpsManager mAppOpsManager;
|
||||
|
||||
|
|
@ -240,6 +244,12 @@ public class NearbyService extends INearbyManager.Stub {
|
|||
return mBluetoothAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BluetoothLeAdvertiserWrapper getBluetoothLeAdvertiserWrapper() {
|
||||
return mBluetoothLeAdvertiserWrapper;
|
||||
};
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public ContextHubManager getContextHubManager() {
|
||||
|
|
@ -263,6 +273,13 @@ public class NearbyService extends INearbyManager.Stub {
|
|||
mBluetoothAdapter = manager.getAdapter();
|
||||
}
|
||||
|
||||
synchronized void initializeBluetoothLeAdvertiserWrapper() {
|
||||
if (mBluetoothLeAdvertiserWrapper != null) {
|
||||
return;
|
||||
}
|
||||
mBluetoothLeAdvertiserWrapper = new BluetoothLeAdvertiserWrapper(mContext);
|
||||
}
|
||||
|
||||
synchronized void initializeContextHubManager() {
|
||||
if (mContextHubManager != null) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (C) 2025 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.injector;
|
||||
|
||||
import static com.android.server.nearby.NearbyService.TAG;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.le.AdvertiseCallback;
|
||||
import android.bluetooth.le.AdvertiseData;
|
||||
import android.bluetooth.le.AdvertiseSettings;
|
||||
import android.bluetooth.le.AdvertisingSetCallback;
|
||||
import android.bluetooth.le.AdvertisingSetParameters;
|
||||
import android.bluetooth.le.BluetoothLeAdvertiser;
|
||||
import android.bluetooth.le.PeriodicAdvertisingParameters;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Wrapper for BluetoothLeAdvertiser.
|
||||
*
|
||||
* This class proxies all functions to BluetoothLeAdvertiser.
|
||||
* It will be mocked for unit tests.
|
||||
*
|
||||
* @see BluetoothLeAdvertiser for the details of each public function APIs.
|
||||
*/
|
||||
public class BluetoothLeAdvertiserWrapper {
|
||||
private final BluetoothAdapter mAdapter;
|
||||
private final BluetoothLeAdvertiser mLeAdvertiser;
|
||||
|
||||
/**
|
||||
* Returns a wrapper of BluetoothLeAdvertiser.
|
||||
*
|
||||
* @return an object of BluetoothLeAdvertiserWrapper
|
||||
* @see BluetoothLeAdvertiser
|
||||
*/
|
||||
public BluetoothLeAdvertiserWrapper(Context context) {
|
||||
BluetoothManager manager = context.getSystemService(BluetoothManager.class);
|
||||
if (manager == null) {
|
||||
mAdapter = null;
|
||||
mLeAdvertiser = null;
|
||||
return;
|
||||
}
|
||||
mAdapter = manager.getAdapter();
|
||||
mLeAdvertiser = mAdapter == null ? null : mAdapter.getBluetoothLeAdvertiser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts BLE advertising.
|
||||
*
|
||||
* @see BluetoothLeAdvertiser
|
||||
*/
|
||||
public void startAdvertising(
|
||||
AdvertiseSettings settings,
|
||||
AdvertiseData advertiseData,
|
||||
final AdvertiseCallback callback) {
|
||||
if (mLeAdvertiser == null) {
|
||||
Log.e(TAG, "Call startAdvertising from null advertiser.");
|
||||
}
|
||||
mLeAdvertiser.startAdvertising(settings, advertiseData, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts BLE advertisingSet.
|
||||
*
|
||||
* @see BluetoothLeAdvertiser
|
||||
*/
|
||||
public void startAdvertisingSet(
|
||||
AdvertisingSetParameters parameters,
|
||||
AdvertiseData advertiseData,
|
||||
AdvertiseData scanResponse,
|
||||
PeriodicAdvertisingParameters periodicParameters,
|
||||
AdvertiseData periodicData,
|
||||
AdvertisingSetCallback callback) {
|
||||
if (mLeAdvertiser == null) {
|
||||
Log.e(TAG, "Call startAdvertisingSet from null advertiser.");
|
||||
}
|
||||
mLeAdvertiser.startAdvertisingSet(
|
||||
parameters,
|
||||
advertiseData,
|
||||
scanResponse,
|
||||
periodicParameters,
|
||||
periodicData,
|
||||
callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops BLE advertising.
|
||||
*
|
||||
* @see BluetoothLeAdvertiser
|
||||
*/
|
||||
public void stopAdvertising(final AdvertiseCallback callback) {
|
||||
if (mLeAdvertiser == null) {
|
||||
Log.e(TAG, "Call startAdvertising from null advertiser.");
|
||||
}
|
||||
mLeAdvertiser.stopAdvertising(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops BLE advertisingSet.
|
||||
*
|
||||
* @see BluetoothLeAdvertiser
|
||||
*/
|
||||
public void stopAdvertisingSet(AdvertisingSetCallback callback) {
|
||||
if (mLeAdvertiser == null) {
|
||||
Log.e(TAG, "Call startAdvertisingSet from null advertiser.");
|
||||
}
|
||||
mLeAdvertiser.stopAdvertisingSet(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if BLE supports extended advertising.
|
||||
*
|
||||
* @return true if extended advertisng is supported.
|
||||
*/
|
||||
public Boolean isLeExtendedAdvertisingSupported() {
|
||||
if (mAdapter == null) {
|
||||
Log.e(TAG, "Checks extended BLE support from null BLE adapter.");
|
||||
}
|
||||
return mAdapter.isLeExtendedAdvertisingSupported();
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,9 @@ public interface Injector {
|
|||
/** Get the BluetoothAdapter for BleDiscoveryProvider to scan. */
|
||||
BluetoothAdapter getBluetoothAdapter();
|
||||
|
||||
/** Get the BluetoothLeAdvertiserWrapper to start BLE broadcast. */
|
||||
BluetoothLeAdvertiserWrapper getBluetoothLeAdvertiserWrapper();
|
||||
|
||||
/** Get the ContextHubManagerAdapter for ChreDiscoveryProvider to scan. */
|
||||
ContextHubManager getContextHubManager();
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,18 @@ package com.android.server.nearby.provider;
|
|||
import static com.android.server.nearby.NearbyService.TAG;
|
||||
import static com.android.server.nearby.presence.PresenceConstants.PRESENCE_UUID;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.le.AdvertiseCallback;
|
||||
import android.bluetooth.le.AdvertiseData;
|
||||
import android.bluetooth.le.AdvertiseSettings;
|
||||
import android.bluetooth.le.AdvertisingSet;
|
||||
import android.bluetooth.le.AdvertisingSetCallback;
|
||||
import android.bluetooth.le.AdvertisingSetParameters;
|
||||
import android.bluetooth.le.BluetoothLeAdvertiser;
|
||||
import android.nearby.BroadcastCallback;
|
||||
import android.nearby.BroadcastRequest;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.server.nearby.injector.BluetoothLeAdvertiserWrapper;
|
||||
import com.android.server.nearby.injector.Injector;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
|
@ -55,6 +54,7 @@ public class BleBroadcastProvider extends AdvertiseCallback {
|
|||
private boolean mIsAdvertising;
|
||||
@VisibleForTesting
|
||||
AdvertisingSetCallback mAdvertisingSetCallback;
|
||||
|
||||
public BleBroadcastProvider(Injector injector, Executor executor) {
|
||||
mInjector = injector;
|
||||
mExecutor = executor;
|
||||
|
|
@ -70,49 +70,45 @@ public class BleBroadcastProvider extends AdvertiseCallback {
|
|||
stop();
|
||||
}
|
||||
boolean advertiseStarted = false;
|
||||
BluetoothAdapter adapter = mInjector.getBluetoothAdapter();
|
||||
if (adapter != null) {
|
||||
BluetoothLeAdvertiser bluetoothLeAdvertiser =
|
||||
mInjector.getBluetoothAdapter().getBluetoothLeAdvertiser();
|
||||
if (bluetoothLeAdvertiser != null) {
|
||||
advertiseStarted = true;
|
||||
AdvertiseData advertiseData =
|
||||
new AdvertiseData.Builder()
|
||||
.addServiceData(PRESENCE_UUID, advertisementPackets).build();
|
||||
try {
|
||||
mBroadcastListener = listener;
|
||||
switch (version) {
|
||||
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()) {
|
||||
if (mAdvertisingSetCallback == null) {
|
||||
mAdvertisingSetCallback = getAdvertisingSetCallback();
|
||||
}
|
||||
bluetoothLeAdvertiser.startAdvertisingSet(
|
||||
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.");
|
||||
advertiseStarted = false;
|
||||
BluetoothLeAdvertiserWrapper advertiser = mInjector.getBluetoothLeAdvertiserWrapper();
|
||||
if (advertiser != null) {
|
||||
advertiseStarted = true;
|
||||
AdvertiseData advertiseData =
|
||||
new AdvertiseData.Builder()
|
||||
.addServiceData(PRESENCE_UUID, advertisementPackets).build();
|
||||
try {
|
||||
mBroadcastListener = listener;
|
||||
switch (version) {
|
||||
case BroadcastRequest.PRESENCE_VERSION_V0:
|
||||
advertiser.startAdvertising(getAdvertiseSettings(),
|
||||
advertiseData, this);
|
||||
Log.v(TAG, "Start to broadcast V0 advertisement.");
|
||||
break;
|
||||
case BroadcastRequest.PRESENCE_VERSION_V1:
|
||||
if (advertiser.isLeExtendedAdvertisingSupported()) {
|
||||
if (mAdvertisingSetCallback == null) {
|
||||
mAdvertisingSetCallback = getAdvertisingSetCallback();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Failed to start advertising set because the advertisement"
|
||||
+ " is wrong.");
|
||||
advertiser.startAdvertisingSet(
|
||||
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.");
|
||||
advertiseStarted = false;
|
||||
}
|
||||
} catch (NullPointerException | IllegalStateException | SecurityException
|
||||
| IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to start advertising.", e);
|
||||
advertiseStarted = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.w(TAG, "Failed to start advertising set because the advertisement"
|
||||
+ " is wrong.");
|
||||
advertiseStarted = false;
|
||||
}
|
||||
} catch (NullPointerException | IllegalStateException | SecurityException
|
||||
| IllegalArgumentException e) {
|
||||
Log.w(TAG, "Failed to start advertising.", e);
|
||||
advertiseStarted = false;
|
||||
}
|
||||
}
|
||||
if (!advertiseStarted) {
|
||||
|
|
@ -125,14 +121,10 @@ public class BleBroadcastProvider extends AdvertiseCallback {
|
|||
*/
|
||||
public void stop() {
|
||||
if (mIsAdvertising) {
|
||||
BluetoothAdapter adapter = mInjector.getBluetoothAdapter();
|
||||
if (adapter != null) {
|
||||
BluetoothLeAdvertiser bluetoothLeAdvertiser =
|
||||
mInjector.getBluetoothAdapter().getBluetoothLeAdvertiser();
|
||||
if (bluetoothLeAdvertiser != null) {
|
||||
bluetoothLeAdvertiser.stopAdvertising(this);
|
||||
bluetoothLeAdvertiser.stopAdvertisingSet(mAdvertisingSetCallback);
|
||||
}
|
||||
BluetoothLeAdvertiserWrapper advertiser = mInjector.getBluetoothLeAdvertiserWrapper();
|
||||
if (advertiser != null) {
|
||||
advertiser.stopAdvertising(this);
|
||||
advertiser.stopAdvertisingSet(mAdvertisingSetCallback);
|
||||
}
|
||||
mBroadcastListener = null;
|
||||
mIsAdvertising = false;
|
||||
|
|
|
|||
|
|
@ -21,19 +21,14 @@ import static org.mockito.Mockito.atLeastOnce;
|
|||
import static org.mockito.Mockito.eq;
|
||||
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.bluetooth.BluetoothManager;
|
||||
import android.bluetooth.le.AdvertiseSettings;
|
||||
import android.bluetooth.le.AdvertisingSetCallback;
|
||||
import android.content.Context;
|
||||
import android.hardware.location.ContextHubManager;
|
||||
import android.nearby.BroadcastCallback;
|
||||
import android.nearby.BroadcastRequest;
|
||||
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
|
||||
import com.android.server.nearby.injector.BluetoothLeAdvertiserWrapper;
|
||||
import com.android.server.nearby.injector.Injector;
|
||||
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
|
@ -42,6 +37,7 @@ import org.junit.Before;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
|
|
@ -52,14 +48,22 @@ public class BleBroadcastProviderTest {
|
|||
@Rule
|
||||
public final MockitoRule mocks = MockitoJUnit.rule();
|
||||
|
||||
@Mock
|
||||
private Injector mInjector;
|
||||
|
||||
@Mock
|
||||
private BluetoothLeAdvertiserWrapper mBluetoothLeAdvertiserWrapper;
|
||||
|
||||
@Mock
|
||||
private BleBroadcastProvider.BroadcastListener mBroadcastListener;
|
||||
private BleBroadcastProvider mBleBroadcastProvider;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mBleBroadcastProvider = new BleBroadcastProvider(new TestInjector(),
|
||||
MoreExecutors.directExecutor());
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mInjector.getBluetoothLeAdvertiserWrapper()).thenReturn(mBluetoothLeAdvertiserWrapper);
|
||||
when(mBluetoothLeAdvertiserWrapper.isLeExtendedAdvertisingSupported()).thenReturn(true);
|
||||
mBleBroadcastProvider = new BleBroadcastProvider(mInjector, MoreExecutors.directExecutor());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -114,24 +118,5 @@ public class BleBroadcastProviderTest {
|
|||
public void testStop() {
|
||||
mBleBroadcastProvider.stop();
|
||||
}
|
||||
|
||||
private static class TestInjector implements Injector {
|
||||
|
||||
@Override
|
||||
public BluetoothAdapter getBluetoothAdapter() {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class);
|
||||
return bluetoothManager.getAdapter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextHubManager getContextHubManager() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppOpsManager getAppOpsManager() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import android.nearby.ScanFilter;
|
|||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.server.nearby.injector.BluetoothLeAdvertiserWrapper;
|
||||
import com.android.server.nearby.injector.Injector;
|
||||
|
||||
import org.junit.Before;
|
||||
|
|
@ -122,6 +123,11 @@ public final class BleDiscoveryProviderTest {
|
|||
return mBluetoothAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BluetoothLeAdvertiserWrapper getBluetoothLeAdvertiserWrapper() {
|
||||
return null;
|
||||
};
|
||||
|
||||
@Override
|
||||
public ContextHubManager getContextHubManager() {
|
||||
return null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue