Merge "[Unit Test] Add BleDiscoveryProviderTest" into tm-dev
diff --git a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
index fc2e4e8..a989143 100644
--- a/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
+++ b/nearby/service/java/com/android/server/nearby/provider/BleDiscoveryProvider.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
 import android.bluetooth.le.ScanFilter;
 import android.bluetooth.le.ScanRecord;
 import android.bluetooth.le.ScanResult;
@@ -37,6 +38,8 @@
 import com.android.server.nearby.presence.PresenceConstants;
 import com.android.server.nearby.util.ForegroundThread;
 
+import com.google.common.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -47,7 +50,8 @@
  */
 public class BleDiscoveryProvider extends AbstractDiscoveryProvider {
 
-    private static final ParcelUuid FAST_PAIR_UUID = new ParcelUuid(Constants.FastPairService.ID);
+    @VisibleForTesting
+    static final ParcelUuid FAST_PAIR_UUID = new ParcelUuid(Constants.FastPairService.ID);
     private static final ParcelUuid PRESENCE_UUID = new ParcelUuid(PresenceConstants.PRESENCE_UUID);
 
     // Don't block the thread as it may be used by other services.
@@ -156,6 +160,7 @@
             if (bluetoothLeScanner == null) {
                 Log.w(TAG, "BleDiscoveryProvider failed to start BLE scanning "
                         + "because BluetoothLeScanner is null.");
+                return;
             }
             bluetoothLeScanner.startScan(scanFilters, scanSettings, scanCallback);
         } catch (NullPointerException | IllegalStateException | SecurityException e) {
@@ -188,4 +193,9 @@
         }
         return new ScanSettings.Builder().setScanMode(bleScanMode).build();
     }
+
+    @VisibleForTesting
+    ScanCallback getScanCallback() {
+        return mScanCallback;
+    }
 }
diff --git a/nearby/tests/unit/src/com/android/server/nearby/NearbyServiceTest.java b/nearby/tests/unit/src/com/android/server/nearby/NearbyServiceTest.java
index 6e414d6..c20cf22 100644
--- a/nearby/tests/unit/src/com/android/server/nearby/NearbyServiceTest.java
+++ b/nearby/tests/unit/src/com/android/server/nearby/NearbyServiceTest.java
@@ -16,12 +16,11 @@
 
 package com.android.server.nearby;
 
+import static org.mockito.MockitoAnnotations.initMocks;
+
 import android.content.Context;
 import android.nearby.IScanListener;
-import android.nearby.NearbyDeviceParcelable;
 import android.nearby.ScanRequest;
-import android.os.IBinder;
-import android.os.RemoteException;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -31,6 +30,7 @@
 
 public final class NearbyServiceTest {
 
+    private Context mContext;
     private NearbyService mService;
     private ScanRequest mScanRequest;
     @Mock
@@ -38,11 +38,11 @@
 
     @Before
     public void setup() {
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        initMocks(this);
 
-        mService = new NearbyService(context);
+        mContext = InstrumentationRegistry.getInstrumentation().getContext();
+        mService = new NearbyService(mContext);
         mScanRequest = createScanRequest();
-        mScanListener = createMockScanListener();
     }
 
     @Test
@@ -61,28 +61,4 @@
                 .setEnableBle(true)
                 .build();
     }
-
-    private IScanListener createMockScanListener() {
-        return new IScanListener() {
-            @Override
-            public void onDiscovered(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-            }
-
-            @Override
-            public void onUpdated(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-            }
-
-            @Override
-            public void onLost(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-        };
-    }
 }
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/BleDiscoveryProviderTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/BleDiscoveryProviderTest.java
new file mode 100644
index 0000000..4c78885
--- /dev/null
+++ b/nearby/tests/unit/src/com/android/server/nearby/provider/BleDiscoveryProviderTest.java
@@ -0,0 +1,116 @@
+/*
+ * 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.provider;
+
+import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.MockitoAnnotations.initMocks;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.ScanRecord;
+import android.bluetooth.le.ScanResult;
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.nearby.injector.Injector;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public final class BleDiscoveryProviderTest {
+
+    private BluetoothAdapter mBluetoothAdapter;
+    private BleDiscoveryProvider mBleDiscoveryProvider;
+    @Mock
+    private AbstractDiscoveryProvider.Listener mListener;
+
+    @Before
+    public void setup() {
+        initMocks(this);
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        Injector injector = new TestInjector();
+
+        mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
+        mBleDiscoveryProvider = new BleDiscoveryProvider(context, injector);
+    }
+
+    @Test
+    public void test_callback() throws InterruptedException {
+        mBleDiscoveryProvider.getController().setListener(mListener);
+        mBleDiscoveryProvider.onStart();
+        mBleDiscoveryProvider.getScanCallback()
+                .onScanResult(CALLBACK_TYPE_ALL_MATCHES, createScanResult());
+
+        // Wait for callback to be invoked
+        Thread.sleep(500);
+        verify(mListener, times(1)).onNearbyDeviceDiscovered(any());
+    }
+
+    @Test
+    public void test_stopScan() {
+        mBleDiscoveryProvider.onStart();
+        mBleDiscoveryProvider.onStop();
+    }
+
+    private class TestInjector implements Injector {
+        @Override
+        public BluetoothAdapter getBluetoothAdapter() {
+            return mBluetoothAdapter;
+        }
+    }
+
+    private ScanResult createScanResult() {
+        BluetoothDevice bluetoothDevice = mBluetoothAdapter
+                .getRemoteDevice("11:22:33:44:55:66");
+        byte[] scanRecord = new byte[] {2, 1, 6, 6, 22, 44, -2, 113, -116, 23, 2, 10, -11, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+        return new ScanResult(
+                bluetoothDevice,
+                /* eventType= */ 0,
+                /* primaryPhy= */ 0,
+                /* secondaryPhy= */ 0,
+                /* advertisingSid= */ 0,
+                -31,
+                -50,
+                /* periodicAdvertisingInterval= */ 0,
+                parseScanRecord(scanRecord),
+                1645579363003L);
+    }
+
+    private static ScanRecord parseScanRecord(byte[] bytes) {
+        Class<?> scanRecordClass = ScanRecord.class;
+        try {
+            Method method = scanRecordClass
+                    .getDeclaredMethod("parseFromBytes", byte[].class);
+            return (ScanRecord) method.invoke(null, bytes);
+        } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException
+                | InvocationTargetException e) {
+            return null;
+        }
+    }
+}
diff --git a/nearby/tests/unit/src/com/android/server/nearby/provider/DiscoveryProviderManagerTest.java b/nearby/tests/unit/src/com/android/server/nearby/provider/DiscoveryProviderManagerTest.java
deleted file mode 100644
index b34d195..0000000
--- a/nearby/tests/unit/src/com/android/server/nearby/provider/DiscoveryProviderManagerTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.nearby.provider;
-
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.nearby.IScanListener;
-import android.nearby.NearbyDeviceParcelable;
-import android.nearby.ScanRequest;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.server.nearby.injector.Injector;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-
-@SmallTest
-public final class DiscoveryProviderManagerTest {
-    @Mock
-    private Context mContext;
-    @Mock
-    private BluetoothAdapter mBluetoothAdapter;
-    private TestInjector mInjector;
-    // TODO(b/215435710) NearbyDeviceParcelable Cannot be accessed because it is a system API.
-    // Need to fix this to add more test logic.
-    private DiscoveryProviderManager mManager;
-
-    @Before
-    public void setUp() {
-        mInjector = new TestInjector();
-        mManager = new DiscoveryProviderManager(mContext, mInjector);
-    }
-
-    private class TestInjector implements Injector {
-        @Override
-        public BluetoothAdapter getBluetoothAdapter() {
-            return mBluetoothAdapter;
-        }
-    }
-
-    @Test
-    public void testRegisterListener() throws Exception {
-        IScanListener listener = createMockScanListener();
-        mManager.registerScanListener(createScanRequest(), listener);
-    }
-
-    private ScanRequest createScanRequest() {
-        return new ScanRequest.Builder()
-                .setScanType(ScanRequest.SCAN_TYPE_FAST_PAIR)
-                .setEnableBle(true)
-                .build();
-    }
-
-    private IScanListener createMockScanListener() {
-        return new IScanListener() {
-            @Override
-            public void onDiscovered(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-
-            }
-
-            @Override
-            public void onUpdated(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-
-            }
-
-            @Override
-            public void onLost(NearbyDeviceParcelable nearbyDeviceParcelable)
-                    throws RemoteException {
-
-            }
-
-            @Override
-            public IBinder asBinder() {
-                return null;
-            }
-        };
-    }
-}