Add unit tests for testability.

Test: unit test
Bug: 235406470
Ignore-AOSP-First: nearby_not_in_aosp_yet

Change-Id: Ifccd4510b486e10edabc25b5d2ac60477a1ba50d
diff --git a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDevice.java b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDevice.java
index 5b45f61..b2002c5 100644
--- a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDevice.java
+++ b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDevice.java
@@ -187,12 +187,6 @@
         return mWrappedBluetoothDevice.createInsecureRfcommSocketToServiceRecord(uuid);
     }
 
-    /** See {@link android.bluetooth.BluetoothDevice#setPin(byte[])}. */
-    @TargetApi(19)
-    public boolean setPairingConfirmation(byte[] pin) {
-        return mWrappedBluetoothDevice.setPin(pin);
-    }
-
     /** See {@link android.bluetooth.BluetoothDevice#setPairingConfirmation(boolean)}. */
     public boolean setPairingConfirmation(boolean confirm) {
         return mWrappedBluetoothDevice.setPairingConfirmation(confirm);
diff --git a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServer.java b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServer.java
index 3f6f361..d4873fd 100644
--- a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServer.java
+++ b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServer.java
@@ -51,6 +51,11 @@
         return new BluetoothGattServer(instance);
     }
 
+    /** Unwraps a Bluetooth Gatt server. */
+    public android.bluetooth.BluetoothGattServer unwrap() {
+        return mWrappedInstance;
+    }
+
     /**
      * See {@link android.bluetooth.BluetoothGattServer#connect(
      * android.bluetooth.BluetoothDevice, boolean)}
diff --git a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeAdvertiser.java b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeAdvertiser.java
index 6fe4432..b2c61ab 100644
--- a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -71,4 +71,10 @@
         }
         return new BluetoothLeAdvertiser(bluetoothLeAdvertiser);
     }
+
+    /** Unwraps a Bluetooth LE advertiser. */
+    @Nullable
+    public android.bluetooth.le.BluetoothLeAdvertiser unwrap() {
+        return mWrappedInstance;
+    }
 }
diff --git a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeScanner.java b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeScanner.java
index 8a13abe..9b3447e 100644
--- a/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeScanner.java
+++ b/nearby/service/java/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/le/BluetoothLeScanner.java
@@ -77,6 +77,12 @@
         mWrappedBluetoothLeScanner.stopScan(callbackIntent);
     }
 
+    /** Unwraps a Bluetooth LE scanner. */
+    @Nullable
+    public android.bluetooth.le.BluetoothLeScanner unwrap() {
+        return mWrappedBluetoothLeScanner;
+    }
+
     /** Wraps a Bluetooth LE scanner. */
     @Nullable
     public static BluetoothLeScanner wrap(
diff --git a/nearby/tests/unit/AndroidManifest.xml b/nearby/tests/unit/AndroidManifest.xml
index 9f58baf..7dcb263 100644
--- a/nearby/tests/unit/AndroidManifest.xml
+++ b/nearby/tests/unit/AndroidManifest.xml
@@ -23,6 +23,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
+    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothAdapterTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothAdapterTest.java
new file mode 100644
index 0000000..6ebe373
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothAdapterTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for {@link BluetoothAdapter}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothAdapterTest {
+
+    private static final byte[] BYTES = new byte[]{0, 1, 2, 3, 4, 5};
+    private static final String ADDRESS = "00:11:22:33:AA:BB";
+
+    @Mock private android.bluetooth.BluetoothAdapter mBluetoothAdapter;
+    @Mock private android.bluetooth.BluetoothDevice mBluetoothDevice;
+    @Mock private android.bluetooth.le.BluetoothLeAdvertiser mBluetoothLeAdvertiser;
+    @Mock private android.bluetooth.le.BluetoothLeScanner mBluetoothLeScanner;
+
+    BluetoothAdapter mTestabilityBluetoothAdapter;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mTestabilityBluetoothAdapter = BluetoothAdapter.wrap(mBluetoothAdapter);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWrapNullAdapter_isNull() {
+        assertThat(BluetoothAdapter.wrap(null)).isNull();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWrapNonNullAdapter_isNotNull_unWrapSame() {
+        assertThat(mTestabilityBluetoothAdapter).isNotNull();
+        assertThat(mTestabilityBluetoothAdapter.unwrap()).isSameInstanceAs(mBluetoothAdapter);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testDisable_callsWrapped() {
+        when(mBluetoothAdapter.disable()).thenReturn(true);
+        assertThat(mTestabilityBluetoothAdapter.disable()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testEnable_callsWrapped() {
+        when(mBluetoothAdapter.enable()).thenReturn(true);
+        assertThat(mTestabilityBluetoothAdapter.enable()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetBluetoothLeAdvertiser_callsWrapped() {
+        when(mBluetoothAdapter.getBluetoothLeAdvertiser()).thenReturn(mBluetoothLeAdvertiser);
+        assertThat(mTestabilityBluetoothAdapter.getBluetoothLeAdvertiser().unwrap())
+                .isSameInstanceAs(mBluetoothLeAdvertiser);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetBluetoothLeScanner_callsWrapped() {
+        when(mBluetoothAdapter.getBluetoothLeScanner()).thenReturn(mBluetoothLeScanner);
+        assertThat(mTestabilityBluetoothAdapter.getBluetoothLeScanner().unwrap())
+                .isSameInstanceAs(mBluetoothLeScanner);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetBondedDevices_callsWrapped() {
+        when(mBluetoothAdapter.getBondedDevices()).thenReturn(null);
+        assertThat(mTestabilityBluetoothAdapter.getBondedDevices()).isNull();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testIsDiscovering_pcallsWrapped() {
+        when(mBluetoothAdapter.isDiscovering()).thenReturn(true);
+        assertThat(mTestabilityBluetoothAdapter.isDiscovering()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testStartDiscovery_callsWrapped() {
+        when(mBluetoothAdapter.startDiscovery()).thenReturn(true);
+        assertThat(mTestabilityBluetoothAdapter.startDiscovery()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testCancelDiscovery_callsWrapped() {
+        when(mBluetoothAdapter.cancelDiscovery()).thenReturn(true);
+        assertThat(mTestabilityBluetoothAdapter.cancelDiscovery()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetRemoteDeviceBytes_callsWrapped() {
+        when(mBluetoothAdapter.getRemoteDevice(BYTES)).thenReturn(mBluetoothDevice);
+        assertThat(mTestabilityBluetoothAdapter.getRemoteDevice(BYTES).unwrap())
+                .isSameInstanceAs(mBluetoothDevice);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetRemoteDeviceString_callsWrapped() {
+        when(mBluetoothAdapter.getRemoteDevice(ADDRESS)).thenReturn(mBluetoothDevice);
+        assertThat(mTestabilityBluetoothAdapter.getRemoteDevice(ADDRESS).unwrap())
+                .isSameInstanceAs(mBluetoothDevice);
+
+    }
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDeviceTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDeviceTest.java
new file mode 100644
index 0000000..a962b16
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothDeviceTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.util.UUID;
+
+/**
+ * Unit tests for {@link BluetoothDevice}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothDeviceTest {
+    private static final UUID UUID_CONST = UUID.randomUUID();
+    private static final String ADDRESS = "ADDRESS";
+    private static final String STRING = "STRING";
+
+    @Mock private android.bluetooth.BluetoothDevice mBluetoothDevice;
+    @Mock private android.bluetooth.BluetoothGatt mBluetoothGatt;
+    @Mock private android.bluetooth.BluetoothSocket mBluetoothSocket;
+    @Mock private android.bluetooth.BluetoothClass mBluetoothClass;
+
+    BluetoothDevice mTestabilityBluetoothDevice;
+    BluetoothGattCallback mTestBluetoothGattCallback;
+    Context mContext;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mTestabilityBluetoothDevice = BluetoothDevice.wrap(mBluetoothDevice);
+        mTestBluetoothGattCallback = new TestBluetoothGattCallback();
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWrapNonNullAdapter_isNotNull_unWrapSame() {
+        assertThat(mTestabilityBluetoothDevice).isNotNull();
+        assertThat(mTestabilityBluetoothDevice.unwrap()).isSameInstanceAs(mBluetoothDevice);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testEquality_asExpected() {
+        assertThat(mTestabilityBluetoothDevice.equals(null)).isFalse();
+        assertThat(mTestabilityBluetoothDevice.equals(mTestabilityBluetoothDevice)).isTrue();
+        assertThat(mTestabilityBluetoothDevice.equals(BluetoothDevice.wrap(mBluetoothDevice)))
+                .isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testConnectGattWithThreeParameters_callsWrapped() {
+        when(mBluetoothDevice
+                .connectGatt(mContext, true, mTestBluetoothGattCallback.unwrap()))
+                .thenReturn(mBluetoothGatt);
+        assertThat(mTestabilityBluetoothDevice
+                .connectGatt(mContext, true, mTestBluetoothGattCallback)
+                .unwrap())
+                .isSameInstanceAs(mBluetoothGatt);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testConnectGattWithFourParameters_callsWrapped() {
+        when(mBluetoothDevice
+                .connectGatt(mContext, true, mTestBluetoothGattCallback.unwrap(), 1))
+                .thenReturn(mBluetoothGatt);
+        assertThat(mTestabilityBluetoothDevice
+                .connectGatt(mContext, true, mTestBluetoothGattCallback, 1)
+                .unwrap())
+                .isSameInstanceAs(mBluetoothGatt);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testCreateRfcommSocketToServiceRecord_callsWrapped() throws IOException {
+        when(mBluetoothDevice.createRfcommSocketToServiceRecord(UUID_CONST))
+                .thenReturn(mBluetoothSocket);
+        assertThat(mTestabilityBluetoothDevice.createRfcommSocketToServiceRecord(UUID_CONST))
+                .isSameInstanceAs(mBluetoothSocket);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testCreateInsecureRfcommSocketToServiceRecord_callsWrapped() throws IOException {
+        when(mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(UUID_CONST))
+                .thenReturn(mBluetoothSocket);
+        assertThat(mTestabilityBluetoothDevice
+                .createInsecureRfcommSocketToServiceRecord(UUID_CONST))
+                .isSameInstanceAs(mBluetoothSocket);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testSetPairingConfirmation_callsWrapped() throws IOException {
+        when(mBluetoothDevice.setPairingConfirmation(true)).thenReturn(true);
+        assertThat(mTestabilityBluetoothDevice.setPairingConfirmation(true)).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testFetchUuidsWithSdp_callsWrapped() throws IOException {
+        when(mBluetoothDevice.fetchUuidsWithSdp()).thenReturn(true);
+        assertThat(mTestabilityBluetoothDevice.fetchUuidsWithSdp()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testCreateBond_callsWrapped() throws IOException {
+        when(mBluetoothDevice.createBond()).thenReturn(true);
+        assertThat(mTestabilityBluetoothDevice.createBond()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetUuids_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getUuids()).thenReturn(null);
+        assertThat(mTestabilityBluetoothDevice.getUuids()).isNull();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetBondState_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getBondState()).thenReturn(1);
+        assertThat(mTestabilityBluetoothDevice.getBondState()).isEqualTo(1);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetAddress_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getAddress()).thenReturn(ADDRESS);
+        assertThat(mTestabilityBluetoothDevice.getAddress()).isSameInstanceAs(ADDRESS);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetBluetoothClass_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getBluetoothClass()).thenReturn(mBluetoothClass);
+        assertThat(mTestabilityBluetoothDevice.getBluetoothClass())
+                .isSameInstanceAs(mBluetoothClass);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetType_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getType()).thenReturn(1);
+        assertThat(mTestabilityBluetoothDevice.getType()).isEqualTo(1);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetName_callsWrapped() throws IOException {
+        when(mBluetoothDevice.getName()).thenReturn(STRING);
+        assertThat(mTestabilityBluetoothDevice.getName()).isSameInstanceAs(STRING);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testToString_callsWrapped() {
+        when(mBluetoothDevice.toString()).thenReturn(STRING);
+        assertThat(mTestabilityBluetoothDevice.toString()).isSameInstanceAs(STRING);
+    }
+
+    private static class TestBluetoothGattCallback extends BluetoothGattCallback {}
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattCallbackTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattCallbackTest.java
new file mode 100644
index 0000000..26ae6d7
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattCallbackTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * Unit tests for {@link BluetoothGattCallback}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothGattCallbackTest {
+    @Mock private android.bluetooth.BluetoothGatt mBluetoothGatt;
+    @Mock private android.bluetooth.BluetoothGattCharacteristic mBluetoothGattCharacteristic;
+    @Mock private android.bluetooth.BluetoothGattDescriptor mBluetoothGattDescriptor;
+
+    TestBluetoothGattCallback mTestBluetoothGattCallback = new TestBluetoothGattCallback();
+
+    @Test
+    public void testOnConnectionStateChange_notCrash() {
+        mTestBluetoothGattCallback.unwrap()
+                .onConnectionStateChange(mBluetoothGatt, 1, 1);
+    }
+
+    @Test
+    public void testOnServiceDiscovered_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onServicesDiscovered(mBluetoothGatt, 1);
+    }
+
+    @Test
+    public void testOnCharacteristicRead_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onCharacteristicRead(mBluetoothGatt,
+                mBluetoothGattCharacteristic, 1);
+    }
+
+    @Test
+    public void testOnCharacteristicWrite_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onCharacteristicWrite(mBluetoothGatt,
+                mBluetoothGattCharacteristic, 1);
+    }
+
+    @Test
+    public void testOnDescriptionRead_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onDescriptorRead(mBluetoothGatt,
+                mBluetoothGattDescriptor, 1);
+    }
+
+    @Test
+    public void testOnDescriptionWrite_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onDescriptorWrite(mBluetoothGatt,
+                mBluetoothGattDescriptor, 1);
+    }
+
+    @Test
+    public void testOnReadRemoteRssi_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onReadRemoteRssi(mBluetoothGatt, 1, 1);
+    }
+
+    @Test
+    public void testOnReliableWriteCompleted_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onReliableWriteCompleted(mBluetoothGatt, 1);
+    }
+
+    @Test
+    public void testOnMtuChanged_notCrash() {
+        mTestBluetoothGattCallback.unwrap().onMtuChanged(mBluetoothGatt, 1, 1);
+    }
+
+    @Test
+    public void testOnCharacteristicChanged_notCrash() {
+        mTestBluetoothGattCallback.unwrap()
+                .onCharacteristicChanged(mBluetoothGatt, mBluetoothGattCharacteristic);
+    }
+
+    private static class TestBluetoothGattCallback extends BluetoothGattCallback { }
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerCallbackTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerCallbackTest.java
new file mode 100644
index 0000000..fb99317
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerCallbackTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+/**
+ * Unit tests for {@link BluetoothGattServerCallback}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothGattServerCallbackTest {
+    @Mock
+    private android.bluetooth.BluetoothDevice mBluetoothDevice;
+    @Mock
+    private android.bluetooth.BluetoothGattService mBluetoothGattService;
+    @Mock
+    private android.bluetooth.BluetoothGattCharacteristic mBluetoothGattCharacteristic;
+    @Mock
+    private android.bluetooth.BluetoothGattDescriptor mBluetoothGattDescriptor;
+
+    TestBluetoothGattServerCallback
+            mTestBluetoothGattServerCallback = new TestBluetoothGattServerCallback();
+
+    @Test
+    public void testOnCharacteristicReadRequest_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onCharacteristicReadRequest(
+                mBluetoothDevice, 1, 1, mBluetoothGattCharacteristic);
+    }
+
+    @Test
+    public void testOnCharacteristicWriteRequest_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onCharacteristicWriteRequest(
+                mBluetoothDevice,
+                1,
+                mBluetoothGattCharacteristic,
+                false,
+                true,
+                1,
+                new byte[]{1});
+    }
+
+    @Test
+    public void testOnConnectionStateChange_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onConnectionStateChange(
+                mBluetoothDevice,
+                1,
+                2);
+    }
+
+    @Test
+    public void testOnDescriptorReadRequest_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onDescriptorReadRequest(
+                mBluetoothDevice,
+                1,
+                2, mBluetoothGattDescriptor);
+    }
+
+    @Test
+    public void testOnDescriptorWriteRequest_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onDescriptorWriteRequest(
+                mBluetoothDevice,
+                1,
+                mBluetoothGattDescriptor,
+                false,
+                true,
+                2,
+                new byte[]{1});
+    }
+
+    @Test
+    public void testOnExecuteWrite_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onExecuteWrite(
+                mBluetoothDevice,
+                1,
+                false);
+    }
+
+    @Test
+    public void testOnMtuChanged_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onMtuChanged(
+                mBluetoothDevice,
+                1);
+    }
+
+    @Test
+    public void testOnNotificationSent_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onNotificationSent(
+                mBluetoothDevice,
+                1);
+    }
+
+    @Test
+    public void testOnServiceAdded_notCrash() {
+        mTestBluetoothGattServerCallback.unwrap().onServiceAdded(1, mBluetoothGattService);
+    }
+
+    private static class TestBluetoothGattServerCallback extends BluetoothGattServerCallback { }
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerTest.java
new file mode 100644
index 0000000..48283d1
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattServerTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.UUID;
+
+/**
+ * Unit tests for {@link BluetoothGattServer}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothGattServerTest {
+    private static final UUID UUID_CONST = UUID.randomUUID();
+    private static final byte[] BYTES = new byte[]{1, 2, 3};
+
+    @Mock private android.bluetooth.BluetoothDevice mBluetoothDevice;
+    @Mock private android.bluetooth.BluetoothGattServer mBluetoothGattServer;
+    @Mock private android.bluetooth.BluetoothGattService mBluetoothGattService;
+    @Mock private android.bluetooth.BluetoothGattCharacteristic mBluetoothGattCharacteristic;
+
+    BluetoothGattServer mTestabilityBluetoothGattServer;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mTestabilityBluetoothGattServer = BluetoothGattServer.wrap(mBluetoothGattServer);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWrapNonNullAdapter_isNotNull_unWrapSame() {
+        assertThat(mTestabilityBluetoothGattServer).isNotNull();
+        assertThat(mTestabilityBluetoothGattServer.unwrap()).isSameInstanceAs(mBluetoothGattServer);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testConnect_callsWrapped() {
+        when(mBluetoothGattServer
+                .connect(mBluetoothDevice, true))
+                .thenReturn(true);
+        assertThat(mTestabilityBluetoothGattServer
+                .connect(BluetoothDevice.wrap(mBluetoothDevice), true))
+                .isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testAddService_callsWrapped() {
+        when(mBluetoothGattServer
+                .addService(mBluetoothGattService))
+                .thenReturn(true);
+        assertThat(mTestabilityBluetoothGattServer
+                .addService(mBluetoothGattService))
+                .isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testClearServices_callsWrapped() {
+        doNothing().when(mBluetoothGattServer).clearServices();
+        mTestabilityBluetoothGattServer.clearServices();
+        verify(mBluetoothGattServer).clearServices();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testClose_callsWrapped() {
+        doNothing().when(mBluetoothGattServer).close();
+        mTestabilityBluetoothGattServer.close();
+        verify(mBluetoothGattServer).close();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testNotifyCharacteristicChanged_callsWrapped() {
+        when(mBluetoothGattServer
+                .notifyCharacteristicChanged(
+                        mBluetoothDevice,
+                        mBluetoothGattCharacteristic,
+                        true))
+                .thenReturn(true);
+        assertThat(mTestabilityBluetoothGattServer
+                .notifyCharacteristicChanged(
+                        BluetoothDevice.wrap(mBluetoothDevice),
+                        mBluetoothGattCharacteristic,
+                        true))
+                .isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testSendResponse_callsWrapped() {
+        when(mBluetoothGattServer.sendResponse(
+                mBluetoothDevice, 1, 1, 1, BYTES)).thenReturn(true);
+        mTestabilityBluetoothGattServer.sendResponse(
+                BluetoothDevice.wrap(mBluetoothDevice), 1, 1, 1, BYTES);
+        verify(mBluetoothGattServer).sendResponse(
+                mBluetoothDevice, 1, 1, 1, BYTES);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testCancelConnection_callsWrapped() {
+        doNothing().when(mBluetoothGattServer).cancelConnection(mBluetoothDevice);
+        mTestabilityBluetoothGattServer.cancelConnection(BluetoothDevice.wrap(mBluetoothDevice));
+        verify(mBluetoothGattServer).cancelConnection(mBluetoothDevice);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetService_callsWrapped() {
+        when(mBluetoothGattServer.getService(UUID_CONST)).thenReturn(null);
+        assertThat(mTestabilityBluetoothGattServer.getService(UUID_CONST)).isNull();
+    }
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattWrapperTest.java b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattWrapperTest.java
new file mode 100644
index 0000000..ef37323
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/common/bluetooth/testability/android/bluetooth/BluetoothGattWrapperTest.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.nearby.common.bluetooth.testability.android.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SdkSuppress;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.UUID;
+
+/**
+ * Unit tests for {@link BluetoothGattWrapper}.
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BluetoothGattWrapperTest {
+    private static final UUID UUID_CONST = UUID.randomUUID();
+    private static final byte[] BYTES = new byte[]{1, 2, 3};
+
+    @Mock private android.bluetooth.BluetoothDevice mBluetoothDevice;
+    @Mock private android.bluetooth.BluetoothGatt mBluetoothGatt;
+    @Mock private android.bluetooth.BluetoothGattService mBluetoothGattService;
+    @Mock private android.bluetooth.BluetoothGattCharacteristic mBluetoothGattCharacteristic;
+    @Mock private android.bluetooth.BluetoothGattDescriptor mBluetoothGattDescriptor;
+
+    BluetoothGattWrapper mBluetoothGattWrapper;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+        mBluetoothGattWrapper = BluetoothGattWrapper.wrap(mBluetoothGatt);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWrapNonNullAdapter_isNotNull_unWrapSame() {
+        assertThat(mBluetoothGattWrapper).isNotNull();
+        assertThat(mBluetoothGattWrapper.unwrap()).isSameInstanceAs(mBluetoothGatt);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testEquality_asExpected() {
+        assertThat(mBluetoothGattWrapper.equals(null)).isFalse();
+        assertThat(mBluetoothGattWrapper.equals(mBluetoothGattWrapper)).isTrue();
+        assertThat(mBluetoothGattWrapper.equals(BluetoothGattWrapper.wrap(mBluetoothGatt)))
+                .isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetDevice_callsWrapped() {
+        when(mBluetoothGatt.getDevice()).thenReturn(mBluetoothDevice);
+        assertThat(mBluetoothGattWrapper.getDevice().unwrap()).isSameInstanceAs(mBluetoothDevice);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetServices_callsWrapped() {
+        when(mBluetoothGatt.getServices()).thenReturn(null);
+        assertThat(mBluetoothGattWrapper.getServices()).isNull();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testGetService_callsWrapped() {
+        when(mBluetoothGatt.getService(UUID_CONST)).thenReturn(mBluetoothGattService);
+        assertThat(mBluetoothGattWrapper.getService(UUID_CONST))
+                .isSameInstanceAs(mBluetoothGattService);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testDiscoverServices_callsWrapped() {
+        when(mBluetoothGatt.discoverServices()).thenReturn(true);
+        assertThat(mBluetoothGattWrapper.discoverServices()).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testReadCharacteristic_callsWrapped() {
+        when(mBluetoothGatt.readCharacteristic(mBluetoothGattCharacteristic)).thenReturn(true);
+        assertThat(mBluetoothGattWrapper.readCharacteristic(mBluetoothGattCharacteristic)).isTrue();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWriteCharacteristic_callsWrapped() {
+        when(mBluetoothGatt.writeCharacteristic(mBluetoothGattCharacteristic, BYTES, 1))
+                .thenReturn(1);
+        assertThat(mBluetoothGattWrapper.writeCharacteristic(
+                mBluetoothGattCharacteristic, BYTES, 1)).isEqualTo(1);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testReadDescriptor_callsWrapped() {
+        when(mBluetoothGatt.readDescriptor(mBluetoothGattDescriptor)).thenReturn(false);
+        assertThat(mBluetoothGattWrapper.readDescriptor(mBluetoothGattDescriptor)).isFalse();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testWriteDescriptor_callsWrapped() {
+        when(mBluetoothGatt.writeDescriptor(mBluetoothGattDescriptor, BYTES)).thenReturn(5);
+        assertThat(mBluetoothGattWrapper.writeDescriptor(mBluetoothGattDescriptor, BYTES))
+                .isEqualTo(5);
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testReadRemoteRssi_callsWrapped() {
+        when(mBluetoothGatt.readRemoteRssi()).thenReturn(false);
+        assertThat(mBluetoothGattWrapper.readRemoteRssi()).isFalse();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testRequestConnectionPriority_callsWrapped() {
+        when(mBluetoothGatt.requestConnectionPriority(5)).thenReturn(false);
+        assertThat(mBluetoothGattWrapper.requestConnectionPriority(5)).isFalse();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testRequestMtu_callsWrapped() {
+        when(mBluetoothGatt.requestMtu(5)).thenReturn(false);
+        assertThat(mBluetoothGattWrapper.requestMtu(5)).isFalse();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testSetCharacteristicNotification_callsWrapped() {
+        when(mBluetoothGatt.setCharacteristicNotification(mBluetoothGattCharacteristic, true))
+                .thenReturn(false);
+        assertThat(mBluetoothGattWrapper
+                .setCharacteristicNotification(mBluetoothGattCharacteristic, true)).isFalse();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testDisconnect_callsWrapped() {
+        doNothing().when(mBluetoothGatt).disconnect();
+        mBluetoothGatt.disconnect();
+        verify(mBluetoothGatt).disconnect();
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 32, codeName = "T")
+    public void testClose_callsWrapped() {
+        doNothing().when(mBluetoothGatt).close();
+        mBluetoothGatt.close();
+        verify(mBluetoothGatt).close();
+    }
+}