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