blob: 6ec864c0525888a5f13836486713e2200dff9a31 [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;
64import androidx.test.filters.SmallTest;
65import androidx.test.runner.AndroidJUnit4;
66
Amith Yamasani17fffee2017-09-29 13:17:43 -070067import com.android.server.SystemService;
68
69import org.junit.Before;
70import org.junit.Test;
71import org.junit.runner.RunWith;
72
73import java.io.File;
74import java.util.ArrayList;
Sudheer Shanka101c3532018-01-08 16:28:42 -080075import java.util.Arrays;
Amith Yamasani17fffee2017-09-29 13:17:43 -070076import java.util.List;
Sudheer Shanka101c3532018-01-08 16:28:42 -080077import java.util.Set;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -070078import java.util.concurrent.CountDownLatch;
79import java.util.concurrent.TimeUnit;
Amith Yamasani17fffee2017-09-29 13:17:43 -070080
81/**
82 * Unit test for AppStandbyController.
83 */
84@RunWith(AndroidJUnit4.class)
Amith Yamasani53f06ea2018-01-05 17:53:46 -080085@Presubmit
86@SmallTest
Amith Yamasani17fffee2017-09-29 13:17:43 -070087public class AppStandbyControllerTests {
88
89 private static final String PACKAGE_1 = "com.example.foo";
90 private static final int UID_1 = 10000;
Amith Yamasani777b1532018-01-28 23:20:07 +000091 private static final String PACKAGE_EXEMPTED_1 = "com.android.exempted";
92 private static final int UID_EXEMPTED_1 = 10001;
Amith Yamasani17fffee2017-09-29 13:17:43 -070093 private static final int USER_ID = 0;
Sudheer Shanka101c3532018-01-08 16:28:42 -080094 private static final int USER_ID2 = 10;
95
Varun Shah7609b752018-10-15 15:07:47 -070096 private static final String PACKAGE_UNKNOWN = "com.example.unknown";
97
Sudheer Shanka101c3532018-01-08 16:28:42 -080098 private static final String ADMIN_PKG = "com.android.admin";
99 private static final String ADMIN_PKG2 = "com.android.admin2";
100 private static final String ADMIN_PKG3 = "com.android.admin3";
Amith Yamasani17fffee2017-09-29 13:17:43 -0700101
102 private static final long MINUTE_MS = 60 * 1000;
103 private static final long HOUR_MS = 60 * MINUTE_MS;
104 private static final long DAY_MS = 24 * HOUR_MS;
105
Amith Yamasani301e94a2017-11-17 16:35:44 -0800106 private static final long WORKING_SET_THRESHOLD = 12 * HOUR_MS;
107 private static final long FREQUENT_THRESHOLD = 24 * HOUR_MS;
108 private static final long RARE_THRESHOLD = 48 * HOUR_MS;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700109 // Short STABLE_CHARGING_THRESHOLD for testing purposes
110 private static final long STABLE_CHARGING_THRESHOLD = 2000;
Amith Yamasani301e94a2017-11-17 16:35:44 -0800111
Varun Shah7609b752018-10-15 15:07:47 -0700112 /** Mock variable used in {@link MyInjector#isPackageInstalled(String, int, int)} */
113 private static boolean isPackageInstalled = true;
114
Amith Yamasani17fffee2017-09-29 13:17:43 -0700115 private MyInjector mInjector;
Amith Yamasani93885192017-12-13 11:52:10 -0800116 private AppStandbyController mController;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700117
118 static class MyContextWrapper extends ContextWrapper {
119 PackageManager mockPm = mock(PackageManager.class);
120
121 public MyContextWrapper(Context base) {
122 super(base);
123 }
124
125 public PackageManager getPackageManager() {
126 return mockPm;
127 }
128 }
129
130 static class MyInjector extends AppStandbyController.Injector {
131 long mElapsedRealtime;
Kweku Adams1e8947c2018-11-05 18:06:13 -0800132 boolean mIsAppIdleEnabled = true;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700133 boolean mIsCharging;
134 List<String> mPowerSaveWhitelistExceptIdle = new ArrayList<>();
135 boolean mDisplayOn;
136 DisplayManager.DisplayListener mDisplayListener;
Amith Yamasani777b1532018-01-28 23:20:07 +0000137 String mBoundWidgetPackage = PACKAGE_EXEMPTED_1;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700138
139 MyInjector(Context context, Looper looper) {
140 super(context, looper);
141 }
142
143 @Override
144 void onBootPhase(int phase) {
145 }
146
147 @Override
148 int getBootPhase() {
149 return SystemService.PHASE_BOOT_COMPLETED;
150 }
151
152 @Override
153 long elapsedRealtime() {
154 return mElapsedRealtime;
155 }
156
157 @Override
158 long currentTimeMillis() {
159 return mElapsedRealtime;
160 }
161
162 @Override
163 boolean isAppIdleEnabled() {
Kweku Adams1e8947c2018-11-05 18:06:13 -0800164 return mIsAppIdleEnabled;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700165 }
166
167 @Override
168 boolean isCharging() {
169 return mIsCharging;
170 }
171
172 @Override
173 boolean isPowerSaveWhitelistExceptIdleApp(String packageName) throws RemoteException {
174 return mPowerSaveWhitelistExceptIdle.contains(packageName);
175 }
176
177 @Override
178 File getDataSystemDirectory() {
179 return new File(getContext().getFilesDir(), Long.toString(Math.randomLongInternal()));
180 }
181
182 @Override
183 void noteEvent(int event, String packageName, int uid) throws RemoteException {
184 }
185
186 @Override
187 boolean isPackageEphemeral(int userId, String packageName) {
188 // TODO: update when testing ephemeral apps scenario
189 return false;
190 }
191
192 @Override
Varun Shah7609b752018-10-15 15:07:47 -0700193 boolean isPackageInstalled(String packageName, int flags, int userId) {
194 // Should always return true (default value) unless testing for an uninstalled app
195 return isPackageInstalled;
196 }
197
198 @Override
Amith Yamasani17fffee2017-09-29 13:17:43 -0700199 int[] getRunningUserIds() {
200 return new int[] {USER_ID};
201 }
202
203 @Override
204 boolean isDefaultDisplayOn() {
205 return mDisplayOn;
206 }
207
208 @Override
209 void registerDisplayListener(DisplayManager.DisplayListener listener, Handler handler) {
210 mDisplayListener = listener;
211 }
212
213 @Override
214 String getActiveNetworkScorer() {
215 return null;
216 }
217
218 @Override
219 public boolean isBoundWidgetPackage(AppWidgetManager appWidgetManager, String packageName,
220 int userId) {
221 return packageName != null && packageName.equals(mBoundWidgetPackage);
222 }
223
Amith Yamasani301e94a2017-11-17 16:35:44 -0800224 @Override
225 String getAppIdleSettings() {
226 return "screen_thresholds=0/0/0/" + HOUR_MS + ",elapsed_thresholds=0/"
227 + WORKING_SET_THRESHOLD + "/"
228 + FREQUENT_THRESHOLD + "/"
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700229 + RARE_THRESHOLD + ","
230 + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
Amith Yamasani301e94a2017-11-17 16:35:44 -0800231 }
232
Makoto Onukid5f25d22018-05-22 16:02:17 -0700233 @Override
234 public boolean isDeviceIdleMode() {
235 return false;
236 }
237
Amith Yamasani17fffee2017-09-29 13:17:43 -0700238 // Internal methods
239
240 void setDisplayOn(boolean on) {
241 mDisplayOn = on;
242 if (mDisplayListener != null) {
243 mDisplayListener.onDisplayChanged(Display.DEFAULT_DISPLAY);
244 }
245 }
246 }
247
248 private void setupPm(PackageManager mockPm) throws PackageManager.NameNotFoundException {
249 List<PackageInfo> packages = new ArrayList<>();
250 PackageInfo pi = new PackageInfo();
251 pi.applicationInfo = new ApplicationInfo();
252 pi.applicationInfo.uid = UID_1;
253 pi.packageName = PACKAGE_1;
254 packages.add(pi);
255
Amith Yamasani777b1532018-01-28 23:20:07 +0000256 PackageInfo pie = new PackageInfo();
257 pie.applicationInfo = new ApplicationInfo();
258 pie.applicationInfo.uid = UID_EXEMPTED_1;
259 pie.packageName = PACKAGE_EXEMPTED_1;
260 packages.add(pie);
261
Amith Yamasani17fffee2017-09-29 13:17:43 -0700262 doReturn(packages).when(mockPm).getInstalledPackagesAsUser(anyInt(), anyInt());
263 try {
Amith Yamasani777b1532018-01-28 23:20:07 +0000264 doReturn(UID_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_1), anyInt(), anyInt());
265 doReturn(UID_EXEMPTED_1).when(mockPm).getPackageUidAsUser(eq(PACKAGE_EXEMPTED_1),
266 anyInt(), anyInt());
267 doReturn(pi.applicationInfo).when(mockPm).getApplicationInfo(eq(pi.packageName),
268 anyInt());
269 doReturn(pie.applicationInfo).when(mockPm).getApplicationInfo(eq(pie.packageName),
270 anyInt());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700271 } catch (PackageManager.NameNotFoundException nnfe) {}
272 }
273
274 private void setChargingState(AppStandbyController controller, boolean charging) {
275 mInjector.mIsCharging = charging;
276 if (controller != null) {
277 controller.setChargingState(charging);
278 }
279 }
280
Kweku Adams1e8947c2018-11-05 18:06:13 -0800281 private void setAppIdleEnabled(AppStandbyController controller, boolean enabled) {
282 mInjector.mIsAppIdleEnabled = enabled;
283 if (controller != null) {
284 controller.setAppIdleEnabled(enabled);
285 }
286 }
287
Amith Yamasani17fffee2017-09-29 13:17:43 -0700288 private AppStandbyController setupController() throws Exception {
289 mInjector.mElapsedRealtime = 0;
Amith Yamasani777b1532018-01-28 23:20:07 +0000290 setupPm(mInjector.getContext().getPackageManager());
Amith Yamasani17fffee2017-09-29 13:17:43 -0700291 AppStandbyController controller = new AppStandbyController(mInjector);
Amith Yamasani777b1532018-01-28 23:20:07 +0000292 controller.initializeDefaultsForSystemApps(USER_ID);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700293 controller.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
294 controller.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
295 mInjector.setDisplayOn(false);
296 mInjector.setDisplayOn(true);
297 setChargingState(controller, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700298 controller.checkIdleStates(USER_ID);
Amith Yamasani777b1532018-01-28 23:20:07 +0000299 assertEquals(STANDBY_BUCKET_EXEMPTED,
300 controller.getAppStandbyBucket(PACKAGE_EXEMPTED_1, USER_ID,
301 mInjector.mElapsedRealtime, false));
302 assertNotEquals(STANDBY_BUCKET_EXEMPTED,
303 controller.getAppStandbyBucket(PACKAGE_1, USER_ID,
304 mInjector.mElapsedRealtime, false));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700305
306 return controller;
307 }
308
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700309 private long getCurrentTime() {
310 return TimeUnit.NANOSECONDS.toMillis(System.nanoTime());
311 }
312
Amith Yamasani17fffee2017-09-29 13:17:43 -0700313 @Before
314 public void setUp() throws Exception {
315 MyContextWrapper myContext = new MyContextWrapper(InstrumentationRegistry.getContext());
316 mInjector = new MyInjector(myContext, Looper.getMainLooper());
Amith Yamasani93885192017-12-13 11:52:10 -0800317 mController = setupController();
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700318 setChargingState(mController, false);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700319 }
320
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700321 private class TestParoleListener extends UsageStatsManagerInternal.AppIdleStateChangeListener {
322 private boolean mOnParole = false;
323 private CountDownLatch mLatch;
324 private long mLastParoleChangeTime;
Kweku Adams374719b2019-02-28 13:53:21 -0800325 private boolean mIsExpecting = false;
326 private boolean mExpectedParoleState;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700327
328 public boolean getParoleState() {
329 synchronized (this) {
330 return mOnParole;
331 }
332 }
333
334 public void rearmLatch() {
335 synchronized (this) {
336 mLatch = new CountDownLatch(1);
Kweku Adams374719b2019-02-28 13:53:21 -0800337 mIsExpecting = false;
338 }
339 }
340
341 public void rearmLatch(boolean expectedParoleState) {
342 synchronized (this) {
343 mLatch = new CountDownLatch(1);
344 mIsExpecting = true;
345 mExpectedParoleState = expectedParoleState;
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700346 }
347 }
348
349 public void awaitOnLatch(long time) throws Exception {
350 mLatch.await(time, TimeUnit.MILLISECONDS);
351 }
352
353 public long getLastParoleChangeTime() {
354 synchronized (this) {
355 return mLastParoleChangeTime;
356 }
357 }
358
359 @Override
360 public void onAppIdleStateChanged(String packageName, int userId, boolean idle,
361 int bucket, int reason) {
362 }
363
364 @Override
365 public void onParoleStateChanged(boolean isParoleOn) {
366 synchronized (this) {
367 // Only record information if it is being looked for
Kweku Adams1e8947c2018-11-05 18:06:13 -0800368 if (mLatch != null && mLatch.getCount() > 0) {
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700369 mOnParole = isParoleOn;
370 mLastParoleChangeTime = getCurrentTime();
Kweku Adams374719b2019-02-28 13:53:21 -0800371 if (!mIsExpecting || isParoleOn == mExpectedParoleState) {
372 mLatch.countDown();
373 }
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700374 }
375 }
376 }
377 }
378
Amith Yamasani17fffee2017-09-29 13:17:43 -0700379 @Test
380 public void testCharging() throws Exception {
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700381 long startTime;
382 TestParoleListener paroleListener = new TestParoleListener();
383 long marginOfError = 200;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700384
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700385 // Charging
386 paroleListener.rearmLatch();
387 mController.addListener(paroleListener);
388 startTime = getCurrentTime();
Amith Yamasani93885192017-12-13 11:52:10 -0800389 setChargingState(mController, true);
Michael Wachenschwanz5ca5cb62018-04-25 16:12:59 -0700390 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
391 assertTrue(paroleListener.mOnParole);
392 // Parole will only be granted after device has been charging for a sufficient amount of
393 // time.
394 assertEquals(STABLE_CHARGING_THRESHOLD,
395 paroleListener.getLastParoleChangeTime() - startTime,
396 marginOfError);
397
398 // Discharging
399 paroleListener.rearmLatch();
400 startTime = getCurrentTime();
401 setChargingState(mController, false);
402 mController.checkIdleStates(USER_ID);
403 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
404 assertFalse(paroleListener.getParoleState());
405 // Parole should be revoked immediately
406 assertEquals(0,
407 paroleListener.getLastParoleChangeTime() - startTime,
408 marginOfError);
409
410 // Brief Charging
411 paroleListener.rearmLatch();
412 setChargingState(mController, true);
413 setChargingState(mController, false);
414 // Device stopped charging before the stable charging threshold.
415 // Parole should not be granted at the end of the threshold
416 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
417 assertFalse(paroleListener.getParoleState());
418
419 // Charging Again
420 paroleListener.rearmLatch();
421 startTime = getCurrentTime();
422 setChargingState(mController, true);
423 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
424 assertTrue(paroleListener.getParoleState());
425 assertTrue(paroleListener.mOnParole);
426 assertEquals(STABLE_CHARGING_THRESHOLD,
427 paroleListener.getLastParoleChangeTime() - startTime,
428 marginOfError);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700429 }
430
Kweku Adams1e8947c2018-11-05 18:06:13 -0800431 @Test
432 public void testEnabledState() throws Exception {
433 TestParoleListener paroleListener = new TestParoleListener();
Kweku Adams374719b2019-02-28 13:53:21 -0800434 paroleListener.rearmLatch(true);
Kweku Adams1e8947c2018-11-05 18:06:13 -0800435 mController.addListener(paroleListener);
436 long lastUpdateTime;
437
438 // Test that listeners are notified if enabled changes when the device is not in parole.
439 setChargingState(mController, false);
440
Kweku Adams374719b2019-02-28 13:53:21 -0800441 // Start off not enabled. Device is effectively in permanent parole.
Kweku Adams1e8947c2018-11-05 18:06:13 -0800442 setAppIdleEnabled(mController, false);
Kweku Adams374719b2019-02-28 13:53:21 -0800443 // Since AppStandbyController uses a handler to notify listeners of a state change, there is
444 // some inherent latency between changing the state and getting the notification. We need to
445 // wait until the paroleListener has been notified that parole is on before continuing with
446 // the test.
447 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
448 assertTrue(paroleListener.mOnParole);
Kweku Adams1e8947c2018-11-05 18:06:13 -0800449
450 // Enable controller
451 paroleListener.rearmLatch();
452 setAppIdleEnabled(mController, true);
453 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
454 assertFalse(paroleListener.mOnParole);
455 lastUpdateTime = paroleListener.getLastParoleChangeTime();
456
457 paroleListener.rearmLatch();
458 setAppIdleEnabled(mController, true);
459 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
460 assertFalse(paroleListener.mOnParole);
461 // Make sure AppStandbyController doesn't notify listeners when there's no change.
462 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
463
464 // Disable controller
465 paroleListener.rearmLatch();
466 setAppIdleEnabled(mController, false);
467 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
468 assertTrue(paroleListener.mOnParole);
469 lastUpdateTime = paroleListener.getLastParoleChangeTime();
470
471 paroleListener.rearmLatch();
472 setAppIdleEnabled(mController, false);
473 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
474 assertTrue(paroleListener.mOnParole);
475 // Make sure AppStandbyController doesn't notify listeners when there's no change.
476 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
477
478
479 // Test that listeners aren't notified if enabled status changes when the device is already
480 // in parole.
481
482 // A device is in parole whenever it's charging.
483 setChargingState(mController, true);
484
485 // Start off not enabled.
486 paroleListener.rearmLatch();
487 setAppIdleEnabled(mController, false);
488 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
489 assertTrue(paroleListener.mOnParole);
490 lastUpdateTime = paroleListener.getLastParoleChangeTime();
491
492 // Test that toggling doesn't notify the listener.
493 paroleListener.rearmLatch();
494 setAppIdleEnabled(mController, true);
495 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
496 assertTrue(paroleListener.mOnParole);
497 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
498
499 paroleListener.rearmLatch();
500 setAppIdleEnabled(mController, false);
501 paroleListener.awaitOnLatch(STABLE_CHARGING_THRESHOLD * 3 / 2);
502 assertTrue(paroleListener.mOnParole);
503 assertEquals(lastUpdateTime, paroleListener.getLastParoleChangeTime());
504 }
505
Amith Yamasani17fffee2017-09-29 13:17:43 -0700506 private void assertTimeout(AppStandbyController controller, long elapsedTime, int bucket) {
507 mInjector.mElapsedRealtime = elapsedTime;
508 controller.checkIdleStates(USER_ID);
509 assertEquals(bucket,
510 controller.getAppStandbyBucket(PACKAGE_1, USER_ID, mInjector.mElapsedRealtime,
511 false));
512 }
513
Varun Shah7609b752018-10-15 15:07:47 -0700514 private void reportEvent(AppStandbyController controller, int eventType, long elapsedTime,
515 String packageName) {
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800516 // Back to ACTIVE on event
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800517 mInjector.mElapsedRealtime = elapsedTime;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800518 UsageEvents.Event ev = new UsageEvents.Event();
Varun Shah7609b752018-10-15 15:07:47 -0700519 ev.mPackage = packageName;
Amith Yamasani803eab692017-11-09 17:47:04 -0800520 ev.mEventType = eventType;
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800521 controller.reportEvent(ev, elapsedTime, USER_ID);
522 }
523
Varun Shah7609b752018-10-15 15:07:47 -0700524 private int getStandbyBucket(AppStandbyController controller, String packageName) {
525 return controller.getAppStandbyBucket(packageName, USER_ID, mInjector.mElapsedRealtime,
Amith Yamasani803eab692017-11-09 17:47:04 -0800526 true);
527 }
528
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800529 private void assertBucket(int bucket) {
Varun Shah7609b752018-10-15 15:07:47 -0700530 assertEquals(bucket, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800531 }
532
Amith Yamasani17fffee2017-09-29 13:17:43 -0700533 @Test
534 public void testBuckets() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800535 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700536
Varun Shah7609b752018-10-15 15:07:47 -0700537 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800538
Amith Yamasani17fffee2017-09-29 13:17:43 -0700539 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800540 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700541
542 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800543 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700544
545 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800546 assertTimeout(mController, FREQUENT_THRESHOLD - 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700547
548 // FREQUENT bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800549 assertTimeout(mController, FREQUENT_THRESHOLD + 1, STANDBY_BUCKET_FREQUENT);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700550
551 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800552 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700553
Varun Shah7609b752018-10-15 15:07:47 -0700554 reportEvent(mController, USER_INTERACTION, RARE_THRESHOLD + 1, PACKAGE_1);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700555
Amith Yamasani93885192017-12-13 11:52:10 -0800556 assertTimeout(mController, RARE_THRESHOLD + 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700557
558 // RARE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800559 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700560 }
561
562 @Test
Varun Shah7609b752018-10-15 15:07:47 -0700563 public void testSetAppStandbyBucket() throws Exception {
564 // For a known package, standby bucket should be set properly
565 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
566 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
567 REASON_MAIN_TIMEOUT, HOUR_MS);
568 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
569
570 // For an unknown package, standby bucket should not be set, hence NEVER is returned
571 // Ensure the unknown package is not already in history by removing it
572 mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
573 isPackageInstalled = false; // Mock package is not installed
574 mController.setAppStandbyBucket(PACKAGE_UNKNOWN, USER_ID, STANDBY_BUCKET_ACTIVE,
575 REASON_MAIN_TIMEOUT, HOUR_MS);
576 isPackageInstalled = true; // Reset mocked variable for other tests
577 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
578 }
579
580 @Test
581 public void testAppStandbyBucketOnInstallAndUninstall() throws Exception {
582 // On package install, standby bucket should be ACTIVE
583 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_UNKNOWN);
584 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_UNKNOWN));
585
586 // On uninstall, package should not exist in history and should return a NEVER bucket
587 mController.clearAppIdleForPackage(PACKAGE_UNKNOWN, USER_ID);
588 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_UNKNOWN));
589 // Ensure uninstalled app is not in history
590 List<AppStandbyInfo> buckets = mController.getAppStandbyBuckets(USER_ID);
591 for(AppStandbyInfo bucket : buckets) {
592 if (bucket.mPackageName.equals(PACKAGE_UNKNOWN)) {
593 fail("packageName found in app idle history after uninstall.");
594 }
595 }
596 }
597
598 @Test
Amith Yamasani17fffee2017-09-29 13:17:43 -0700599 public void testScreenTimeAndBuckets() throws Exception {
Amith Yamasani17fffee2017-09-29 13:17:43 -0700600 mInjector.setDisplayOn(false);
601
Amith Yamasani93885192017-12-13 11:52:10 -0800602 assertTimeout(mController, 0, STANDBY_BUCKET_NEVER);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800603
Varun Shah7609b752018-10-15 15:07:47 -0700604 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani84cd7b72017-11-07 13:59:37 -0800605
Amith Yamasani17fffee2017-09-29 13:17:43 -0700606 // ACTIVE bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800607 assertTimeout(mController, WORKING_SET_THRESHOLD - 1, STANDBY_BUCKET_ACTIVE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700608
609 // WORKING_SET bucket
Amith Yamasani93885192017-12-13 11:52:10 -0800610 assertTimeout(mController, WORKING_SET_THRESHOLD + 1, STANDBY_BUCKET_WORKING_SET);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700611
612 // RARE bucket, should fail because the screen wasn't ON.
Amith Yamasani301e94a2017-11-17 16:35:44 -0800613 mInjector.mElapsedRealtime = RARE_THRESHOLD + 1;
Amith Yamasani93885192017-12-13 11:52:10 -0800614 mController.checkIdleStates(USER_ID);
Varun Shah7609b752018-10-15 15:07:47 -0700615 assertNotEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700616
617 mInjector.setDisplayOn(true);
Amith Yamasani93885192017-12-13 11:52:10 -0800618 assertTimeout(mController, RARE_THRESHOLD * 2 + 2, STANDBY_BUCKET_RARE);
Amith Yamasani17fffee2017-09-29 13:17:43 -0700619 }
620
621 @Test
622 public void testForcedIdle() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800623 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700624 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800625 assertTrue(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700626
Amith Yamasani93885192017-12-13 11:52:10 -0800627 mController.forceIdleState(PACKAGE_1, USER_ID, false);
628 assertEquals(STANDBY_BUCKET_ACTIVE, mController.getAppStandbyBucket(PACKAGE_1, USER_ID, 0,
Amith Yamasani17fffee2017-09-29 13:17:43 -0700629 true));
Amith Yamasani93885192017-12-13 11:52:10 -0800630 assertFalse(mController.isAppIdleFiltered(PACKAGE_1, UID_1, USER_ID, 0));
Amith Yamasani17fffee2017-09-29 13:17:43 -0700631 }
Amith Yamasani803eab692017-11-09 17:47:04 -0800632
633 @Test
634 public void testNotificationEvent() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700635 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
636 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800637 mInjector.mElapsedRealtime = 1;
Varun Shah7609b752018-10-15 15:07:47 -0700638 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
639 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800640
Amith Yamasani93885192017-12-13 11:52:10 -0800641 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700642 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
643 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani803eab692017-11-09 17:47:04 -0800644 }
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800645
646 @Test
Jason Monk1918ef72018-03-14 09:20:39 -0400647 public void testSlicePinnedEvent() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700648 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
649 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400650 mInjector.mElapsedRealtime = 1;
Varun Shah7609b752018-10-15 15:07:47 -0700651 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
652 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400653
654 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700655 reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime, PACKAGE_1);
656 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400657 }
658
659 @Test
660 public void testSlicePinnedPrivEvent() throws Exception {
Jason Monk1918ef72018-03-14 09:20:39 -0400661 mController.forceIdleState(PACKAGE_1, USER_ID, true);
Varun Shah7609b752018-10-15 15:07:47 -0700662 reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime, PACKAGE_1);
663 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Jason Monk1918ef72018-03-14 09:20:39 -0400664 }
665
666 @Test
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800667 public void testPredictionTimedout() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800668 // Set it to timeout or usage, so that prediction can override it
669 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700670 REASON_MAIN_TIMEOUT, HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700671 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800672
673 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700674 REASON_MAIN_PREDICTED, HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700675 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800676
677 // Fast forward 12 hours
678 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800679 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800680 // Should still be in predicted bucket, since prediction timeout is 1 day since prediction
Varun Shah7609b752018-10-15 15:07:47 -0700681 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800682 // Fast forward two more hours
683 mInjector.mElapsedRealtime += 2 * HOUR_MS;
Amith Yamasani93885192017-12-13 11:52:10 -0800684 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800685 // Should have now applied prediction timeout
Varun Shah7609b752018-10-15 15:07:47 -0700686 assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800687
688 // Fast forward RARE bucket
689 mInjector.mElapsedRealtime += RARE_THRESHOLD;
Amith Yamasani93885192017-12-13 11:52:10 -0800690 mController.checkIdleStates(USER_ID);
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800691 // Should continue to apply prediction timeout
Varun Shah7609b752018-10-15 15:07:47 -0700692 assertEquals(STANDBY_BUCKET_RARE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800693 }
694
695 @Test
696 public void testOverrides() throws Exception {
Amith Yamasani93885192017-12-13 11:52:10 -0800697 // Can force to NEVER
698 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800699 REASON_MAIN_FORCED, 1 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700700 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800701
702 // Prediction can't override FORCED reason
703 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800704 REASON_MAIN_FORCED, 1 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800705 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800706 REASON_MAIN_PREDICTED, 1 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700707 assertEquals(STANDBY_BUCKET_FREQUENT, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800708
709 // Prediction can't override NEVER
710 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800711 REASON_MAIN_DEFAULT, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800712 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800713 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700714 assertEquals(STANDBY_BUCKET_NEVER, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasani93885192017-12-13 11:52:10 -0800715
716 // Prediction can't set to NEVER
717 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800718 REASON_MAIN_USAGE, 2 * HOUR_MS);
Amith Yamasani93885192017-12-13 11:52:10 -0800719 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_NEVER,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800720 REASON_MAIN_PREDICTED, 2 * HOUR_MS);
Varun Shah7609b752018-10-15 15:07:47 -0700721 assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController, PACKAGE_1));
Amith Yamasanibd7b3022017-12-06 17:40:25 -0800722 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800723
724 @Test
725 public void testTimeout() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700726 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800727 assertBucket(STANDBY_BUCKET_ACTIVE);
728
729 mInjector.mElapsedRealtime = 2000;
730 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800731 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800732 assertBucket(STANDBY_BUCKET_ACTIVE);
733
734 // bucketing works after timeout
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700735 mInjector.mElapsedRealtime = mController.mPredictionTimeoutMillis - 100;
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800736 mController.checkIdleStates(USER_ID);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700737 // Use recent prediction
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800738 assertBucket(STANDBY_BUCKET_FREQUENT);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700739
740 // Way past prediction timeout, use system thresholds
741 mInjector.mElapsedRealtime = RARE_THRESHOLD * 4;
742 mController.checkIdleStates(USER_ID);
743 assertBucket(STANDBY_BUCKET_RARE);
Sudheer Shanka101c3532018-01-08 16:28:42 -0800744 }
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800745
Sudheer Shanka101c3532018-01-08 16:28:42 -0800746 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800747 public void testCascadingTimeouts() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700748 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800749 assertBucket(STANDBY_BUCKET_ACTIVE);
750
Varun Shah7609b752018-10-15 15:07:47 -0700751 reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800752 assertBucket(STANDBY_BUCKET_ACTIVE);
753
754 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_WORKING_SET,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800755 REASON_MAIN_PREDICTED, 1000);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800756 assertBucket(STANDBY_BUCKET_ACTIVE);
757
758 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800759 REASON_MAIN_PREDICTED, 2000 + mController.mStrongUsageTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800760 assertBucket(STANDBY_BUCKET_WORKING_SET);
761
762 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800763 REASON_MAIN_PREDICTED, 2000 + mController.mNotificationSeenTimeoutMillis);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800764 assertBucket(STANDBY_BUCKET_FREQUENT);
765 }
766
767 @Test
768 public void testOverlappingTimeouts() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700769 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800770 assertBucket(STANDBY_BUCKET_ACTIVE);
771
Varun Shah7609b752018-10-15 15:07:47 -0700772 reportEvent(mController, NOTIFICATION_SEEN, 1000, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800773 assertBucket(STANDBY_BUCKET_ACTIVE);
774
775 // Overlapping USER_INTERACTION before previous one times out
Varun Shah7609b752018-10-15 15:07:47 -0700776 reportEvent(mController, USER_INTERACTION, mController.mStrongUsageTimeoutMillis - 1000,
777 PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800778 assertBucket(STANDBY_BUCKET_ACTIVE);
779
780 // Still in ACTIVE after first USER_INTERACTION times out
781 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis + 1000;
782 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800783 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800784 assertBucket(STANDBY_BUCKET_ACTIVE);
785
786 // Both timed out, so NOTIFICATION_SEEN timeout should be effective
787 mInjector.mElapsedRealtime = mController.mStrongUsageTimeoutMillis * 2 + 2000;
788 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800789 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800790 assertBucket(STANDBY_BUCKET_WORKING_SET);
791
792 mInjector.mElapsedRealtime = mController.mNotificationSeenTimeoutMillis + 2000;
793 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_RARE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800794 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800795 assertBucket(STANDBY_BUCKET_RARE);
796 }
797
798 @Test
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700799 public void testSystemInteractionTimeout() throws Exception {
800 setChargingState(mController, false);
801
Varun Shah7609b752018-10-15 15:07:47 -0700802 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700803 // Fast forward to RARE
804 mInjector.mElapsedRealtime = RARE_THRESHOLD + 100;
805 mController.checkIdleStates(USER_ID);
806 assertBucket(STANDBY_BUCKET_RARE);
807
808 // Trigger a SYSTEM_INTERACTION and verify bucket
Varun Shah7609b752018-10-15 15:07:47 -0700809 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasani7f53c7b2018-03-25 21:55:50 -0700810 assertBucket(STANDBY_BUCKET_ACTIVE);
811
812 // Verify it's still in ACTIVE close to end of timeout
813 mInjector.mElapsedRealtime += mController.mSystemInteractionTimeoutMillis - 100;
814 mController.checkIdleStates(USER_ID);
815 assertBucket(STANDBY_BUCKET_ACTIVE);
816
817 // Verify bucket moves to RARE after timeout
818 mInjector.mElapsedRealtime += 200;
819 mController.checkIdleStates(USER_ID);
820 assertBucket(STANDBY_BUCKET_RARE);
821 }
822
823 @Test
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800824 public void testPredictionNotOverridden() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700825 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800826 assertBucket(STANDBY_BUCKET_ACTIVE);
827
828 mInjector.mElapsedRealtime = WORKING_SET_THRESHOLD - 1000;
Varun Shah7609b752018-10-15 15:07:47 -0700829 reportEvent(mController, NOTIFICATION_SEEN, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800830 assertBucket(STANDBY_BUCKET_ACTIVE);
831
832 // Falls back to WORKING_SET
833 mInjector.mElapsedRealtime += 5000;
834 mController.checkIdleStates(USER_ID);
835 assertBucket(STANDBY_BUCKET_WORKING_SET);
836
837 // Predict to ACTIVE
838 mInjector.mElapsedRealtime += 1000;
839 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_ACTIVE,
Amith Yamasani119be9a2018-02-18 22:23:00 -0800840 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
Amith Yamasanibbbad9c2018-02-10 16:46:38 -0800841 assertBucket(STANDBY_BUCKET_ACTIVE);
842
843 // CheckIdleStates should not change the prediction
844 mInjector.mElapsedRealtime += 1000;
845 mController.checkIdleStates(USER_ID);
846 assertBucket(STANDBY_BUCKET_ACTIVE);
847 }
848
849 @Test
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700850 public void testPredictionStrikesBack() throws Exception {
Varun Shah7609b752018-10-15 15:07:47 -0700851 reportEvent(mController, USER_INTERACTION, 0, PACKAGE_1);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700852 assertBucket(STANDBY_BUCKET_ACTIVE);
853
854 // Predict to FREQUENT
855 mInjector.mElapsedRealtime = RARE_THRESHOLD;
856 mController.setAppStandbyBucket(PACKAGE_1, USER_ID, STANDBY_BUCKET_FREQUENT,
857 REASON_MAIN_PREDICTED, mInjector.mElapsedRealtime);
858 assertBucket(STANDBY_BUCKET_FREQUENT);
859
860 // Add a short timeout event
861 mInjector.mElapsedRealtime += 1000;
Varun Shah7609b752018-10-15 15:07:47 -0700862 reportEvent(mController, SYSTEM_INTERACTION, mInjector.mElapsedRealtime, PACKAGE_1);
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700863 assertBucket(STANDBY_BUCKET_ACTIVE);
864 mInjector.mElapsedRealtime += 1000;
865 mController.checkIdleStates(USER_ID);
866 assertBucket(STANDBY_BUCKET_ACTIVE);
867
868 // Verify it reverted to predicted
869 mInjector.mElapsedRealtime += WORKING_SET_THRESHOLD / 2;
870 mController.checkIdleStates(USER_ID);
871 assertBucket(STANDBY_BUCKET_FREQUENT);
872 }
873
874 @Test
Sudheer Shanka101c3532018-01-08 16:28:42 -0800875 public void testAddActiveDeviceAdmin() {
876 assertActiveAdmins(USER_ID, (String[]) null);
877 assertActiveAdmins(USER_ID2, (String[]) null);
878
879 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
880 assertActiveAdmins(USER_ID, ADMIN_PKG);
881 assertActiveAdmins(USER_ID2, (String[]) null);
882
883 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
884 assertActiveAdmins(USER_ID, ADMIN_PKG);
885 assertActiveAdmins(USER_ID2, (String[]) null);
886
887 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
888 assertActiveAdmins(USER_ID, ADMIN_PKG);
889 assertActiveAdmins(USER_ID2, ADMIN_PKG2);
890 }
891
892 @Test
893 public void testSetActiveAdminApps() {
894 assertActiveAdmins(USER_ID, (String[]) null);
895 assertActiveAdmins(USER_ID2, (String[]) null);
896
897 setActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
898 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
899 assertActiveAdmins(USER_ID2, (String[]) null);
900
901 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
902 setActiveAdmins(USER_ID2, ADMIN_PKG);
903 assertActiveAdmins(USER_ID, ADMIN_PKG, ADMIN_PKG2);
904 assertActiveAdmins(USER_ID2, ADMIN_PKG);
905
906 mController.setActiveAdminApps(null, USER_ID);
907 assertActiveAdmins(USER_ID, (String[]) null);
908 }
909
910 @Test
911 public void isActiveDeviceAdmin() {
912 assertActiveAdmins(USER_ID, (String[]) null);
913 assertActiveAdmins(USER_ID2, (String[]) null);
914
915 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID);
916 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
917 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
918
919 mController.addActiveDeviceAdmin(ADMIN_PKG2, USER_ID2);
920 mController.addActiveDeviceAdmin(ADMIN_PKG, USER_ID2);
921 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
922 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
923 assertIsActiveAdmin(ADMIN_PKG, USER_ID2);
924 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
925
926 setActiveAdmins(USER_ID2, ADMIN_PKG2);
927 assertIsActiveAdmin(ADMIN_PKG2, USER_ID2);
928 assertIsNotActiveAdmin(ADMIN_PKG, USER_ID2);
929 assertIsActiveAdmin(ADMIN_PKG, USER_ID);
930 assertIsNotActiveAdmin(ADMIN_PKG2, USER_ID);
931 }
932
933 private String getAdminAppsStr(int userId) {
934 return getAdminAppsStr(userId, mController.getActiveAdminAppsForTest(userId));
935 }
936
937 private String getAdminAppsStr(int userId, Set<String> adminApps) {
938 return "admin apps for u" + userId + ": "
939 + (adminApps == null ? "null" : Arrays.toString(adminApps.toArray()));
940 }
941
942 private void assertIsActiveAdmin(String adminApp, int userId) {
943 assertTrue(adminApp + " should be an active admin; " + getAdminAppsStr(userId),
944 mController.isActiveDeviceAdmin(adminApp, userId));
945 }
946
947 private void assertIsNotActiveAdmin(String adminApp, int userId) {
948 assertFalse(adminApp + " shouldn't be an active admin; " + getAdminAppsStr(userId),
949 mController.isActiveDeviceAdmin(adminApp, userId));
950 }
951
952 private void assertActiveAdmins(int userId, String... admins) {
953 final Set<String> actualAdminApps = mController.getActiveAdminAppsForTest(userId);
954 if (admins == null) {
955 if (actualAdminApps != null && !actualAdminApps.isEmpty()) {
956 fail("Admin apps should be null; " + getAdminAppsStr(userId, actualAdminApps));
957 }
958 return;
959 }
960 assertEquals("No. of admin apps not equal; " + getAdminAppsStr(userId, actualAdminApps)
961 + "; expected=" + Arrays.toString(admins), admins.length, actualAdminApps.size());
962 final Set<String> adminAppsCopy = new ArraySet<>(actualAdminApps);
963 for (String admin : admins) {
964 adminAppsCopy.remove(admin);
965 }
966 assertTrue("Unexpected admin apps; " + getAdminAppsStr(userId, actualAdminApps)
967 + "; expected=" + Arrays.toString(admins), adminAppsCopy.isEmpty());
968 }
969
970 private void setActiveAdmins(int userId, String... admins) {
971 mController.setActiveAdminApps(new ArraySet<>(Arrays.asList(admins)), userId);
Amith Yamasani53f06ea2018-01-05 17:53:46 -0800972 }
Amith Yamasani17fffee2017-09-29 13:17:43 -0700973}