blob: 8171469d4da4db024788efbc31433bfd0b6d9eb7 [file] [log] [blame]
Amith Yamasani17fffee2017-09-29 13:17:43 -07001/*
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
17package com.android.server.usage;
18
Amith Yamasani803eab692017-11-09 17:47:04 -080019import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
Jason Monk1918ef72018-03-14 09:20:39 -040020import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
21import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
Amith Yamasani7f53c7b2018-03-25 21:55:50 -070022import static android.app.usage.UsageEvents.Event.SYSTEM_INTERACTION;
Amith Yamasani803eab692017-11-09 17:47:04 -080023import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
Amith Yamasani119be9a2018-02-18 22:23:00 -080024import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
25import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
26import static android.app.usage.UsageStatsManager.REASON_MAIN_PREDICTED;
27import static android.app.usage.UsageStatsManager.REASON_MAIN_TIMEOUT;
28import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080029import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_ACTIVE;
Amith Yamasani777b1532018-01-28 23:20:07 +000030import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_EXEMPTED;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080031import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
Amith Yamasani93885192017-12-13 11:52:10 -080032import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
Amith Yamasaniafbccb72017-11-27 10:44:24 -080033import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
34import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
Amith Yamasani803eab692017-11-09 17:47:04 -080035
Amith Yamasani17fffee2017-09-29 13:17:43 -070036import static org.junit.Assert.assertEquals;
37import static org.junit.Assert.assertFalse;
38import static org.junit.Assert.assertNotEquals;
39import static org.junit.Assert.assertTrue;
Sudheer Shanka101c3532018-01-08 16:28:42 -080040import static org.junit.Assert.fail;
Amith Yamasani777b1532018-01-28 23:20:07 +000041import static org.mockito.ArgumentMatchers.eq;
Amith Yamasani17fffee2017-09-29 13:17:43 -070042import static org.mockito.Matchers.anyInt;
Amith Yamasani17fffee2017-09-29 13:17:43 -070043import static org.mockito.Mockito.doReturn;
44import static org.mockito.Mockito.mock;
45
Varun Shah7609b752018-10-15 15:07:47 -070046import android.app.usage.AppStandbyInfo;
Amith Yamasani17fffee2017-09-29 13:17:43 -070047import android.app.usage.UsageEvents;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -070048import android.app.usage.UsageStatsManagerInternal;
Amith Yamasani17fffee2017-09-29 13:17:43 -070049import android.appwidget.AppWidgetManager;
50import android.content.Context;
51import android.content.ContextWrapper;
52import android.content.pm.ApplicationInfo;
53import android.content.pm.PackageInfo;
54import android.content.pm.PackageManager;
55import android.hardware.display.DisplayManager;
56import android.os.Handler;
57import android.os.Looper;
58import android.os.RemoteException;
Amith Yamasani53f06ea2018-01-05 17:53:46 -080059import android.platform.test.annotations.Presubmit;
Sudheer Shanka101c3532018-01-08 16:28:42 -080060import android.util.ArraySet;
Amith Yamasani17fffee2017-09-29 13:17:43 -070061import android.view.Display;
62
Brett Chabota26eda92018-07-23 13:08:30 -070063import androidx.test.InstrumentationRegistry;
David James3bd6d2e2019-01-13 21:05:49 +000064import androidx.test.filters.FlakyTest;
Brett Chabota26eda92018-07-23 13:08:30 -070065import androidx.test.filters.SmallTest;
66import androidx.test.runner.AndroidJUnit4;
67
Amith Yamasani17fffee2017-09-29 13:17:43 -070068import com.android.server.SystemService;
69
70import org.junit.Before;
71import org.junit.Test;
72import org.junit.runner.RunWith;
73
74import java.io.File;
75import java.util.ArrayList;
Sudheer Shanka101c3532018-01-08 16:28:42 -080076import java.util.Arrays;
Amith Yamasani17fffee2017-09-29 13:17:43 -070077import java.util.List;
Sudheer Shanka101c3532018-01-08 16:28:42 -080078import java.util.Set;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -070079import java.util.concurrent.CountDownLatch;
80import java.util.concurrent.TimeUnit;
Amith Yamasani17fffee2017-09-29 13:17:43 -070081
82/**
83 * Unit test for AppStandbyController.
84 */
85@RunWith(AndroidJUnit4.class)
Amith Yamasani53f06ea2018-01-05 17:53:46 -080086@Presubmit
87@SmallTest
Amith Yamasani17fffee2017-09-29 13:17:43 -070088public class AppStandbyControllerTests {
89
90 private static final String PACKAGE_1 = "com.example.foo";
91 private static final int UID_1 = 10000;
Amith Yamasani777b1532018-01-28 23:20:07 +000092 private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
93 private static final int UID_EXEMPTED_1 = 10001;
Amith Yamasani17fffee2017-09-29 13:17:43 -070094 private static final int USER_ID = 0;
Sudheer Shanka101c3532018-01-08 16:28:42 -080095 private static final int USER_ID2 = 10;
96
Varun Shah7609b752018-10-15 15:07:47 -070097 private static final String PACKAGE_UNKNOWN = "com.example.unknown";
98
Sudheer Shanka101c3532018-01-08 16:28:42 -080099 private static final String ADMIN_PKG = "com.android.admin";
100 private static final String ADMIN_PKG2 = "com.android.admin2";
101 private static final String ADMIN_PKG3 = "com.android.admin3";
Amith Yamasani17fffee2017-09-29 13:17:43 -0700102
103 private static final long MINUTE_MS = 60 * 1000;
104 private static final long HOUR_MS = 60 * MINUTE_MS;
105 private static final long DAY_MS = 24 * HOUR_MS;
106
Amith Yamasani301e94a2017-11-17 16:35:44 -0800107 private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
108 private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
109 private static final long RARE_THRESHOLD = 48 * HOUR_MS;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700110 // Short STABLE_CHARGING_THRESHOLD for testing purposes
111 private static final long STABLE_CHARGING_THRESHOLD = 2000;
Amith Yamasani301e94a2017-11-17 16:35:44 -0800112
Varun Shah7609b752018-10-15 15:07:47 -0700113 /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
114 private static boolean isPackageInstalled = true;
115
Amith Yamasani17fffee2017-09-29 13:17:43 -0700116 private MyInjector mInjector;
Amith Yamasani93885192017-12-13 11:52:10 -0800117 private AppStandbyController mController;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700118
119 static class MyContextWrapper extends ContextWrapper {
120 PackageManager mockPm = mock(PackageManager.class);
121
122 public MyContextWrapper(Context base) {
123 super(base);
124 }
125
126 public PackageManager getPackageManager() {
127 return mockPm;
128 }
129 }
130
131 static class MyInjector extends AppStandbyController.Injector {
132 long mElapsedRealtime;
Kweku Adams1e8947c2018-11-05 18:06:13 -0800133 boolean mIsAppIdleEnabled = true;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700134 boolean mIsCharging;
135 List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
136 boolean mDisplayOn;
137 DisplayManager.DisplayListener mDisplayListener;
Amith Yamasani777b1532018-01-28 23:20:07 +0000138 String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700139
140 MyInjector(Context context, Looper looper) {
141 super(context, looper);
142 }
143
144 @Override
145 void onBootPhase(int phase) {
146 }
147
148 @Override
149 int getBootPhase() {
150 return SystemService.PHASE_BOOT_COMPLETED;
151 }
152
153 @Override
154 long elapsedRealtime() {
155 return mElapsedRealtime;
156 }
157
158 @Override
159 long currentTimeMillis() {
160 return mElapsedRealtime;
161 }
162
163 @Override
164 boolean isAppIdleEnabled() {
Kweku Adams1e8947c2018-11-05 18:06:13 -0800165 return mIsAppIdleEnabled;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700166 }
167
168 @Override
169 boolean isCharging() {
170 return mIsCharging;
171 }
172
173 @Override
174 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
175 return mPowerSaveWhitelistExceptIdle.contains(packageName);
176 }
177
178 @Override
179 File getDataSystemDirectory() {
180 return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
181 }
182
183 @Override
184 void noteEvent(int event, String packageName, int uid) throws RemoteException {
185 }
186
187 @Override
188 boolean isPackageEphemeral(int userId, String packageName) {
189 // TODO: update when testing ephemeral apps scenario
190 return false;
191 }
192
193 @Override
Varun Shah7609b752018-10-15 15:07:47 -0700194 boolean isPackageInstalled(String packageName, int flags, int userId) {
195 // Should always return true (default value) unless testing for an uninstalled app
196 return isPackageInstalled;
197 }
198
199 @Override
Amith Yamasani17fffee2017-09-29 13:17:43 -0700200 int[] getRunningUserIds() {
201 return new int[] {USER_ID};
202 }
203
204 @Override
205 boolean isDefaultDisplayOn() {
206 return mDisplayOn;
207 }
208
209 @Override
210 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
211 mDisplayListener = listener;
212 }
213
214 @Override
215 String getActiveNetworkScorer() {
216 return null;
217 }
218
219 @Override
220 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
221 int userId) {
222 return packageName != null && packageName.equals(mBoundWidgetPackage);
223 }
224
Amith Yamasani301e94a2017-11-17 16:35:44 -0800225 @Override
226 String getAppIdleSettings() {
227 return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
228 + WORKING_SET_THRESHOLD + "/"
229 + FREQUENT_THRESHOLD + "/"
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700230 + RARE_THRESHOLD + ","
231 + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
Amith Yamasani301e94a2017-11-17 16:35:44 -0800232 }
233
Makoto Onukid5f25d22018-05-22 16:02:17 -0700234 @Override
235 public boolean isDeviceIdleMode() {
236 return false;
237 }
238
Amith Yamasani17fffee2017-09-29 13:17:43 -0700239 // Internal methods
240
241 void setDisplayOn(boolean on) {
242 mDisplayOn = on;
243 if (mDisplayListener != null) {
244 mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY);
245 }
246 }
247 }
248
249 private void setupPm(PackageManager mockPm) throws PackageManager.NameNotFoundException {
250 List<PackageInfo> packages = new ArrayList<>();
251 PackageInfo pi = new PackageInfo();
252 pi.applicationInfo = new ApplicationInfo();
253 pi.applicationInfo.uid = UID_1;
254 pi.packageName = PACKAGE_1;
255 packages.add(pi);
256
Amith Yamasani777b1532018-01-28 23:20:07 +0000257 PackageInfo pie = new PackageInfo();
258 pie.applicationInfo = new ApplicationInfo();
259 pie.applicationInfo.uid = UID_EXEMPTED_1;
260 pie.packageName = PACKAGE_EXEMPTED_1;
261 packages.add(pie);
262
Amith Yamasani17fffee2017-09-29 13:17:43 -0700263 doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
264 try {
Amith Yamasani777b1532018-01-28 23:20:07 +0000265 doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
266 doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
267 anyInt(), anyInt());
268 doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
269 anyInt());
270 doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
271 anyInt());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700272 } catch (PackageManager.NameNotFoundException nnfe) {}
273 }
274
275 private void setChargingState(AppStandbyController controller, boolean charging) {
276 mInjector.mIsCharging = charging;
277 if (controller != null) {
278 controller.setChargingState(charging);
279 }
280 }
281
Kweku Adams1e8947c2018-11-05 18:06:13 -0800282 private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
283 mInjector.mIsAppIdleEnabled = enabled;
284 if (controller != null) {
285 controller.setAppIdleEnabled(enabled);
286 }
287 }
288
Amith Yamasani17fffee2017-09-29 13:17:43 -0700289 private AppStandbyController setupController() throws Exception {
290 mInjector.mElapsedRealtime = 0;
Amith Yamasani777b1532018-01-28 23:20:07 +0000291 setupPm(mInjector.getContext().getPackageManager());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700292 AppStandbyController controller = new AppStandbyController(mInjector);
Amith Yamasani777b1532018-01-28 23:20:07 +0000293 controller.initializeDefaultsForSystemApps(USER_ID);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700294 controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
295 controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
296 mInjector.setDisplayOn(false);
297 mInjector.setDisplayOn(true);
298 setChargingState(controller, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700299 controller.checkIdleStates(USER_ID);
Amith Yamasani777b1532018-01-28 23:20:07 +0000300 assertEquals(STANDBY_BUCKET_EXEMPTED,
301 controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
302 mInjector.mElapsedRealtime, false));
303 assertNotEquals(STANDBY_BUCKET_EXEMPTED,
304 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
305 mInjector.mElapsedRealtime, false));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700306
307 return controller;
308 }
309
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700310 private long getCurrentTime() {
311 return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
312 }
313
Amith Yamasani17fffee2017-09-29 13:17:43 -0700314 @Before
315 public void setUp() throws Exception {
316 MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
317 mInjector = new MyInjector(myContext, Looper.getMainLooper());
Amith Yamasani93885192017-12-13 11:52:10 -0800318 mController = setupController();
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700319 setChargingState(mController, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700320 }
321
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700322 private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener {
323 private boolean mOnParole = false;
324 private CountDownLatch mLatch;
325 private long mLastParoleChangeTime;
326
327 public boolean getParoleState() {
328 synchronized (this) {
329 return mOnParole;
330 }
331 }
332
333 public void rearmLatch() {
334 synchronized (this) {
335 mLatch = new CountDownLatch(1);
336 }
337 }
338
339 public void awaitOnLatch(long time) throws Exception {
340 mLatch.await(time, TimeUnit.MILLISECONDS);
341 }
342
343 public long getLastParoleChangeTime() {
344 synchronized (this) {
345 return mLastParoleChangeTime;
346 }
347 }
348
349 @Override
350 public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
351 int bucket, int reason) {
352 }
353
354 @Override
355 public void onParoleStateChanged(boolean isParoleOn) {
356 synchronized (this) {
357 // Only record information if it is being looked for
Kweku Adams1e8947c2018-11-05 18:06:13 -0800358 if (mLatch != null && mLatch.getCount() > 0) {
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700359 mOnParole = isParoleOn;
360 mLastParoleChangeTime = getCurrentTime();
361 mLatch.countDown();
362 }
363 }
364 }
365 }
366
Amith Yamasani17fffee2017-09-29 13:17:43 -0700367 @Test
368 public void testCharging() throws Exception {
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700369 long startTime;
370 TestParoleListener paroleListener = new TestParoleListener();
371 long marginOfError = 200;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700372
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700373 // Charging
374 paroleListener.rearmLatch();
375 mController.addListener(paroleListener);
376 startTime = getCurrentTime();
Amith Yamasani93885192017-12-13 11:52:10 -0800377 setChargingState(mController, true);
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700378 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
379 assertTrue(paroleListener.mOnParole);
380 // Parole will only be granted after device has been charging for a sufficient amount of
381 // time.
382 assertEquals(STABLE_CHARGING_THRESHOLD,
383 paroleListener.getLastParoleChangeTime() - startTime,
384 marginOfError);
385
386 // Discharging
387 paroleListener.rearmLatch();
388 startTime = getCurrentTime();
389 setChargingState(mController, false);
390 mController.checkIdleStates(USER_ID);
391 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
392 assertFalse(paroleListener.getParoleState());
393 // Parole should be revoked immediately
394 assertEquals(0,
395 paroleListener.getLastParoleChangeTime() - startTime,
396 marginOfError);
397
398 // Brief Charging
399 paroleListener.rearmLatch();
400 setChargingState(mController, true);
401 setChargingState(mController, false);
402 // Device stopped charging before the stable charging threshold.
403 // Parole should not be granted at the end of the threshold
404 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
405 assertFalse(paroleListener.getParoleState());
406
407 // Charging Again
408 paroleListener.rearmLatch();
409 startTime = getCurrentTime();
410 setChargingState(mController, true);
411 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
412 assertTrue(paroleListener.getParoleState());
413 assertTrue(paroleListener.mOnParole);
414 assertEquals(STABLE_CHARGING_THRESHOLD,
415 paroleListener.getLastParoleChangeTime() - startTime,
416 marginOfError);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700417 }
418
Kweku Adams1e8947c2018-11-05 18:06:13 -0800419 @Test
David James3bd6d2e2019-01-13 21:05:49 +0000420 @FlakyTest(bugId = 119774928)
Kweku Adams1e8947c2018-11-05 18:06:13 -0800421 public void testEnabledState() throws Exception {
422 TestParoleListener paroleListener = new TestParoleListener();
423 mController.addListener(paroleListener);
424 long lastUpdateTime;
425
426 // Test that listeners are notified if enabled changes when the device is not in parole.
427 setChargingState(mController, false);
428
429 // Start off not enabled. Device is effectively on permanent parole.
430 setAppIdleEnabled(mController, false);
431
432 // Enable controller
433 paroleListener.rearmLatch();
434 setAppIdleEnabled(mController, true);
435 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
436 assertFalse(paroleListener.mOnParole);
437 lastUpdateTime = paroleListener.getLastParoleChangeTime();
438
439 paroleListener.rearmLatch();
440 setAppIdleEnabled(mController, true);
441 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
442 assertFalse(paroleListener.mOnParole);
443 // Make sure AppStandbyController doesn't notify listeners when there's no change.
444 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
445
446 // Disable controller
447 paroleListener.rearmLatch();
448 setAppIdleEnabled(mController, false);
449 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
450 assertTrue(paroleListener.mOnParole);
451 lastUpdateTime = paroleListener.getLastParoleChangeTime();
452
453 paroleListener.rearmLatch();
454 setAppIdleEnabled(mController, false);
455 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
456 assertTrue(paroleListener.mOnParole);
457 // Make sure AppStandbyController doesn't notify listeners when there's no change.
458 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
459
460
461 // Test that listeners aren't notified if enabled status changes when the device is already
462 // in parole.
463
464 // A device is in parole whenever it's charging.
465 setChargingState(mController, true);
466
467 // Start off not enabled.
468 paroleListener.rearmLatch();
469 setAppIdleEnabled(mController, false);
470 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
471 assertTrue(paroleListener.mOnParole);
472 lastUpdateTime = paroleListener.getLastParoleChangeTime();
473
474 // Test that toggling doesn't notify the listener.
475 paroleListener.rearmLatch();
476 setAppIdleEnabled(mController, true);
477 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
478 assertTrue(paroleListener.mOnParole);
479 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
480
481 paroleListener.rearmLatch();
482 setAppIdleEnabled(mController, false);
483 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
484 assertTrue(paroleListener.mOnParole);
485 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
486 }
487
Amith Yamasani17fffee2017-09-29 13:17:43 -0700488 private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
489 mInjector.mElapsedRealtime = elapsedTime;
490 controller.checkIdleStates(USER_ID);
491 assertEquals(bucket,
492 controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
493 false));
494 }
495
Varun Shah7609b752018-10-15 15:07:47 -0700496 private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime,
497 String packageName) {
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800498 // Back to ACTIVE on event
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800499 mInjector.mElapsedRealtime = elapsedTime;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800500 UsageEvents.Event ev = new UsageEvents.Event();
Varun Shah7609b752018-10-15 15:07:47 -0700501 ev.mPackage = packageName;
Amith Yamasani803eab692017-11-09 17:47:04 -0800502 ev.mEventType = eventType;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800503 controller.reportEvent(ev, elapsedTime, USER_ID);
504 }
505
Varun Shah7609b752018-10-15 15:07:47 -0700506 private int getStandbyBucket(AppStandbyController controller, String packageName) {
507 return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime,
Amith Yamasani803eab692017-11-09 17:47:04 -0800508 true);
509 }
510
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800511 private void assertBucket(int bucket) {
Varun Shah7609b752018-10-15 15:07:47 -0700512 assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800513 }
514
Amith Yamasani17fffee2017-09-29 13:17:43 -0700515 @Test
516 public void testBuckets() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800517 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700518
Varun Shah7609b752018-10-15 15:07:47 -0700519 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800520
Amith Yamasani17fffee2017-09-29 13:17:43 -0700521 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800522 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700523
524 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800525 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700526
527 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800528 assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700529
530 // FREQUENT bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800531 assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700532
533 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800534 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700535
Varun Shah7609b752018-10-15 15:07:47 -0700536 reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700537
Amith Yamasani93885192017-12-13 11:52:10 -0800538 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700539
540 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800541 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700542 }
543
544 @Test
Varun Shah7609b752018-10-15 15:07:47 -0700545 public void testSetAppStandbyBucket() throws Exception {
546 // For a known package, standby bucket should be set properly
547 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
548 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
549 REASON_MAIN_TIMEOUT, HOUR_MS);
550 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
551
552 // For an unknown package, standby bucket should not be set, hence NEVER is returned
553 // Ensure the unknown package is not already in history by removing it
554 mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
555 isPackageInstalled = false; // Mock package is not installed
556 mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
557 REASON_MAIN_TIMEOUT, HOUR_MS);
558 isPackageInstalled = true; // Reset mocked variable for other tests
559 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
560 }
561
562 @Test
563 public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
564 // On package install, standby bucket should be ACTIVE
565 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
566 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN));
567
568 // On uninstall, package should not exist in history and should return a NEVER bucket
569 mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
570 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
571 // Ensure uninstalled app is not in history
572 List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID);
573 for(AppStandbyInfo bucket : buckets) {
574 if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) {
575 fail("packageName found in app idle history after uninstall.");
576 }
577 }
578 }
579
580 @Test
Amith Yamasani17fffee2017-09-29 13:17:43 -0700581 public void testScreenTimeAndBuckets() throws Exception {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700582 mInjector.setDisplayOn(false);
583
Amith Yamasani93885192017-12-13 11:52:10 -0800584 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800585
Varun Shah7609b752018-10-15 15:07:47 -0700586 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800587
Amith Yamasani17fffee2017-09-29 13:17:43 -0700588 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800589 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700590
591 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800592 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700593
594 // RARE bucket, should fail because the screen wasn't ON.
Amith Yamasani301e94a2017-11-17 16:35:44 -0800595 mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
Amith Yamasani93885192017-12-13 11:52:10 -0800596 mController.checkIdleStates(USER_ID);
Varun Shah7609b752018-10-15 15:07:47 -0700597 assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700598
599 mInjector.setDisplayOn(true);
Amith Yamasani93885192017-12-13 11:52:10 -0800600 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700601 }
602
603 @Test
604 public void testForcedIdle() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800605 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700606 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800607 assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700608
Amith Yamasani93885192017-12-13 11:52:10 -0800609 mController.forceIdleState(PACKAGE_1, USER_ID, false);
610 assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700611 true));
Amith Yamasani93885192017-12-13 11:52:10 -0800612 assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700613 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800614
615 @Test
616 public void testNotificationEvent() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700617 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
618 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800619 mInjector.mElapsedRealtime = 1;
Varun Shah7609b752018-10-15 15:07:47 -0700620 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
621 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800622
Amith Yamasani93885192017-12-13 11:52:10 -0800623 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700624 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
625 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800626 }
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800627
628 @Test
Jason Monk1918ef72018-03-14 09:20:39 -0400629 public void testSlicePinnedEvent() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700630 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
631 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400632 mInjector.mElapsedRealtime = 1;
Varun Shah7609b752018-10-15 15:07:47 -0700633 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
634 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400635
636 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700637 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
638 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400639 }
640
641 @Test
642 public void testSlicePinnedPrivEvent() throws Exception {
Jason Monk1918ef72018-03-14 09:20:39 -0400643 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700644 reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
645 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400646 }
647
648 @Test
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800649 public void testPredictionTimedout() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800650 // Set it to timeout or usage, so that prediction can override it
651 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700652 REASON_MAIN_TIMEOUT, HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700653 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800654
655 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700656 REASON_MAIN_PREDICTED, HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700657 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800658
659 // Fast forward 12 hours
660 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800661 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800662 // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
Varun Shah7609b752018-10-15 15:07:47 -0700663 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800664 // Fast forward two more hours
665 mInjector.mElapsedRealtime += 2 * HOUR_MS;
Amith Yamasani93885192017-12-13 11:52:10 -0800666 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800667 // Should have now applied prediction timeout
Varun Shah7609b752018-10-15 15:07:47 -0700668 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800669
670 // Fast forward RARE bucket
671 mInjector.mElapsedRealtime += RARE_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800672 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800673 // Should continue to apply prediction timeout
Varun Shah7609b752018-10-15 15:07:47 -0700674 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800675 }
676
677 @Test
678 public void testOverrides() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800679 // Can force to NEVER
680 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800681 REASON_MAIN_FORCED, 1 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700682 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800683
684 // Prediction can't override FORCED reason
685 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800686 REASON_MAIN_FORCED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800687 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800688 REASON_MAIN_PREDICTED, 1 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700689 assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800690
691 // Prediction can't override NEVER
692 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800693 REASON_MAIN_DEFAULT, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800694 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800695 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700696 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800697
698 // Prediction can't set to NEVER
699 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800700 REASON_MAIN_USAGE, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800701 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800702 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700703 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800704 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800705
706 @Test
707 public void testTimeout() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700708 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800709 assertBucket(STANDBY_BUCKET_ACTIVE);
710
711 mInjector.mElapsedRealtime = 2000;
712 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800713 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800714 assertBucket(STANDBY_BUCKET_ACTIVE);
715
716 // bucketing works after timeout
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700717 mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100;
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800718 mController.checkIdleStates(USER_ID);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700719 // Use recent prediction
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800720 assertBucket(STANDBY_BUCKET_FREQUENT);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700721
722 // Way past prediction timeout, use system thresholds
723 mInjector.mElapsedRealtime = RARE_THRESHOLD * 4;
724 mController.checkIdleStates(USER_ID);
725 assertBucket(STANDBY_BUCKET_RARE);
Sudheer Shanka101c3532018-01-08 16:28:42 -0800726 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800727
Sudheer Shanka101c3532018-01-08 16:28:42 -0800728 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800729 public void testCascadingTimeouts() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700730 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800731 assertBucket(STANDBY_BUCKET_ACTIVE);
732
Varun Shah7609b752018-10-15 15:07:47 -0700733 reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800734 assertBucket(STANDBY_BUCKET_ACTIVE);
735
736 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800737 REASON_MAIN_PREDICTED, 1000);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800738 assertBucket(STANDBY_BUCKET_ACTIVE);
739
740 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800741 REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800742 assertBucket(STANDBY_BUCKET_WORKING_SET);
743
744 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800745 REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800746 assertBucket(STANDBY_BUCKET_FREQUENT);
747 }
748
749 @Test
750 public void testOverlappingTimeouts() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700751 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800752 assertBucket(STANDBY_BUCKET_ACTIVE);
753
Varun Shah7609b752018-10-15 15:07:47 -0700754 reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800755 assertBucket(STANDBY_BUCKET_ACTIVE);
756
757 // Overlapping USER_INTERACTION before previous one times out
Varun Shah7609b752018-10-15 15:07:47 -0700758 reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000,
759 PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800760 assertBucket(STANDBY_BUCKET_ACTIVE);
761
762 // Still in ACTIVE after first USER_INTERACTION times out
763 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
764 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800765 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800766 assertBucket(STANDBY_BUCKET_ACTIVE);
767
768 // Both timed out, so NOTIFICATION_SEEN timeout should be effective
769 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
770 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800771 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800772 assertBucket(STANDBY_BUCKET_WORKING_SET);
773
774 mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
775 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800776 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800777 assertBucket(STANDBY_BUCKET_RARE);
778 }
779
780 @Test
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700781 public void testSystemInteractionTimeout() throws Exception {
782 setChargingState(mController, false);
783
Varun Shah7609b752018-10-15 15:07:47 -0700784 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700785 // Fast forward to RARE
786 mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
787 mController.checkIdleStates(USER_ID);
788 assertBucket(STANDBY_BUCKET_RARE);
789
790 // Trigger a SYSTEM_INTERACTION and verify bucket
Varun Shah7609b752018-10-15 15:07:47 -0700791 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700792 assertBucket(STANDBY_BUCKET_ACTIVE);
793
794 // Verify it's still in ACTIVE close to end of timeout
795 mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100;
796 mController.checkIdleStates(USER_ID);
797 assertBucket(STANDBY_BUCKET_ACTIVE);
798
799 // Verify bucket moves to RARE after timeout
800 mInjector.mElapsedRealtime += 200;
801 mController.checkIdleStates(USER_ID);
802 assertBucket(STANDBY_BUCKET_RARE);
803 }
804
805 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800806 public void testPredictionNotOverridden() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700807 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800808 assertBucket(STANDBY_BUCKET_ACTIVE);
809
810 mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
Varun Shah7609b752018-10-15 15:07:47 -0700811 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800812 assertBucket(STANDBY_BUCKET_ACTIVE);
813
814 // Falls back to WORKING_SET
815 mInjector.mElapsedRealtime += 5000;
816 mController.checkIdleStates(USER_ID);
817 assertBucket(STANDBY_BUCKET_WORKING_SET);
818
819 // Predict to ACTIVE
820 mInjector.mElapsedRealtime += 1000;
821 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800822 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800823 assertBucket(STANDBY_BUCKET_ACTIVE);
824
825 // CheckIdleStates should not change the prediction
826 mInjector.mElapsedRealtime += 1000;
827 mController.checkIdleStates(USER_ID);
828 assertBucket(STANDBY_BUCKET_ACTIVE);
829 }
830
831 @Test
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700832 public void testPredictionStrikesBack() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700833 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700834 assertBucket(STANDBY_BUCKET_ACTIVE);
835
836 // Predict to FREQUENT
837 mInjector.mElapsedRealtime = RARE_THRESHOLD;
838 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
839 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
840 assertBucket(STANDBY_BUCKET_FREQUENT);
841
842 // Add a short timeout event
843 mInjector.mElapsedRealtime += 1000;
Varun Shah7609b752018-10-15 15:07:47 -0700844 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700845 assertBucket(STANDBY_BUCKET_ACTIVE);
846 mInjector.mElapsedRealtime += 1000;
847 mController.checkIdleStates(USER_ID);
848 assertBucket(STANDBY_BUCKET_ACTIVE);
849
850 // Verify it reverted to predicted
851 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2;
852 mController.checkIdleStates(USER_ID);
853 assertBucket(STANDBY_BUCKET_FREQUENT);
854 }
855
856 @Test
Sudheer Shanka101c3532018-01-08 16:28:42 -0800857 public void testAddActiveDeviceAdmin() {
858 assertActiveAdmins(USER_ID, (String[]) null);
859 assertActiveAdmins(USER_ID2, (String[]) null);
860
861 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
862 assertActiveAdmins(USER_ID, ADMIN_PKG);
863 assertActiveAdmins(USER_ID2, (String[]) null);
864
865 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
866 assertActiveAdmins(USER_ID, ADMIN_PKG);
867 assertActiveAdmins(USER_ID2, (String[]) null);
868
869 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
870 assertActiveAdmins(USER_ID, ADMIN_PKG);
871 assertActiveAdmins(USER_ID2, ADMIN_PKG2);
872 }
873
874 @Test
875 public void testSetActiveAdminApps() {
876 assertActiveAdmins(USER_ID, (String[]) null);
877 assertActiveAdmins(USER_ID2, (String[]) null);
878
879 setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
880 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
881 assertActiveAdmins(USER_ID2, (String[]) null);
882
883 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
884 setActiveAdmins(USER_ID2, ADMIN_PKG);
885 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
886 assertActiveAdmins(USER_ID2, ADMIN_PKG);
887
888 mController.setActiveAdminApps(null, USER_ID);
889 assertActiveAdmins(USER_ID, (String[]) null);
890 }
891
892 @Test
893 public void isActiveDeviceAdmin() {
894 assertActiveAdmins(USER_ID, (String[]) null);
895 assertActiveAdmins(USER_ID2, (String[]) null);
896
897 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
898 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
899 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
900
901 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
902 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2);
903 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
904 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
905 assertIsActiveAdmin(ADMIN_PKG, USER_ID2);
906 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
907
908 setActiveAdmins(USER_ID2, ADMIN_PKG2);
909 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
910 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
911 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
912 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
913 }
914
915 private String getAdminAppsStr(int userId) {
916 return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
917 }
918
919 private String getAdminAppsStr(int userId, Set<String> adminApps) {
920 return "admin apps for u" + userId + ": "
921 + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray()));
922 }
923
924 private void assertIsActiveAdmin(String adminApp, int userId) {
925 assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId),
926 mController.isActiveDeviceAdmin(adminApp, userId));
927 }
928
929 private void assertIsNotActiveAdmin(String adminApp, int userId) {
930 assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId),
931 mController.isActiveDeviceAdmin(adminApp, userId));
932 }
933
934 private void assertActiveAdmins(int userId, String... admins) {
935 final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId);
936 if (admins == null) {
937 if (actualAdminApps != null && !actualAdminApps.isEmpty()) {
938 fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps));
939 }
940 return;
941 }
942 assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps)
943 + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size());
944 final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps);
945 for (String admin : admins) {
946 adminAppsCopy.remove(admin);
947 }
948 assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps)
949 + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty());
950 }
951
952 private void setActiveAdmins(int userId, String... admins) {
953 mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800954 }
Amith Yamasani17fffee2017-09-29 13:17:43 -0700955}