• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.bluetooth.le_scan;
18 
19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
20 import static android.bluetooth.BluetoothDevice.PHY_LE_1M;
21 import static android.bluetooth.BluetoothDevice.PHY_LE_1M_MASK;
22 import static android.bluetooth.BluetoothDevice.PHY_LE_CODED;
23 import static android.bluetooth.BluetoothDevice.PHY_LE_CODED_MASK;
24 import static android.bluetooth.BluetoothProfile.STATE_CONNECTING;
25 import static android.bluetooth.BluetoothProfile.STATE_DISCONNECTED;
26 import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH;
27 import static android.bluetooth.le.ScanSettings.PHY_LE_ALL_SUPPORTED;
28 import static android.bluetooth.le.ScanSettings.SCAN_MODE_AMBIENT_DISCOVERY;
29 import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
30 import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;
31 import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_POWER;
32 import static android.bluetooth.le.ScanSettings.SCAN_MODE_OPPORTUNISTIC;
33 import static android.bluetooth.le.ScanSettings.SCAN_MODE_SCREEN_OFF;
34 import static android.bluetooth.le.ScanSettings.SCAN_MODE_SCREEN_OFF_BALANCED;
35 
36 import static com.android.bluetooth.TestUtils.MockitoRule;
37 import static com.android.bluetooth.btservice.AdapterService.DeviceConfigListener.DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS;
38 import static com.android.bluetooth.btservice.AdapterService.DeviceConfigListener.DEFAULT_SCAN_TIMEOUT_MILLIS;
39 import static com.android.bluetooth.btservice.AdapterService.DeviceConfigListener.DEFAULT_SCAN_UPGRADE_DURATION_MILLIS;
40 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_BALANCED_INTERVAL_MS;
41 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_BALANCED_WINDOW_MS;
42 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_LOW_LATENCY_INTERVAL_MS;
43 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_LOW_LATENCY_WINDOW_MS;
44 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_SCREEN_OFF_BALANCED_INTERVAL_MS;
45 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_SCREEN_OFF_BALANCED_WINDOW_MS;
46 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_SCREEN_OFF_LOW_POWER_INTERVAL_MS;
47 import static com.android.bluetooth.le_scan.ScanManager.SCAN_MODE_SCREEN_OFF_LOW_POWER_WINDOW_MS;
48 
49 import static com.google.common.truth.Truth.assertThat;
50 
51 import static org.mockito.ArgumentMatchers.any;
52 import static org.mockito.ArgumentMatchers.anyBoolean;
53 import static org.mockito.ArgumentMatchers.anyInt;
54 import static org.mockito.ArgumentMatchers.anyLong;
55 import static org.mockito.Mockito.atLeastOnce;
56 import static org.mockito.Mockito.doReturn;
57 import static org.mockito.Mockito.eq;
58 import static org.mockito.Mockito.inOrder;
59 import static org.mockito.Mockito.never;
60 import static org.mockito.Mockito.spy;
61 import static org.mockito.Mockito.verify;
62 
63 import android.app.ActivityManager;
64 import android.app.AlarmManager;
65 import android.bluetooth.BluetoothProfile;
66 import android.bluetooth.BluetoothProtoEnums;
67 import android.bluetooth.le.ScanFilter;
68 import android.bluetooth.le.ScanSettings;
69 import android.content.Context;
70 import android.hardware.display.DisplayManager;
71 import android.location.LocationManager;
72 import android.os.BatteryStatsManager;
73 import android.os.Binder;
74 import android.os.Bundle;
75 import android.os.Message;
76 import android.os.ParcelUuid;
77 import android.os.WorkSource;
78 import android.platform.test.annotations.DisableFlags;
79 import android.platform.test.annotations.EnableFlags;
80 import android.platform.test.flag.junit.SetFlagsRule;
81 import android.provider.Settings;
82 import android.test.mock.MockContentProvider;
83 import android.test.mock.MockContentResolver;
84 import android.util.Log;
85 import android.util.SparseIntArray;
86 
87 import androidx.test.filters.SmallTest;
88 import androidx.test.platform.app.InstrumentationRegistry;
89 
90 import com.android.bluetooth.BluetoothStatsLog;
91 import com.android.bluetooth.TestLooper;
92 import com.android.bluetooth.TestUtils;
93 import com.android.bluetooth.TestUtils.FakeTimeProvider;
94 import com.android.bluetooth.Utils;
95 import com.android.bluetooth.btservice.AdapterService;
96 import com.android.bluetooth.btservice.BluetoothAdapterProxy;
97 import com.android.bluetooth.btservice.MetricsLogger;
98 import com.android.bluetooth.flags.Flags;
99 import com.android.bluetooth.gatt.GattNativeInterface;
100 import com.android.bluetooth.gatt.GattObjectsFactory;
101 import com.android.bluetooth.util.SystemProperties;
102 
103 import com.google.testing.junit.testparameterinjector.TestParameter;
104 import com.google.testing.junit.testparameterinjector.TestParameterInjector;
105 
106 import org.junit.After;
107 import org.junit.Before;
108 import org.junit.Rule;
109 import org.junit.Test;
110 import org.junit.runner.RunWith;
111 import org.mockito.InOrder;
112 import org.mockito.Mock;
113 import org.mockito.Mockito;
114 import org.mockito.Spy;
115 
116 import java.time.Duration;
117 import java.util.ArrayList;
118 import java.util.List;
119 import java.util.Map;
120 import java.util.Set;
121 import java.util.UUID;
122 
123 /** Test cases for {@link ScanManager}. */
124 @SmallTest
125 @RunWith(TestParameterInjector.class)
126 public class ScanManagerTest {
127     private static final String TAG = ScanManagerTest.class.getSimpleName();
128 
129     @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
130     @Rule public final MockitoRule mMockitoRule = new MockitoRule();
131 
132     @Mock private AdapterService mAdapterService;
133     @Mock private BluetoothAdapterProxy mBluetoothAdapterProxy;
134     @Mock private GattNativeInterface mNativeInterface;
135     @Mock private LocationManager mLocationManager;
136     @Mock private MetricsLogger mMetricsLogger;
137     @Mock private ScanNativeInterface mScanNativeInterface;
138     @Mock private ScanController mScanController;
139     @Mock private SystemProperties.MockableSystemProperties mProperties;
140 
141     @Spy private GattObjectsFactory mGattObjectsFactory = GattObjectsFactory.getInstance();
142     @Spy private ScanObjectsFactory mScanObjectsFactory = ScanObjectsFactory.getInstance();
143 
144     private static final int DEFAULT_REGULAR_SCAN_REPORT_DELAY_MS = 0;
145     private static final int DEFAULT_BATCH_SCAN_REPORT_DELAY_MS = 100;
146     private static final int DEFAULT_NUM_OFFLOAD_SCAN_FILTER = 16;
147     private static final int DEFAULT_BYTES_OFFLOAD_SCAN_RESULT_STORAGE = 4096;
148     private static final int DEFAULT_TOTAL_NUM_OF_TRACKABLE_ADVERTISEMENTS = 32;
149     private static final int TEST_SCAN_QUOTA_COUNT = 5;
150     private static final String TEST_APP_NAME = "Test";
151     private static final String TEST_PACKAGE_NAME = "com.test.package";
152 
153     // MSFT-based hardware scan offload sysprop
154     private static final String MSFT_HCI_EXT_ENABLED = "bluetooth.core.le.use_msft_hci_ext";
155 
156     private static final Map<Integer, Integer> defaultScanMode =
157             Map.of(
158                     SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER,
159                     SCAN_MODE_BALANCED, SCAN_MODE_BALANCED,
160                     SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY,
161                     SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
162 
163     private final Context mTargetContext =
164             InstrumentationRegistry.getInstrumentation().getTargetContext();
165 
166     private AppScanStats mMockAppScanStats;
167     private MockContentResolver mMockContentResolver;
168 
169     private ScanManager mScanManager;
170     private TestLooper mLooper;
171     private long mScanReportDelay;
172     private FakeTimeProvider mTimeProvider;
173     private InOrder mInOrder;
174     private int mClientId;
175 
176     @Before
setUp()177     public void setUp() throws Exception {
178         doReturn(DEFAULT_SCAN_TIMEOUT_MILLIS).when(mAdapterService).getScanTimeoutMillis();
179         doReturn(DEFAULT_NUM_OFFLOAD_SCAN_FILTER)
180                 .when(mAdapterService)
181                 .getNumOfOffloadedScanFilterSupported();
182         doReturn(DEFAULT_BYTES_OFFLOAD_SCAN_RESULT_STORAGE)
183                 .when(mAdapterService)
184                 .getOffloadedScanResultStorage();
185         doReturn(TEST_SCAN_QUOTA_COUNT).when(mAdapterService).getScanQuotaCount();
186         doReturn(SCAN_MODE_SCREEN_OFF_LOW_POWER_WINDOW_MS)
187                 .when(mAdapterService)
188                 .getScreenOffLowPowerWindowMillis();
189         doReturn(SCAN_MODE_SCREEN_OFF_BALANCED_WINDOW_MS)
190                 .when(mAdapterService)
191                 .getScreenOffBalancedWindowMillis();
192         doReturn(SCAN_MODE_SCREEN_OFF_LOW_POWER_INTERVAL_MS)
193                 .when(mAdapterService)
194                 .getScreenOffLowPowerIntervalMillis();
195         doReturn(SCAN_MODE_SCREEN_OFF_BALANCED_INTERVAL_MS)
196                 .when(mAdapterService)
197                 .getScreenOffBalancedIntervalMillis();
198         doReturn(DEFAULT_TOTAL_NUM_OF_TRACKABLE_ADVERTISEMENTS)
199                 .when(mAdapterService)
200                 .getTotalNumOfTrackableAdvertisements();
201 
202         TestUtils.mockGetSystemService(
203                 mAdapterService, Context.LOCATION_SERVICE, LocationManager.class, mLocationManager);
204         doReturn(true).when(mLocationManager).isLocationEnabled();
205 
206         // DisplayManager and BatteryStatsManager are final and cannot be mocked with regular
207         // mockito, so just return real implementation
208         TestUtils.mockGetSystemService(
209                 mAdapterService,
210                 Context.DISPLAY_SERVICE,
211                 DisplayManager.class,
212                 mTargetContext.getSystemService(DisplayManager.class));
213         TestUtils.mockGetSystemService(
214                 mAdapterService, Context.BATTERY_STATS_SERVICE, BatteryStatsManager.class);
215         TestUtils.mockGetSystemService(mAdapterService, Context.ALARM_SERVICE, AlarmManager.class);
216 
217         mMockContentResolver = new MockContentResolver(mTargetContext);
218         mMockContentResolver.addProvider(
219                 Settings.AUTHORITY,
220                 new MockContentProvider() {
221                     @Override
222                     public Bundle call(String method, String request, Bundle args) {
223                         return Bundle.EMPTY;
224                     }
225                 });
226         doReturn(mMockContentResolver).when(mAdapterService).getContentResolver();
227         BluetoothAdapterProxy.setInstanceForTesting(mBluetoothAdapterProxy);
228         // Needed to mock Native call/callback when hw offload scan filter is enabled
229         doReturn(true).when(mBluetoothAdapterProxy).isOffloadedScanFilteringSupported();
230 
231         GattObjectsFactory.setInstanceForTesting(mGattObjectsFactory);
232         ScanObjectsFactory.setInstanceForTesting(mScanObjectsFactory);
233         doReturn(mNativeInterface).when(mGattObjectsFactory).getNativeInterface();
234         doReturn(mScanNativeInterface).when(mScanObjectsFactory).getScanNativeInterface();
235         // Mock JNI callback in ScanNativeInterface
236         doReturn(true).when(mScanNativeInterface).waitForCallback(anyInt());
237 
238         MetricsLogger.setInstanceForTesting(mMetricsLogger);
239         mInOrder = inOrder(mMetricsLogger);
240 
241         doReturn(mTargetContext.getUser()).when(mAdapterService).getUser();
242         doReturn(mTargetContext.getPackageName()).when(mAdapterService).getPackageName();
243 
244         mClientId = 0;
245         mTimeProvider = new FakeTimeProvider();
246         mLooper = new TestLooper();
247         mScanManager =
248                 new ScanManager(
249                         mAdapterService,
250                         mScanController,
251                         mBluetoothAdapterProxy,
252                         mLooper.getLooper(),
253                         mTimeProvider);
254 
255         mScanReportDelay = DEFAULT_BATCH_SCAN_REPORT_DELAY_MS;
256         mMockAppScanStats =
257                 spy(
258                         new AppScanStats(
259                                 TEST_APP_NAME,
260                                 null,
261                                 null,
262                                 mAdapterService,
263                                 mScanController,
264                                 mTimeProvider));
265     }
266 
267     @After
tearDown()268     public void tearDown() throws Exception {
269         SystemProperties.mProperties = null;
270         BluetoothAdapterProxy.setInstanceForTesting(null);
271         GattObjectsFactory.setInstanceForTesting(null);
272         ScanObjectsFactory.setInstanceForTesting(null);
273         MetricsLogger.setInstanceForTesting(null);
274         MetricsLogger.getInstance();
275     }
276 
advanceTime(Duration amountToAdvance)277     private void advanceTime(Duration amountToAdvance) {
278         mLooper.moveTimeForward(amountToAdvance.toMillis());
279         mTimeProvider.advanceTime(amountToAdvance);
280     }
281 
advanceTime(long amountToAdvanceMillis)282     private void advanceTime(long amountToAdvanceMillis) {
283         mLooper.moveTimeForward(amountToAdvanceMillis);
284         mTimeProvider.advanceTime(Duration.ofMillis(amountToAdvanceMillis));
285     }
286 
syncHandler(int... what)287     private void syncHandler(int... what) {
288         TestUtils.syncHandler(mLooper, what);
289     }
290 
sendMessageWaitForProcessed(Message msg)291     private void sendMessageWaitForProcessed(Message msg) {
292         mScanManager.mHandler.sendMessage(msg);
293         mLooper.dispatchAll();
294     }
295 
createScanClient( boolean isFiltered, int scanMode, boolean isBatch, boolean isAutoBatch, int appUid, AppScanStats appScanStats, List<ScanFilter> scanFilterList)296     private ScanClient createScanClient(
297             boolean isFiltered,
298             int scanMode,
299             boolean isBatch,
300             boolean isAutoBatch,
301             int appUid,
302             AppScanStats appScanStats,
303             List<ScanFilter> scanFilterList) {
304         ScanSettings scanSettings = createScanSettings(scanMode, isBatch, isAutoBatch);
305 
306         mClientId = mClientId + 1;
307         ScanClient client = new ScanClient(mClientId, scanSettings, scanFilterList, appUid);
308         client.mStats = appScanStats;
309         client.mStats.recordScanStart(
310                 scanSettings, scanFilterList, isFiltered, false, mClientId, null);
311         return client;
312     }
313 
createScanClient( boolean isFiltered, boolean isEmptyFilter, int scanMode, boolean isBatch, boolean isAutoBatch, int appUid, AppScanStats appScanStats)314     private ScanClient createScanClient(
315             boolean isFiltered,
316             boolean isEmptyFilter,
317             int scanMode,
318             boolean isBatch,
319             boolean isAutoBatch,
320             int appUid,
321             AppScanStats appScanStats) {
322         List<ScanFilter> scanFilterList = createScanFilterList(isFiltered, isEmptyFilter);
323         return createScanClient(
324                 isFiltered, scanMode, isBatch, isAutoBatch, appUid, appScanStats, scanFilterList);
325     }
326 
createScanClient(boolean isFiltered, int scanMode)327     private ScanClient createScanClient(boolean isFiltered, int scanMode) {
328         return createScanClient(
329                 isFiltered,
330                 false,
331                 scanMode,
332                 false,
333                 false,
334                 Binder.getCallingUid(),
335                 mMockAppScanStats);
336     }
337 
createScanClient( boolean isFiltered, int scanMode, int appUid, AppScanStats appScanStats)338     private ScanClient createScanClient(
339             boolean isFiltered, int scanMode, int appUid, AppScanStats appScanStats) {
340         return createScanClient(isFiltered, false, scanMode, false, false, appUid, appScanStats);
341     }
342 
createScanClient( boolean isFiltered, int scanMode, boolean isBatch, boolean isAutoBatch)343     private ScanClient createScanClient(
344             boolean isFiltered, int scanMode, boolean isBatch, boolean isAutoBatch) {
345         return createScanClient(
346                 isFiltered,
347                 false,
348                 scanMode,
349                 isBatch,
350                 isAutoBatch,
351                 Binder.getCallingUid(),
352                 mMockAppScanStats);
353     }
354 
createScanClient(boolean isFiltered, boolean isEmptyFilter, int scanMode)355     private ScanClient createScanClient(boolean isFiltered, boolean isEmptyFilter, int scanMode) {
356         return createScanClient(
357                 isFiltered,
358                 isEmptyFilter,
359                 scanMode,
360                 false,
361                 false,
362                 Binder.getCallingUid(),
363                 mMockAppScanStats);
364     }
365 
createScanFilterList( boolean isFiltered, boolean isEmptyFilter)366     private static List<ScanFilter> createScanFilterList(
367             boolean isFiltered, boolean isEmptyFilter) {
368         List<ScanFilter> scanFilterList = null;
369         if (isFiltered) {
370             scanFilterList = new ArrayList<>();
371             if (isEmptyFilter) {
372                 scanFilterList.add(new ScanFilter.Builder().build());
373             } else {
374                 scanFilterList.add(new ScanFilter.Builder().setDeviceName("TestName").build());
375             }
376         }
377         return scanFilterList;
378     }
379 
createScanSettings(int scanMode, boolean isBatch, boolean isAutoBatch)380     private ScanSettings createScanSettings(int scanMode, boolean isBatch, boolean isAutoBatch) {
381 
382         ScanSettings scanSettings = null;
383         if (isBatch && isAutoBatch) {
384             int autoCallbackType = CALLBACK_TYPE_ALL_MATCHES_AUTO_BATCH;
385             scanSettings =
386                     new ScanSettings.Builder()
387                             .setScanMode(scanMode)
388                             .setReportDelay(mScanReportDelay)
389                             .setCallbackType(autoCallbackType)
390                             .build();
391         } else if (isBatch) {
392             scanSettings =
393                     new ScanSettings.Builder()
394                             .setScanMode(scanMode)
395                             .setReportDelay(mScanReportDelay)
396                             .build();
397         } else {
398             scanSettings = new ScanSettings.Builder().setScanMode(scanMode).build();
399         }
400         return scanSettings;
401     }
402 
createScanSettingsWithPhy(int scanMode, int phy)403     private static ScanSettings createScanSettingsWithPhy(int scanMode, int phy) {
404         ScanSettings scanSettings;
405         scanSettings = new ScanSettings.Builder().setScanMode(scanMode).setPhy(phy).build();
406 
407         return scanSettings;
408     }
409 
createScanClientWithPhy( int id, boolean isFiltered, boolean isEmptyFilter, int scanMode, int phy)410     private ScanClient createScanClientWithPhy(
411             int id, boolean isFiltered, boolean isEmptyFilter, int scanMode, int phy) {
412         List<ScanFilter> scanFilterList = createScanFilterList(isFiltered, isEmptyFilter);
413         ScanSettings scanSettings = createScanSettingsWithPhy(scanMode, phy);
414 
415         ScanClient client = new ScanClient(id, scanSettings, scanFilterList);
416         client.mStats = mMockAppScanStats;
417         client.mStats.recordScanStart(scanSettings, scanFilterList, isFiltered, false, id, null);
418         return client;
419     }
420 
createStartStopScanMessage(boolean isStartScan, Object obj)421     private static Message createStartStopScanMessage(boolean isStartScan, Object obj) {
422         Message message = new Message();
423         message.what = isStartScan ? ScanManager.MSG_START_BLE_SCAN : ScanManager.MSG_STOP_BLE_SCAN;
424         message.obj = obj;
425         return message;
426     }
427 
createScreenOnOffMessage(boolean isScreenOn)428     private static Message createScreenOnOffMessage(boolean isScreenOn) {
429         Message message = new Message();
430         message.what = isScreenOn ? ScanManager.MSG_SCREEN_ON : ScanManager.MSG_SCREEN_OFF;
431         message.obj = null;
432         return message;
433     }
434 
createLocationOnOffMessage(boolean isLocationOn)435     private static Message createLocationOnOffMessage(boolean isLocationOn) {
436         Message message = new Message();
437         message.what = isLocationOn ? ScanManager.MSG_RESUME_SCANS : ScanManager.MSG_SUSPEND_SCANS;
438         message.obj = null;
439         return message;
440     }
441 
createImportanceMessage(boolean isForeground)442     private static Message createImportanceMessage(boolean isForeground) {
443         return createImportanceMessage(isForeground, Binder.getCallingUid());
444     }
445 
createImportanceMessage(boolean isForeground, int uid)446     private static Message createImportanceMessage(boolean isForeground, int uid) {
447         final int importance =
448                 isForeground
449                         ? ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE
450                         : ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE + 1;
451         Message message = new Message();
452         message.what = ScanManager.MSG_IMPORTANCE_CHANGE;
453         message.obj = new ScanManager.UidImportance(uid, importance);
454         return message;
455     }
456 
createConnectingMessage(boolean isConnectingOn)457     private static Message createConnectingMessage(boolean isConnectingOn) {
458         Message message = new Message();
459         message.what =
460                 isConnectingOn ? ScanManager.MSG_START_CONNECTING : ScanManager.MSG_STOP_CONNECTING;
461         message.obj = null;
462         return message;
463     }
464 
465     @Test
testScreenOffStartUnfilteredScan()466     public void testScreenOffStartUnfilteredScan() {
467         // Set filtered scan flag
468         final boolean isFiltered = false;
469 
470         defaultScanMode.forEach(
471                 (scanMode, expectedScanMode) -> {
472                     mClientId = mClientId + 1;
473                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
474 
475                     // Turn off screen
476                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
477                     // Create scan client
478                     ScanClient client = createScanClient(isFiltered, scanMode);
479                     // Start scan
480                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
481                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
482                     assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
483                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
484                 });
485     }
486 
487     @Test
testScreenOffStartFilteredScan()488     public void testScreenOffStartFilteredScan() {
489         // Set filtered scan flag
490         final boolean isFiltered = true;
491         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
492         SparseIntArray scanModeMap = new SparseIntArray();
493         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
494         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF_BALANCED);
495         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
496         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF_BALANCED);
497 
498         for (int i = 0; i < scanModeMap.size(); i++) {
499             int scanMode = scanModeMap.keyAt(i);
500             int expectedScanMode = scanModeMap.get(scanMode);
501             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
502 
503             // Turn off screen
504             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
505             // Create scan client
506             ScanClient client = createScanClient(isFiltered, scanMode);
507             // Start scan
508             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
509             assertThat(mScanManager.getRegularScanQueue()).contains(client);
510             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
511             assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
512         }
513     }
514 
515     @Test
testScreenOffStartEmptyFilterScan()516     public void testScreenOffStartEmptyFilterScan() {
517         // Set filtered scan flag
518         final boolean isFiltered = true;
519         final boolean isEmptyFilter = true;
520 
521         defaultScanMode.forEach(
522                 (scanMode, expectedScanMode) -> {
523                     mClientId = mClientId + 1;
524                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
525 
526                     // Turn off screen
527                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
528                     // Create scan client
529                     ScanClient client = createScanClient(isFiltered, isEmptyFilter, scanMode);
530                     // Start scan
531                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
532                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
533                     assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
534                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
535                 });
536     }
537 
538     @Test
testScreenOnStartUnfilteredScan()539     public void testScreenOnStartUnfilteredScan() {
540         // Set filtered scan flag
541         final boolean isFiltered = false;
542 
543         defaultScanMode.forEach(
544                 (scanMode, expectedScanMode) -> {
545                     mClientId = mClientId + 1;
546                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
547 
548                     // Turn on screen
549                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
550                     // Create scan client
551                     ScanClient client = createScanClient(isFiltered, scanMode);
552                     // Start scan
553                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
554                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
555                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
556                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
557                 });
558     }
559 
560     @Test
testScreenOnStartFilteredScan()561     public void testScreenOnStartFilteredScan() {
562         // Set filtered scan flag
563         final boolean isFiltered = true;
564 
565         defaultScanMode.forEach(
566                 (scanMode, expectedScanMode) -> {
567                     mClientId = mClientId + 1;
568                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
569 
570                     // Turn on screen
571                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
572                     // Create scan client
573                     ScanClient client = createScanClient(isFiltered, scanMode);
574                     // Start scan
575                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
576                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
577                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
578                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
579                 });
580     }
581 
582     @Test
testResumeUnfilteredScanAfterScreenOn()583     public void testResumeUnfilteredScanAfterScreenOn() {
584         // Set filtered scan flag
585         final boolean isFiltered = false;
586         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
587         SparseIntArray scanModeMap = new SparseIntArray();
588         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
589         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF_BALANCED);
590         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
591         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF_BALANCED);
592 
593         for (int i = 0; i < scanModeMap.size(); i++) {
594             int scanMode = scanModeMap.keyAt(i);
595             int expectedScanMode = scanModeMap.get(scanMode);
596             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
597 
598             // Turn off screen
599             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
600             // Create scan client
601             ScanClient client = createScanClient(isFiltered, scanMode);
602             // Start scan
603             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
604             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
605             assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
606             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
607             // Turn on screen
608             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
609             assertThat(mScanManager.getRegularScanQueue()).contains(client);
610             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
611             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
612         }
613     }
614 
615     @Test
testResumeFilteredScanAfterScreenOn()616     public void testResumeFilteredScanAfterScreenOn() {
617         // Set filtered scan flag
618         final boolean isFiltered = true;
619         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
620         SparseIntArray scanModeMap = new SparseIntArray();
621         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
622         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF_BALANCED);
623         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
624         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF_BALANCED);
625 
626         for (int i = 0; i < scanModeMap.size(); i++) {
627             int scanMode = scanModeMap.keyAt(i);
628             int expectedScanMode = scanModeMap.get(scanMode);
629             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
630 
631             // Turn off screen
632             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
633             // Create scan client
634             ScanClient client = createScanClient(isFiltered, scanMode);
635             // Start scan
636             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
637             assertThat(mScanManager.getRegularScanQueue()).contains(client);
638             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
639             assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
640             // Turn on screen
641             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
642             assertThat(mScanManager.getRegularScanQueue()).contains(client);
643             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
644             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
645         }
646     }
647 
648     @Test
testUnfilteredScanTimeout()649     public void testUnfilteredScanTimeout() {
650         // Set filtered scan flag
651         final boolean isFiltered = false;
652 
653         defaultScanMode.forEach(
654                 (scanMode, expectedScanMode) -> {
655                     mClientId = mClientId + 1;
656                     expectedScanMode = SCAN_MODE_OPPORTUNISTIC;
657                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
658 
659                     // Turn on screen
660                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
661                     // Create scan client
662                     ScanClient client = createScanClient(isFiltered, scanMode);
663                     // Start scan
664                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
665                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
666                     // Wait for scan timeout
667                     advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
668                     mLooper.dispatchAll();
669                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
670                     assertThat(client.mStats.isScanTimeout(client.mScannerId)).isTrue();
671                     // Turn off screen
672                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
673                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
674                     // Turn on screen
675                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
676                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
677                     // Set as background app
678                     sendMessageWaitForProcessed(createImportanceMessage(false));
679                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
680                     // Set as foreground app
681                     sendMessageWaitForProcessed(createImportanceMessage(true));
682                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
683                 });
684     }
685 
686     @Test
testFilteredScanTimeout()687     public void testFilteredScanTimeout() {
688         // Set filtered scan flag
689         final boolean isFiltered = true;
690 
691         defaultScanMode.forEach(
692                 (scanMode, expectedScanMode) -> {
693                     mClientId = mClientId + 1;
694                     expectedScanMode = SCAN_MODE_LOW_POWER;
695                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
696 
697                     // Turn on screen
698                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
699                     // Create scan client
700                     ScanClient client = createScanClient(isFiltered, scanMode);
701                     // Start scan, this sends scan timeout message with delay
702                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
703                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
704                     // Move time forward so scan timeout message can be dispatched
705                     advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS);
706                     // Since we are using a TestLooper, need to mock AppScanStats.isScanningTooLong
707                     // to
708                     // return true because no real time is elapsed
709                     doReturn(true).when(mMockAppScanStats).isScanningTooLong();
710                     syncHandler(ScanManager.MSG_SCAN_TIMEOUT);
711                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
712                     assertThat(client.mStats.isScanTimeout(client.mScannerId)).isTrue();
713                     // Turn off screen
714                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
715                     assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
716                     // Set as background app
717                     sendMessageWaitForProcessed(createImportanceMessage(false));
718                     assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_SCREEN_OFF);
719                     // Turn on screen
720                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
721                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
722                     // Set as foreground app
723                     sendMessageWaitForProcessed(createImportanceMessage(true));
724                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
725                 });
726     }
727 
728     @Test
testScanTimeoutResetForNewScan()729     public void testScanTimeoutResetForNewScan() {
730         // Set filtered scan flag
731         final boolean isFiltered = false;
732         // Turn on screen
733         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
734         // Create scan client
735         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
736 
737         // Put a timeout message in the queue to emulate the scan being started already
738         Message timeoutMessage =
739                 mScanManager.mHandler.obtainMessage(ScanManager.MSG_SCAN_TIMEOUT, client);
740         mScanManager.mHandler.sendMessageDelayed(timeoutMessage, DEFAULT_SCAN_TIMEOUT_MILLIS / 2);
741         mScanManager.mHandler.sendMessage(createStartStopScanMessage(true, client));
742         // Dispatching all messages only runs start scan
743         assertThat(mLooper.dispatchAll()).isEqualTo(1);
744 
745         advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS / 2);
746         // After restarting the scan, we can check that the initial timeout message is not triggered
747         assertThat(mLooper.dispatchAll()).isEqualTo(0);
748 
749         // After timeout, the next message that is run should be a timeout message
750         advanceTime(DEFAULT_SCAN_TIMEOUT_MILLIS / 2);
751         Message nextMessage = mLooper.nextMessage();
752         assertThat(nextMessage.what).isEqualTo(ScanManager.MSG_SCAN_TIMEOUT);
753         assertThat(nextMessage.obj).isEqualTo(client);
754     }
755 
756     @Test
testSwitchForeBackgroundUnfilteredScan()757     public void testSwitchForeBackgroundUnfilteredScan() {
758         // Set filtered scan flag
759         final boolean isFiltered = false;
760 
761         defaultScanMode.forEach(
762                 (scanMode, expectedScanMode) -> {
763                     mClientId = mClientId + 1;
764                     expectedScanMode = SCAN_MODE_LOW_POWER;
765                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
766 
767                     // Turn on screen
768                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
769                     // Create scan client
770                     ScanClient client = createScanClient(isFiltered, scanMode);
771                     // Start scan
772                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
773                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
774                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
775                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
776                     // Set as background app
777                     sendMessageWaitForProcessed(createImportanceMessage(false));
778                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
779                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
780                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
781                     // Set as foreground app
782                     sendMessageWaitForProcessed(createImportanceMessage(true));
783                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
784                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
785                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
786                 });
787     }
788 
789     @Test
testSwitchForeBackgroundFilteredScan()790     public void testSwitchForeBackgroundFilteredScan() {
791         // Set filtered scan flag
792         final boolean isFiltered = true;
793 
794         defaultScanMode.forEach(
795                 (scanMode, expectedScanMode) -> {
796                     mClientId = mClientId + 1;
797                     expectedScanMode = SCAN_MODE_LOW_POWER;
798                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
799 
800                     // Turn on screen
801                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
802                     // Create scan client
803                     ScanClient client = createScanClient(isFiltered, scanMode);
804                     // Start scan
805                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
806                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
807                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
808                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
809                     // Set as background app
810                     sendMessageWaitForProcessed(createImportanceMessage(false));
811                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
812                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
813                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
814                     // Set as foreground app
815                     sendMessageWaitForProcessed(createImportanceMessage(true));
816                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
817                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
818                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
819                 });
820     }
821 
822     @Test
testUpgradeStartScan()823     public void testUpgradeStartScan() {
824         // Set filtered scan flag
825         final boolean isFiltered = true;
826         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
827         SparseIntArray scanModeMap = new SparseIntArray();
828         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_BALANCED);
829         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_LOW_LATENCY);
830         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
831         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_LATENCY);
832         doReturn(DEFAULT_SCAN_UPGRADE_DURATION_MILLIS)
833                 .when(mAdapterService)
834                 .getScanUpgradeDurationMillis();
835 
836         for (int i = 0; i < scanModeMap.size(); i++) {
837             int scanMode = scanModeMap.keyAt(i);
838             int expectedScanMode = scanModeMap.get(scanMode);
839             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
840 
841             // Turn on screen
842             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
843             // Set as foreground app
844             sendMessageWaitForProcessed(createImportanceMessage(true));
845             // Create scan client
846             ScanClient client = createScanClient(isFiltered, scanMode);
847             // Start scan
848             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
849             assertThat(mScanManager.getRegularScanQueue()).contains(client);
850             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
851             assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
852             // Wait for upgrade duration
853             advanceTime(DEFAULT_SCAN_UPGRADE_DURATION_MILLIS);
854             mLooper.dispatchAll();
855             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
856         }
857     }
858 
859     @Test
testUpDowngradeStartScanForConcurrency()860     public void testUpDowngradeStartScanForConcurrency() {
861         doReturn(DEFAULT_SCAN_UPGRADE_DURATION_MILLIS)
862                 .when(mAdapterService)
863                 .getScanUpgradeDurationMillis();
864         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
865                 .when(mAdapterService)
866                 .getScanDowngradeDurationMillis();
867 
868         // Set filtered scan flag
869         final boolean isFiltered = true;
870 
871         defaultScanMode.forEach(
872                 (scanMode, expectedScanMode) -> {
873                     mClientId = mClientId + 1;
874                     expectedScanMode = SCAN_MODE_BALANCED;
875                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
876 
877                     // Turn on screen
878                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
879                     // Set as foreground app
880                     sendMessageWaitForProcessed(createImportanceMessage(true));
881                     // Set connecting state
882                     sendMessageWaitForProcessed(createConnectingMessage(true));
883                     // Create scan client
884                     ScanClient client = createScanClient(isFiltered, scanMode);
885                     // Start scan
886                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
887                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
888                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
889                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
890                     // Wait for upgrade and downgrade duration
891                     int max_duration =
892                             DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
893                                             > DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS
894                                     ? DEFAULT_SCAN_UPGRADE_DURATION_MILLIS
895                                     : DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS;
896                     advanceTime(max_duration);
897                     mLooper.dispatchAll();
898                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
899                 });
900     }
901 
902     @Test
testDowngradeDuringScanForConcurrency()903     public void testDowngradeDuringScanForConcurrency() {
904         // Set filtered scan flag
905         final boolean isFiltered = true;
906         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
907         SparseIntArray scanModeMap = new SparseIntArray();
908         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
909         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
910         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_BALANCED);
911         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_AMBIENT_DISCOVERY);
912 
913         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
914                 .when(mAdapterService)
915                 .getScanDowngradeDurationMillis();
916 
917         for (int i = 0; i < scanModeMap.size(); i++) {
918             int scanMode = scanModeMap.keyAt(i);
919             int expectedScanMode = scanModeMap.get(scanMode);
920             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
921 
922             // Turn on screen
923             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
924             // Set as foreground app
925             sendMessageWaitForProcessed(createImportanceMessage(true));
926             // Create scan client
927             ScanClient client = createScanClient(isFiltered, scanMode);
928             // Start scan
929             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
930             assertThat(mScanManager.getRegularScanQueue()).contains(client);
931             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
932             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
933             // Set connecting state
934             sendMessageWaitForProcessed(createConnectingMessage(true));
935             assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
936             // Wait for downgrade duration
937             advanceTime(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS);
938             mLooper.dispatchAll();
939             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
940         }
941     }
942 
943     @Test
testDowngradeDuringScanForConcurrencyScreenOff()944     public void testDowngradeDuringScanForConcurrencyScreenOff() {
945         // Set filtered scan flag
946         final boolean isFiltered = true;
947         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
948         SparseIntArray scanModeMap = new SparseIntArray();
949         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_SCREEN_OFF);
950         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_SCREEN_OFF_BALANCED);
951         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
952         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_SCREEN_OFF_BALANCED);
953 
954         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
955                 .when(mAdapterService)
956                 .getScanDowngradeDurationMillis();
957 
958         for (int i = 0; i < scanModeMap.size(); i++) {
959             int scanMode = scanModeMap.keyAt(i);
960             int expectedScanMode = scanModeMap.get(scanMode);
961             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
962 
963             // Turn on screen
964             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
965             // Set as foreground app
966             sendMessageWaitForProcessed(createImportanceMessage(true));
967             // Create scan client
968             ScanClient client = createScanClient(isFiltered, scanMode);
969             // Start scan
970             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
971             assertThat(mScanManager.getRegularScanQueue()).contains(client);
972             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
973             assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
974             // Set connecting state
975             sendMessageWaitForProcessed(createConnectingMessage(true));
976             // Turn off screen
977             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
978             // Move time forward so that MSG_STOP_CONNECTING can be dispatched
979             advanceTime(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS);
980             syncHandler(ScanManager.MSG_STOP_CONNECTING);
981             mLooper.dispatchAll();
982             assertThat(mScanManager.getRegularScanQueue()).contains(client);
983             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
984             assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
985         }
986     }
987 
988     @Test
testDowngradeDuringScanForConcurrencyBackground()989     public void testDowngradeDuringScanForConcurrencyBackground() {
990         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
991                 .when(mAdapterService)
992                 .getScanDowngradeDurationMillis();
993 
994         // Set filtered scan flag
995         final boolean isFiltered = true;
996 
997         defaultScanMode.forEach(
998                 (scanMode, expectedScanMode) -> {
999                     mClientId = mClientId + 1;
1000                     expectedScanMode = SCAN_MODE_LOW_POWER;
1001                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1002 
1003                     // Turn on screen
1004                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1005                     // Set as foreground app
1006                     sendMessageWaitForProcessed(createImportanceMessage(true));
1007                     // Create scan client
1008                     ScanClient client = createScanClient(isFiltered, scanMode);
1009                     // Start scan
1010                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1011                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
1012                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1013                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
1014                     // Set connecting state
1015                     sendMessageWaitForProcessed(createConnectingMessage(true));
1016                     // Set as background app
1017                     sendMessageWaitForProcessed(createImportanceMessage(false));
1018                     // Wait for downgrade duration
1019                     advanceTime(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS);
1020                     mLooper.dispatchAll();
1021                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
1022                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1023                     assertThat(client.mSettings.getScanMode()).isEqualTo(expectedScanMode);
1024                 });
1025     }
1026 
1027     @Test
testStartUnfilteredBatchScan()1028     public void testStartUnfilteredBatchScan() {
1029         // Set filtered and batch scan flag
1030         final boolean isFiltered = false;
1031         final boolean isBatch = true;
1032         final boolean isAutoBatch = false;
1033         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
1034         SparseIntArray scanModeMap = new SparseIntArray();
1035         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
1036         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
1037         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
1038         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_LATENCY);
1039 
1040         for (int i = 0; i < scanModeMap.size(); i++) {
1041             int scanMode = scanModeMap.keyAt(i);
1042             int expectedScanMode = scanModeMap.get(scanMode);
1043             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1044 
1045             // Turn off screen
1046             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1047             // Create scan client
1048             ScanClient client = createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
1049             // Start scan
1050             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1051             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1052             assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1053             assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
1054             // Turn on screen
1055             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1056             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1057             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1058             assertThat(mScanManager.getBatchScanQueue()).contains(client);
1059             assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
1060         }
1061     }
1062 
1063     @Test
testStartFilteredBatchScan()1064     public void testStartFilteredBatchScan() {
1065         // Set filtered and batch scan flag
1066         final boolean isFiltered = true;
1067         final boolean isBatch = true;
1068         final boolean isAutoBatch = false;
1069         // Set scan mode map {original scan mode (ScanMode) : expected scan mode (expectedScanMode)}
1070         SparseIntArray scanModeMap = new SparseIntArray();
1071         scanModeMap.put(SCAN_MODE_LOW_POWER, SCAN_MODE_LOW_POWER);
1072         scanModeMap.put(SCAN_MODE_BALANCED, SCAN_MODE_BALANCED);
1073         scanModeMap.put(SCAN_MODE_LOW_LATENCY, SCAN_MODE_LOW_LATENCY);
1074         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, SCAN_MODE_LOW_LATENCY);
1075 
1076         for (int i = 0; i < scanModeMap.size(); i++) {
1077             int scanMode = scanModeMap.keyAt(i);
1078             int expectedScanMode = scanModeMap.get(scanMode);
1079             Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1080 
1081             // Turn off screen
1082             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1083             // Create scan client
1084             ScanClient client = createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
1085             // Start scan
1086             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1087             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1088             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1089             assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
1090             // Turn on screen
1091             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1092             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1093             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1094             assertThat(mScanManager.getBatchScanQueue()).contains(client);
1095             assertThat(mScanManager.getBatchScanParams().mScanMode).isEqualTo(expectedScanMode);
1096         }
1097     }
1098 
1099     @Test
testUnfilteredAutoBatchScan()1100     public void testUnfilteredAutoBatchScan() {
1101         // Set filtered and batch scan flag
1102         final boolean isFiltered = false;
1103         final boolean isBatch = true;
1104         final boolean isAutoBatch = true;
1105         // Set report delay for auto batch scan callback type
1106         mScanReportDelay = ScanSettings.AUTO_BATCH_MIN_REPORT_DELAY_MILLIS;
1107 
1108         defaultScanMode.forEach(
1109                 (scanMode, expectedScanMode) -> {
1110                     mClientId = mClientId + 1;
1111                     expectedScanMode = SCAN_MODE_SCREEN_OFF;
1112                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1113 
1114                     // Turn off screen
1115                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1116                     // Create scan client
1117                     ScanClient client =
1118                             createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
1119                     // Start scan
1120                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1121                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1122                     assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1123                     assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
1124                     assertThat(mScanManager.getBatchScanParams()).isNull();
1125                     // Turn on screen
1126                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1127                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
1128                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
1129                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1130                     assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
1131                     assertThat(mScanManager.getBatchScanParams()).isNull();
1132                     // Turn off screen
1133                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1134                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1135                     assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1136                     assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
1137                     assertThat(mScanManager.getBatchScanParams()).isNull();
1138                 });
1139     }
1140 
1141     @Test
testFilteredAutoBatchScan()1142     public void testFilteredAutoBatchScan() {
1143         // Set filtered and batch scan flag
1144         final boolean isFiltered = true;
1145         final boolean isBatch = true;
1146         final boolean isAutoBatch = true;
1147         // Set report delay for auto batch scan callback type
1148         mScanReportDelay = ScanSettings.AUTO_BATCH_MIN_REPORT_DELAY_MILLIS;
1149 
1150         defaultScanMode.forEach(
1151                 (scanMode, expectedScanMode) -> {
1152                     mClientId = mClientId + 1;
1153                     expectedScanMode = SCAN_MODE_SCREEN_OFF;
1154                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1155 
1156                     // Turn off screen
1157                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1158                     // Create scan client
1159                     ScanClient client =
1160                             createScanClient(isFiltered, scanMode, isBatch, isAutoBatch);
1161                     // Start scan
1162                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1163                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1164                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1165                     assertThat(mScanManager.getBatchScanQueue()).contains(client);
1166                     assertThat(mScanManager.getBatchScanParams().mScanMode)
1167                             .isEqualTo(expectedScanMode);
1168                     // Turn on screen
1169                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1170                     assertThat(mScanManager.getRegularScanQueue()).contains(client);
1171                     assertThat(client.mSettings.getScanMode()).isEqualTo(scanMode);
1172                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1173                     assertThat(mScanManager.getBatchScanQueue()).doesNotContain(client);
1174                     assertThat(mScanManager.getBatchScanParams()).isNull();
1175                     // Turn off screen
1176                     sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1177                     assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1178                     assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1179                     assertThat(mScanManager.getBatchScanQueue()).contains(client);
1180                     assertThat(mScanManager.getBatchScanParams().mScanMode)
1181                             .isEqualTo(expectedScanMode);
1182                 });
1183     }
1184 
1185     @Test
testLocationAndScreenOnOffResumeUnfilteredScan()1186     public void testLocationAndScreenOnOffResumeUnfilteredScan() {
1187         // Set filtered scan flag
1188         final boolean isFiltered = false;
1189         // Set scan mode array
1190         int[] scanModeArr = {
1191             SCAN_MODE_LOW_POWER,
1192             SCAN_MODE_BALANCED,
1193             SCAN_MODE_LOW_LATENCY,
1194             SCAN_MODE_AMBIENT_DISCOVERY
1195         };
1196 
1197         for (int i = 0; i < scanModeArr.length; i++) {
1198             int scanMode = scanModeArr[i];
1199             Log.d(TAG, "ScanMode: " + scanMode);
1200             // Turn on screen
1201             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1202             // Create scan client
1203             ScanClient client = createScanClient(isFiltered, scanMode);
1204             // Start scan
1205             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1206             assertThat(mScanManager.getRegularScanQueue()).contains(client);
1207             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1208             // Turn off location
1209             doReturn(false).when(mLocationManager).isLocationEnabled();
1210             sendMessageWaitForProcessed(createLocationOnOffMessage(false));
1211             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1212             assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1213             // Turn off screen
1214             sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1215             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1216             assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1217             // Turn on screen
1218             sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1219             assertThat(mScanManager.getRegularScanQueue()).doesNotContain(client);
1220             assertThat(mScanManager.getSuspendedScanQueue()).contains(client);
1221             // Turn on location
1222             doReturn(true).when(mLocationManager).isLocationEnabled();
1223             sendMessageWaitForProcessed(createLocationOnOffMessage(true));
1224             assertThat(mScanManager.getRegularScanQueue()).contains(client);
1225             assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1226         }
1227     }
1228 
1229     @Test
testMetricsAppScanScreenOn()1230     public void testMetricsAppScanScreenOn() {
1231         // Set filtered scan flag
1232         final boolean isFiltered = true;
1233         final long scanTestDuration = 100;
1234         // Turn on screen
1235         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1236 
1237         // Set scan mode map {original scan mode (ScanMode) : logged scan mode (loggedScanMode)}
1238         SparseIntArray scanModeMap = new SparseIntArray();
1239         scanModeMap.put(
1240                 SCAN_MODE_LOW_POWER,
1241                 BluetoothStatsLog.LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_POWER);
1242         scanModeMap.put(
1243                 SCAN_MODE_BALANCED,
1244                 BluetoothStatsLog.LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_BALANCED);
1245         scanModeMap.put(
1246                 SCAN_MODE_LOW_LATENCY,
1247                 BluetoothStatsLog.LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_LATENCY);
1248         scanModeMap.put(
1249                 SCAN_MODE_AMBIENT_DISCOVERY,
1250                 BluetoothStatsLog
1251                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_AMBIENT_DISCOVERY);
1252 
1253         for (int i = 0; i < scanModeMap.size(); i++) {
1254             int scanMode = scanModeMap.keyAt(i);
1255             int loggedScanMode = scanModeMap.get(scanMode);
1256 
1257             // Create workSource for the app
1258             final String APP_NAME = TEST_APP_NAME + i;
1259             final int UID = 10000 + i;
1260             final String PACKAGE_NAME = TEST_PACKAGE_NAME + i;
1261             WorkSource source = new WorkSource(UID, PACKAGE_NAME);
1262             // Create app scan stats for the app
1263             AppScanStats appScanStats =
1264                     spy(
1265                             new AppScanStats(
1266                                     APP_NAME,
1267                                     source,
1268                                     null,
1269                                     mAdapterService,
1270                                     mScanController,
1271                                     mTimeProvider));
1272             // Set app importance as Foreground Service for the stats
1273             appScanStats.setAppImportance(IMPORTANCE_FOREGROUND_SERVICE);
1274             // Create scan client for the app, which also records scan start
1275             ScanClient client = createScanClient(isFiltered, scanMode, UID, appScanStats);
1276             // Verify that the app scan start is logged
1277             mInOrder.verify(mMetricsLogger)
1278                     .logAppScanStateChanged(
1279                             new int[] {UID},
1280                             new String[] {PACKAGE_NAME},
1281                             true,
1282                             true,
1283                             false,
1284                             BluetoothStatsLog
1285                                     .LE_APP_SCAN_STATE_CHANGED__SCAN_CALLBACK_TYPE__TYPE_ALL_MATCHES,
1286                             BluetoothStatsLog
1287                                     .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR,
1288                             loggedScanMode,
1289                             DEFAULT_REGULAR_SCAN_REPORT_DELAY_MS,
1290                             0,
1291                             0,
1292                             true,
1293                             false,
1294                             IMPORTANCE_FOREGROUND_SERVICE,
1295                             "");
1296 
1297             advanceTime(scanTestDuration);
1298             // Record scan stop
1299             client.mStats.recordScanStop(mClientId);
1300             // Verify that the app scan stop is logged
1301             mInOrder.verify(mMetricsLogger)
1302                     .logAppScanStateChanged(
1303                             eq(new int[] {UID}),
1304                             eq(new String[] {PACKAGE_NAME}),
1305                             eq(false),
1306                             eq(true),
1307                             eq(false),
1308                             eq(
1309                                     BluetoothStatsLog
1310                                             .LE_APP_SCAN_STATE_CHANGED__SCAN_CALLBACK_TYPE__TYPE_ALL_MATCHES),
1311                             eq(
1312                                     BluetoothStatsLog
1313                                             .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1314                             eq(loggedScanMode),
1315                             eq((long) DEFAULT_REGULAR_SCAN_REPORT_DELAY_MS),
1316                             eq(scanTestDuration),
1317                             eq(0),
1318                             eq(true),
1319                             eq(false),
1320                             eq(IMPORTANCE_FOREGROUND_SERVICE),
1321                             eq(""));
1322         }
1323     }
1324 
1325     @Test
testMetricsRadioScanScreenOnOffMultiScan()1326     public void testMetricsRadioScanScreenOnOffMultiScan() {
1327         // Set filtered scan flag
1328         final boolean isFiltered = true;
1329         final long scanTestDuration = 100;
1330         // Turn on screen
1331         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1332 
1333         // Create workSource for the first app
1334         final int UID_1 = 10001;
1335         final String APP_NAME_1 = TEST_APP_NAME + UID_1;
1336         final String PACKAGE_NAME_1 = TEST_PACKAGE_NAME + UID_1;
1337         WorkSource source1 = new WorkSource(UID_1, PACKAGE_NAME_1);
1338         // Create app scan stats for the first app
1339         AppScanStats appScanStats1 =
1340                 spy(
1341                         new AppScanStats(
1342                                 APP_NAME_1,
1343                                 source1,
1344                                 null,
1345                                 mAdapterService,
1346                                 mScanController,
1347                                 mTimeProvider));
1348         // Set app importance as Foreground Service for the stats
1349         appScanStats1.setAppImportance(IMPORTANCE_FOREGROUND_SERVICE);
1350         // Create scan client for the first app
1351         ScanClient client1 =
1352                 createScanClient(isFiltered, SCAN_MODE_LOW_POWER, UID_1, appScanStats1);
1353         // Start scan with lower duty cycle for the first app
1354         sendMessageWaitForProcessed(createStartStopScanMessage(true, client1));
1355         advanceTime(scanTestDuration);
1356 
1357         // Create workSource for the second app
1358         final int UID_2 = 10002;
1359         final String APP_NAME_2 = TEST_APP_NAME + UID_2;
1360         final String PACKAGE_NAME_2 = TEST_PACKAGE_NAME + UID_2;
1361         WorkSource source2 = new WorkSource(UID_2, PACKAGE_NAME_2);
1362         // Create app scan stats for the second app
1363         AppScanStats appScanStats2 =
1364                 spy(
1365                         new AppScanStats(
1366                                 APP_NAME_2,
1367                                 source2,
1368                                 null,
1369                                 mAdapterService,
1370                                 mScanController,
1371                                 mTimeProvider));
1372         // Set app importance as Foreground Service for the stats
1373         appScanStats2.setAppImportance(IMPORTANCE_FOREGROUND_SERVICE);
1374         // Create scan client for the second app
1375         ScanClient client2 = createScanClient(isFiltered, SCAN_MODE_BALANCED, UID_2, appScanStats2);
1376         // Start scan with higher duty cycle for the second app
1377         sendMessageWaitForProcessed(createStartStopScanMessage(true, client2));
1378         // Verify radio scan stop is logged with the first app
1379         mInOrder.verify(mMetricsLogger)
1380                 .logRadioScanStopped(
1381                         eq(new int[] {UID_1}),
1382                         eq(new String[] {PACKAGE_NAME_1}),
1383                         eq(
1384                                 BluetoothStatsLog
1385                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1386                         eq(
1387                                 BluetoothStatsLog
1388                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_POWER),
1389                         eq((long) ScanManager.SCAN_MODE_LOW_POWER_INTERVAL_MS),
1390                         eq((long) ScanManager.SCAN_MODE_LOW_POWER_WINDOW_MS),
1391                         eq(true),
1392                         eq(scanTestDuration),
1393                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1394                         eq(""));
1395         advanceTime(scanTestDuration);
1396 
1397         // Create workSource for the third app
1398         final int UID_3 = 10003;
1399         final String APP_NAME_3 = TEST_APP_NAME + UID_3;
1400         final String PACKAGE_NAME_3 = TEST_PACKAGE_NAME + UID_3;
1401         WorkSource source3 = new WorkSource(UID_3, PACKAGE_NAME_3);
1402         // Create app scan stats for the third app
1403         AppScanStats appScanStats3 =
1404                 spy(
1405                         new AppScanStats(
1406                                 APP_NAME_3,
1407                                 source3,
1408                                 null,
1409                                 mAdapterService,
1410                                 mScanController,
1411                                 mTimeProvider));
1412         // Set app importance as Foreground Service for the stats
1413         appScanStats3.setAppImportance(IMPORTANCE_FOREGROUND_SERVICE);
1414         // Create scan client for the third app
1415         ScanClient client3 =
1416                 createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY, UID_3, appScanStats3);
1417         // Start scan with highest duty cycle for the third app
1418         sendMessageWaitForProcessed(createStartStopScanMessage(true, client3));
1419         // Verify radio scan stop is logged with the second app
1420         mInOrder.verify(mMetricsLogger)
1421                 .logRadioScanStopped(
1422                         eq(new int[] {UID_2}),
1423                         eq(new String[] {PACKAGE_NAME_2}),
1424                         eq(
1425                                 BluetoothStatsLog
1426                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1427                         eq(
1428                                 BluetoothStatsLog
1429                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_BALANCED),
1430                         eq((long) ScanManager.SCAN_MODE_BALANCED_INTERVAL_MS),
1431                         eq((long) ScanManager.SCAN_MODE_BALANCED_WINDOW_MS),
1432                         eq(true),
1433                         eq(scanTestDuration),
1434                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1435                         eq(""));
1436         advanceTime(scanTestDuration);
1437 
1438         // Create workSource for the fourth app
1439         final int UID_4 = 10004;
1440         final String APP_NAME_4 = TEST_APP_NAME + UID_4;
1441         final String PACKAGE_NAME_4 = TEST_PACKAGE_NAME + UID_4;
1442         WorkSource source4 = new WorkSource(UID_4, PACKAGE_NAME_4);
1443         // Create app scan stats for the fourth app
1444         AppScanStats appScanStats4 =
1445                 spy(
1446                         new AppScanStats(
1447                                 APP_NAME_4,
1448                                 source4,
1449                                 null,
1450                                 mAdapterService,
1451                                 mScanController,
1452                                 mTimeProvider));
1453         // Set app importance as Foreground Service for the stats
1454         appScanStats4.setAppImportance(IMPORTANCE_FOREGROUND_SERVICE);
1455         // Create scan client for the fourth app
1456         ScanClient client4 =
1457                 createScanClient(isFiltered, SCAN_MODE_AMBIENT_DISCOVERY, UID_4, appScanStats4);
1458         // Start scan with lower duty cycle for the fourth app
1459         sendMessageWaitForProcessed(createStartStopScanMessage(true, client4));
1460         // Verify radio scan stop is not logged with the third app since there is no change in radio
1461         // scan
1462         mInOrder.verify(mMetricsLogger, never())
1463                 .logRadioScanStopped(
1464                         eq(new int[] {UID_3}),
1465                         eq(new String[] {PACKAGE_NAME_3}),
1466                         anyInt(),
1467                         anyInt(),
1468                         anyLong(),
1469                         anyLong(),
1470                         anyBoolean(),
1471                         anyLong(),
1472                         anyInt(),
1473                         eq(""));
1474         advanceTime(scanTestDuration);
1475 
1476         // Set as background app
1477         sendMessageWaitForProcessed(createImportanceMessage(false, UID_1));
1478         sendMessageWaitForProcessed(createImportanceMessage(false, UID_2));
1479         sendMessageWaitForProcessed(createImportanceMessage(false, UID_3));
1480         sendMessageWaitForProcessed(createImportanceMessage(false, UID_4));
1481         // Turn off screen
1482         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1483         // Verify radio scan stop is logged with the third app when screen turns off
1484         mInOrder.verify(mMetricsLogger)
1485                 .logRadioScanStopped(
1486                         eq(new int[] {UID_3}),
1487                         eq(new String[] {PACKAGE_NAME_3}),
1488                         eq(
1489                                 BluetoothStatsLog
1490                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1491                         eq(
1492                                 BluetoothStatsLog
1493                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_LATENCY),
1494                         eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_INTERVAL_MS),
1495                         eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_WINDOW_MS),
1496                         eq(true),
1497                         eq(scanTestDuration * 2),
1498                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1499                         eq(""));
1500         advanceTime(scanTestDuration);
1501 
1502         // Get the most aggressive scan client when screen is off
1503         // Since all the clients are updated to SCAN_MODE_SCREEN_OFF when screen is off and
1504         // app is in background mode, get the first client in the iterator
1505         Set<ScanClient> scanClients = mScanManager.getRegularScanQueue();
1506         ScanClient mostAggressiveClient = scanClients.iterator().next();
1507 
1508         // Turn on screen
1509         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1510         // Set as foreground app
1511         sendMessageWaitForProcessed(createImportanceMessage(true, UID_1));
1512         sendMessageWaitForProcessed(createImportanceMessage(true, UID_2));
1513         sendMessageWaitForProcessed(createImportanceMessage(true, UID_3));
1514         sendMessageWaitForProcessed(createImportanceMessage(true, UID_4));
1515         // Verify radio scan stop is logged with the third app when screen turns on
1516         mInOrder.verify(mMetricsLogger)
1517                 .logRadioScanStopped(
1518                         eq(new int[] {mostAggressiveClient.mAppUid}),
1519                         eq(new String[] {TEST_PACKAGE_NAME + mostAggressiveClient.mAppUid}),
1520                         eq(
1521                                 BluetoothStatsLog
1522                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1523                         eq(AppScanStats.convertScanMode(mostAggressiveClient.mScanModeApp)),
1524                         eq((long) SCAN_MODE_SCREEN_OFF_LOW_POWER_INTERVAL_MS),
1525                         eq((long) SCAN_MODE_SCREEN_OFF_LOW_POWER_WINDOW_MS),
1526                         eq(false),
1527                         eq(scanTestDuration),
1528                         eq(IMPORTANCE_FOREGROUND_SERVICE + 1),
1529                         eq(""));
1530         advanceTime(scanTestDuration);
1531 
1532         // Stop scan for the fourth app
1533         sendMessageWaitForProcessed(createStartStopScanMessage(false, client4));
1534         // Verify radio scan stop is not logged with the third app since there is no change in radio
1535         // scan
1536         mInOrder.verify(mMetricsLogger, never())
1537                 .logRadioScanStopped(
1538                         eq(new int[] {UID_3}),
1539                         eq(new String[] {PACKAGE_NAME_3}),
1540                         anyInt(),
1541                         anyInt(),
1542                         anyLong(),
1543                         anyLong(),
1544                         anyBoolean(),
1545                         anyLong(),
1546                         anyInt(),
1547                         eq(""));
1548         advanceTime(scanTestDuration);
1549 
1550         // Stop scan for the third app
1551         sendMessageWaitForProcessed(createStartStopScanMessage(false, client3));
1552         // Verify radio scan stop is logged with the third app
1553         mInOrder.verify(mMetricsLogger)
1554                 .logRadioScanStopped(
1555                         eq(new int[] {UID_3}),
1556                         eq(new String[] {PACKAGE_NAME_3}),
1557                         eq(
1558                                 BluetoothStatsLog
1559                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1560                         eq(
1561                                 BluetoothStatsLog
1562                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_LATENCY),
1563                         eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_INTERVAL_MS),
1564                         eq((long) ScanManager.SCAN_MODE_LOW_LATENCY_WINDOW_MS),
1565                         eq(true),
1566                         eq(scanTestDuration * 2),
1567                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1568                         eq(""));
1569         advanceTime(scanTestDuration);
1570 
1571         // Stop scan for the second app
1572         sendMessageWaitForProcessed(createStartStopScanMessage(false, client2));
1573         // Verify radio scan stop is logged with the second app
1574         mInOrder.verify(mMetricsLogger)
1575                 .logRadioScanStopped(
1576                         eq(new int[] {UID_2}),
1577                         eq(new String[] {PACKAGE_NAME_2}),
1578                         eq(
1579                                 BluetoothStatsLog
1580                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1581                         eq(
1582                                 BluetoothStatsLog
1583                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_BALANCED),
1584                         eq((long) ScanManager.SCAN_MODE_BALANCED_INTERVAL_MS),
1585                         eq((long) ScanManager.SCAN_MODE_BALANCED_WINDOW_MS),
1586                         eq(true),
1587                         eq(scanTestDuration),
1588                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1589                         eq(""));
1590         advanceTime(scanTestDuration);
1591 
1592         // Stop scan for the first app
1593         sendMessageWaitForProcessed(createStartStopScanMessage(false, client1));
1594         // Verify radio scan stop is logged with the first app
1595         mInOrder.verify(mMetricsLogger)
1596                 .logRadioScanStopped(
1597                         eq(new int[] {UID_1}),
1598                         eq(new String[] {PACKAGE_NAME_1}),
1599                         eq(
1600                                 BluetoothStatsLog
1601                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_TYPE__SCAN_TYPE_REGULAR),
1602                         eq(
1603                                 BluetoothStatsLog
1604                                         .LE_APP_SCAN_STATE_CHANGED__LE_SCAN_MODE__SCAN_MODE_LOW_POWER),
1605                         eq((long) ScanManager.SCAN_MODE_LOW_POWER_INTERVAL_MS),
1606                         eq((long) ScanManager.SCAN_MODE_LOW_POWER_WINDOW_MS),
1607                         eq(true),
1608                         eq(scanTestDuration),
1609                         eq(IMPORTANCE_FOREGROUND_SERVICE),
1610                         eq(""));
1611     }
1612 
1613     @Test
testMetricsScanRadioDurationScreenOn()1614     public void testMetricsScanRadioDurationScreenOn() {
1615         // Set filtered scan flag
1616         final boolean isFiltered = true;
1617         // Turn on screen
1618         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1619         Mockito.clearInvocations(mMetricsLogger);
1620         // Create scan client
1621         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
1622         // Start scan
1623         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1624         mInOrder.verify(mMetricsLogger, never())
1625                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1626         mInOrder.verify(mMetricsLogger, never())
1627                 .cacheCount(
1628                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1629                         anyLong());
1630         mInOrder.verify(mMetricsLogger, never())
1631                 .cacheCount(
1632                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1633                         anyLong());
1634         advanceTime(50);
1635         // Stop scan
1636         sendMessageWaitForProcessed(createStartStopScanMessage(false, client));
1637         mInOrder.verify(mMetricsLogger)
1638                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1639         mInOrder.verify(mMetricsLogger)
1640                 .cacheCount(
1641                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1642                         anyLong());
1643         mInOrder.verify(mMetricsLogger, never())
1644                 .cacheCount(
1645                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1646                         anyLong());
1647     }
1648 
1649     @Test
testMetricsScanRadioDurationScreenOnOff()1650     public void testMetricsScanRadioDurationScreenOnOff() {
1651         // Set filtered scan flag
1652         final boolean isFiltered = true;
1653         // Turn on screen
1654         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1655         Mockito.clearInvocations(mMetricsLogger);
1656         // Create scan client
1657         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
1658         // Start scan
1659         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1660         mInOrder.verify(mMetricsLogger, never())
1661                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1662         mInOrder.verify(mMetricsLogger, never())
1663                 .cacheCount(
1664                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1665                         anyLong());
1666         mInOrder.verify(mMetricsLogger, never())
1667                 .cacheCount(
1668                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1669                         anyLong());
1670         advanceTime(50);
1671         // Turn off screen
1672         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1673         mInOrder.verify(mMetricsLogger)
1674                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1675         mInOrder.verify(mMetricsLogger)
1676                 .cacheCount(
1677                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1678                         anyLong());
1679         mInOrder.verify(mMetricsLogger, never())
1680                 .cacheCount(
1681                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1682                         anyLong());
1683         advanceTime(50);
1684         // Turn on screen
1685         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1686         mInOrder.verify(mMetricsLogger)
1687                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1688         mInOrder.verify(mMetricsLogger, never())
1689                 .cacheCount(
1690                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1691                         anyLong());
1692         mInOrder.verify(mMetricsLogger)
1693                 .cacheCount(
1694                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1695                         anyLong());
1696         advanceTime(50);
1697         // Stop scan
1698         sendMessageWaitForProcessed(createStartStopScanMessage(false, client));
1699         mInOrder.verify(mMetricsLogger)
1700                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1701         mInOrder.verify(mMetricsLogger)
1702                 .cacheCount(
1703                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1704                         anyLong());
1705         mInOrder.verify(mMetricsLogger, never())
1706                 .cacheCount(
1707                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1708                         anyLong());
1709     }
1710 
1711     @Test
testMetricsScanRadioDurationMultiScan()1712     public void testMetricsScanRadioDurationMultiScan() {
1713         // Set filtered scan flag
1714         final boolean isFiltered = true;
1715         // Turn on screen
1716         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1717         Mockito.clearInvocations(mMetricsLogger);
1718         // Create scan clients with different duty cycles
1719         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_POWER);
1720         ScanClient client2 = createScanClient(isFiltered, SCAN_MODE_BALANCED);
1721         // Start scan with lower duty cycle
1722         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1723         mInOrder.verify(mMetricsLogger, never())
1724                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1725         mInOrder.verify(mMetricsLogger, never())
1726                 .cacheCount(
1727                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1728                         anyLong());
1729         mInOrder.verify(mMetricsLogger, never())
1730                 .cacheCount(
1731                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1732                         anyLong());
1733         advanceTime(50);
1734         // Start scan with higher duty cycle
1735         sendMessageWaitForProcessed(createStartStopScanMessage(true, client2));
1736         mInOrder.verify(mMetricsLogger)
1737                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1738         mInOrder.verify(mMetricsLogger)
1739                 .cacheCount(
1740                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1741                         anyLong());
1742         mInOrder.verify(mMetricsLogger, never())
1743                 .cacheCount(
1744                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1745                         anyLong());
1746         advanceTime(50);
1747         // Stop scan with lower duty cycle
1748         sendMessageWaitForProcessed(createStartStopScanMessage(false, client));
1749         mInOrder.verify(mMetricsLogger, never()).cacheCount(anyInt(), anyLong());
1750         // Stop scan with higher duty cycle
1751         sendMessageWaitForProcessed(createStartStopScanMessage(false, client2));
1752         mInOrder.verify(mMetricsLogger)
1753                 .cacheCount(eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR), anyLong());
1754         mInOrder.verify(mMetricsLogger)
1755                 .cacheCount(
1756                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_ON),
1757                         anyLong());
1758         mInOrder.verify(mMetricsLogger, never())
1759                 .cacheCount(
1760                         eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR_SCREEN_OFF),
1761                         anyLong());
1762     }
1763 
1764     @Test
testMetricsScanRadioWeightedDuration()1765     public void testMetricsScanRadioWeightedDuration() {
1766         // Set filtered scan flag
1767         final boolean isFiltered = true;
1768         final long scanTestDuration = 100;
1769         // Set scan mode map {scan mode (ScanMode) : scan weight (ScanWeight)}
1770         SparseIntArray scanModeMap = new SparseIntArray();
1771         scanModeMap.put(SCAN_MODE_SCREEN_OFF, AppScanStats.SCREEN_OFF_LOW_POWER_WEIGHT);
1772         scanModeMap.put(SCAN_MODE_LOW_POWER, AppScanStats.LOW_POWER_WEIGHT);
1773         scanModeMap.put(SCAN_MODE_BALANCED, AppScanStats.BALANCED_WEIGHT);
1774         scanModeMap.put(SCAN_MODE_LOW_LATENCY, AppScanStats.LOW_LATENCY_WEIGHT);
1775         scanModeMap.put(SCAN_MODE_AMBIENT_DISCOVERY, AppScanStats.AMBIENT_DISCOVERY_WEIGHT);
1776 
1777         // Turn on screen
1778         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1779         for (int i = 0; i < scanModeMap.size(); i++) {
1780             int scanMode = scanModeMap.keyAt(i);
1781             long weightedScanDuration =
1782                     (long) (scanTestDuration * scanModeMap.get(scanMode) * 0.01);
1783             Log.d(TAG, "ScanMode: " + scanMode + " weightedScanDuration: " + weightedScanDuration);
1784 
1785             // Create scan client
1786             ScanClient client = createScanClient(isFiltered, scanMode);
1787             // Start scan
1788             sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1789             // Wait for scan test duration
1790             advanceTime(Duration.ofMillis(scanTestDuration));
1791             // Stop scan
1792             sendMessageWaitForProcessed(createStartStopScanMessage(false, client));
1793             mInOrder.verify(mMetricsLogger)
1794                     .cacheCount(
1795                             eq(BluetoothProtoEnums.LE_SCAN_RADIO_DURATION_REGULAR),
1796                             eq(weightedScanDuration));
1797         }
1798     }
1799 
1800     @Test
testMetricsScreenOnOff()1801     public void testMetricsScreenOnOff() {
1802         // Turn off screen initially
1803         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1804         Mockito.clearInvocations(mMetricsLogger);
1805         // Turn on screen
1806         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1807         mInOrder.verify(mMetricsLogger, never())
1808                 .cacheCount(eq(BluetoothProtoEnums.SCREEN_OFF_EVENT), anyLong());
1809         mInOrder.verify(mMetricsLogger)
1810                 .cacheCount(eq(BluetoothProtoEnums.SCREEN_ON_EVENT), anyLong());
1811         // Turn off screen
1812         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1813         mInOrder.verify(mMetricsLogger, never())
1814                 .cacheCount(eq(BluetoothProtoEnums.SCREEN_ON_EVENT), anyLong());
1815         mInOrder.verify(mMetricsLogger)
1816                 .cacheCount(eq(BluetoothProtoEnums.SCREEN_OFF_EVENT), anyLong());
1817     }
1818 
1819     @Test
testDowngradeWithNonNullClientAppScanStats()1820     public void testDowngradeWithNonNullClientAppScanStats() {
1821         // Set filtered scan flag
1822         final boolean isFiltered = true;
1823 
1824         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
1825                 .when(mAdapterService)
1826                 .getScanDowngradeDurationMillis();
1827 
1828         // Turn off screen
1829         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1830         // Create scan client
1831         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY);
1832         // Start Scan
1833         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1834         assertThat(mScanManager.getRegularScanQueue()).contains(client);
1835         assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1836         assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_LOW_LATENCY);
1837         // Set connecting state
1838         sendMessageWaitForProcessed(createConnectingMessage(true));
1839         // SCAN_MODE_LOW_LATENCY is now downgraded to SCAN_MODE_BALANCED
1840         assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_BALANCED);
1841     }
1842 
1843     @Test
testDowngradeWithNullClientAppScanStats()1844     public void testDowngradeWithNullClientAppScanStats() {
1845         // Set filtered scan flag
1846         final boolean isFiltered = true;
1847 
1848         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
1849                 .when(mAdapterService)
1850                 .getScanDowngradeDurationMillis();
1851 
1852         // Turn off screen
1853         sendMessageWaitForProcessed(createScreenOnOffMessage(false));
1854         // Create scan client
1855         ScanClient client = createScanClient(isFiltered, SCAN_MODE_LOW_LATENCY);
1856         // Start Scan
1857         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1858         assertThat(mScanManager.getRegularScanQueue()).contains(client);
1859         assertThat(mScanManager.getSuspendedScanQueue()).doesNotContain(client);
1860         assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_LOW_LATENCY);
1861         // Set AppScanStats to null
1862         client.mStats = null;
1863         // Set connecting state
1864         sendMessageWaitForProcessed(createConnectingMessage(true));
1865         // Since AppScanStats is null, no downgrade takes place for scan mode
1866         assertThat(client.mSettings.getScanMode()).isEqualTo(SCAN_MODE_LOW_LATENCY);
1867     }
1868 
1869     @Test
profileConnectionStateChanged_sendStartConnectionMessage()1870     public void profileConnectionStateChanged_sendStartConnectionMessage() {
1871         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
1872                 .when(mAdapterService)
1873                 .getScanDowngradeDurationMillis();
1874         assertThat(mScanManager.mIsConnecting).isFalse();
1875 
1876         mScanManager.handleBluetoothProfileConnectionStateChanged(
1877                 BluetoothProfile.A2DP, STATE_DISCONNECTED, STATE_CONNECTING);
1878 
1879         mLooper.dispatchAll();
1880         assertThat(mScanManager.mIsConnecting).isTrue();
1881     }
1882 
1883     @Test
multipleProfileConnectionStateChanged_updateCountersCorrectly()1884     public void multipleProfileConnectionStateChanged_updateCountersCorrectly() {
1885         doReturn(DEFAULT_SCAN_DOWNGRADE_DURATION_BT_CONNECTING_MILLIS)
1886                 .when(mAdapterService)
1887                 .getScanDowngradeDurationMillis();
1888         assertThat(mScanManager.mIsConnecting).isFalse();
1889 
1890         mScanManager.handleBluetoothProfileConnectionStateChanged(
1891                 BluetoothProfile.HEADSET, STATE_DISCONNECTED, STATE_CONNECTING);
1892         mScanManager.handleBluetoothProfileConnectionStateChanged(
1893                 BluetoothProfile.A2DP, STATE_DISCONNECTED, STATE_CONNECTING);
1894         mScanManager.handleBluetoothProfileConnectionStateChanged(
1895                 BluetoothProfile.HID_HOST, STATE_DISCONNECTED, STATE_CONNECTING);
1896         mLooper.dispatchAll();
1897         assertThat(mScanManager.mProfilesConnecting).isEqualTo(3);
1898     }
1899 
1900     @Test
1901     @DisableFlags(Flags.FLAG_CHANGE_DEFAULT_TRACKABLE_ADV_NUMBER)
getNumOfTrackingAdvertisements_withMaxTrackable_flagEnabled()1902     public void getNumOfTrackingAdvertisements_withMaxTrackable_flagEnabled() {
1903         ScanSettings scanSettings;
1904         scanSettings =
1905                 new ScanSettings.Builder()
1906                         .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
1907                         .build();
1908 
1909         assertThat(mScanManager.mScanNative.getNumOfTrackingAdvertisements(scanSettings))
1910                 .isEqualTo(DEFAULT_TOTAL_NUM_OF_TRACKABLE_ADVERTISEMENTS / 2);
1911     }
1912 
1913     @Test
1914     @EnableFlags(Flags.FLAG_CHANGE_DEFAULT_TRACKABLE_ADV_NUMBER)
getNumOfTrackingAdvertisements_withMaxTrackable_flagDisabled()1915     public void getNumOfTrackingAdvertisements_withMaxTrackable_flagDisabled() {
1916         ScanSettings scanSettings;
1917         scanSettings =
1918                 new ScanSettings.Builder()
1919                         .setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT)
1920                         .build();
1921 
1922         assertThat(mScanManager.mScanNative.getNumOfTrackingAdvertisements(scanSettings))
1923                 .isEqualTo(DEFAULT_TOTAL_NUM_OF_TRACKABLE_ADVERTISEMENTS / 4);
1924     }
1925 
1926     // PHY_LE_1M: 1, PHY_LE_CODED: 3, PHY_LE_ALL_SUPPORTED: 255
1927     @Test
1928     @EnableFlags(Flags.FLAG_PHY_TO_NATIVE)
startScan_basicPhyTest(@estParameter{"1", "3", "255"}) int phy)1929     public void startScan_basicPhyTest(@TestParameter({"1", "3", "255"}) int phy) {
1930         doPhyTest(phy, true);
1931     }
1932 
1933     @Test
1934     @DisableFlags(Flags.FLAG_PHY_TO_NATIVE)
startScan_basicPhyTest_ignorePhy(@estParameter{"1", "3", "255"}) int phy)1935     public void startScan_basicPhyTest_ignorePhy(@TestParameter({"1", "3", "255"}) int phy) {
1936         doPhyTest(phy, false);
1937     }
1938 
doPhyTest(int phy, boolean respectPhy)1939     private void doPhyTest(int phy, boolean respectPhy) {
1940         final boolean isFiltered = false;
1941         final boolean isEmptyFilter = false;
1942         final boolean expect1m;
1943         final boolean expectCoded;
1944         final int expectedPhyMask;
1945         switch (phy) {
1946             case PHY_LE_1M:
1947                 expectedPhyMask = PHY_LE_1M_MASK;
1948                 expect1m = true;
1949                 expectCoded = false;
1950                 break;
1951             case PHY_LE_CODED:
1952                 expectedPhyMask = respectPhy ? PHY_LE_CODED_MASK : PHY_LE_1M_MASK;
1953                 expectCoded = respectPhy;
1954                 expect1m = !respectPhy;
1955                 break;
1956             case PHY_LE_ALL_SUPPORTED:
1957             default:
1958                 expectedPhyMask = respectPhy ? PHY_LE_1M_MASK | PHY_LE_CODED_MASK : PHY_LE_1M_MASK;
1959                 expect1m = true;
1960                 expectCoded = respectPhy;
1961                 break;
1962         }
1963 
1964         defaultScanMode.forEach(
1965                 (scanMode, expectedScanMode) -> {
1966                     mClientId = mClientId + 1;
1967                     Log.d(TAG, "ScanMode: " + scanMode + " expectedScanMode: " + expectedScanMode);
1968 
1969                     // Turn on screen
1970                     sendMessageWaitForProcessed(createScreenOnOffMessage(true));
1971                     // Create scan client
1972                     ScanClient client =
1973                             createScanClientWithPhy(
1974                                     mClientId, isFiltered, isEmptyFilter, scanMode, phy);
1975                     // Start scan
1976                     sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
1977 
1978                     assertThat(client.mSettings.getPhy()).isEqualTo(phy);
1979                     verify(mScanNativeInterface)
1980                             .gattSetScanParameters(
1981                                     eq(expect1m ? mClientId : 0),
1982                                     anyInt(),
1983                                     anyInt(),
1984                                     eq(expectCoded ? mClientId : 0),
1985                                     anyInt(),
1986                                     anyInt(),
1987                                     eq(expectedPhyMask));
1988 
1989                     // Stop scan
1990                     sendMessageWaitForProcessed(createStartStopScanMessage(false, client));
1991                 });
1992     }
1993 
1994     @Test
1995     @EnableFlags(Flags.FLAG_PHY_TO_NATIVE)
startScan_phyTestMultiplexing()1996     public void startScan_phyTestMultiplexing() {
1997         int clientId1m = ++mClientId;
1998         int clientIdCoded = ++mClientId;
1999 
2000         // Turn on screen
2001         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
2002 
2003         // Create 1m scan client
2004         ScanClient client1m =
2005                 createScanClientWithPhy(clientId1m, true, false, SCAN_MODE_LOW_LATENCY, PHY_LE_1M);
2006 
2007         // Start scan on 1m
2008         sendMessageWaitForProcessed(createStartStopScanMessage(true, client1m));
2009 
2010         assertThat(client1m.mSettings.getPhy()).isEqualTo(PHY_LE_1M);
2011         verify(mScanNativeInterface)
2012                 .gattSetScanParameters(
2013                         eq(clientId1m),
2014                         eq(Utils.millsToUnit(SCAN_MODE_LOW_LATENCY_INTERVAL_MS)),
2015                         eq(Utils.millsToUnit(SCAN_MODE_LOW_LATENCY_WINDOW_MS)),
2016                         eq(0),
2017                         anyInt(),
2018                         anyInt(),
2019                         eq(PHY_LE_1M_MASK));
2020 
2021         // Create coded scan client
2022         ScanClient clientCoded =
2023                 createScanClientWithPhy(
2024                         clientIdCoded, true, false, SCAN_MODE_BALANCED, PHY_LE_CODED);
2025 
2026         // Start scan on coded
2027         sendMessageWaitForProcessed(createStartStopScanMessage(true, clientCoded));
2028 
2029         assertThat(clientCoded.mSettings.getPhy()).isEqualTo(PHY_LE_CODED);
2030         verify(mScanNativeInterface)
2031                 .gattSetScanParameters(
2032                         eq(clientId1m),
2033                         eq(Utils.millsToUnit(SCAN_MODE_LOW_LATENCY_INTERVAL_MS)),
2034                         eq(Utils.millsToUnit(SCAN_MODE_LOW_LATENCY_WINDOW_MS)),
2035                         eq(clientIdCoded),
2036                         eq(Utils.millsToUnit(SCAN_MODE_BALANCED_INTERVAL_MS)),
2037                         eq(Utils.millsToUnit(SCAN_MODE_BALANCED_WINDOW_MS)),
2038                         eq(PHY_LE_1M_MASK | PHY_LE_CODED_MASK));
2039 
2040         // Stop scan on 1m
2041         sendMessageWaitForProcessed(createStartStopScanMessage(false, client1m));
2042 
2043         verify(mScanNativeInterface)
2044                 .gattSetScanParameters(
2045                         eq(0),
2046                         anyInt(),
2047                         anyInt(),
2048                         eq(clientIdCoded),
2049                         eq(Utils.millsToUnit(SCAN_MODE_BALANCED_INTERVAL_MS)),
2050                         eq(Utils.millsToUnit(SCAN_MODE_BALANCED_WINDOW_MS)),
2051                         eq(PHY_LE_CODED_MASK));
2052 
2053         // Stop scan on coded
2054         sendMessageWaitForProcessed(createStartStopScanMessage(false, clientCoded));
2055 
2056         verify(mScanNativeInterface, atLeastOnce()).gattClientScan(false);
2057         verify(mScanNativeInterface, never())
2058                 .gattSetScanParameters(
2059                         anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), eq(0));
2060     }
2061 
2062     @Test
2063     @EnableFlags(Flags.FLAG_LE_SCAN_MSFT_SUPPORT)
testMsftScan()2064     public void testMsftScan() {
2065         doReturn(true).when(mScanNativeInterface).gattClientIsMsftSupported();
2066         doReturn(false).when(mBluetoothAdapterProxy).isOffloadedScanFilteringSupported();
2067 
2068         final boolean isFiltered = true;
2069         final ParcelUuid serviceUuid =
2070                 new ParcelUuid(UUID.fromString("12345678-90AB-CDEF-1234-567890ABCDEF"));
2071         final byte[] serviceData = new byte[] {0x01, 0x02, 0x03};
2072 
2073         doReturn(true).when(mProperties).getBoolean(eq(MSFT_HCI_EXT_ENABLED), anyBoolean());
2074         SystemProperties.mProperties = mProperties;
2075 
2076         // Create new ScanManager since sysprop and MSFT support are only checked when
2077         // ScanManager is created
2078         mScanManager =
2079                 new ScanManager(
2080                         mAdapterService,
2081                         mScanController,
2082                         mBluetoothAdapterProxy,
2083                         mLooper.getLooper(),
2084                         mTimeProvider);
2085 
2086         // Turn on screen
2087         sendMessageWaitForProcessed(createScreenOnOffMessage(true));
2088         // Create scan client with service data
2089         List<ScanFilter> scanFilterList =
2090                 List.of(new ScanFilter.Builder().setServiceData(serviceUuid, serviceData).build());
2091         ScanClient client =
2092                 createScanClient(
2093                         isFiltered,
2094                         SCAN_MODE_LOW_POWER,
2095                         false,
2096                         false,
2097                         Binder.getCallingUid(),
2098                         mMockAppScanStats,
2099                         scanFilterList);
2100         // Start scan
2101         sendMessageWaitForProcessed(createStartStopScanMessage(true, client));
2102 
2103         // Create another scan client with the same service data
2104         ScanClient anotherClient =
2105                 createScanClient(
2106                         isFiltered,
2107                         SCAN_MODE_LOW_POWER,
2108                         false,
2109                         false,
2110                         Binder.getCallingUid(),
2111                         mMockAppScanStats,
2112                         scanFilterList);
2113         // Start scan
2114         sendMessageWaitForProcessed(createStartStopScanMessage(true, anotherClient));
2115 
2116         // Verify MSFT APIs are only called once
2117         verify(mScanNativeInterface)
2118                 .gattClientMsftAdvMonitorAdd(
2119                         any(MsftAdvMonitor.Monitor.class),
2120                         any(MsftAdvMonitor.Pattern[].class),
2121                         any(MsftAdvMonitor.Address.class),
2122                         anyInt());
2123         verify(mScanNativeInterface).gattClientMsftAdvMonitorEnable(eq(true));
2124     }
2125 }
2126