1 /*
2  * Copyright (C) 2017 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.server.usage;
18 
19 import static android.app.usage.UsageEvents.Event.FOREGROUND_SERVICE_START;
20 import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
21 import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
22 import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
23 import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION;
24 import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
25 import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
26 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_SYSTEM;
27 import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED_BY_USER;
28 import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
29 import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
30 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
31 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE;
32 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE;
33 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY;
34 import static android.app.usage.UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_UNDEFINED;
35 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
36 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
37 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYNC_ADAPTER;
38 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_SYSTEM_INTERACTION;
39 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_USER_INTERACTION;
40 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
41 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
42 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
43 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
44 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
45 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RESTRICTED;
46 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
47 import static android.content.pm.PackageManager.PERMISSION_DENIED;
48 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
49 
50 import static com.android.server.usage.AppStandbyController.DEFAULT_ELAPSED_TIME_THRESHOLDS;
51 import static com.android.server.usage.AppStandbyController.DEFAULT_SCREEN_TIME_THRESHOLDS;
52 import static com.android.server.usage.AppStandbyController.MINIMUM_ELAPSED_TIME_THRESHOLDS;
53 import static com.android.server.usage.AppStandbyController.MINIMUM_SCREEN_TIME_THRESHOLDS;
54 
55 import static org.junit.Assert.assertEquals;
56 import static org.junit.Assert.assertFalse;
57 import static org.junit.Assert.assertNotEquals;
58 import static org.junit.Assert.assertTrue;
59 import static org.junit.Assert.fail;
60 import static org.junit.Assume.assumeTrue;
61 import static org.mockito.AdditionalMatchers.not;
62 import static org.mockito.ArgumentMatchers.anyLong;
63 import static org.mockito.ArgumentMatchers.anyString;
64 import static org.mockito.ArgumentMatchers.eq;
65 import static org.mockito.Matchers.any;
66 import static org.mockito.Matchers.anyInt;
67 import static org.mockito.Matchers.eq;
68 import static org.mockito.Matchers.intThat;
69 import static org.mockito.Mockito.doReturn;
70 import static org.mockito.Mockito.mock;
71 import static org.mockito.Mockito.spy;
72 import static org.mockito.Mockito.when;
73 
74 import android.annotation.NonNull;
75 import android.app.ActivityManager;
76 import android.app.usage.AppStandbyInfo;
77 import android.app.usage.UsageEvents;
78 import android.app.usage.UsageStatsManagerInternal;
79 import android.appwidget.AppWidgetManager;
80 import android.content.Context;
81 import android.content.ContextWrapper;
82 import android.content.Intent;
83 import android.content.pm.ActivityInfo;
84 import android.content.pm.ApplicationInfo;
85 import android.content.pm.PackageInfo;
86 import android.content.pm.PackageManager;
87 import android.content.pm.PackageManagerInternal;
88 import android.content.pm.ResolveInfo;
89 import android.hardware.display.DisplayManager;
90 import android.os.BatteryStats;
91 import android.os.Handler;
92 import android.os.Looper;
93 import android.os.RemoteException;
94 import android.os.UserHandle;
95 import android.platform.test.annotations.Presubmit;
96 import android.provider.DeviceConfig;
97 import android.util.ArraySet;
98 import android.util.Pair;
99 import android.view.Display;
100 
101 import androidx.test.InstrumentationRegistry;
102 import androidx.test.filters.FlakyTest;
103 import androidx.test.filters.SmallTest;
104 import androidx.test.runner.AndroidJUnit4;
105 
106 import com.android.internal.util.ArrayUtils;
107 import com.android.server.LocalServices;
108 import com.android.server.SystemService;
109 import com.android.server.usage.AppStandbyInternal.AppIdleStateChangeListener;
110 
111 import org.junit.After;
112 import org.junit.Before;
113 import org.junit.Test;
114 import org.junit.runner.RunWith;
115 import org.mockito.Mock;
116 import org.mockito.MockitoAnnotations;
117 
118 import java.io.File;
119 import java.util.ArrayList;
120 import java.util.Arrays;
121 import java.util.Collections;
122 import java.util.List;
123 import java.util.Objects;
124 import java.util.Random;
125 import java.util.Set;
126 import java.util.concurrent.CountDownLatch;
127 import java.util.concurrent.TimeUnit;
128 import java.util.stream.Collectors;
129 
130 /**
131  * Unit test for AppStandbyController.
132  */
133 @RunWith(AndroidJUnit4.class)
134 @Presubmit
135 @SmallTest
136 public class AppStandbyControllerTests {
137 
138     private static final String PACKAGE_1 = "com.example.foo.1";
139     private static final int UID_1 = 10000;
140     private static final String PACKAGE_2 = "com.example.foo.2";
141     private static final int UID_2 = 20000;
142     private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
143     private static final int UID_EXEMPTED_1 = 10001;
144     private static final String PACKAGE_SYSTEM_HEADFULL = "com.example.system.headfull";
145     private static final int UID_SYSTEM_HEADFULL = 10002;
146     private static final String PACKAGE_SYSTEM_HEADLESS = "com.example.system.headless";
147     private static final int UID_SYSTEM_HEADLESS = 10003;
148     private static final String PACKAGE_WELLBEING = "com.example.wellbeing";
149     private static final int UID_WELLBEING = 10004;
150     private static final String PACKAGE_BACKGROUND_LOCATION = "com.example.backgroundLocation";
151     private static final int UID_BACKGROUND_LOCATION = 10005;
152     private static final int USER_ID = 0;
153     private static final int USER_ID2 = 10;
154     private static final UserHandle USER_HANDLE_USER2 = new UserHandle(USER_ID2);
155     private static final int USER_ID3 = 11;
156 
157     private static final String PACKAGE_UNKNOWN = "com.example.unknown";
158 
159     private static final String ADMIN_PKG = "com.android.admin";
160     private static final String ADMIN_PKG2 = "com.android.admin2";
161     private static final String ADMIN_PKG3 = "com.android.admin3";
162 
163     private static final String ADMIN_PROTECTED_PKG = "com.android.admin.protected";
164     private static final String ADMIN_PROTECTED_PKG2 = "com.android.admin.protected2";
165 
166     private static final long MINUTE_MS = 60 * 1000;
167     private static final long HOUR_MS = 60 * MINUTE_MS;
168     private static final long DAY_MS = 24 * HOUR_MS;
169 
170     private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
171     private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
172     private static final long RARE_THRESHOLD = 48 * HOUR_MS;
173     private static final long RESTRICTED_THRESHOLD = 96 * HOUR_MS;
174 
175     private static final int ASSERT_RETRY_ATTEMPTS = 20;
176     private static final int ASSERT_RETRY_DELAY_MILLISECONDS = 500;
177 
178     /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
179     private static boolean isPackageInstalled = true;
180 
181     private static final Random sRandom = new Random();
182 
183     private MyInjector mInjector;
184     private AppStandbyController mController;
185 
186     private CountDownLatch mStateChangedLatch = new CountDownLatch(1);
187     private CountDownLatch mQuotaBumpLatch = new CountDownLatch(1);
188     private String mLatchPkgName = null;
189     private int mLatchUserId = -1;
190     private AppIdleStateChangeListener mListener = new AppIdleStateChangeListener() {
191         @Override
192         public void onAppIdleStateChanged(String packageName, int userId,
193                 boolean idle, int bucket, int reason) {
194             // Ignore events not related to mLatchPkgName, if set.
195             if (mLatchPkgName != null && !mLatchPkgName.equals(packageName)) return;
196             mStateChangedLatch.countDown();
197         }
198 
199         @Override
200         public void triggerTemporaryQuotaBump(String packageName, int userId) {
201             // Ignore events not related to mLatchPkgName, if set.
202             if ((mLatchPkgName != null && !mLatchPkgName.equals(packageName))
203                     || (mLatchUserId != -1 && mLatchUserId != userId)) {
204                 return;
205             }
206             mQuotaBumpLatch.countDown();
207         }
208     };
209 
210     static class MyContextWrapper extends ContextWrapper {
211         PackageManager mockPm = mock(PackageManager.class);
212 
MyContextWrapper(Context base)213         public MyContextWrapper(Context base) {
214             super(base);
215         }
216 
getPackageManager()217         public PackageManager getPackageManager() {
218             return mockPm;
219         }
220 
getSystemService(@onNull String name)221         public Object getSystemService(@NonNull String name) {
222             if (Context.ACTIVITY_SERVICE.equals(name)) {
223                 return mock(ActivityManager.class);
224             }
225             return super.getSystemService(name);
226         }
227     }
228 
229     static class MyInjector extends AppStandbyController.Injector {
230         @Mock
231         private PackageManagerInternal mPackageManagerInternal;
232         long mElapsedRealtime;
233         boolean mIsAppIdleEnabled = true;
234         boolean mIsCharging;
235         List<String> mNonIdleWhitelistApps = new ArrayList<>();
236         boolean mDisplayOn;
237         DisplayManager.DisplayListener mDisplayListener;
238         String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
239         int[] mRunningUsers = new int[] {USER_ID};
240         List<UserHandle> mCrossProfileTargets = Collections.emptyList();
241         boolean mDeviceIdleMode = false;
242         Set<Pair<String, Integer>> mClockApps = new ArraySet<>();
243         DeviceConfig.Properties.Builder mSettingsBuilder =
244                 new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_APP_STANDBY)
245                         .setLong("screen_threshold_active", 0)
246                         .setLong("screen_threshold_working_set", 0)
247                         .setLong("screen_threshold_frequent", 0)
248                         .setLong("screen_threshold_rare", HOUR_MS)
249                         // screen_threshold_restricted intentionally skipped
250                         .setLong("elapsed_threshold_active", 0)
251                         .setLong("elapsed_threshold_working_set", WORKING_SET_THRESHOLD)
252                         .setLong("elapsed_threshold_frequent", FREQUENT_THRESHOLD)
253                         .setLong("elapsed_threshold_rare", RARE_THRESHOLD)
254                         .setLong("elapsed_threshold_restricted", RESTRICTED_THRESHOLD);
255         DeviceConfig.OnPropertiesChangedListener mPropertiesChangedListener;
256         String mExpectedNoteEventPackage = null;
257         int mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
258 
MyInjector(Context context, Looper looper)259         MyInjector(Context context, Looper looper) {
260             super(context, looper);
261             MockitoAnnotations.initMocks(this);
262         }
263 
264         @Override
onBootPhase(int phase)265         void onBootPhase(int phase) {
266         }
267 
268         @Override
getBootPhase()269         int getBootPhase() {
270             return SystemService.PHASE_BOOT_COMPLETED;
271         }
272 
273         @Override
elapsedRealtime()274         long elapsedRealtime() {
275             return mElapsedRealtime;
276         }
277 
278         @Override
currentTimeMillis()279         long currentTimeMillis() {
280             return mElapsedRealtime;
281         }
282 
283         @Override
isAppIdleEnabled()284         boolean isAppIdleEnabled() {
285             return mIsAppIdleEnabled;
286         }
287 
288         @Override
isCharging()289         boolean isCharging() {
290             return mIsCharging;
291         }
292 
293         @Override
isNonIdleWhitelisted(String packageName)294         boolean isNonIdleWhitelisted(String packageName) {
295             return mNonIdleWhitelistApps.contains(packageName);
296         }
297 
298         @Override
isWellbeingPackage(String packageName)299         boolean isWellbeingPackage(String packageName) {
300             return PACKAGE_WELLBEING.equals(packageName);
301         }
302 
303         @Override
shouldGetExactAlarmBucketElevation(String packageName, int uid)304         boolean shouldGetExactAlarmBucketElevation(String packageName, int uid) {
305             return mClockApps.contains(Pair.create(packageName, uid));
306         }
307 
308         @Override
getPackageManagerInternal()309         PackageManagerInternal getPackageManagerInternal() {
310             return mPackageManagerInternal;
311         }
312 
313         @Override
updatePowerWhitelistCache()314         void updatePowerWhitelistCache() {
315         }
316 
317         @Override
getDataSystemDirectory()318         File getDataSystemDirectory() {
319             return new File(getContext().getFilesDir(), Long.toString(sRandom.nextLong()));
320         }
321 
322         @Override
noteEvent(int event, String packageName, int uid)323         void noteEvent(int event, String packageName, int uid) throws RemoteException {
324             if (Objects.equals(mExpectedNoteEventPackage, packageName)) {
325                 mLastNoteEvent = event;
326             }
327         }
328 
329         @Override
isPackageEphemeral(int userId, String packageName)330         boolean isPackageEphemeral(int userId, String packageName) {
331             // TODO: update when testing ephemeral apps scenario
332             return false;
333         }
334 
335         @Override
isPackageInstalled(String packageName, int flags, int userId)336         boolean isPackageInstalled(String packageName, int flags, int userId) {
337             // Should always return true (default value) unless testing for an uninstalled app
338             return isPackageInstalled;
339         }
340 
341         @Override
getRunningUserIds()342         int[] getRunningUserIds() {
343             return mRunningUsers;
344         }
345 
346         @Override
isDefaultDisplayOn()347         boolean isDefaultDisplayOn() {
348             return mDisplayOn;
349         }
350 
351         @Override
registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler)352         void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
353             mDisplayListener = listener;
354         }
355 
356         @Override
getActiveNetworkScorer()357         String getActiveNetworkScorer() {
358             return null;
359         }
360 
361         @Override
isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName, int userId)362         public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
363                 int userId) {
364             return packageName != null && packageName.equals(mBoundWidgetPackage);
365         }
366 
367         @Override
368         @NonNull
getDeviceConfigProperties(String... keys)369         DeviceConfig.Properties getDeviceConfigProperties(String... keys) {
370             return mSettingsBuilder.build();
371         }
372 
373         @Override
isDeviceIdleMode()374         public boolean isDeviceIdleMode() {
375             return mDeviceIdleMode;
376         }
377 
378         @Override
getValidCrossProfileTargets(String pkg, int userId)379         public List<UserHandle> getValidCrossProfileTargets(String pkg, int userId) {
380             return mCrossProfileTargets;
381         }
382 
383         @Override
registerDeviceConfigPropertiesChangedListener( @onNull DeviceConfig.OnPropertiesChangedListener listener)384         public void registerDeviceConfigPropertiesChangedListener(
385                 @NonNull DeviceConfig.OnPropertiesChangedListener listener) {
386             mPropertiesChangedListener = listener;
387         }
388 
389         // Internal methods
390 
setDisplayOn(boolean on)391         void setDisplayOn(boolean on) {
392             mDisplayOn = on;
393             if (mDisplayListener != null) {
394                 mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY);
395             }
396         }
397     }
398 
setupPm(PackageManager mockPm)399     private void setupPm(PackageManager mockPm) throws PackageManager.NameNotFoundException {
400         List<PackageInfo> packages = new ArrayList<>();
401         PackageInfo pi = new PackageInfo();
402         pi.applicationInfo = new ApplicationInfo();
403         pi.applicationInfo.uid = UID_1;
404         pi.packageName = PACKAGE_1;
405         packages.add(pi);
406 
407         PackageInfo pInfo = new PackageInfo();
408         pInfo.applicationInfo = new ApplicationInfo();
409         pInfo.applicationInfo.uid = UID_2;
410         pInfo.packageName = PACKAGE_2;
411         packages.add(pInfo);
412 
413         PackageInfo pie = new PackageInfo();
414         pie.applicationInfo = new ApplicationInfo();
415         pie.applicationInfo.uid = UID_EXEMPTED_1;
416         pie.packageName = PACKAGE_EXEMPTED_1;
417         packages.add(pie);
418 
419         PackageInfo pis = new PackageInfo();
420         pis.activities = new ActivityInfo[]{mock(ActivityInfo.class)};
421         pis.applicationInfo = new ApplicationInfo();
422         pis.applicationInfo.uid = UID_SYSTEM_HEADFULL;
423         pis.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
424         pis.packageName = PACKAGE_SYSTEM_HEADFULL;
425         packages.add(pis);
426 
427         PackageInfo pish = new PackageInfo();
428         pish.applicationInfo = new ApplicationInfo();
429         pish.applicationInfo.uid = UID_SYSTEM_HEADLESS;
430         pish.applicationInfo.flags = ApplicationInfo.FLAG_SYSTEM;
431         pish.packageName = PACKAGE_SYSTEM_HEADLESS;
432         packages.add(pish);
433 
434         PackageInfo piw = new PackageInfo();
435         piw.applicationInfo = new ApplicationInfo();
436         piw.applicationInfo.uid = UID_WELLBEING;
437         piw.packageName = PACKAGE_WELLBEING;
438         packages.add(piw);
439 
440         PackageInfo pib = new PackageInfo();
441         pib.applicationInfo = new ApplicationInfo();
442         pib.applicationInfo.uid = UID_BACKGROUND_LOCATION;
443         pib.packageName = PACKAGE_BACKGROUND_LOCATION;
444         packages.add(pib);
445 
446 
447         // Set up getInstalledPackagesAsUser().
448         doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(),
449                 anyInt());
450 
451         // Set up getInstalledPackagesAsUser() for "MATCH_ONLY_SYSTEM"
452         doReturn(
453                 packages.stream().filter(pinfo -> pinfo.applicationInfo.isSystemApp())
454                 .collect(Collectors.toList())
455         ).when(mockPm).getInstalledPackagesAsUser(
456                 intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
457                 anyInt());
458 
459         // Set up queryIntentActivitiesAsUser()
460         final ArrayList<ResolveInfo> systemFrontDoorActivities = new ArrayList<>();
461         final ResolveInfo frontDoorActivity = new ResolveInfo();
462         frontDoorActivity.activityInfo = new ActivityInfo();
463         frontDoorActivity.activityInfo.packageName = pis.packageName;
464         systemFrontDoorActivities.add(frontDoorActivity);
465         doReturn(systemFrontDoorActivities).when(mockPm)
466                 .queryIntentActivitiesAsUser(any(Intent.class),
467                 intThat(i -> (i & PackageManager.MATCH_SYSTEM_ONLY) != 0),
468                 anyInt());
469 
470         // Set up other APIs.
471         try {
472             for (int i = 0; i < packages.size(); ++i) {
473                 PackageInfo pkg = packages.get(i);
474 
475                 doReturn(pkg.applicationInfo.uid).when(mockPm)
476                         .getPackageUidAsUser(eq(pkg.packageName), anyInt());
477                 doReturn(pkg.applicationInfo.uid).when(mockPm)
478                         .getPackageUidAsUser(eq(pkg.packageName), anyInt(), anyInt());
479                 doReturn(pkg.applicationInfo).when(mockPm)
480                         .getApplicationInfo(eq(pkg.packageName), anyInt());
481 
482                 if (pkg.packageName.equals(PACKAGE_BACKGROUND_LOCATION)) {
483                     doReturn(PERMISSION_GRANTED).when(mockPm).checkPermission(
484                             eq(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION),
485                             eq(pkg.packageName));
486                     doReturn(PERMISSION_DENIED).when(mockPm).checkPermission(
487                             not(eq(android.Manifest.permission.ACCESS_BACKGROUND_LOCATION)),
488                             eq(pkg.packageName));
489                 } else {
490                     doReturn(PERMISSION_DENIED).when(mockPm).checkPermission(anyString(),
491                             eq(pkg.packageName));
492                 }
493             }
494         } catch (PackageManager.NameNotFoundException nnfe) {}
495     }
496 
setChargingState(AppStandbyController controller, boolean charging)497     private void setChargingState(AppStandbyController controller, boolean charging) {
498         mInjector.mIsCharging = charging;
499         if (controller != null) {
500             controller.setChargingState(charging);
501         }
502     }
503 
setAppIdleEnabled(AppStandbyController controller, boolean enabled)504     private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
505         mInjector.mIsAppIdleEnabled = enabled;
506         if (controller != null) {
507             controller.setAppIdleEnabled(enabled);
508         }
509     }
510 
setupController()511     private AppStandbyController setupController() throws Exception {
512         mInjector.mElapsedRealtime = 0;
513         setupPm(mInjector.getContext().getPackageManager());
514         AppStandbyController controller = new AppStandbyController(mInjector);
515         controller.initializeDefaultsForSystemApps(USER_ID);
516         controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
517         controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
518         mInjector.setDisplayOn(false);
519         mInjector.setDisplayOn(true);
520         setChargingState(controller, false);
521         controller.checkIdleStates(USER_ID);
522         assertNotEquals(STANDBY_BUCKET_EXEMPTED,
523                 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
524                         mInjector.mElapsedRealtime, false));
525 
526         controller.addListener(mListener);
527         mLatchPkgName = null;
528         return controller;
529     }
530 
setupInitialUsageHistory()531     private void setupInitialUsageHistory() throws Exception {
532         final int[] userIds = new int[] { USER_ID, USER_ID2, USER_ID3 };
533         final String[] packages = new String[] {
534                 PACKAGE_1,
535                 PACKAGE_2,
536                 PACKAGE_EXEMPTED_1,
537                 PACKAGE_SYSTEM_HEADFULL,
538                 PACKAGE_SYSTEM_HEADLESS,
539                 PACKAGE_WELLBEING,
540                 PACKAGE_BACKGROUND_LOCATION,
541                 ADMIN_PKG,
542                 ADMIN_PKG2,
543                 ADMIN_PKG3
544         };
545         for (int userId : userIds) {
546             for (String pkg : packages) {
547                 final AppIdleHistory.AppUsageHistory usageHistory = mController
548                         .getAppIdleHistoryForTest().getAppUsageHistory(
549                                 pkg, userId, mInjector.mElapsedRealtime);
550                 usageHistory.lastUsedElapsedTime = 0;
551                 usageHistory.lastUsedByUserElapsedTime = 0;
552                 usageHistory.lastUsedScreenTime = 0;
553             }
554         }
555     }
556 
557     @Before
setUp()558     public void setUp() throws Exception {
559         LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
560         LocalServices.addService(
561                 UsageStatsManagerInternal.class, mock(UsageStatsManagerInternal.class));
562         MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
563         mInjector = new MyInjector(myContext, Looper.getMainLooper());
564         mController = setupController();
565         setupInitialUsageHistory();
566     }
567 
568     @After
tearDown()569     public void tearDown() {
570         LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
571     }
572 
573     @Test
574     @FlakyTest(bugId = 185169504)
testBoundWidgetPackageExempt()575     public void testBoundWidgetPackageExempt() throws Exception {
576         assumeTrue(mInjector.getContext().getSystemService(AppWidgetManager.class) != null);
577         assertEquals(STANDBY_BUCKET_ACTIVE,
578                 mController.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
579                         mInjector.mElapsedRealtime, false));
580     }
581 
582     @Test
testGetIdleUidsForUser()583     public void testGetIdleUidsForUser() {
584         final AppStandbyController controllerUnderTest = spy(mController);
585 
586         final int userIdForTest = 325;
587         final int[] uids = new int[]{129, 23, 129, 129, 44, 23, 41, 751};
588         final boolean[] idle = new boolean[]{true, true, false, true, false, true, false, true};
589         // Based on uids[] and idle[], the only two uids that have all true's in idle[].
590         final int[] expectedIdleUids = new int[]{23, 751};
591 
592         final List<ApplicationInfo> installedApps = new ArrayList<>();
593         for (int i = 0; i < uids.length; i++) {
594             final ApplicationInfo ai = mock(ApplicationInfo.class);
595             ai.uid = uids[i];
596             ai.packageName = "example.package.name." + i;
597             installedApps.add(ai);
598             when(controllerUnderTest.isAppIdleFiltered(eq(ai.packageName),
599                     eq(UserHandle.getAppId(ai.uid)), eq(userIdForTest), anyLong()))
600                     .thenReturn(idle[i]);
601         }
602         when(mInjector.mPackageManagerInternal.getInstalledApplications(anyLong(),
603                 eq(userIdForTest), anyInt())).thenReturn(installedApps);
604         final int[] returnedIdleUids = controllerUnderTest.getIdleUidsForUser(userIdForTest);
605 
606         assertEquals(expectedIdleUids.length, returnedIdleUids.length);
607         for (final int uid : expectedIdleUids) {
608             assertTrue("Idle uid: " + uid + " not found in result: " + Arrays.toString(
609                     returnedIdleUids), ArrayUtils.contains(returnedIdleUids, uid));
610         }
611     }
612 
613     private static class TestParoleListener extends AppIdleStateChangeListener {
614         private boolean mIsParoleOn = false;
615         private CountDownLatch mLatch;
616         private boolean mIsExpecting = false;
617         private boolean mExpectedParoleState;
618 
getParoleState()619         boolean getParoleState() {
620             synchronized (this) {
621                 return mIsParoleOn;
622             }
623         }
624 
rearmLatch(boolean expectedParoleState)625         void rearmLatch(boolean expectedParoleState) {
626             synchronized (this) {
627                 mLatch = new CountDownLatch(1);
628                 mIsExpecting = true;
629                 mExpectedParoleState = expectedParoleState;
630             }
631         }
632 
awaitOnLatch(long time)633         void awaitOnLatch(long time) throws Exception {
634             mLatch.await(time, TimeUnit.MILLISECONDS);
635         }
636 
637         @Override
onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket, int reason)638         public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
639                 int bucket, int reason) {
640         }
641 
642         @Override
onParoleStateChanged(boolean isParoleOn)643         public void onParoleStateChanged(boolean isParoleOn) {
644             synchronized (this) {
645                 // Only record information if it is being looked for
646                 if (mLatch != null && mLatch.getCount() > 0) {
647                     mIsParoleOn = isParoleOn;
648                     if (mIsExpecting && isParoleOn == mExpectedParoleState) {
649                         mLatch.countDown();
650                     }
651                 }
652             }
653         }
654     }
655 
656     @Test
657     @FlakyTest(bugId = 185169504)
testIsAppIdle_Charging()658     public void testIsAppIdle_Charging() throws Exception {
659         TestParoleListener paroleListener = new TestParoleListener();
660         mController.addListener(paroleListener);
661 
662         setChargingState(mController, false);
663         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
664                 REASON_MAIN_FORCED_BY_SYSTEM);
665         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
666         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
667         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
668         assertFalse(mController.isInParole());
669 
670         paroleListener.rearmLatch(true);
671         setChargingState(mController, true);
672         paroleListener.awaitOnLatch(2000);
673         assertTrue(paroleListener.getParoleState());
674         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
675         assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
676         assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
677         assertTrue(mController.isInParole());
678 
679         paroleListener.rearmLatch(false);
680         setChargingState(mController, false);
681         paroleListener.awaitOnLatch(2000);
682         assertFalse(paroleListener.getParoleState());
683         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
684         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
685         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
686         assertFalse(mController.isInParole());
687     }
688 
689     @Test
690     @FlakyTest(bugId = 185169504)
testIsAppIdle_Enabled()691     public void testIsAppIdle_Enabled() throws Exception {
692         setChargingState(mController, false);
693         TestParoleListener paroleListener = new TestParoleListener();
694         mController.addListener(paroleListener);
695 
696         setAppIdleEnabled(mController, true);
697         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
698                 REASON_MAIN_FORCED_BY_SYSTEM);
699         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
700         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
701         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
702 
703         paroleListener.rearmLatch(false);
704         setAppIdleEnabled(mController, false);
705         paroleListener.awaitOnLatch(2000);
706         assertTrue(paroleListener.mIsParoleOn);
707         assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
708         assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
709 
710         paroleListener.rearmLatch(true);
711         setAppIdleEnabled(mController, true);
712         paroleListener.awaitOnLatch(2000);
713         assertFalse(paroleListener.getParoleState());
714         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
715         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
716         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, false));
717     }
718 
assertTimeout(AppStandbyController controller, long elapsedTime, int bucket)719     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
720         assertTimeout(controller, elapsedTime, bucket, USER_ID);
721     }
722 
assertTimeout(AppStandbyController controller, long elapsedTime, int bucket, int userId)723     private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket,
724             int userId) {
725         mInjector.mElapsedRealtime = elapsedTime;
726         controller.checkIdleStates(userId);
727         assertEquals(bucket,
728                 controller.getAppStandbyBucket(PACKAGE_1, userId, mInjector.mElapsedRealtime,
729                         false));
730     }
731 
reportEvent(AppStandbyController controller, int eventType, long elapsedTime, String packageName)732     private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime,
733             String packageName) {
734         // Back to ACTIVE on event
735         mInjector.mElapsedRealtime = elapsedTime;
736         UsageEvents.Event ev = new UsageEvents.Event();
737         ev.mPackage = packageName;
738         ev.mEventType = eventType;
739         controller.onUsageEvent(USER_ID, ev);
740     }
741 
getStandbyBucket(AppStandbyController controller, String packageName)742     private int getStandbyBucket(AppStandbyController controller, String packageName) {
743         return getStandbyBucket(USER_ID, controller, packageName);
744     }
745 
getStandbyBucket(int userId, AppStandbyController controller, String packageName)746     private int getStandbyBucket(int userId, AppStandbyController controller, String packageName) {
747         return controller.getAppStandbyBucket(packageName, userId, mInjector.mElapsedRealtime,
748                 true);
749     }
750 
getStandbyBucketReason(String packageName)751     private int getStandbyBucketReason(String packageName) {
752         return mController.getAppStandbyBucketReason(packageName, USER_ID,
753                 mInjector.mElapsedRealtime);
754     }
755 
assertBucket(int bucket)756     private void assertBucket(int bucket) throws InterruptedException {
757         assertBucket(bucket, PACKAGE_1);
758     }
759 
assertBucket(int bucket, String pkg)760     private void assertBucket(int bucket, String pkg) throws InterruptedException {
761         int retries = 0;
762         do {
763             if (bucket == getStandbyBucket(mController, pkg)) {
764                 // Success
765                 return;
766             }
767             Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
768             retries++;
769         } while(retries < ASSERT_RETRY_ATTEMPTS);
770         // try one last time
771         assertEquals(bucket, getStandbyBucket(mController, pkg));
772     }
773 
assertNotBucket(int bucket)774     private void assertNotBucket(int bucket) throws InterruptedException {
775         final String pkg = PACKAGE_1;
776         int retries = 0;
777         do {
778             if (bucket != getStandbyBucket(mController, pkg)) {
779                 // Success
780                 return;
781             }
782             Thread.sleep(ASSERT_RETRY_DELAY_MILLISECONDS);
783             retries++;
784         } while(retries < ASSERT_RETRY_ATTEMPTS);
785         // try one last time
786         assertNotEquals(bucket, getStandbyBucket(mController, pkg));
787     }
788 
789     @Test
790     @FlakyTest(bugId = 185169504)
testBuckets()791     public void testBuckets() throws Exception {
792         assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
793 
794         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
795 
796         // ACTIVE bucket
797         assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
798 
799         // WORKING_SET bucket
800         assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
801 
802         // WORKING_SET bucket
803         assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET);
804 
805         // FREQUENT bucket
806         assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT);
807 
808         // RARE bucket
809         assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);
810 
811         // RESTRICTED bucket
812         assertTimeout(mController, RESTRICTED_THRESHOLD + 1, STANDBY_BUCKET_RESTRICTED);
813 
814         reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1);
815 
816         assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);
817 
818         // RESTRICTED bucket
819         assertTimeout(mController, RESTRICTED_THRESHOLD * 2 + 2, STANDBY_BUCKET_RESTRICTED);
820     }
821 
822     @Test
823     @FlakyTest(bugId = 185169504)
testSetAppStandbyBucket()824     public void testSetAppStandbyBucket() throws Exception {
825         // For a known package, standby bucket should be set properly
826         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
827         mInjector.mElapsedRealtime = HOUR_MS;
828         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
829                 REASON_MAIN_TIMEOUT);
830         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
831 
832         // For an unknown package, standby bucket should not be set, hence NEVER is returned
833         // Ensure the unknown package is not already in history by removing it
834         mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
835         isPackageInstalled = false; // Mock package is not installed
836         mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
837                 REASON_MAIN_TIMEOUT);
838         isPackageInstalled = true; // Reset mocked variable for other tests
839         assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
840     }
841 
842     @Test
843     @FlakyTest(bugId = 185169504)
testAppStandbyBucketOnInstallAndUninstall()844     public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
845         // On package install, standby bucket should be ACTIVE
846         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
847         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN));
848 
849         // On uninstall, package should not exist in history and should return a NEVER bucket
850         mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
851         assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
852         // Ensure uninstalled app is not in history
853         List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID);
854         for(AppStandbyInfo bucket : buckets) {
855             if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) {
856                 fail("packageName found in app idle history after uninstall.");
857             }
858         }
859     }
860 
861     @Test
862     @FlakyTest(bugId = 185169504)
testScreenTimeAndBuckets()863     public void testScreenTimeAndBuckets() throws Exception {
864         mInjector.setDisplayOn(false);
865 
866         assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
867 
868         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
869 
870         // ACTIVE bucket
871         assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
872 
873         // WORKING_SET bucket
874         assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
875 
876         // RARE bucket, should fail because the screen wasn't ON.
877         mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
878         mController.checkIdleStates(USER_ID);
879         assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
880 
881         mInjector.setDisplayOn(true);
882         assertTimeout(mController, RARE_THRESHOLD + 2 * HOUR_MS + 1, STANDBY_BUCKET_RARE);
883     }
884 
885     @Test
886     @FlakyTest(bugId = 185169504)
testForcedIdle()887     public void testForcedIdle() throws Exception {
888         mController.forceIdleState(PACKAGE_1, USER_ID, true);
889         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
890         assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
891 
892         mController.forceIdleState(PACKAGE_1, USER_ID, false);
893         assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0,
894                 true));
895         assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
896     }
897 
898     @Test
testNotificationEvent_bucketPromotion()899     public void testNotificationEvent_bucketPromotion() throws Exception {
900         mInjector.mPropertiesChangedListener
901                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
902 
903         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
904         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
905         mInjector.mElapsedRealtime = 1;
906         rearmQuotaBumpLatch(PACKAGE_1, USER_ID);
907         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
908         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
909 
910         mController.forceIdleState(PACKAGE_1, USER_ID, true);
911         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
912         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
913         assertFalse(mQuotaBumpLatch.await(1, TimeUnit.SECONDS));
914     }
915 
916     @Test
testNotificationEvent_bucketPromotion_changePromotedBucket()917     public void testNotificationEvent_bucketPromotion_changePromotedBucket() throws Exception {
918         mInjector.mPropertiesChangedListener
919                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
920         mController.forceIdleState(PACKAGE_1, USER_ID, true);
921         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
922         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
923 
924         // TODO: Avoid hardcoding these string constants.
925         mInjector.mSettingsBuilder.setInt("notification_seen_promoted_bucket",
926                 STANDBY_BUCKET_FREQUENT);
927         mInjector.mPropertiesChangedListener.onPropertiesChanged(
928                 mInjector.getDeviceConfigProperties());
929         mController.forceIdleState(PACKAGE_1, USER_ID, true);
930         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
931         assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
932     }
933 
934     @Test
935     @FlakyTest(bugId = 185169504)
testNotificationEvent_quotaBump()936     public void testNotificationEvent_quotaBump() throws Exception {
937         mInjector.mSettingsBuilder
938                 .setBoolean("trigger_quota_bump_on_notification_seen", true);
939         mInjector.mSettingsBuilder
940                 .setInt("notification_seen_promoted_bucket", STANDBY_BUCKET_NEVER);
941         mInjector.mPropertiesChangedListener
942                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
943 
944         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
945         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
946         mInjector.mElapsedRealtime = RARE_THRESHOLD * 2;
947         setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
948 
949         rearmQuotaBumpLatch(PACKAGE_1, USER_ID);
950         mInjector.mElapsedRealtime += 1;
951 
952         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
953         assertTrue(mQuotaBumpLatch.await(1, TimeUnit.SECONDS));
954         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
955     }
956 
957     @Test
958     @FlakyTest(bugId = 185169504)
testSlicePinnedEvent()959     public void testSlicePinnedEvent() throws Exception {
960         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
961         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
962         mInjector.mElapsedRealtime = 1;
963         reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
964         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
965 
966         mController.forceIdleState(PACKAGE_1, USER_ID, true);
967         reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
968         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
969     }
970 
971     @Test
972     @FlakyTest(bugId = 185169504)
testSlicePinnedPrivEvent()973     public void testSlicePinnedPrivEvent() throws Exception {
974         mController.forceIdleState(PACKAGE_1, USER_ID, true);
975         reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
976         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
977     }
978 
979     @Test
980     @FlakyTest(bugId = 185169504)
testPredictionTimedOut()981     public void testPredictionTimedOut() throws Exception {
982         // Set it to timeout or usage, so that prediction can override it
983         mInjector.mElapsedRealtime = HOUR_MS;
984         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
985                 REASON_MAIN_TIMEOUT);
986         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
987 
988         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
989                 REASON_MAIN_PREDICTED);
990         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
991 
992         // Fast forward 12 hours
993         mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
994         mController.checkIdleStates(USER_ID);
995         // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
996         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
997         // Fast forward two more hours
998         mInjector.mElapsedRealtime += 2 * HOUR_MS;
999         mController.checkIdleStates(USER_ID);
1000         // Should have now applied prediction timeout
1001         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1002 
1003         // Fast forward RARE bucket
1004         mInjector.mElapsedRealtime += RARE_THRESHOLD;
1005         mController.checkIdleStates(USER_ID);
1006         // Should continue to apply prediction timeout
1007         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
1008     }
1009 
1010     @Test
1011     @FlakyTest(bugId = 185169504)
testOverrides()1012     public void testOverrides() throws Exception {
1013         // Can force to NEVER
1014         mInjector.mElapsedRealtime = HOUR_MS;
1015         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
1016                 REASON_MAIN_FORCED_BY_USER);
1017         assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
1018 
1019         // Prediction can't override FORCED reasons
1020         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1021                 REASON_MAIN_FORCED_BY_SYSTEM);
1022         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1023                 REASON_MAIN_PREDICTED);
1024         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
1025 
1026         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1027                 REASON_MAIN_FORCED_BY_USER);
1028         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1029                 REASON_MAIN_PREDICTED);
1030         assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
1031 
1032         // Prediction can't override NEVER
1033         mInjector.mElapsedRealtime = 2 * HOUR_MS;
1034         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
1035                 REASON_MAIN_DEFAULT);
1036         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1037                 REASON_MAIN_PREDICTED);
1038         assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
1039 
1040         // Prediction can't set to NEVER
1041         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1042                 REASON_MAIN_USAGE);
1043         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
1044                 REASON_MAIN_PREDICTED);
1045         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
1046 
1047         // Prediction can't remove from RESTRICTED
1048         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1049                 REASON_MAIN_FORCED_BY_USER);
1050         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1051                 REASON_MAIN_PREDICTED);
1052         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1053 
1054         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1055                 REASON_MAIN_FORCED_BY_SYSTEM);
1056         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1057                 REASON_MAIN_PREDICTED);
1058         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1059 
1060         // Force from user can remove from RESTRICTED
1061         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1062                 REASON_MAIN_FORCED_BY_USER);
1063         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1064                 REASON_MAIN_FORCED_BY_USER);
1065         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1066 
1067         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1068                 REASON_MAIN_FORCED_BY_SYSTEM);
1069         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1070                 REASON_MAIN_FORCED_BY_USER);
1071         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1072 
1073         // Force from system can remove from RESTRICTED if it was put it in due to system
1074         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1075                 REASON_MAIN_FORCED_BY_SYSTEM);
1076         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1077                 REASON_MAIN_FORCED_BY_SYSTEM);
1078         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1079 
1080         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1081                 REASON_MAIN_FORCED_BY_USER);
1082         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1083                 REASON_MAIN_FORCED_BY_SYSTEM);
1084         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1085 
1086         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1087                 REASON_MAIN_PREDICTED);
1088         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1089                 REASON_MAIN_FORCED_BY_SYSTEM);
1090         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1091 
1092         // Non-user usage can't remove from RESTRICTED
1093         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1094                 REASON_MAIN_FORCED_BY_SYSTEM);
1095         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1096                 REASON_MAIN_USAGE);
1097         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1098         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1099                 REASON_MAIN_USAGE | REASON_SUB_USAGE_SYSTEM_INTERACTION);
1100         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1101         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1102                 REASON_MAIN_USAGE | REASON_SUB_USAGE_SYNC_ADAPTER);
1103         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1104         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1105                 REASON_MAIN_USAGE | REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE);
1106         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1107 
1108         // Explicit user usage can remove from RESTRICTED
1109         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1110                 REASON_MAIN_FORCED_BY_USER);
1111         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1112                 REASON_MAIN_USAGE | REASON_SUB_USAGE_USER_INTERACTION);
1113         assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1114         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1115                 REASON_MAIN_FORCED_BY_SYSTEM);
1116         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1117                 REASON_MAIN_USAGE | REASON_SUB_USAGE_MOVE_TO_FOREGROUND);
1118         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
1119     }
1120 
1121     @Test
1122     @FlakyTest(bugId = 185169504)
testTimeout()1123     public void testTimeout() throws Exception {
1124         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1125         assertBucket(STANDBY_BUCKET_ACTIVE);
1126 
1127         mInjector.mElapsedRealtime = 2000;
1128         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1129                 REASON_MAIN_PREDICTED);
1130         assertBucket(STANDBY_BUCKET_ACTIVE);
1131 
1132         // bucketing works after timeout
1133         mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100;
1134         mController.checkIdleStates(USER_ID);
1135         // Use recent prediction
1136         assertBucket(STANDBY_BUCKET_FREQUENT);
1137 
1138         // Way past prediction timeout, use system thresholds
1139         mInjector.mElapsedRealtime = RARE_THRESHOLD;
1140         mController.checkIdleStates(USER_ID);
1141         assertBucket(STANDBY_BUCKET_RARE);
1142     }
1143 
1144     /** Test that timeouts still work properly even if invalid configuration values are set. */
1145     @Test
1146     @FlakyTest(bugId = 185169504)
testTimeout_InvalidThresholds()1147     public void testTimeout_InvalidThresholds() throws Exception {
1148         mInjector.mSettingsBuilder
1149                 .setLong("screen_threshold_active", -1)
1150                 .setLong("screen_threshold_working_set", -1)
1151                 .setLong("screen_threshold_frequent", -1)
1152                 .setLong("screen_threshold_rare", -1)
1153                 .setLong("screen_threshold_restricted", -1)
1154                 .setLong("elapsed_threshold_active", -1)
1155                 .setLong("elapsed_threshold_working_set", -1)
1156                 .setLong("elapsed_threshold_frequent", -1)
1157                 .setLong("elapsed_threshold_rare", -1)
1158                 .setLong("elapsed_threshold_restricted", -1);
1159         mInjector.mPropertiesChangedListener
1160                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1161 
1162         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1163         mController.checkIdleStates(USER_ID);
1164         assertBucket(STANDBY_BUCKET_ACTIVE);
1165 
1166         mInjector.mElapsedRealtime = HOUR_MS;
1167         mController.checkIdleStates(USER_ID);
1168         assertBucket(STANDBY_BUCKET_FREQUENT);
1169 
1170         mInjector.mElapsedRealtime = 2 * HOUR_MS;
1171         mController.checkIdleStates(USER_ID);
1172         assertBucket(STANDBY_BUCKET_RARE);
1173 
1174         mInjector.mElapsedRealtime = 4 * HOUR_MS;
1175         mController.checkIdleStates(USER_ID);
1176         assertBucket(STANDBY_BUCKET_RESTRICTED);
1177     }
1178 
1179     /**
1180      * Test that setAppStandbyBucket to RESTRICTED doesn't change the bucket until the usage
1181      * timeout has passed.
1182      */
1183     @Test
1184     @FlakyTest(bugId = 185169504)
testTimeoutBeforeRestricted()1185     public void testTimeoutBeforeRestricted() throws Exception {
1186         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1187         assertBucket(STANDBY_BUCKET_ACTIVE);
1188 
1189         mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
1190         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1191                 REASON_MAIN_FORCED_BY_SYSTEM);
1192         // Bucket shouldn't change
1193         assertBucket(STANDBY_BUCKET_ACTIVE);
1194 
1195         // bucketing works after timeout
1196         mInjector.mElapsedRealtime += DAY_MS;
1197         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1198                 REASON_MAIN_FORCED_BY_SYSTEM);
1199         assertBucket(STANDBY_BUCKET_RESTRICTED);
1200 
1201         // Way past all timeouts. Make sure timeout processing doesn't raise bucket.
1202         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1203         mController.checkIdleStates(USER_ID);
1204         assertBucket(STANDBY_BUCKET_RESTRICTED);
1205     }
1206 
1207     /**
1208      * Test that an app is put into the RESTRICTED bucket after enough time has passed.
1209      */
1210     @Test
1211     @FlakyTest(bugId = 185169504)
testRestrictedDelay()1212     public void testRestrictedDelay() throws Exception {
1213         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1214         assertBucket(STANDBY_BUCKET_ACTIVE);
1215 
1216         mInjector.mElapsedRealtime += mInjector.getAutoRestrictedBucketDelayMs() - 5000;
1217         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1218                 REASON_MAIN_FORCED_BY_SYSTEM);
1219         // Bucket shouldn't change
1220         assertBucket(STANDBY_BUCKET_ACTIVE);
1221 
1222         // bucketing works after timeout
1223         mInjector.mElapsedRealtime += 6000;
1224 
1225         Thread.sleep(6000);
1226         // Enough time has passed. The app should automatically be put into the RESTRICTED bucket.
1227         assertBucket(STANDBY_BUCKET_RESTRICTED);
1228     }
1229 
1230     /**
1231      * Test that an app is put into the RESTRICTED bucket after enough time has passed.
1232      */
1233     @Test
1234     @FlakyTest(bugId = 185169504)
testRestrictedDelay_DelayChange()1235     public void testRestrictedDelay_DelayChange() throws Exception {
1236         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1237         assertBucket(STANDBY_BUCKET_ACTIVE);
1238 
1239         mInjector.mAutoRestrictedBucketDelayMs = 2 * HOUR_MS;
1240         mInjector.mElapsedRealtime += 2 * HOUR_MS - 5000;
1241         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1242                 REASON_MAIN_FORCED_BY_SYSTEM);
1243         // Bucket shouldn't change
1244         assertBucket(STANDBY_BUCKET_ACTIVE);
1245 
1246         // bucketing works after timeout
1247         mInjector.mElapsedRealtime += 6000;
1248 
1249         Thread.sleep(6000);
1250         // Enough time has passed. The app should automatically be put into the RESTRICTED bucket.
1251         assertBucket(STANDBY_BUCKET_RESTRICTED);
1252     }
1253 
1254     /**
1255      * Test that an app is "timed out" into the RESTRICTED bucket if prediction tries to put it into
1256      * a low bucket after the RESTRICTED timeout.
1257      */
1258     @Test
1259     @FlakyTest(bugId = 185169504)
testRestrictedTimeoutOverridesRestoredLowBucketPrediction()1260     public void testRestrictedTimeoutOverridesRestoredLowBucketPrediction() throws Exception {
1261         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1262         assertBucket(STANDBY_BUCKET_ACTIVE);
1263 
1264         // Predict to RARE Not long enough to time out into RESTRICTED.
1265         mInjector.mElapsedRealtime += RARE_THRESHOLD;
1266         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1267                 REASON_MAIN_PREDICTED);
1268         assertBucket(STANDBY_BUCKET_RARE);
1269 
1270         // Add a short timeout event
1271         mInjector.mElapsedRealtime += 1000;
1272         reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1273         assertBucket(STANDBY_BUCKET_ACTIVE);
1274         mInjector.mElapsedRealtime += 1000;
1275         mController.checkIdleStates(USER_ID);
1276         assertBucket(STANDBY_BUCKET_ACTIVE);
1277 
1278         // Long enough that it could have timed out into RESTRICTED. Instead of reverting to
1279         // predicted RARE, should go into RESTRICTED
1280         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1281         mController.checkIdleStates(USER_ID);
1282         assertBucket(STANDBY_BUCKET_RESTRICTED);
1283 
1284         // Ensure that prediction can still raise it out despite this override.
1285         mInjector.mElapsedRealtime += 1;
1286         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1287                 REASON_MAIN_PREDICTED);
1288         assertBucket(STANDBY_BUCKET_ACTIVE);
1289     }
1290 
1291     /**
1292      * Test that an app is "timed out" into the RESTRICTED bucket if prediction tries to put it into
1293      * a low bucket after the RESTRICTED timeout.
1294      */
1295     @Test
1296     @FlakyTest(bugId = 185169504)
testRestrictedTimeoutOverridesPredictionLowBucket()1297     public void testRestrictedTimeoutOverridesPredictionLowBucket() throws Exception {
1298         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1299 
1300         // Not long enough to time out into RESTRICTED.
1301         mInjector.mElapsedRealtime += RARE_THRESHOLD;
1302         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1303                 REASON_MAIN_PREDICTED);
1304         assertBucket(STANDBY_BUCKET_RARE);
1305 
1306         mInjector.mElapsedRealtime += 1;
1307         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1308 
1309         // Long enough that it could have timed out into RESTRICTED.
1310         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1311         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1312                 REASON_MAIN_PREDICTED);
1313         assertBucket(STANDBY_BUCKET_ACTIVE);
1314         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1315                 REASON_MAIN_PREDICTED);
1316         assertBucket(STANDBY_BUCKET_RESTRICTED);
1317     }
1318 
1319     /**
1320      * Test that an app that "timed out" into the RESTRICTED bucket can be raised out by system
1321      * interaction.
1322      */
1323     @Test
1324     @FlakyTest(bugId = 185169504)
testSystemInteractionOverridesRestrictedTimeout()1325     public void testSystemInteractionOverridesRestrictedTimeout() throws Exception {
1326         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1327         assertBucket(STANDBY_BUCKET_ACTIVE);
1328 
1329         // Long enough that it could have timed out into RESTRICTED.
1330         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1331         mController.checkIdleStates(USER_ID);
1332         assertBucket(STANDBY_BUCKET_RESTRICTED);
1333 
1334         // Report system interaction.
1335         mInjector.mElapsedRealtime += 1000;
1336         reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1337 
1338         // Ensure that it's raised out of RESTRICTED for the system interaction elevation duration.
1339         assertBucket(STANDBY_BUCKET_ACTIVE);
1340         mInjector.mElapsedRealtime += 1000;
1341         mController.checkIdleStates(USER_ID);
1342         assertBucket(STANDBY_BUCKET_ACTIVE);
1343 
1344         // Elevation duration over. Should fall back down.
1345         mInjector.mElapsedRealtime += 10 * MINUTE_MS;
1346         mController.checkIdleStates(USER_ID);
1347         assertBucket(STANDBY_BUCKET_RESTRICTED);
1348     }
1349 
1350     @Test
1351     @FlakyTest(bugId = 185169504)
testPredictionRaiseFromRestrictedTimeout_highBucket()1352     public void testPredictionRaiseFromRestrictedTimeout_highBucket() throws Exception {
1353         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1354 
1355         // Way past all timeouts. App times out into RESTRICTED bucket.
1356         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1357         mController.checkIdleStates(USER_ID);
1358         assertBucket(STANDBY_BUCKET_RESTRICTED);
1359 
1360         // Since the app timed out into RESTRICTED, prediction should be able to remove from the
1361         // bucket.
1362         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
1363         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1364                 REASON_MAIN_PREDICTED);
1365         assertBucket(STANDBY_BUCKET_ACTIVE);
1366     }
1367 
1368     @Test
1369     @FlakyTest(bugId = 185169504)
testPredictionRaiseFromRestrictedTimeout_lowBucket()1370     public void testPredictionRaiseFromRestrictedTimeout_lowBucket() throws Exception {
1371         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1372 
1373         // Way past all timeouts. App times out into RESTRICTED bucket.
1374         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1375         mController.checkIdleStates(USER_ID);
1376         assertBucket(STANDBY_BUCKET_RESTRICTED);
1377 
1378         // Prediction into a low bucket means no expectation of the app being used, so we shouldn't
1379         // elevate the app from RESTRICTED.
1380         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
1381         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1382                 REASON_MAIN_PREDICTED);
1383         assertBucket(STANDBY_BUCKET_RESTRICTED);
1384     }
1385 
1386     @Test
1387     @FlakyTest(bugId = 185169504)
testCascadingTimeouts()1388     public void testCascadingTimeouts() throws Exception {
1389         mInjector.mPropertiesChangedListener
1390                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1391 
1392         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1393         assertBucket(STANDBY_BUCKET_ACTIVE);
1394 
1395         reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
1396         assertBucket(STANDBY_BUCKET_ACTIVE);
1397 
1398         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
1399                 REASON_MAIN_PREDICTED);
1400         assertBucket(STANDBY_BUCKET_ACTIVE);
1401 
1402         mInjector.mElapsedRealtime = 2000 + mController.mStrongUsageTimeoutMillis;
1403         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1404                 REASON_MAIN_PREDICTED);
1405         assertBucket(STANDBY_BUCKET_WORKING_SET);
1406 
1407         mInjector.mElapsedRealtime = 2000 + mController.mNotificationSeenTimeoutMillis;
1408         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1409                 REASON_MAIN_PREDICTED);
1410         assertBucket(STANDBY_BUCKET_FREQUENT);
1411     }
1412 
1413     @Test
1414     @FlakyTest(bugId = 185169504)
testOverlappingTimeouts()1415     public void testOverlappingTimeouts() throws Exception {
1416         mInjector.mPropertiesChangedListener
1417                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1418 
1419         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1420         assertBucket(STANDBY_BUCKET_ACTIVE);
1421 
1422         reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
1423         assertBucket(STANDBY_BUCKET_ACTIVE);
1424 
1425         // Overlapping USER_INTERACTION before previous one times out
1426         reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000,
1427                 PACKAGE_1);
1428         assertBucket(STANDBY_BUCKET_ACTIVE);
1429 
1430         // Still in ACTIVE after first USER_INTERACTION times out
1431         mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
1432         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1433                 REASON_MAIN_PREDICTED);
1434         assertBucket(STANDBY_BUCKET_ACTIVE);
1435 
1436         // Both timed out, so NOTIFICATION_SEEN timeout should be effective
1437         mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
1438         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1439                 REASON_MAIN_PREDICTED);
1440         assertBucket(STANDBY_BUCKET_WORKING_SET);
1441 
1442         mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
1443         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1444                 REASON_MAIN_PREDICTED);
1445         assertBucket(STANDBY_BUCKET_RARE);
1446     }
1447 
1448     @Test
1449     @FlakyTest(bugId = 185169504)
testSystemInteractionTimeout()1450     public void testSystemInteractionTimeout() throws Exception {
1451         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1452         // Fast forward to RARE
1453         mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
1454         mController.checkIdleStates(USER_ID);
1455         assertBucket(STANDBY_BUCKET_RARE);
1456 
1457         // Trigger a SYSTEM_INTERACTION and verify bucket
1458         reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1459         assertBucket(STANDBY_BUCKET_ACTIVE);
1460 
1461         // Verify it's still in ACTIVE close to end of timeout
1462         mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100;
1463         mController.checkIdleStates(USER_ID);
1464         assertBucket(STANDBY_BUCKET_ACTIVE);
1465 
1466         // Verify bucket moves to RARE after timeout
1467         mInjector.mElapsedRealtime += 200;
1468         mController.checkIdleStates(USER_ID);
1469         assertBucket(STANDBY_BUCKET_RARE);
1470     }
1471 
1472     @Test
1473     @FlakyTest(bugId = 185169504)
testInitialForegroundServiceTimeout()1474     public void testInitialForegroundServiceTimeout() throws Exception {
1475         mInjector.mElapsedRealtime = 1 * RARE_THRESHOLD + 100;
1476         // Make sure app is in NEVER bucket
1477         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
1478                 REASON_MAIN_FORCED_BY_USER);
1479         mController.checkIdleStates(USER_ID);
1480         assertBucket(STANDBY_BUCKET_NEVER);
1481 
1482         mInjector.mElapsedRealtime += 100;
1483 
1484         // Trigger a FOREGROUND_SERVICE_START and verify bucket
1485         reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1);
1486         mController.checkIdleStates(USER_ID);
1487         assertBucket(STANDBY_BUCKET_ACTIVE);
1488 
1489         // Verify it's still in ACTIVE close to end of timeout
1490         mInjector.mElapsedRealtime += mController.mInitialForegroundServiceStartTimeoutMillis - 100;
1491         mController.checkIdleStates(USER_ID);
1492         assertBucket(STANDBY_BUCKET_ACTIVE);
1493 
1494         // Verify bucket moves to RARE after timeout
1495         mInjector.mElapsedRealtime += 200;
1496         mController.checkIdleStates(USER_ID);
1497         assertBucket(STANDBY_BUCKET_RARE);
1498 
1499         // Trigger a FOREGROUND_SERVICE_START again
1500         reportEvent(mController, FOREGROUND_SERVICE_START, mInjector.mElapsedRealtime, PACKAGE_1);
1501         mController.checkIdleStates(USER_ID);
1502         // Bucket should not be immediately elevated on subsequent service starts
1503         assertBucket(STANDBY_BUCKET_RARE);
1504     }
1505 
1506     @Test
1507     @FlakyTest(bugId = 185169504)
testPredictionNotOverridden()1508     public void testPredictionNotOverridden() throws Exception {
1509         mInjector.mPropertiesChangedListener
1510                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1511 
1512         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1513         assertBucket(STANDBY_BUCKET_ACTIVE);
1514 
1515         mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
1516         reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
1517         assertBucket(STANDBY_BUCKET_ACTIVE);
1518 
1519         // Falls back to WORKING_SET
1520         mInjector.mElapsedRealtime += 5000;
1521         mController.checkIdleStates(USER_ID);
1522         assertBucket(STANDBY_BUCKET_WORKING_SET);
1523 
1524         // Predict to ACTIVE
1525         mInjector.mElapsedRealtime += 1000;
1526         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1527                 REASON_MAIN_PREDICTED);
1528         assertBucket(STANDBY_BUCKET_ACTIVE);
1529 
1530         // CheckIdleStates should not change the prediction
1531         mInjector.mElapsedRealtime += 1000;
1532         mController.checkIdleStates(USER_ID);
1533         assertBucket(STANDBY_BUCKET_ACTIVE);
1534     }
1535 
1536     @Test
1537     @FlakyTest(bugId = 185169504)
testPredictionStrikesBack()1538     public void testPredictionStrikesBack() throws Exception {
1539         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1540         assertBucket(STANDBY_BUCKET_ACTIVE);
1541 
1542         // Predict to FREQUENT
1543         mInjector.mElapsedRealtime = RARE_THRESHOLD;
1544         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1545                 REASON_MAIN_PREDICTED);
1546         assertBucket(STANDBY_BUCKET_FREQUENT);
1547 
1548         // Add a short timeout event
1549         mInjector.mElapsedRealtime += 1000;
1550         reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1551         assertBucket(STANDBY_BUCKET_ACTIVE);
1552         mInjector.mElapsedRealtime += 1000;
1553         mController.checkIdleStates(USER_ID);
1554         assertBucket(STANDBY_BUCKET_ACTIVE);
1555 
1556         // Verify it reverted to predicted
1557         mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2;
1558         mController.checkIdleStates(USER_ID);
1559         assertBucket(STANDBY_BUCKET_FREQUENT);
1560     }
1561 
1562     @Test
1563     @FlakyTest(bugId = 185169504)
testSystemForcedFlags_NotAddedForUserForce()1564     public void testSystemForcedFlags_NotAddedForUserForce() throws Exception {
1565         final int expectedReason = REASON_MAIN_FORCED_BY_USER;
1566         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1567                 REASON_MAIN_FORCED_BY_USER);
1568         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1569         assertEquals(expectedReason, getStandbyBucketReason(PACKAGE_1));
1570 
1571         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1572                 REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE);
1573         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1574         assertEquals(expectedReason, getStandbyBucketReason(PACKAGE_1));
1575     }
1576 
1577     @Test
1578     @FlakyTest(bugId = 185169504)
testSystemForcedFlags_AddedForSystemForce()1579     public void testSystemForcedFlags_AddedForSystemForce() throws Exception {
1580         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1581                 REASON_MAIN_DEFAULT);
1582         mInjector.mElapsedRealtime += 4 * RESTRICTED_THRESHOLD;
1583 
1584         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1585                 REASON_MAIN_FORCED_BY_SYSTEM
1586                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE);
1587         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1588         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM
1589                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE,
1590                 getStandbyBucketReason(PACKAGE_1));
1591 
1592         mController.restrictApp(PACKAGE_1, USER_ID, REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE);
1593         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1594         // Flags should be combined
1595         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM
1596                 | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE
1597                 | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE, getStandbyBucketReason(PACKAGE_1));
1598     }
1599 
1600     @Test
1601     @FlakyTest(bugId = 185169504)
testSystemForcedFlags_SystemForceChangesBuckets()1602     public void testSystemForcedFlags_SystemForceChangesBuckets() throws Exception {
1603         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1604                 REASON_MAIN_DEFAULT);
1605         mInjector.mElapsedRealtime += 4 * RESTRICTED_THRESHOLD;
1606 
1607         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1608                 REASON_MAIN_FORCED_BY_SYSTEM
1609                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE);
1610         assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
1611         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM
1612                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE,
1613                 getStandbyBucketReason(PACKAGE_1));
1614 
1615         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
1616                 REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE);
1617         assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
1618         // Flags should be combined
1619         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM
1620                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE
1621                         | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE,
1622                 getStandbyBucketReason(PACKAGE_1));
1623 
1624         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1625                 REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
1626         assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
1627         // Flags should be combined
1628         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY,
1629                 getStandbyBucketReason(PACKAGE_1));
1630 
1631         mController.restrictApp(PACKAGE_1, USER_ID, REASON_SUB_FORCED_SYSTEM_FLAG_UNDEFINED);
1632         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1633         // Flags should not be combined since the bucket changed.
1634         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_UNDEFINED,
1635                 getStandbyBucketReason(PACKAGE_1));
1636     }
1637 
1638     @Test
1639     @FlakyTest(bugId = 185169504)
testRestrictApp_MainReason()1640     public void testRestrictApp_MainReason() throws Exception {
1641         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
1642                 REASON_MAIN_DEFAULT);
1643         mInjector.mElapsedRealtime += 4 * RESTRICTED_THRESHOLD;
1644 
1645         mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_PREDICTED, 0);
1646         // Call should be ignored.
1647         assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
1648 
1649         mController.restrictApp(PACKAGE_1, USER_ID, REASON_MAIN_FORCED_BY_USER, 0);
1650         // Call should go through
1651         assertEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1652     }
1653 
1654     @Test
testAddActiveDeviceAdmin()1655     public void testAddActiveDeviceAdmin() throws Exception {
1656         assertActiveAdmins(USER_ID, (String[]) null);
1657         assertActiveAdmins(USER_ID2, (String[]) null);
1658 
1659         mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
1660         assertActiveAdmins(USER_ID, ADMIN_PKG);
1661         assertActiveAdmins(USER_ID2, (String[]) null);
1662 
1663         mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
1664         assertActiveAdmins(USER_ID, ADMIN_PKG);
1665         assertActiveAdmins(USER_ID2, (String[]) null);
1666 
1667         mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
1668         assertActiveAdmins(USER_ID, ADMIN_PKG);
1669         assertActiveAdmins(USER_ID2, ADMIN_PKG2);
1670     }
1671 
1672     @Test
testSetActiveAdminApps()1673     public void testSetActiveAdminApps() {
1674         assertActiveAdmins(USER_ID, (String[]) null);
1675         assertActiveAdmins(USER_ID2, (String[]) null);
1676 
1677         setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
1678         assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
1679         assertActiveAdmins(USER_ID2, (String[]) null);
1680 
1681         mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
1682         setActiveAdmins(USER_ID2, ADMIN_PKG);
1683         assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
1684         assertActiveAdmins(USER_ID2, ADMIN_PKG);
1685 
1686         mController.setActiveAdminApps(null, USER_ID);
1687         assertActiveAdmins(USER_ID, (String[]) null);
1688     }
1689 
1690     @Test
isActiveDeviceAdmin()1691     public void isActiveDeviceAdmin() throws Exception {
1692         assertActiveAdmins(USER_ID, (String[]) null);
1693         assertActiveAdmins(USER_ID2, (String[]) null);
1694 
1695         mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
1696         assertIsActiveAdmin(ADMIN_PKG, USER_ID);
1697         assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
1698 
1699         mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
1700         mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2);
1701         assertIsActiveAdmin(ADMIN_PKG, USER_ID);
1702         assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
1703         assertIsActiveAdmin(ADMIN_PKG, USER_ID2);
1704         assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
1705 
1706         setActiveAdmins(USER_ID2, ADMIN_PKG2);
1707         assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
1708         assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
1709         assertIsActiveAdmin(ADMIN_PKG, USER_ID);
1710         assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
1711     }
1712 
1713     @Test
testSetAdminProtectedPackages()1714     public void testSetAdminProtectedPackages() {
1715         assertAdminProtectedPackagesForTest(USER_ID, (String[]) null);
1716         assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null);
1717 
1718         setAdminProtectedPackages(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2);
1719         assertAdminProtectedPackagesForTest(USER_ID, ADMIN_PROTECTED_PKG, ADMIN_PROTECTED_PKG2);
1720         assertAdminProtectedPackagesForTest(USER_ID2, (String[]) null);
1721 
1722         setAdminProtectedPackages(USER_ID, (String[]) null);
1723         assertAdminProtectedPackagesForTest(USER_ID, (String[]) null);
1724     }
1725 
1726     @Test
1727     @FlakyTest(bugId = 185169504)
testUserInteraction_CrossProfile()1728     public void testUserInteraction_CrossProfile() throws Exception {
1729         mInjector.mRunningUsers = new int[] {USER_ID, USER_ID2, USER_ID3};
1730         mInjector.mCrossProfileTargets = Arrays.asList(USER_HANDLE_USER2);
1731         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1732         assertEquals("Cross profile connected package bucket should be elevated on usage",
1733                 STANDBY_BUCKET_ACTIVE, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
1734         assertEquals("Not Cross profile connected package bucket should not be elevated on usage",
1735                 STANDBY_BUCKET_NEVER, getStandbyBucket(USER_ID3, mController, PACKAGE_1));
1736 
1737         assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID);
1738         assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE, USER_ID2);
1739 
1740         assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID);
1741         assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET, USER_ID2);
1742 
1743         mInjector.mCrossProfileTargets = Collections.emptyList();
1744         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
1745         assertEquals("No longer cross profile connected package bucket should not be "
1746                         + "elevated on usage",
1747                 STANDBY_BUCKET_WORKING_SET, getStandbyBucket(USER_ID2, mController, PACKAGE_1));
1748     }
1749 
1750     @Test
1751     @FlakyTest(bugId = 185169504)
testUnexemptedSyncScheduled()1752     public void testUnexemptedSyncScheduled() throws Exception {
1753         rearmLatch(PACKAGE_1);
1754         mController.addListener(mListener);
1755         assertEquals("Test package did not start in the Never bucket", STANDBY_BUCKET_NEVER,
1756                 getStandbyBucket(mController, PACKAGE_1));
1757 
1758         mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false);
1759         mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
1760         assertEquals("Unexempted sync scheduled should bring the package out of the Never bucket",
1761                 STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1762 
1763         setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
1764 
1765         rearmLatch(PACKAGE_1);
1766         mController.postReportSyncScheduled(PACKAGE_1, USER_ID, false);
1767         mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
1768         assertEquals("Unexempted sync scheduled should not elevate a non Never bucket",
1769                 STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
1770     }
1771 
1772     @Test
1773     @FlakyTest(bugId = 185169504)
testExemptedSyncScheduled()1774     public void testExemptedSyncScheduled() throws Exception {
1775         setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
1776         mInjector.mDeviceIdleMode = true;
1777         rearmLatch(PACKAGE_1);
1778         mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true);
1779         mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
1780         assertEquals("Exempted sync scheduled in doze should set bucket to working set",
1781                 STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
1782 
1783         setAndAssertBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE, REASON_MAIN_FORCED_BY_SYSTEM);
1784         mInjector.mDeviceIdleMode = false;
1785         rearmLatch(PACKAGE_1);
1786         mController.postReportSyncScheduled(PACKAGE_1, USER_ID, true);
1787         mStateChangedLatch.await(1000, TimeUnit.MILLISECONDS);
1788         assertEquals("Exempted sync scheduled while not in doze should set bucket to active",
1789                 STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
1790     }
1791 
1792     @Test
testAppUpdateOnRestrictedBucketStatus()1793     public void testAppUpdateOnRestrictedBucketStatus() throws Exception {
1794         // Updates shouldn't change bucket if the app timed out.
1795         // Way past all timeouts. App times out into RESTRICTED bucket.
1796         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1797         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1798         mController.checkIdleStates(USER_ID);
1799         assertBucket(STANDBY_BUCKET_RESTRICTED);
1800 
1801         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID);
1802         assertBucket(STANDBY_BUCKET_RESTRICTED);
1803         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2);
1804         assertBucket(STANDBY_BUCKET_RESTRICTED);
1805         mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID);
1806         assertBucket(STANDBY_BUCKET_RESTRICTED);
1807 
1808         // Updates shouldn't change bucket if the app was forced by the system for a non-buggy
1809         // reason.
1810         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1811         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1812         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1813                 REASON_MAIN_FORCED_BY_SYSTEM
1814                         | REASON_SUB_FORCED_SYSTEM_FLAG_BACKGROUND_RESOURCE_USAGE);
1815 
1816         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID);
1817         assertBucket(STANDBY_BUCKET_RESTRICTED);
1818         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2);
1819         assertBucket(STANDBY_BUCKET_RESTRICTED);
1820         mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID);
1821         assertBucket(STANDBY_BUCKET_RESTRICTED);
1822 
1823         // Updates should change bucket if the app was forced by the system for a buggy reason.
1824         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1825         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1826         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1827                 REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
1828 
1829         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2);
1830         assertBucket(STANDBY_BUCKET_RESTRICTED);
1831         mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID);
1832         assertBucket(STANDBY_BUCKET_RESTRICTED);
1833         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID);
1834         assertNotEquals(STANDBY_BUCKET_RESTRICTED, getStandbyBucket(mController, PACKAGE_1));
1835 
1836         // Updates shouldn't change bucket if the app was forced by the system for more than just
1837         // a buggy reason.
1838         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1839         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1840         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1841                 REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE
1842                         | REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);
1843 
1844         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID);
1845         assertBucket(STANDBY_BUCKET_RESTRICTED);
1846         assertEquals(REASON_MAIN_FORCED_BY_SYSTEM | REASON_SUB_FORCED_SYSTEM_FLAG_ABUSE,
1847                 getStandbyBucketReason(PACKAGE_1));
1848         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2);
1849         assertBucket(STANDBY_BUCKET_RESTRICTED);
1850         mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID);
1851         assertBucket(STANDBY_BUCKET_RESTRICTED);
1852 
1853         // Updates shouldn't change bucket if the app was forced by the user.
1854         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1855         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD * 4;
1856         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
1857                 REASON_MAIN_FORCED_BY_USER);
1858 
1859         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID);
1860         assertBucket(STANDBY_BUCKET_RESTRICTED);
1861         mController.maybeUnrestrictBuggyApp(PACKAGE_1, USER_ID2);
1862         assertBucket(STANDBY_BUCKET_RESTRICTED);
1863         mController.maybeUnrestrictBuggyApp("com.random.package", USER_ID);
1864         assertBucket(STANDBY_BUCKET_RESTRICTED);
1865     }
1866 
1867     @Test
testSystemHeadlessAppElevated()1868     public void testSystemHeadlessAppElevated() throws Exception {
1869         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1870         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
1871                 PACKAGE_SYSTEM_HEADFULL);
1872         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
1873                 PACKAGE_SYSTEM_HEADLESS);
1874         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
1875 
1876 
1877         mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADFULL, USER_ID, STANDBY_BUCKET_RARE,
1878                 REASON_MAIN_TIMEOUT);
1879         assertBucket(STANDBY_BUCKET_RARE, PACKAGE_SYSTEM_HEADFULL);
1880 
1881         // Make sure headless system apps don't get lowered.
1882         mController.setAppStandbyBucket(PACKAGE_SYSTEM_HEADLESS, USER_ID, STANDBY_BUCKET_RARE,
1883                 REASON_MAIN_TIMEOUT);
1884         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_SYSTEM_HEADLESS);
1885 
1886         // Package 1 doesn't have activities and is headless, but is not a system app, so it can
1887         // be lowered.
1888         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1889                 REASON_MAIN_TIMEOUT);
1890         assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
1891     }
1892 
1893     @Test
testWellbeingAppElevated()1894     public void testWellbeingAppElevated() throws Exception {
1895         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_WELLBEING);
1896         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_WELLBEING);
1897         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1898         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_1);
1899         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
1900 
1901         // Make sure the default wellbeing app does not get lowered below WORKING_SET.
1902         mController.setAppStandbyBucket(PACKAGE_WELLBEING, USER_ID, STANDBY_BUCKET_RARE,
1903                 REASON_MAIN_TIMEOUT);
1904         assertBucket(STANDBY_BUCKET_WORKING_SET, PACKAGE_WELLBEING);
1905 
1906         // A non default wellbeing app should be able to fall lower than WORKING_SET.
1907         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1908                 REASON_MAIN_TIMEOUT);
1909         assertBucket(STANDBY_BUCKET_RARE, PACKAGE_1);
1910     }
1911 
1912     @Test
testClockAppElevated()1913     public void testClockAppElevated() throws Exception {
1914         mInjector.mClockApps.add(Pair.create(PACKAGE_1, UID_1));
1915 
1916         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
1917         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_1);
1918 
1919         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_2);
1920         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_2);
1921 
1922         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
1923 
1924         // Make sure a clock app does not get lowered below WORKING_SET.
1925         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
1926                 REASON_MAIN_TIMEOUT);
1927         assertBucket(STANDBY_BUCKET_WORKING_SET, PACKAGE_1);
1928 
1929         // A non clock app should be able to fall lower than WORKING_SET.
1930         mController.setAppStandbyBucket(PACKAGE_2, USER_ID, STANDBY_BUCKET_RARE,
1931                 REASON_MAIN_TIMEOUT);
1932         assertBucket(STANDBY_BUCKET_RARE, PACKAGE_2);
1933     }
1934 
1935     @Test
testChangingSettings_ElapsedThreshold_Invalid()1936     public void testChangingSettings_ElapsedThreshold_Invalid() {
1937         mInjector.mSettingsBuilder
1938                 .setLong("elapsed_threshold_active", -1)
1939                 .setLong("elapsed_threshold_working_set", -1)
1940                 .setLong("elapsed_threshold_frequent", -1)
1941                 .setLong("elapsed_threshold_rare", -1)
1942                 .setLong("elapsed_threshold_restricted", -1);
1943         mInjector.mPropertiesChangedListener
1944                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1945         for (int i = 0; i < MINIMUM_ELAPSED_TIME_THRESHOLDS.length; ++i) {
1946             assertEquals(MINIMUM_ELAPSED_TIME_THRESHOLDS[i],
1947                     mController.mAppStandbyElapsedThresholds[i]);
1948         }
1949     }
1950 
1951     @Test
testChangingSettings_ElapsedThreshold_Valid()1952     public void testChangingSettings_ElapsedThreshold_Valid() {
1953         // Effectively clear values
1954         mInjector.mSettingsBuilder
1955                 .setString("elapsed_threshold_active", null)
1956                 .setString("elapsed_threshold_working_set", null)
1957                 .setString("elapsed_threshold_frequent", null)
1958                 .setString("elapsed_threshold_rare", null)
1959                 .setString("elapsed_threshold_restricted", null);
1960         mInjector.mPropertiesChangedListener
1961                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1962         for (int i = 0; i < DEFAULT_ELAPSED_TIME_THRESHOLDS.length; ++i) {
1963             assertEquals(DEFAULT_ELAPSED_TIME_THRESHOLDS[i],
1964                     mController.mAppStandbyElapsedThresholds[i]);
1965         }
1966 
1967         // Set really high thresholds
1968         mInjector.mSettingsBuilder
1969                 .setLong("elapsed_threshold_active", 90 * DAY_MS)
1970                 .setLong("elapsed_threshold_working_set", 91 * DAY_MS)
1971                 .setLong("elapsed_threshold_frequent", 92 * DAY_MS)
1972                 .setLong("elapsed_threshold_rare", 93 * DAY_MS)
1973                 .setLong("elapsed_threshold_restricted", 94 * DAY_MS);
1974         mInjector.mPropertiesChangedListener
1975                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1976         for (int i = 0; i < mController.mAppStandbyElapsedThresholds.length; ++i) {
1977             assertEquals((90 + i) * DAY_MS, mController.mAppStandbyElapsedThresholds[i]);
1978         }
1979 
1980         // Only set a few values
1981         mInjector.mSettingsBuilder
1982                 .setString("elapsed_threshold_active", null)
1983                 .setLong("elapsed_threshold_working_set", 31 * DAY_MS)
1984                 .setLong("elapsed_threshold_frequent", 62 * DAY_MS)
1985                 .setString("elapsed_threshold_rare", null)
1986                 .setLong("elapsed_threshold_restricted", 93 * DAY_MS);
1987         mInjector.mPropertiesChangedListener
1988                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
1989 
1990         assertEquals(DEFAULT_ELAPSED_TIME_THRESHOLDS[0],
1991                 mController.mAppStandbyElapsedThresholds[0]);
1992         assertEquals(31 * DAY_MS, mController.mAppStandbyElapsedThresholds[1]);
1993         assertEquals(62 * DAY_MS, mController.mAppStandbyElapsedThresholds[2]);
1994         assertEquals(DEFAULT_ELAPSED_TIME_THRESHOLDS[3],
1995                 mController.mAppStandbyElapsedThresholds[3]);
1996         assertEquals(93 * DAY_MS, mController.mAppStandbyElapsedThresholds[4]);
1997     }
1998 
1999     @Test
testChangingSettings_ScreenThreshold_Invalid()2000     public void testChangingSettings_ScreenThreshold_Invalid() {
2001         mInjector.mSettingsBuilder
2002                 .setLong("screen_threshold_active", -1)
2003                 .setLong("screen_threshold_working_set", -1)
2004                 .setLong("screen_threshold_frequent", -1)
2005                 .setLong("screen_threshold_rare", -1)
2006                 .setLong("screen_threshold_restricted", -1);
2007         mInjector.mPropertiesChangedListener
2008                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
2009         for (int i = 0; i < MINIMUM_SCREEN_TIME_THRESHOLDS.length; ++i) {
2010             assertEquals(MINIMUM_SCREEN_TIME_THRESHOLDS[i],
2011                     mController.mAppStandbyScreenThresholds[i]);
2012         }
2013     }
2014 
2015     @Test
testChangingSettings_ScreenThreshold_Valid()2016     public void testChangingSettings_ScreenThreshold_Valid() {
2017         // Effectively clear values
2018         mInjector.mSettingsBuilder
2019                 .setString("screen_threshold_active", null)
2020                 .setString("screen_threshold_working_set", null)
2021                 .setString("screen_threshold_frequent", null)
2022                 .setString("screen_threshold_rare", null)
2023                 .setString("screen_threshold_restricted", null);
2024         mInjector.mPropertiesChangedListener
2025                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
2026         for (int i = 0; i < DEFAULT_SCREEN_TIME_THRESHOLDS.length; ++i) {
2027             assertEquals(DEFAULT_SCREEN_TIME_THRESHOLDS[i],
2028                     mController.mAppStandbyScreenThresholds[i]);
2029         }
2030 
2031         // Set really high thresholds
2032         mInjector.mSettingsBuilder
2033                 .setLong("screen_threshold_active", 90 * DAY_MS)
2034                 .setLong("screen_threshold_working_set", 91 * DAY_MS)
2035                 .setLong("screen_threshold_frequent", 92 * DAY_MS)
2036                 .setLong("screen_threshold_rare", 93 * DAY_MS)
2037                 .setLong("screen_threshold_restricted", 94 * DAY_MS);
2038         mInjector.mPropertiesChangedListener
2039                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
2040         for (int i = 0; i < mController.mAppStandbyScreenThresholds.length; ++i) {
2041             assertEquals((90 + i) * DAY_MS, mController.mAppStandbyScreenThresholds[i]);
2042         }
2043 
2044         // Only set a few values
2045         mInjector.mSettingsBuilder
2046                 .setString("screen_threshold_active", null)
2047                 .setLong("screen_threshold_working_set", 31 * DAY_MS)
2048                 .setLong("screen_threshold_frequent", 62 * DAY_MS)
2049                 .setString("screen_threshold_rare", null)
2050                 .setLong("screen_threshold_restricted", 93 * DAY_MS);
2051         mInjector.mPropertiesChangedListener
2052                 .onPropertiesChanged(mInjector.getDeviceConfigProperties());
2053 
2054         assertEquals(DEFAULT_SCREEN_TIME_THRESHOLDS[0], mController.mAppStandbyScreenThresholds[0]);
2055         assertEquals(31 * DAY_MS, mController.mAppStandbyScreenThresholds[1]);
2056         assertEquals(62 * DAY_MS, mController.mAppStandbyScreenThresholds[2]);
2057         assertEquals(DEFAULT_SCREEN_TIME_THRESHOLDS[3], mController.mAppStandbyScreenThresholds[3]);
2058         assertEquals(93 * DAY_MS, mController.mAppStandbyScreenThresholds[4]);
2059     }
2060 
2061     /**
2062      * Package with ACCESS_BACKGROUND_LOCATION permission has minimum bucket
2063      * STANDBY_BUCKET_FREQUENT.
2064      * @throws Exception
2065      */
2066     @Test
testBackgroundLocationBucket()2067     public void testBackgroundLocationBucket() throws Exception {
2068         reportEvent(mController, USER_INTERACTION, mInjector.mElapsedRealtime,
2069                 PACKAGE_BACKGROUND_LOCATION);
2070         assertBucket(STANDBY_BUCKET_ACTIVE, PACKAGE_BACKGROUND_LOCATION);
2071 
2072         mInjector.mElapsedRealtime += RESTRICTED_THRESHOLD;
2073         // Make sure PACKAGE_BACKGROUND_LOCATION does not get lowered than STANDBY_BUCKET_FREQUENT.
2074         mController.setAppStandbyBucket(PACKAGE_BACKGROUND_LOCATION, USER_ID, STANDBY_BUCKET_RARE,
2075                 REASON_MAIN_TIMEOUT);
2076         assertBucket(STANDBY_BUCKET_FREQUENT, PACKAGE_BACKGROUND_LOCATION);
2077     }
2078 
2079     @Test
testBatteryStatsNoteEvent()2080     public void testBatteryStatsNoteEvent() throws Exception {
2081         mInjector.mExpectedNoteEventPackage = PACKAGE_1;
2082         reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
2083 
2084         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
2085                 REASON_MAIN_FORCED_BY_USER);
2086         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
2087 
2088         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
2089                 REASON_MAIN_FORCED_BY_USER);
2090         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
2091 
2092         // Since we're staying on the PACKAGE_ACTIVE side, noteEvent shouldn't be called.
2093         // Reset the last event to confirm the method isn't called.
2094         mInjector.mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
2095         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
2096                 REASON_MAIN_FORCED_BY_USER);
2097         assertEquals(BatteryStats.HistoryItem.EVENT_NONE, mInjector.mLastNoteEvent);
2098 
2099         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
2100                 REASON_MAIN_FORCED_BY_USER);
2101         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
2102 
2103         // Since we're staying on the PACKAGE_ACTIVE side, noteEvent shouldn't be called.
2104         // Reset the last event to confirm the method isn't called.
2105         mInjector.mLastNoteEvent = BatteryStats.HistoryItem.EVENT_NONE;
2106         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
2107                 REASON_MAIN_FORCED_BY_USER);
2108         assertEquals(BatteryStats.HistoryItem.EVENT_NONE, mInjector.mLastNoteEvent);
2109 
2110         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
2111                 REASON_MAIN_FORCED_BY_USER);
2112         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
2113 
2114         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RESTRICTED,
2115                 REASON_MAIN_FORCED_BY_USER);
2116         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_INACTIVE, mInjector.mLastNoteEvent);
2117 
2118         mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_EXEMPTED,
2119                 REASON_MAIN_FORCED_BY_USER);
2120         assertEquals(BatteryStats.HistoryItem.EVENT_PACKAGE_ACTIVE, mInjector.mLastNoteEvent);
2121     }
2122 
getAdminAppsStr(int userId)2123     private String getAdminAppsStr(int userId) {
2124         return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
2125     }
2126 
getAdminAppsStr(int userId, Set<String> adminApps)2127     private String getAdminAppsStr(int userId, Set<String> adminApps) {
2128         return "admin apps for u" + userId + ": "
2129                 + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray()));
2130     }
2131 
assertIsActiveAdmin(String adminApp, int userId)2132     private void assertIsActiveAdmin(String adminApp, int userId) {
2133         assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId),
2134                 mController.isActiveDeviceAdmin(adminApp, userId));
2135     }
2136 
assertIsNotActiveAdmin(String adminApp, int userId)2137     private void assertIsNotActiveAdmin(String adminApp, int userId) {
2138         assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId),
2139                 mController.isActiveDeviceAdmin(adminApp, userId));
2140     }
2141 
assertActiveAdmins(int userId, String... admins)2142     private void assertActiveAdmins(int userId, String... admins) {
2143         final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId);
2144         if (admins == null) {
2145             if (actualAdminApps != null && !actualAdminApps.isEmpty()) {
2146                 fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps));
2147             }
2148             return;
2149         }
2150         assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps)
2151                 + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size());
2152         final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps);
2153         for (String admin : admins) {
2154             adminAppsCopy.remove(admin);
2155         }
2156         assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps)
2157                 + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty());
2158     }
2159 
setActiveAdmins(int userId, String... admins)2160     private void setActiveAdmins(int userId, String... admins) {
2161         mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
2162     }
2163 
setAdminProtectedPackages(int userId, String... packageNames)2164     private void setAdminProtectedPackages(int userId, String... packageNames) {
2165         Set<String> adminProtectedPackages = packageNames != null ? new ArraySet<>(
2166                 Arrays.asList(packageNames)) : null;
2167         mController.setAdminProtectedPackages(adminProtectedPackages, userId);
2168     }
2169 
assertAdminProtectedPackagesForTest(int userId, String... packageNames)2170     private void assertAdminProtectedPackagesForTest(int userId, String... packageNames) {
2171         final Set<String> actualAdminProtectedPackages =
2172                 mController.getAdminProtectedPackagesForTest(userId);
2173         if (packageNames == null) {
2174             if (actualAdminProtectedPackages != null && !actualAdminProtectedPackages.isEmpty()) {
2175                 fail("Admin protected packages should be null; " + getAdminAppsStr(userId,
2176                         actualAdminProtectedPackages));
2177             }
2178             return;
2179         }
2180         assertEquals(packageNames.length, actualAdminProtectedPackages.size());
2181         for (String adminProtectedPackage : packageNames) {
2182             assertTrue(actualAdminProtectedPackages.contains(adminProtectedPackage));
2183         }
2184     }
2185 
setAndAssertBucket(String pkg, int user, int bucket, int reason)2186     private void setAndAssertBucket(String pkg, int user, int bucket, int reason) throws Exception {
2187         rearmLatch(pkg);
2188         mController.setAppStandbyBucket(pkg, user, bucket, reason);
2189         mStateChangedLatch.await(1, TimeUnit.SECONDS);
2190         assertEquals("Failed to set package bucket", bucket,
2191                 getStandbyBucket(mController, PACKAGE_1));
2192     }
2193 
rearmLatch(String pkgName)2194     private void rearmLatch(String pkgName) {
2195         mLatchPkgName = pkgName;
2196         mStateChangedLatch = new CountDownLatch(1);
2197     }
2198 
rearmLatch()2199     private void rearmLatch() {
2200         rearmLatch(null);
2201     }
2202 
rearmQuotaBumpLatch(String pkgName, int userId)2203     private void rearmQuotaBumpLatch(String pkgName, int userId) {
2204         mLatchPkgName = pkgName;
2205         mLatchUserId = userId;
2206         mQuotaBumpLatch = new CountDownLatch(1);
2207     }
2208 }
2209