summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-03-16 14:18:37 -0700
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-03-16 14:18:37 -0700
commit36c6c02c91330a6485ab810e01ddbad9eeea23ca (patch)
tree6c5de28fbe26fe3e931f778aaa6e124f87c51457
parentff729f726b44cc7e410fb5f87efa7fd9665adf35 (diff)
parent084f6ced41f860f06e50e316f9e8d2bce1df5388 (diff)
Snap for 13222886 from 084f6ced41f860f06e50e316f9e8d2bce1df5388 to 25Q2-release
Change-Id: I4577ffcd607e0edda48570e621f1475af327bd1c
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattService.java483
-rw-r--r--android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java499
-rw-r--r--android/app/tests/unit/Android.bp9
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java202
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt201
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java119
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt112
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java41
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java194
-rw-r--r--android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt187
-rw-r--r--flags/hci.aconfig7
-rw-r--r--flags/l2cap.aconfig10
-rw-r--r--flags/pairing.aconfig10
-rw-r--r--flags/security.aconfig17
-rw-r--r--system/gd/hci/controller.cc4
-rw-r--r--system/stack/btm/btm_sec.cc15
-rw-r--r--system/stack/l2cap/l2c_ble.cc9
-rw-r--r--system/stack/smp/smp_l2c.cc7
18 files changed, 1022 insertions, 1104 deletions
diff --git a/android/app/src/com/android/bluetooth/gatt/GattService.java b/android/app/src/com/android/bluetooth/gatt/GattService.java
index 5c26f6e960..6e5faefa9f 100644
--- a/android/app/src/com/android/bluetooth/gatt/GattService.java
+++ b/android/app/src/com/android/bluetooth/gatt/GattService.java
@@ -24,7 +24,6 @@ import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
import static android.bluetooth.BluetoothUtils.toAnonymizedAddress;
import static com.android.bluetooth.Utils.callbackToApp;
-import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser;
import static com.android.bluetooth.Utils.checkCallerTargetSdk;
import static com.android.bluetooth.Utils.checkConnectPermissionForDataDelivery;
import static com.android.bluetooth.util.AttributionSourceUtil.getLastAttributionTag;
@@ -44,7 +43,6 @@ import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.bluetooth.BluetoothStatusCodes;
-import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothGattServerCallback;
import android.companion.CompanionDeviceManager;
@@ -213,7 +211,7 @@ public class GattService extends ProfileService {
@Override
protected IProfileServiceBinder initBinder() {
- return new BluetoothGattBinder(this);
+ return new GattServiceBinder(this);
}
@Override
@@ -264,6 +262,10 @@ public class GattService extends ProfileService {
return mScanController;
}
+ CompanionDeviceManager getCompanionDeviceManager() {
+ return mCompanionDeviceManager;
+ }
+
@Override
protected void setTestModeEnabled(boolean enableTestMode) {
if (mScanController != null) {
@@ -331,479 +333,6 @@ public class GattService extends ProfileService {
}
}
- /** Handlers for incoming service calls */
- @VisibleForTesting
- static class BluetoothGattBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
- private GattService mService;
-
- BluetoothGattBinder(GattService svc) {
- mService = svc;
- }
-
- @Override
- public void cleanup() {
- mService = null;
- }
-
- private GattService getService() {
- // Cache mService because it can change while getService is called
- GattService service = mService;
-
- if (service == null || !service.isAvailable()) {
- Log.e(TAG, "getService() - Service requested, but not available!");
- return null;
- }
-
- return service;
- }
-
- @Override
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(
- int[] states, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return Collections.emptyList();
- }
- return service.getDevicesMatchingConnectionStates(states, source);
- }
-
- @Override
- public void registerClient(
- ParcelUuid uuid,
- IBluetoothGattCallback callback,
- boolean eattSupport,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.registerClient(uuid.getUuid(), callback, eattSupport, source);
- }
-
- @Override
- public void unregisterClient(int clientIf, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.unregisterClient(
- clientIf, source, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
- }
-
- @Override
- public void clientConnect(
- int clientIf,
- String address,
- int addressType,
- boolean isDirect,
- int transport,
- boolean opportunistic,
- int phy,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.clientConnect(
- clientIf,
- address,
- addressType,
- isDirect,
- transport,
- opportunistic,
- phy,
- source);
- }
-
- @Override
- public void clientDisconnect(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.clientDisconnect(clientIf, address, source);
- }
-
- @Override
- public void clientSetPreferredPhy(
- int clientIf,
- String address,
- int txPhy,
- int rxPhy,
- int phyOptions,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions, source);
- }
-
- @Override
- public void clientReadPhy(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.clientReadPhy(clientIf, address, source);
- }
-
- @Override
- public void refreshDevice(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.refreshDevice(clientIf, address, source);
- }
-
- @Override
- public void discoverServices(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.discoverServices(clientIf, address, source);
- }
-
- @Override
- public void discoverServiceByUuid(
- int clientIf, String address, ParcelUuid uuid, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), source);
- }
-
- @Override
- public void readCharacteristic(
- int clientIf, String address, int handle, int authReq, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.readCharacteristic(clientIf, address, handle, authReq, source);
- }
-
- @Override
- public void readUsingCharacteristicUuid(
- int clientIf,
- String address,
- ParcelUuid uuid,
- int startHandle,
- int endHandle,
- int authReq,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.readUsingCharacteristicUuid(
- clientIf, address, uuid.getUuid(), startHandle, endHandle, authReq, source);
- }
-
- @Override
- public int writeCharacteristic(
- int clientIf,
- String address,
- int handle,
- int writeType,
- int authReq,
- byte[] value,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
- return service.writeCharacteristic(
- clientIf, address, handle, writeType, authReq, value, source);
- }
-
- @Override
- public void readDescriptor(
- int clientIf, String address, int handle, int authReq, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.readDescriptor(clientIf, address, handle, authReq, source);
- }
-
- @Override
- public int writeDescriptor(
- int clientIf,
- String address,
- int handle,
- int authReq,
- byte[] value,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
- return service.writeDescriptor(clientIf, address, handle, authReq, value, source);
- }
-
- @Override
- public void beginReliableWrite(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.beginReliableWrite(clientIf, address, source);
- }
-
- @Override
- public void endReliableWrite(
- int clientIf, String address, boolean execute, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.endReliableWrite(clientIf, address, execute, source);
- }
-
- @Override
- public void registerForNotification(
- int clientIf,
- String address,
- int handle,
- boolean enable,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.registerForNotification(clientIf, address, handle, enable, source);
- }
-
- @Override
- public void readRemoteRssi(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.readRemoteRssi(clientIf, address, source);
- }
-
- @Override
- public void configureMTU(int clientIf, String address, int mtu, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.configureMTU(clientIf, address, mtu, source);
- }
-
- @Override
- public void connectionParameterUpdate(
- int clientIf, String address, int connectionPriority, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.connectionParameterUpdate(clientIf, address, connectionPriority, source);
- }
-
- @Override
- public void leConnectionUpdate(
- int clientIf,
- String address,
- int minConnectionInterval,
- int maxConnectionInterval,
- int peripheralLatency,
- int supervisionTimeout,
- int minConnectionEventLen,
- int maxConnectionEventLen,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.leConnectionUpdate(
- clientIf,
- address,
- minConnectionInterval,
- maxConnectionInterval,
- peripheralLatency,
- supervisionTimeout,
- minConnectionEventLen,
- maxConnectionEventLen,
- source);
- }
-
- @Override
- public int subrateModeRequest(
- int clientIf, BluetoothDevice device, int subrateMode, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "subrateModeRequest")) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
- }
-
- if (!checkConnectPermissionForDataDelivery(
- service, source, TAG, "subrateModeRequest")) {
- return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
- }
-
- Utils.enforceCdmAssociationIfNotBluetoothPrivileged(
- service, service.mCompanionDeviceManager, source, device);
-
- if (subrateMode < BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED
- || subrateMode > BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER) {
- throw new IllegalArgumentException("Subrate Mode not within valid range");
- }
-
- requireNonNull(device);
- String address = device.getAddress();
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- throw new IllegalArgumentException("Invalid device address: " + address);
- }
-
- return service.subrateModeRequest(clientIf, device, subrateMode);
- }
-
- @Override
- public void registerServer(
- ParcelUuid uuid,
- IBluetoothGattServerCallback callback,
- boolean eattSupport,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.registerServer(uuid.getUuid(), callback, eattSupport, source);
- }
-
- @Override
- public void unregisterServer(int serverIf, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.unregisterServer(serverIf, source);
- }
-
- @Override
- public void serverConnect(
- int serverIf,
- String address,
- int addressType,
- boolean isDirect,
- int transport,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.serverConnect(serverIf, address, addressType, isDirect, transport, source);
- }
-
- @Override
- public void serverDisconnect(int serverIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.serverDisconnect(serverIf, address, source);
- }
-
- @Override
- public void serverSetPreferredPhy(
- int serverIf,
- String address,
- int txPhy,
- int rxPhy,
- int phyOptions,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions, source);
- }
-
- @Override
- public void serverReadPhy(int clientIf, String address, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.serverReadPhy(clientIf, address, source);
- }
-
- @Override
- public void addService(int serverIf, BluetoothGattService svc, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.addService(serverIf, svc, source);
- }
-
- @Override
- public void removeService(int serverIf, int handle, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.removeService(serverIf, handle, source);
- }
-
- @Override
- public void clearServices(int serverIf, AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.clearServices(serverIf, source);
- }
-
- @Override
- public void sendResponse(
- int serverIf,
- String address,
- int requestId,
- int status,
- int offset,
- byte[] value,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.sendResponse(serverIf, address, requestId, status, offset, value, source);
- }
-
- @Override
- public int sendNotification(
- int serverIf,
- String address,
- int handle,
- boolean confirm,
- byte[] value,
- AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
- return service.sendNotification(serverIf, address, handle, confirm, value, source);
- }
-
- @Override
- public void disconnectAll(AttributionSource source) {
- GattService service = getService();
- if (service == null) {
- return;
- }
- service.disconnectAll(source);
- }
- }
-
/**************************************************************************
* Callback functions - CLIENT
*************************************************************************/
@@ -2167,7 +1696,7 @@ public class GattService extends ProfileService {
maxConnectionEventLen);
}
- private int subrateModeRequest(int clientIf, BluetoothDevice device, int subrateMode) {
+ int subrateModeRequest(int clientIf, BluetoothDevice device, int subrateMode) {
int subrateMin;
int subrateMax;
int maxLatency;
diff --git a/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java b/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java
new file mode 100644
index 0000000000..7be287677c
--- /dev/null
+++ b/android/app/src/com/android/bluetooth/gatt/GattServiceBinder.java
@@ -0,0 +1,499 @@
+/*
+ * 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.bluetooth.gatt;
+
+import static com.android.bluetooth.Utils.callerIsSystemOrActiveOrManagedUser;
+import static com.android.bluetooth.Utils.checkConnectPermissionForDataDelivery;
+
+import static java.util.Objects.requireNonNull;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothStatusCodes;
+import android.bluetooth.IBluetoothGatt;
+import android.bluetooth.IBluetoothGattCallback;
+import android.bluetooth.IBluetoothGattServerCallback;
+import android.content.AttributionSource;
+import android.os.ParcelUuid;
+
+import com.android.bluetooth.Utils;
+import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
+
+import java.util.Collections;
+import java.util.List;
+
+/** Handlers for incoming service calls */
+class GattServiceBinder extends IBluetoothGatt.Stub implements IProfileServiceBinder {
+ private static final String TAG =
+ GattServiceConfig.TAG_PREFIX + GattServiceBinder.class.getSimpleName();
+
+ private GattService mService;
+
+ GattServiceBinder(GattService svc) {
+ mService = svc;
+ }
+
+ @Override
+ public void cleanup() {
+ mService = null;
+ }
+
+ private GattService getService() {
+ GattService service = mService;
+
+ if (!Utils.checkServiceAvailable(service, TAG)) {
+ return null;
+ }
+
+ return service;
+ }
+
+ @Override
+ public List<BluetoothDevice> getDevicesMatchingConnectionStates(
+ int[] states, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return Collections.emptyList();
+ }
+ return service.getDevicesMatchingConnectionStates(states, source);
+ }
+
+ @Override
+ public void registerClient(
+ ParcelUuid uuid,
+ IBluetoothGattCallback callback,
+ boolean eattSupport,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.registerClient(uuid.getUuid(), callback, eattSupport, source);
+ }
+
+ @Override
+ public void unregisterClient(int clientIf, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.unregisterClient(
+ clientIf, source, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
+ }
+
+ @Override
+ public void clientConnect(
+ int clientIf,
+ String address,
+ int addressType,
+ boolean isDirect,
+ int transport,
+ boolean opportunistic,
+ int phy,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.clientConnect(
+ clientIf, address, addressType, isDirect, transport, opportunistic, phy, source);
+ }
+
+ @Override
+ public void clientDisconnect(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.clientDisconnect(clientIf, address, source);
+ }
+
+ @Override
+ public void clientSetPreferredPhy(
+ int clientIf,
+ String address,
+ int txPhy,
+ int rxPhy,
+ int phyOptions,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.clientSetPreferredPhy(clientIf, address, txPhy, rxPhy, phyOptions, source);
+ }
+
+ @Override
+ public void clientReadPhy(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.clientReadPhy(clientIf, address, source);
+ }
+
+ @Override
+ public void refreshDevice(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.refreshDevice(clientIf, address, source);
+ }
+
+ @Override
+ public void discoverServices(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.discoverServices(clientIf, address, source);
+ }
+
+ @Override
+ public void discoverServiceByUuid(
+ int clientIf, String address, ParcelUuid uuid, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.discoverServiceByUuid(clientIf, address, uuid.getUuid(), source);
+ }
+
+ @Override
+ public void readCharacteristic(
+ int clientIf, String address, int handle, int authReq, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.readCharacteristic(clientIf, address, handle, authReq, source);
+ }
+
+ @Override
+ public void readUsingCharacteristicUuid(
+ int clientIf,
+ String address,
+ ParcelUuid uuid,
+ int startHandle,
+ int endHandle,
+ int authReq,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.readUsingCharacteristicUuid(
+ clientIf, address, uuid.getUuid(), startHandle, endHandle, authReq, source);
+ }
+
+ @Override
+ public int writeCharacteristic(
+ int clientIf,
+ String address,
+ int handle,
+ int writeType,
+ int authReq,
+ byte[] value,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
+ return service.writeCharacteristic(
+ clientIf, address, handle, writeType, authReq, value, source);
+ }
+
+ @Override
+ public void readDescriptor(
+ int clientIf, String address, int handle, int authReq, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.readDescriptor(clientIf, address, handle, authReq, source);
+ }
+
+ @Override
+ public int writeDescriptor(
+ int clientIf,
+ String address,
+ int handle,
+ int authReq,
+ byte[] value,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
+ return service.writeDescriptor(clientIf, address, handle, authReq, value, source);
+ }
+
+ @Override
+ public void beginReliableWrite(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.beginReliableWrite(clientIf, address, source);
+ }
+
+ @Override
+ public void endReliableWrite(
+ int clientIf, String address, boolean execute, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.endReliableWrite(clientIf, address, execute, source);
+ }
+
+ @Override
+ public void registerForNotification(
+ int clientIf, String address, int handle, boolean enable, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.registerForNotification(clientIf, address, handle, enable, source);
+ }
+
+ @Override
+ public void readRemoteRssi(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.readRemoteRssi(clientIf, address, source);
+ }
+
+ @Override
+ public void configureMTU(int clientIf, String address, int mtu, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.configureMTU(clientIf, address, mtu, source);
+ }
+
+ @Override
+ public void connectionParameterUpdate(
+ int clientIf, String address, int connectionPriority, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.connectionParameterUpdate(clientIf, address, connectionPriority, source);
+ }
+
+ @Override
+ public void leConnectionUpdate(
+ int clientIf,
+ String address,
+ int minConnectionInterval,
+ int maxConnectionInterval,
+ int peripheralLatency,
+ int supervisionTimeout,
+ int minConnectionEventLen,
+ int maxConnectionEventLen,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.leConnectionUpdate(
+ clientIf,
+ address,
+ minConnectionInterval,
+ maxConnectionInterval,
+ peripheralLatency,
+ supervisionTimeout,
+ minConnectionEventLen,
+ maxConnectionEventLen,
+ source);
+ }
+
+ @Override
+ public int subrateModeRequest(
+ int clientIf, BluetoothDevice device, int subrateMode, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
+ }
+ if (!callerIsSystemOrActiveOrManagedUser(service, TAG, "subrateModeRequest")) {
+ return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED;
+ }
+ if (!checkConnectPermissionForDataDelivery(service, source, TAG, "subrateModeRequest")) {
+ return BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION;
+ }
+
+ Utils.enforceCdmAssociationIfNotBluetoothPrivileged(
+ service, service.getCompanionDeviceManager(), source, device);
+
+ if (subrateMode < BluetoothGatt.SUBRATE_REQUEST_MODE_BALANCED
+ || subrateMode > BluetoothGatt.SUBRATE_REQUEST_MODE_LOW_POWER) {
+ throw new IllegalArgumentException("Subrate Mode not within valid range");
+ }
+
+ requireNonNull(device);
+ String address = device.getAddress();
+ if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+ throw new IllegalArgumentException("Invalid device address: " + address);
+ }
+
+ return service.subrateModeRequest(clientIf, device, subrateMode);
+ }
+
+ @Override
+ public void registerServer(
+ ParcelUuid uuid,
+ IBluetoothGattServerCallback callback,
+ boolean eattSupport,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.registerServer(uuid.getUuid(), callback, eattSupport, source);
+ }
+
+ @Override
+ public void unregisterServer(int serverIf, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.unregisterServer(serverIf, source);
+ }
+
+ @Override
+ public void serverConnect(
+ int serverIf,
+ String address,
+ int addressType,
+ boolean isDirect,
+ int transport,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.serverConnect(serverIf, address, addressType, isDirect, transport, source);
+ }
+
+ @Override
+ public void serverDisconnect(int serverIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.serverDisconnect(serverIf, address, source);
+ }
+
+ @Override
+ public void serverSetPreferredPhy(
+ int serverIf,
+ String address,
+ int txPhy,
+ int rxPhy,
+ int phyOptions,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.serverSetPreferredPhy(serverIf, address, txPhy, rxPhy, phyOptions, source);
+ }
+
+ @Override
+ public void serverReadPhy(int clientIf, String address, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.serverReadPhy(clientIf, address, source);
+ }
+
+ @Override
+ public void addService(int serverIf, BluetoothGattService svc, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.addService(serverIf, svc, source);
+ }
+
+ @Override
+ public void removeService(int serverIf, int handle, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.removeService(serverIf, handle, source);
+ }
+
+ @Override
+ public void clearServices(int serverIf, AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.clearServices(serverIf, source);
+ }
+
+ @Override
+ public void sendResponse(
+ int serverIf,
+ String address,
+ int requestId,
+ int status,
+ int offset,
+ byte[] value,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.sendResponse(serverIf, address, requestId, status, offset, value, source);
+ }
+
+ @Override
+ public int sendNotification(
+ int serverIf,
+ String address,
+ int handle,
+ boolean confirm,
+ byte[] value,
+ AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
+ }
+ return service.sendNotification(serverIf, address, handle, confirm, value, source);
+ }
+
+ @Override
+ public void disconnectAll(AttributionSource source) {
+ GattService service = getService();
+ if (service == null) {
+ return;
+ }
+ service.disconnectAll(source);
+ }
+}
diff --git a/android/app/tests/unit/Android.bp b/android/app/tests/unit/Android.bp
index 01d195cc43..a5b7dc36c8 100644
--- a/android/app/tests/unit/Android.bp
+++ b/android/app/tests/unit/Android.bp
@@ -35,6 +35,7 @@ android_test {
"androidx.room_room-runtime",
"androidx.room_room-testing",
"androidx.test.espresso.intents",
+ "androidx.test.ext.junit",
"androidx.test.ext.truth",
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
@@ -45,6 +46,7 @@ android_test {
"gson",
"guava-android-testlib",
"mmslib",
+ "mockito-kotlin2",
"mockito-target-extended",
"modules-utils-handlerexecutor",
"platform-parametric-runner-lib",
@@ -61,8 +63,11 @@ android_test {
jarjar_rules: ":bluetooth-jarjar-rules",
asset_dirs: ["src/com/android/bluetooth/btservice/storage/schemas"],
- // Include all test java files.
- srcs: ["src/**/*.java"],
+ // Include all test java and kotlin files.
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
jacoco: {
include_filter: ["android.bluetooth.*"],
exclude_filter: [],
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java
deleted file mode 100644
index c78c9ec6db..0000000000
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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.bluetooth.gatt;
-
-import static com.android.bluetooth.TestUtils.MockitoRule;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.le.AdvertiseData;
-import android.bluetooth.le.AdvertisingSetParameters;
-import android.bluetooth.le.IAdvertisingSetCallback;
-import android.bluetooth.le.PeriodicAdvertisingParameters;
-import android.content.AttributionSource;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.bluetooth.btservice.AdapterService;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-/** Test cases for {@link AdvertiseBinder}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AdvertiseBinderTest {
- @Rule public final MockitoRule mMockitoRule = new MockitoRule();
-
- @Mock private AdapterService mAdapterService;
- @Mock private AdvertiseManager mAdvertiseManager;
-
- private final AttributionSource mAttributionSource =
- InstrumentationRegistry.getInstrumentation()
- .getTargetContext()
- .getSystemService(BluetoothManager.class)
- .getAdapter()
- .getAttributionSource();
- private AdvertiseBinder mBinder;
-
- @Before
- public void setUp() {
- doAnswer(
- invocation -> {
- ((Runnable) invocation.getArgument(0)).run();
- return null;
- })
- .when(mAdvertiseManager)
- .doOnAdvertiseThread(any());
- mBinder = new AdvertiseBinder(mAdapterService, mAdvertiseManager);
- }
-
- @Test
- public void startAdvertisingSet() {
- AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build();
- AdvertiseData advertiseData = new AdvertiseData.Builder().build();
- AdvertiseData scanResponse = new AdvertiseData.Builder().build();
- PeriodicAdvertisingParameters periodicParameters =
- new PeriodicAdvertisingParameters.Builder().build();
- AdvertiseData periodicData = new AdvertiseData.Builder().build();
- int duration = 1;
- int maxExtAdvEvents = 2;
- int serverIf = 3;
- IAdvertisingSetCallback callback = mock(IAdvertisingSetCallback.class);
-
- mBinder.startAdvertisingSet(
- parameters,
- advertiseData,
- scanResponse,
- periodicParameters,
- periodicData,
- duration,
- maxExtAdvEvents,
- serverIf,
- callback,
- mAttributionSource);
-
- verify(mAdvertiseManager)
- .startAdvertisingSet(
- parameters,
- advertiseData,
- scanResponse,
- periodicParameters,
- periodicData,
- duration,
- maxExtAdvEvents,
- serverIf,
- callback,
- mAttributionSource);
- }
-
- @Test
- public void stopAdvertisingSet() {
- IAdvertisingSetCallback callback = mock(IAdvertisingSetCallback.class);
-
- mBinder.stopAdvertisingSet(callback, mAttributionSource);
-
- verify(mAdvertiseManager).stopAdvertisingSet(callback);
- }
-
- @Test
- public void setAdvertisingData() {
- int advertiserId = 1;
- AdvertiseData data = new AdvertiseData.Builder().build();
-
- mBinder.setAdvertisingData(advertiserId, data, mAttributionSource);
- verify(mAdvertiseManager).setAdvertisingData(advertiserId, data);
- }
-
- @Test
- public void setAdvertisingParameters() {
- int advertiserId = 1;
- AdvertisingSetParameters parameters = new AdvertisingSetParameters.Builder().build();
-
- mBinder.setAdvertisingParameters(advertiserId, parameters, mAttributionSource);
- verify(mAdvertiseManager).setAdvertisingParameters(advertiserId, parameters);
- }
-
- @Test
- public void setPeriodicAdvertisingData() {
- int advertiserId = 1;
- AdvertiseData data = new AdvertiseData.Builder().build();
-
- mBinder.setPeriodicAdvertisingData(advertiserId, data, mAttributionSource);
- verify(mAdvertiseManager).setPeriodicAdvertisingData(advertiserId, data);
- }
-
- @Test
- public void setPeriodicAdvertisingEnable() {
- int advertiserId = 1;
- boolean enable = true;
-
- mBinder.setPeriodicAdvertisingEnable(advertiserId, enable, mAttributionSource);
- verify(mAdvertiseManager).setPeriodicAdvertisingEnable(advertiserId, enable);
- }
-
- @Test
- public void setPeriodicAdvertisingParameters() {
- int advertiserId = 1;
- PeriodicAdvertisingParameters parameters =
- new PeriodicAdvertisingParameters.Builder().build();
-
- mBinder.setPeriodicAdvertisingParameters(advertiserId, parameters, mAttributionSource);
- verify(mAdvertiseManager).setPeriodicAdvertisingParameters(advertiserId, parameters);
- }
-
- @Test
- public void setScanResponseData() {
- int advertiserId = 1;
- AdvertiseData data = new AdvertiseData.Builder().build();
-
- mBinder.setScanResponseData(advertiserId, data, mAttributionSource);
- verify(mAdvertiseManager).setScanResponseData(advertiserId, data);
- }
-
- @Test
- public void getOwnAddress() {
- int advertiserId = 1;
-
- mBinder.getOwnAddress(advertiserId, mAttributionSource);
- verify(mAdvertiseManager).getOwnAddress(advertiserId);
- }
-
- @Test
- public void enableAdvertisingSet() {
- int advertiserId = 1;
- boolean enable = true;
- int duration = 3;
- int maxExtAdvEvents = 4;
-
- mBinder.enableAdvertisingSet(
- advertiserId, enable, duration, maxExtAdvEvents, mAttributionSource);
- verify(mAdvertiseManager)
- .enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents);
- }
-
- @Test
- public void cleanUp_doesNotCrash() {
- mBinder.cleanup();
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt
new file mode 100644
index 0000000000..6b038678f0
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/AdvertiseBinderTest.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.bluetooth.gatt
+
+import android.bluetooth.BluetoothManager
+import android.bluetooth.le.AdvertiseData
+import android.bluetooth.le.AdvertisingSetParameters
+import android.bluetooth.le.IAdvertisingSetCallback
+import android.bluetooth.le.PeriodicAdvertisingParameters
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.bluetooth.TestUtils.MockitoRule
+import com.android.bluetooth.btservice.AdapterService
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.whenever
+
+/** Test cases for [AdvertiseBinder] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class AdvertiseBinderTest {
+
+ @get:Rule val mockitoRule = MockitoRule()
+
+ @Mock private lateinit var adapterService: AdapterService
+ @Mock private lateinit var advertiseManager: AdvertiseManager
+
+ private val attributionSource =
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .getSystemService(BluetoothManager::class.java)
+ .adapter
+ .attributionSource
+
+ private lateinit var binder: AdvertiseBinder
+
+ @Before
+ fun setUp() {
+ doAnswer { invocation ->
+ (invocation.getArgument(0) as Runnable).run()
+ null
+ }
+ .whenever(advertiseManager)
+ .doOnAdvertiseThread(any())
+ binder = AdvertiseBinder(adapterService, advertiseManager)
+ }
+
+ @Test
+ fun startAdvertisingSet() {
+ val parameters = AdvertisingSetParameters.Builder().build()
+ val advertiseData = AdvertiseData.Builder().build()
+ val scanResponse = AdvertiseData.Builder().build()
+ val periodicParameters = PeriodicAdvertisingParameters.Builder().build()
+ val periodicData = AdvertiseData.Builder().build()
+ val duration = 1
+ val maxExtAdvEvents = 2
+ val serverIf = 3
+ val callback = mock(IAdvertisingSetCallback::class.java)
+
+ binder.startAdvertisingSet(
+ parameters,
+ advertiseData,
+ scanResponse,
+ periodicParameters,
+ periodicData,
+ duration,
+ maxExtAdvEvents,
+ serverIf,
+ callback,
+ attributionSource,
+ )
+ verify(advertiseManager)
+ .startAdvertisingSet(
+ parameters,
+ advertiseData,
+ scanResponse,
+ periodicParameters,
+ periodicData,
+ duration,
+ maxExtAdvEvents,
+ serverIf,
+ callback,
+ attributionSource,
+ )
+ }
+
+ @Test
+ fun stopAdvertisingSet() {
+ val callback = mock(IAdvertisingSetCallback::class.java)
+
+ binder.stopAdvertisingSet(callback, attributionSource)
+ verify(advertiseManager).stopAdvertisingSet(callback)
+ }
+
+ @Test
+ fun setAdvertisingData() {
+ val advertiserId = 1
+ val data = AdvertiseData.Builder().build()
+
+ binder.setAdvertisingData(advertiserId, data, attributionSource)
+ verify(advertiseManager).setAdvertisingData(advertiserId, data)
+ }
+
+ @Test
+ fun setAdvertisingParameters() {
+ val advertiserId = 1
+ val parameters = AdvertisingSetParameters.Builder().build()
+
+ binder.setAdvertisingParameters(advertiserId, parameters, attributionSource)
+ verify(advertiseManager).setAdvertisingParameters(advertiserId, parameters)
+ }
+
+ @Test
+ fun setPeriodicAdvertisingData() {
+ val advertiserId = 1
+ val data = AdvertiseData.Builder().build()
+
+ binder.setPeriodicAdvertisingData(advertiserId, data, attributionSource)
+ verify(advertiseManager).setPeriodicAdvertisingData(advertiserId, data)
+ }
+
+ @Test
+ fun setPeriodicAdvertisingEnable() {
+ val advertiserId = 1
+ val enable = true
+
+ binder.setPeriodicAdvertisingEnable(advertiserId, enable, attributionSource)
+ verify(advertiseManager).setPeriodicAdvertisingEnable(advertiserId, enable)
+ }
+
+ @Test
+ fun setPeriodicAdvertisingParameters() {
+ val advertiserId = 1
+ val parameters = PeriodicAdvertisingParameters.Builder().build()
+
+ binder.setPeriodicAdvertisingParameters(advertiserId, parameters, attributionSource)
+ verify(advertiseManager).setPeriodicAdvertisingParameters(advertiserId, parameters)
+ }
+
+ @Test
+ fun setScanResponseData() {
+ val advertiserId = 1
+ val data = AdvertiseData.Builder().build()
+
+ binder.setScanResponseData(advertiserId, data, attributionSource)
+ verify(advertiseManager).setScanResponseData(advertiserId, data)
+ }
+
+ @Test
+ fun getOwnAddress() {
+ val advertiserId = 1
+
+ binder.getOwnAddress(advertiserId, attributionSource)
+ verify(advertiseManager).getOwnAddress(advertiserId)
+ }
+
+ @Test
+ fun enableAdvertisingSet() {
+ val advertiserId = 1
+ val enable = true
+ val duration = 3
+ val maxExtAdvEvents = 4
+
+ binder.enableAdvertisingSet(
+ advertiserId,
+ enable,
+ duration,
+ maxExtAdvEvents,
+ attributionSource,
+ )
+ verify(advertiseManager)
+ .enableAdvertisingSet(advertiserId, enable, duration, maxExtAdvEvents)
+ }
+
+ @Test
+ fun cleanup_doesNotCrash() {
+ binder.cleanup()
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java
deleted file mode 100644
index a65c805a47..0000000000
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.bluetooth.gatt;
-
-import static com.android.bluetooth.TestUtils.MockitoRule;
-import static com.android.bluetooth.TestUtils.getTestDevice;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.le.DistanceMeasurementMethod;
-import android.bluetooth.le.DistanceMeasurementParams;
-import android.bluetooth.le.IDistanceMeasurementCallback;
-import android.content.AttributionSource;
-import android.os.ParcelUuid;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.bluetooth.btservice.AdapterService;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import java.util.Collections;
-import java.util.UUID;
-
-/** Test cases for {@link DistanceMeasurementBinder}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class DistanceMeasurementBinderTest {
- @Rule public final MockitoRule mMockitoRule = new MockitoRule();
-
- @Mock private DistanceMeasurementManager mDistanceMeasurementManager;
- @Mock private AdapterService mAdapterService;
-
- private final AttributionSource mAttributionSource =
- InstrumentationRegistry.getInstrumentation()
- .getTargetContext()
- .getSystemService(BluetoothManager.class)
- .getAdapter()
- .getAttributionSource();
-
- private DistanceMeasurementBinder mBinder;
-
- @Before
- public void setUp() throws Throwable {
- mBinder = new DistanceMeasurementBinder(mAdapterService, mDistanceMeasurementManager);
- when(mDistanceMeasurementManager.getSupportedDistanceMeasurementMethods())
- .thenReturn(Collections.emptyList());
- when(mDistanceMeasurementManager.runOnDistanceMeasurementThreadAndWaitForResult(any()))
- .thenAnswer(
- invocationOnMock -> {
- DistanceMeasurementManager.GetResultTask task =
- invocationOnMock.getArgument(0);
- return task.getResult();
- });
- doAnswer(
- invocation -> {
- ((Runnable) (invocation.getArgument(0))).run();
- return null;
- })
- .when(mDistanceMeasurementManager)
- .postOnDistanceMeasurementThread(any());
- }
-
- @Test
- public void getSupportedDistanceMeasurementMethods() {
- mBinder.getSupportedDistanceMeasurementMethods(mAttributionSource);
- verify(mDistanceMeasurementManager).getSupportedDistanceMeasurementMethods();
- }
-
- @Test
- public void startDistanceMeasurement() {
- UUID uuid = UUID.randomUUID();
- BluetoothDevice device = getTestDevice(3);
- DistanceMeasurementParams params =
- new DistanceMeasurementParams.Builder(device)
- .setDurationSeconds(123)
- .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW)
- .build();
- IDistanceMeasurementCallback callback = mock(IDistanceMeasurementCallback.class);
- mBinder.startDistanceMeasurement(
- new ParcelUuid(uuid), params, callback, mAttributionSource);
- verify(mDistanceMeasurementManager).startDistanceMeasurement(uuid, params, callback);
- }
-
- @Test
- public void stopDistanceMeasurement() {
- UUID uuid = UUID.randomUUID();
- BluetoothDevice device = getTestDevice(3);
- int method = DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI;
- mBinder.stopDistanceMeasurement(new ParcelUuid(uuid), device, method, mAttributionSource);
- verify(mDistanceMeasurementManager).stopDistanceMeasurement(uuid, device, method, false);
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt
new file mode 100644
index 0000000000..b20eda9a17
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/DistanceMeasurementBinderTest.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.bluetooth.gatt
+
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.bluetooth.le.DistanceMeasurementMethod
+import android.bluetooth.le.DistanceMeasurementParams
+import android.bluetooth.le.IDistanceMeasurementCallback
+import android.os.ParcelUuid
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.bluetooth.TestUtils.MockitoRule
+import com.android.bluetooth.TestUtils.getTestDevice
+import com.android.bluetooth.btservice.AdapterService
+import com.android.bluetooth.gatt.DistanceMeasurementManager.GetResultTask
+import java.util.UUID
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.any
+import org.mockito.Mockito.doAnswer
+import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.whenever
+
+/** Test cases for [DistanceMeasurementBinder] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DistanceMeasurementBinderTest {
+
+ @get:Rule val mockitoRule = MockitoRule()
+
+ @Mock private lateinit var distanceMeasurementManager: DistanceMeasurementManager
+ @Mock private lateinit var adapterService: AdapterService
+
+ private val attributionSource =
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .getSystemService(BluetoothManager::class.java)
+ .adapter
+ .attributionSource
+
+ private lateinit var binder: DistanceMeasurementBinder
+
+ @Before
+ fun setUp() {
+ binder = DistanceMeasurementBinder(adapterService, distanceMeasurementManager)
+ doReturn(emptyList<DistanceMeasurementMethod>())
+ .whenever(distanceMeasurementManager)
+ .getSupportedDistanceMeasurementMethods()
+ doAnswer { invocationOnMock ->
+ val task = invocationOnMock.getArgument<GetResultTask<*>>(0)
+ task.result
+ }
+ .whenever(distanceMeasurementManager)
+ .runOnDistanceMeasurementThreadAndWaitForResult(any<GetResultTask<*>>())
+ doAnswer { invocation ->
+ (invocation.getArgument(0) as Runnable).run()
+ null
+ }
+ .whenever(distanceMeasurementManager)
+ .postOnDistanceMeasurementThread(any())
+ }
+
+ @Test
+ fun getSupportedDistanceMeasurementMethods() {
+ binder.getSupportedDistanceMeasurementMethods(attributionSource)
+ verify(distanceMeasurementManager).supportedDistanceMeasurementMethods
+ }
+
+ @Test
+ fun startDistanceMeasurement() {
+ val uuid = UUID.randomUUID()
+ val device: BluetoothDevice = getTestDevice(3)
+ val params =
+ DistanceMeasurementParams.Builder(device)
+ .setDurationSeconds(123)
+ .setFrequency(DistanceMeasurementParams.REPORT_FREQUENCY_LOW)
+ .build()
+ val callback = mock(IDistanceMeasurementCallback::class.java)
+ binder.startDistanceMeasurement(ParcelUuid(uuid), params, callback, attributionSource)
+ verify(distanceMeasurementManager).startDistanceMeasurement(uuid, params, callback)
+ }
+
+ @Test
+ fun stopDistanceMeasurement() {
+ val uuid = UUID.randomUUID()
+ val device: BluetoothDevice = getTestDevice(3)
+ val method = DistanceMeasurementMethod.DISTANCE_MEASUREMENT_METHOD_RSSI
+ binder.stopDistanceMeasurement(ParcelUuid(uuid), device, method, attributionSource)
+ verify(distanceMeasurementManager).stopDistanceMeasurement(uuid, device, method, false)
+ }
+}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
index 36e96f6007..1a340840bc 100644
--- a/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
+++ b/android/app/tests/unit/src/com/android/bluetooth/gatt/GattServiceBinderTest.java
@@ -53,13 +53,12 @@ public class GattServiceBinderTest {
@Mock private GattService mService;
private AttributionSource mAttributionSource;
-
- private GattService.BluetoothGattBinder mBinder;
+ private GattServiceBinder mBinder;
@Before
public void setUp() throws Exception {
when(mService.isAvailable()).thenReturn(true);
- mBinder = new GattService.BluetoothGattBinder(mService);
+ mBinder = new GattServiceBinder(mService);
mAttributionSource = new AttributionSource.Builder(1).build();
}
@@ -68,7 +67,6 @@ public class GattServiceBinderTest {
int[] states = new int[] {STATE_CONNECTED};
mBinder.getDevicesMatchingConnectionStates(states, mAttributionSource);
-
verify(mService).getDevicesMatchingConnectionStates(states, mAttributionSource);
}
@@ -79,7 +77,6 @@ public class GattServiceBinderTest {
boolean eattSupport = true;
mBinder.registerClient(new ParcelUuid(uuid), callback, eattSupport, mAttributionSource);
-
verify(mService).registerClient(uuid, callback, eattSupport, mAttributionSource);
}
@@ -88,7 +85,6 @@ public class GattServiceBinderTest {
int clientIf = 3;
mBinder.unregisterClient(clientIf, mAttributionSource);
-
verify(mService)
.unregisterClient(
clientIf,
@@ -115,7 +111,6 @@ public class GattServiceBinderTest {
opportunistic,
phy,
mAttributionSource);
-
verify(mService)
.clientConnect(
clientIf,
@@ -134,7 +129,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.clientDisconnect(clientIf, address, mAttributionSource);
-
verify(mService).clientDisconnect(clientIf, address, mAttributionSource);
}
@@ -148,7 +142,6 @@ public class GattServiceBinderTest {
mBinder.clientSetPreferredPhy(
clientIf, address, txPhy, rxPhy, phyOptions, mAttributionSource);
-
verify(mService)
.clientSetPreferredPhy(
clientIf, address, txPhy, rxPhy, phyOptions, mAttributionSource);
@@ -160,7 +153,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.clientReadPhy(clientIf, address, mAttributionSource);
-
verify(mService).clientReadPhy(clientIf, address, mAttributionSource);
}
@@ -170,7 +162,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.refreshDevice(clientIf, address, mAttributionSource);
-
verify(mService).refreshDevice(clientIf, address, mAttributionSource);
}
@@ -180,7 +171,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.discoverServices(clientIf, address, mAttributionSource);
-
verify(mService).discoverServices(clientIf, address, mAttributionSource);
}
@@ -191,7 +181,6 @@ public class GattServiceBinderTest {
UUID uuid = UUID.randomUUID();
mBinder.discoverServiceByUuid(clientIf, address, new ParcelUuid(uuid), mAttributionSource);
-
verify(mService).discoverServiceByUuid(clientIf, address, uuid, mAttributionSource);
}
@@ -203,7 +192,6 @@ public class GattServiceBinderTest {
int authReq = 3;
mBinder.readCharacteristic(clientIf, address, handle, authReq, mAttributionSource);
-
verify(mService).readCharacteristic(clientIf, address, handle, authReq, mAttributionSource);
}
@@ -224,7 +212,6 @@ public class GattServiceBinderTest {
endHandle,
authReq,
mAttributionSource);
-
verify(mService)
.readUsingCharacteristicUuid(
clientIf,
@@ -247,7 +234,6 @@ public class GattServiceBinderTest {
mBinder.writeCharacteristic(
clientIf, address, handle, writeType, authReq, value, mAttributionSource);
-
verify(mService)
.writeCharacteristic(
clientIf, address, handle, writeType, authReq, value, mAttributionSource);
@@ -261,7 +247,6 @@ public class GattServiceBinderTest {
int authReq = 3;
mBinder.readDescriptor(clientIf, address, handle, authReq, mAttributionSource);
-
verify(mService).readDescriptor(clientIf, address, handle, authReq, mAttributionSource);
}
@@ -274,7 +259,6 @@ public class GattServiceBinderTest {
byte[] value = new byte[] {4, 5};
mBinder.writeDescriptor(clientIf, address, handle, authReq, value, mAttributionSource);
-
verify(mService)
.writeDescriptor(clientIf, address, handle, authReq, value, mAttributionSource);
}
@@ -285,7 +269,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.beginReliableWrite(clientIf, address, mAttributionSource);
-
verify(mService).beginReliableWrite(clientIf, address, mAttributionSource);
}
@@ -296,7 +279,6 @@ public class GattServiceBinderTest {
boolean execute = true;
mBinder.endReliableWrite(clientIf, address, execute, mAttributionSource);
-
verify(mService).endReliableWrite(clientIf, address, execute, mAttributionSource);
}
@@ -308,7 +290,6 @@ public class GattServiceBinderTest {
boolean enable = true;
mBinder.registerForNotification(clientIf, address, handle, enable, mAttributionSource);
-
verify(mService)
.registerForNotification(clientIf, address, handle, enable, mAttributionSource);
}
@@ -319,7 +300,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.readRemoteRssi(clientIf, address, mAttributionSource);
-
verify(mService).readRemoteRssi(clientIf, address, mAttributionSource);
}
@@ -330,7 +310,6 @@ public class GattServiceBinderTest {
int mtu = 2;
mBinder.configureMTU(clientIf, address, mtu, mAttributionSource);
-
verify(mService).configureMTU(clientIf, address, mtu, mAttributionSource);
}
@@ -342,7 +321,6 @@ public class GattServiceBinderTest {
mBinder.connectionParameterUpdate(
clientIf, address, connectionPriority, mAttributionSource);
-
verify(mService)
.connectionParameterUpdate(
clientIf, address, connectionPriority, mAttributionSource);
@@ -369,7 +347,6 @@ public class GattServiceBinderTest {
minConnectionEventLen,
maxConnectionEventLen,
mAttributionSource);
-
verify(mService)
.leConnectionUpdate(
clientIf,
@@ -390,7 +367,6 @@ public class GattServiceBinderTest {
boolean eattSupport = true;
mBinder.registerServer(new ParcelUuid(uuid), callback, eattSupport, mAttributionSource);
-
verify(mService).registerServer(uuid, callback, eattSupport, mAttributionSource);
}
@@ -399,7 +375,6 @@ public class GattServiceBinderTest {
int serverIf = 3;
mBinder.unregisterServer(serverIf, mAttributionSource);
-
verify(mService).unregisterServer(serverIf, mAttributionSource);
}
@@ -413,7 +388,6 @@ public class GattServiceBinderTest {
mBinder.serverConnect(
serverIf, address, addressType, isDirect, transport, mAttributionSource);
-
verify(mService)
.serverConnect(
serverIf, address, addressType, isDirect, transport, mAttributionSource);
@@ -425,7 +399,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.serverDisconnect(serverIf, address, mAttributionSource);
-
verify(mService).serverDisconnect(serverIf, address, mAttributionSource);
}
@@ -439,7 +412,6 @@ public class GattServiceBinderTest {
mBinder.serverSetPreferredPhy(
serverIf, address, txPhy, rxPhy, phyOptions, mAttributionSource);
-
verify(mService)
.serverSetPreferredPhy(
serverIf, address, txPhy, rxPhy, phyOptions, mAttributionSource);
@@ -451,7 +423,6 @@ public class GattServiceBinderTest {
String address = REMOTE_DEVICE_ADDRESS;
mBinder.serverReadPhy(serverIf, address, mAttributionSource);
-
verify(mService).serverReadPhy(serverIf, address, mAttributionSource);
}
@@ -461,7 +432,6 @@ public class GattServiceBinderTest {
BluetoothGattService svc = mock(BluetoothGattService.class);
mBinder.addService(serverIf, svc, mAttributionSource);
-
verify(mService).addService(serverIf, svc, mAttributionSource);
}
@@ -471,7 +441,6 @@ public class GattServiceBinderTest {
int handle = 2;
mBinder.removeService(serverIf, handle, mAttributionSource);
-
verify(mService).removeService(serverIf, handle, mAttributionSource);
}
@@ -480,7 +449,6 @@ public class GattServiceBinderTest {
int serverIf = 1;
mBinder.clearServices(serverIf, mAttributionSource);
-
verify(mService).clearServices(serverIf, mAttributionSource);
}
@@ -495,7 +463,6 @@ public class GattServiceBinderTest {
mBinder.sendResponse(
serverIf, address, requestId, status, offset, value, mAttributionSource);
-
verify(mService)
.sendResponse(
serverIf, address, requestId, status, offset, value, mAttributionSource);
@@ -510,7 +477,6 @@ public class GattServiceBinderTest {
byte[] value = new byte[] {5, 6};
mBinder.sendNotification(serverIf, address, handle, confirm, value, mAttributionSource);
-
verify(mService)
.sendNotification(serverIf, address, handle, confirm, value, mAttributionSource);
}
@@ -518,12 +484,11 @@ public class GattServiceBinderTest {
@Test
public void disconnectAll() throws Exception {
mBinder.disconnectAll(mAttributionSource);
-
verify(mService).disconnectAll(mAttributionSource);
}
@Test
- public void cleanUp_doesNotCrash() {
+ public void cleanup_doesNotCrash() {
mBinder.cleanup();
}
}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java
deleted file mode 100644
index 61c7df48b8..0000000000
--- a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * 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.bluetooth.le_scan;
-
-import static com.android.bluetooth.TestUtils.MockitoRule;
-import static com.android.bluetooth.TestUtils.getTestDevice;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.app.PendingIntent;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothManager;
-import android.bluetooth.le.IPeriodicAdvertisingCallback;
-import android.bluetooth.le.IScannerCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
-import android.content.AttributionSource;
-import android.content.Intent;
-import android.os.WorkSource;
-
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** Test cases for {@link ScanBinder}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class ScanBinderTest {
- @Rule public final MockitoRule mMockitoRule = new MockitoRule();
-
- @Mock private ScanController mScanController;
-
- private final AttributionSource mAttributionSource =
- InstrumentationRegistry.getInstrumentation()
- .getTargetContext()
- .getSystemService(BluetoothManager.class)
- .getAdapter()
- .getAttributionSource();
- private final BluetoothDevice mDevice = getTestDevice(89);
- private ScanBinder mBinder;
-
- @Before
- public void setUp() {
- mBinder = new ScanBinder(mScanController);
- }
-
- @Test
- public void registerScanner() {
- IScannerCallback callback = mock(IScannerCallback.class);
- WorkSource workSource = mock(WorkSource.class);
-
- mBinder.registerScanner(callback, workSource, mAttributionSource);
- verify(mScanController).registerScanner(callback, workSource, mAttributionSource);
- }
-
- @Test
- public void unregisterScanner() {
- int scannerId = 1;
-
- mBinder.unregisterScanner(scannerId, mAttributionSource);
- verify(mScanController).unregisterScanner(scannerId, mAttributionSource);
- }
-
- @Test
- public void startScan() {
- int scannerId = 1;
- ScanSettings settings = new ScanSettings.Builder().build();
- List<ScanFilter> filters = new ArrayList<>();
-
- mBinder.startScan(scannerId, settings, filters, mAttributionSource);
- verify(mScanController).startScan(scannerId, settings, filters, mAttributionSource);
- }
-
- @Test
- public void startScanForIntent() {
- PendingIntent intent =
- PendingIntent.getBroadcast(
- InstrumentationRegistry.getInstrumentation().getTargetContext(),
- 0,
- new Intent(),
- PendingIntent.FLAG_IMMUTABLE);
- ScanSettings settings = new ScanSettings.Builder().build();
- List<ScanFilter> filters = new ArrayList<>();
-
- mBinder.startScanForIntent(intent, settings, filters, mAttributionSource);
- verify(mScanController)
- .registerPiAndStartScan(intent, settings, filters, mAttributionSource);
- }
-
- @Test
- public void stopScan_withScannerId() {
- int scannerId = 1;
-
- mBinder.stopScan(scannerId, mAttributionSource);
- verify(mScanController).stopScan(scannerId, mAttributionSource);
- }
-
- @Test
- public void stopScan_withIntent() {
- PendingIntent intent =
- PendingIntent.getBroadcast(
- InstrumentationRegistry.getInstrumentation().getTargetContext(),
- 0,
- new Intent(),
- PendingIntent.FLAG_IMMUTABLE);
-
- mBinder.stopScanForIntent(intent, mAttributionSource);
- verify(mScanController).stopScan(intent, mAttributionSource);
- }
-
- @Test
- public void flushPendingBatchResults() {
- int scannerId = 1;
-
- mBinder.flushPendingBatchResults(scannerId, mAttributionSource);
- verify(mScanController).flushPendingBatchResults(scannerId, mAttributionSource);
- }
-
- @Test
- public void registerSync() {
- ScanResult scanResult = new ScanResult(mDevice, null, 0, 0);
- int skip = 1;
- int timeout = 2;
- IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class);
-
- mBinder.registerSync(scanResult, skip, timeout, callback, mAttributionSource);
- verify(mScanController)
- .registerSync(scanResult, skip, timeout, callback, mAttributionSource);
- }
-
- @Test
- public void unregisterSync() {
- IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class);
-
- mBinder.unregisterSync(callback, mAttributionSource);
- verify(mScanController).unregisterSync(callback, mAttributionSource);
- }
-
- @Test
- public void transferSync() {
- int serviceData = 1;
- int syncHandle = 2;
-
- mBinder.transferSync(mDevice, serviceData, syncHandle, mAttributionSource);
- verify(mScanController).transferSync(mDevice, serviceData, syncHandle, mAttributionSource);
- }
-
- @Test
- public void transferSetInfo() {
- int serviceData = 1;
- int advHandle = 2;
- IPeriodicAdvertisingCallback callback = mock(IPeriodicAdvertisingCallback.class);
-
- mBinder.transferSetInfo(mDevice, serviceData, advHandle, callback, mAttributionSource);
- verify(mScanController)
- .transferSetInfo(mDevice, serviceData, advHandle, callback, mAttributionSource);
- }
-
- @Test
- public void numHwTrackFiltersAvailable() {
- mBinder.numHwTrackFiltersAvailable(mAttributionSource);
- verify(mScanController).numHwTrackFiltersAvailable(mAttributionSource);
- }
-
- @Test
- public void cleanup_doesNotCrash() {
- mBinder.cleanup();
- }
-}
diff --git a/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt
new file mode 100644
index 0000000000..3424c48a54
--- /dev/null
+++ b/android/app/tests/unit/src/com/android/bluetooth/le_scan/ScanBinderTest.kt
@@ -0,0 +1,187 @@
+/*
+ * 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.bluetooth.le_scan
+
+import android.app.PendingIntent
+import android.bluetooth.BluetoothDevice
+import android.bluetooth.BluetoothManager
+import android.bluetooth.le.IPeriodicAdvertisingCallback
+import android.bluetooth.le.IScannerCallback
+import android.bluetooth.le.ScanFilter
+import android.bluetooth.le.ScanResult
+import android.bluetooth.le.ScanSettings
+import android.content.Intent
+import android.os.WorkSource
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.bluetooth.TestUtils.MockitoRule
+import com.android.bluetooth.TestUtils.getTestDevice
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+
+/** Test cases for [ScanBinder] */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ScanBinderTest {
+
+ @get:Rule val mockitoRule = MockitoRule()
+
+ @Mock private lateinit var scanController: ScanController
+
+ private val attributionSource =
+ InstrumentationRegistry.getInstrumentation()
+ .targetContext
+ .getSystemService(BluetoothManager::class.java)
+ .adapter
+ .attributionSource
+ private val device: BluetoothDevice = getTestDevice(89)
+ private lateinit var binder: ScanBinder
+
+ @Before
+ fun setUp() {
+ binder = ScanBinder(scanController)
+ }
+
+ @Test
+ fun registerScanner() {
+ val callback = mock(IScannerCallback::class.java)
+ val workSource = mock(WorkSource::class.java)
+
+ binder.registerScanner(callback, workSource, attributionSource)
+ verify(scanController).registerScanner(callback, workSource, attributionSource)
+ }
+
+ @Test
+ fun unregisterScanner() {
+ val scannerId = 1
+
+ binder.unregisterScanner(scannerId, attributionSource)
+ verify(scanController).unregisterScanner(scannerId, attributionSource)
+ }
+
+ @Test
+ fun startScan() {
+ val scannerId = 1
+ val settings = ScanSettings.Builder().build()
+ val filters = listOf<ScanFilter>()
+
+ binder.startScan(scannerId, settings, filters, attributionSource)
+ verify(scanController).startScan(scannerId, settings, filters, attributionSource)
+ }
+
+ @Test
+ fun startScanForIntent() {
+ val intent =
+ PendingIntent.getBroadcast(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ 0,
+ Intent(),
+ PendingIntent.FLAG_IMMUTABLE,
+ )
+ val settings = ScanSettings.Builder().build()
+ val filters = listOf<ScanFilter>()
+
+ binder.startScanForIntent(intent, settings, filters, attributionSource)
+ verify(scanController).registerPiAndStartScan(intent, settings, filters, attributionSource)
+ }
+
+ @Test
+ fun stopScan_withScannerId() {
+ val scannerId = 1
+
+ binder.stopScan(scannerId, attributionSource)
+ verify(scanController).stopScan(scannerId, attributionSource)
+ }
+
+ @Test
+ fun stopScan_withIntent() {
+ val intent =
+ PendingIntent.getBroadcast(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ 0,
+ Intent(),
+ PendingIntent.FLAG_IMMUTABLE,
+ )
+
+ binder.stopScanForIntent(intent, attributionSource)
+ verify(scanController).stopScan(intent, attributionSource)
+ }
+
+ @Test
+ fun flushPendingBatchResults() {
+ val scannerId = 1
+
+ binder.flushPendingBatchResults(scannerId, attributionSource)
+ verify(scanController).flushPendingBatchResults(scannerId, attributionSource)
+ }
+
+ @Test
+ fun registerSync() {
+ val scanResult = mock(ScanResult::class.java)
+ val skip = 1
+ val timeout = 2
+ val callback = mock(IPeriodicAdvertisingCallback::class.java)
+
+ binder.registerSync(scanResult, skip, timeout, callback, attributionSource)
+ verify(scanController).registerSync(scanResult, skip, timeout, callback, attributionSource)
+ }
+
+ @Test
+ fun unregisterSync() {
+ val callback = mock(IPeriodicAdvertisingCallback::class.java)
+
+ binder.unregisterSync(callback, attributionSource)
+ verify(scanController).unregisterSync(callback, attributionSource)
+ }
+
+ @Test
+ fun transferSync() {
+ val serviceData = 1
+ val syncHandle = 2
+
+ binder.transferSync(device, serviceData, syncHandle, attributionSource)
+ verify(scanController).transferSync(device, serviceData, syncHandle, attributionSource)
+ }
+
+ @Test
+ fun transferSetInfo() {
+ val serviceData = 1
+ val advHandle = 2
+ val callback = mock(IPeriodicAdvertisingCallback::class.java)
+
+ binder.transferSetInfo(device, serviceData, advHandle, callback, attributionSource)
+ verify(scanController)
+ .transferSetInfo(device, serviceData, advHandle, callback, attributionSource)
+ }
+
+ @Test
+ fun numHwTrackFiltersAvailable() {
+ binder.numHwTrackFiltersAvailable(attributionSource)
+ verify(scanController).numHwTrackFiltersAvailable(attributionSource)
+ }
+
+ @Test
+ fun cleanup_doesNotCrash() {
+ binder.cleanup()
+ }
+}
diff --git a/flags/hci.aconfig b/flags/hci.aconfig
index cdd5ca3ab6..6f6b1e70df 100644
--- a/flags/hci.aconfig
+++ b/flags/hci.aconfig
@@ -2,13 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.bt"
flag {
- name: "encryption_change_v2"
- namespace: "bluetooth"
- description: "Enable encryption change V2 event"
- bug: "366018699"
-}
-
-flag {
name: "dont_send_hci_disconnect_repeatedly"
namespace: "bluetooth"
description: "Prevent BT from sending repeated HCI disconnect command"
diff --git a/flags/l2cap.aconfig b/flags/l2cap.aconfig
index fec2edd6d5..f82b596674 100644
--- a/flags/l2cap.aconfig
+++ b/flags/l2cap.aconfig
@@ -9,16 +9,6 @@ flag {
}
flag {
- name: "l2cap_le_do_not_adjust_min_interval"
- namespace: "bluetooth"
- description: "Do not adjust min_interval in connection update request"
- bug: "346960036"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "l2cap_fcs_option_fix"
namespace: "bluetooth"
description: "Use fcs_option for non BASIC mode "
diff --git a/flags/pairing.aconfig b/flags/pairing.aconfig
index 28284f9ed8..f30410db17 100644
--- a/flags/pairing.aconfig
+++ b/flags/pairing.aconfig
@@ -102,16 +102,6 @@ flag {
}
flag {
- name: "smp_state_machine_stuck_after_disconnection_fix"
- namespace: "bluetooth"
- description: "Fix state machine stuck after pairing device disconnection"
- bug: "376306092"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "prevent_service_connections_on_remove_bond"
namespace: "bluetooth"
description: "Disable service connections on remove bond"
diff --git a/flags/security.aconfig b/flags/security.aconfig
index c83dc02b24..8d5a8c1f31 100644
--- a/flags/security.aconfig
+++ b/flags/security.aconfig
@@ -2,13 +2,6 @@ package: "com.android.bluetooth.flags"
container: "com.android.bt"
flag {
- name: "key_missing_classic_device"
- namespace: "bluetooth"
- description: "Key missing broadcast for Classic devices"
- bug: "333634398"
-}
-
-flag {
name: "key_missing_ble_peripheral"
namespace: "bluetooth"
description: "Key missing broadcast for LE devices in peripheral role"
@@ -66,16 +59,6 @@ flag {
}
flag {
- name: "sec_disconnect_on_le_key_missing"
- namespace: "bluetooth"
- description: "Disconnect LE link when keys are missing during encryption"
- bug: "376680866"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
name: "guard_bonded_device_properties"
namespace: "bluetooth"
description: "Don't update device properties for bonded devices from the device discovery results"
diff --git a/system/gd/hci/controller.cc b/system/gd/hci/controller.cc
index b14e434781..919643f14d 100644
--- a/system/gd/hci/controller.cc
+++ b/system/gd/hci/controller.cc
@@ -61,9 +61,7 @@ struct Controller::impl {
handler->BindOn(this, &Controller::impl::NumberOfCompletedPackets));
set_event_mask(kDefaultEventMask);
- if (com::android::bluetooth::flags::encryption_change_v2()) {
- set_event_mask_page_2(kDefaultEventMaskPage2);
- }
+ set_event_mask_page_2(kDefaultEventMaskPage2);
write_le_host_support(Enable::ENABLED, Enable::DISABLED);
hci_->EnqueueCommand(
diff --git a/system/stack/btm/btm_sec.cc b/system/stack/btm/btm_sec.cc
index 3eda3ca519..439fa7bc0f 100644
--- a/system/stack/btm/btm_sec.cc
+++ b/system/stack/btm/btm_sec.cc
@@ -2440,8 +2440,7 @@ void btm_io_capabilities_req(RawAddress p) {
/* If device is bonded, and encrypted it's upgrading security and it's ok.
* If it's bonded and not encrypted, it's remote missing keys scenario */
- if (!p_dev_rec->sec_rec.is_device_encrypted() &&
- com::android::bluetooth::flags::key_missing_classic_device()) {
+ if (!p_dev_rec->sec_rec.is_device_encrypted()) {
log::warn("Incoming bond request, but {} is already bonded (notifying user)", p);
bta_dm_remote_key_missing(p);
btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE,
@@ -2632,8 +2631,7 @@ void btm_io_capabilities_rsp(const tBTM_SP_IO_RSP evt_data) {
/* If device is bonded, and encrypted it's upgrading security and it's ok.
* If it's bonded and not encrypted, it's remote missing keys scenario */
- if (btm_sec_is_a_bonded_dev(evt_data.bd_addr) && !p_dev_rec->sec_rec.is_device_encrypted() &&
- com::android::bluetooth::flags::key_missing_classic_device()) {
+ if (btm_sec_is_a_bonded_dev(evt_data.bd_addr) && !p_dev_rec->sec_rec.is_device_encrypted()) {
log::warn("Incoming bond request, but {} is already bonded (notifying user)", evt_data.bd_addr);
bta_dm_remote_key_missing(evt_data.bd_addr);
btm_sec_disconnect(p_dev_rec->hci_handle, HCI_ERR_AUTH_FAILURE,
@@ -3031,8 +3029,7 @@ void btm_sec_auth_complete(uint16_t handle, tHCI_STATUS status) {
p_dev_rec->sec_rec.classic_link, p_dev_rec->bd_addr,
reinterpret_cast<char const*>(p_dev_rec->sec_bd_name));
- if (status == HCI_ERR_KEY_MISSING &&
- com::android::bluetooth::flags::key_missing_classic_device()) {
+ if (status == HCI_ERR_KEY_MISSING) {
log::warn("auth_complete KEY_MISSING {} is already bonded (notifying user)",
p_dev_rec->bd_addr);
bta_dm_remote_key_missing(p_dev_rec->bd_addr);
@@ -3321,10 +3318,8 @@ void btm_sec_encrypt_change(uint16_t handle, tHCI_STATUS status, uint8_t encr_en
if (status == HCI_ERR_KEY_MISSING) {
log::info("Remote key missing - will report");
bta_dm_remote_key_missing(p_dev_rec->ble.pseudo_addr);
- if (com::android::bluetooth::flags::sec_disconnect_on_le_key_missing()) {
- btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_HOST_REJECT_SECURITY,
- p_dev_rec->ble_hci_handle, "encryption_change:key_missing");
- }
+ btm_sec_send_hci_disconnect(p_dev_rec, HCI_ERR_HOST_REJECT_SECURITY,
+ p_dev_rec->ble_hci_handle, "encryption_change:key_missing");
return;
}
diff --git a/system/stack/l2cap/l2c_ble.cc b/system/stack/l2cap/l2c_ble.cc
index 49dca969dc..d964271002 100644
--- a/system/stack/l2cap/l2c_ble.cc
+++ b/system/stack/l2cap/l2c_ble.cc
@@ -1443,7 +1443,7 @@ tL2CAP_LE_RESULT_CODE l2ble_sec_access_req(const RawAddress& bd_addr, uint16_t p
* constraints. For example, when there is at least one Hearing Aid device
* bonded, the minimum interval is raised. On return, min_interval and
* max_interval are updated. */
-void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interval,
+void L2CA_AdjustConnectionIntervals(uint16_t* /* min_interval */, uint16_t* max_interval,
uint16_t floor_interval) {
// Allow for customization by systemprops for mainline
uint16_t phone_min_interval = floor_interval;
@@ -1462,13 +1462,6 @@ void L2CA_AdjustConnectionIntervals(uint16_t* min_interval, uint16_t* max_interv
log::verbose("Have Hearing Aids. Min. interval is set to {}", phone_min_interval);
}
- if (!com::android::bluetooth::flags::l2cap_le_do_not_adjust_min_interval() &&
- *min_interval < phone_min_interval) {
- log::verbose("requested min_interval={} too small. Set to {}", *min_interval,
- phone_min_interval);
- *min_interval = phone_min_interval;
- }
-
// While this could result in connection parameters that fall
// outside fo the range requested, this will allow the connection
// to remain established.
diff --git a/system/stack/smp/smp_l2c.cc b/system/stack/smp/smp_l2c.cc
index 219cb723f7..69591b10e5 100644
--- a/system/stack/smp/smp_l2c.cc
+++ b/system/stack/smp/smp_l2c.cc
@@ -263,13 +263,6 @@ static void smp_br_connect_callback(uint16_t /* channel */, const RawAddress& bd
log::info("BDA:{} pairing_bda:{}, connected:{}", bd_addr, p_cb->pairing_bda, connected);
if (bd_addr != p_cb->pairing_bda) {
- if (!com::android::bluetooth::flags::smp_state_machine_stuck_after_disconnection_fix()) {
- log::info(
- "If your pairing failed, get a build with "
- "smp_state_machine_stuck_after_disconnection_fix and try again :)");
- return;
- }
-
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
/* When pairing was initiated to RPA, and connection was on LE transport first using RPA, then
* we must check record pseudo address, it might be same device */