• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * 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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16 
17 package android.app.usage.cts;
18 
19 import static android.Manifest.permission.POST_NOTIFICATIONS;
20 import static android.Manifest.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL;
21 import static android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
25 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
26 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
27 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
28 import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
29 import static android.provider.DeviceConfig.NAMESPACE_APP_STANDBY;
30 import static android.text.format.DateUtils.HOUR_IN_MILLIS;
31 import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
32 
33 import static org.junit.Assert.assertArrayEquals;
34 import static org.junit.Assert.assertEquals;
35 import static org.junit.Assert.assertFalse;
36 import static org.junit.Assert.assertNotEquals;
37 import static org.junit.Assert.assertNotNull;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.junit.Assume.assumeFalse;
41 import static org.junit.Assume.assumeTrue;
42 
43 import android.Manifest;
44 import android.app.Activity;
45 import android.app.ActivityManager;
46 import android.app.ActivityOptions;
47 import android.app.AppOpsManager;
48 import android.app.Instrumentation;
49 import android.app.KeyguardManager;
50 import android.app.Notification;
51 import android.app.NotificationChannel;
52 import android.app.NotificationManager;
53 import android.app.PendingIntent;
54 import android.app.UiAutomation;
55 import android.app.usage.EventStats;
56 import android.app.usage.Flags;
57 import android.app.usage.UsageEvents;
58 import android.app.usage.UsageEvents.Event;
59 import android.app.usage.UsageEventsQuery;
60 import android.app.usage.UsageStats;
61 import android.app.usage.UsageStatsManager;
62 import android.content.BroadcastReceiver;
63 import android.content.ComponentName;
64 import android.content.ContentProviderClient;
65 import android.content.Context;
66 import android.content.Intent;
67 import android.content.ServiceConnection;
68 import android.content.pm.PackageManager;
69 import android.database.Cursor;
70 import android.net.Uri;
71 import android.os.Bundle;
72 import android.os.IBinder;
73 import android.os.Parcel;
74 import android.os.PersistableBundle;
75 import android.os.Process;
76 import android.os.SystemClock;
77 import android.os.UserHandle;
78 import android.os.UserManager;
79 import android.permission.PermissionManager;
80 import android.permission.cts.PermissionUtils;
81 import android.platform.test.annotations.AppModeFull;
82 import android.platform.test.annotations.AppModeInstant;
83 import android.platform.test.annotations.AsbSecurityTest;
84 import android.platform.test.annotations.RequiresFlagsDisabled;
85 import android.platform.test.annotations.RequiresFlagsEnabled;
86 import android.platform.test.flag.junit.CheckFlagsRule;
87 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
88 import android.provider.Settings;
89 import android.server.wm.WindowManagerState;
90 import android.server.wm.WindowManagerStateHelper;
91 import android.text.format.DateUtils;
92 import android.util.ArrayMap;
93 import android.util.Log;
94 import android.util.SparseArray;
95 import android.util.SparseLongArray;
96 import android.view.KeyEvent;
97 
98 import androidx.test.InstrumentationRegistry;
99 import androidx.test.filters.MediumTest;
100 import androidx.test.uiautomator.By;
101 import androidx.test.uiautomator.UiDevice;
102 import androidx.test.uiautomator.Until;
103 
104 import com.android.compatibility.common.util.AppStandbyUtils;
105 import com.android.compatibility.common.util.BatteryUtils;
106 import com.android.compatibility.common.util.DeviceConfigStateHelper;
107 import com.android.compatibility.common.util.PollingCheck;
108 import com.android.compatibility.common.util.SystemUtil;
109 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
110 
111 import org.junit.After;
112 import org.junit.Before;
113 import org.junit.Ignore;
114 import org.junit.Rule;
115 import org.junit.Test;
116 import org.junit.runner.RunWith;
117 
118 import java.io.IOException;
119 import java.text.MessageFormat;
120 import java.time.Duration;
121 import java.util.ArrayList;
122 import java.util.Arrays;
123 import java.util.List;
124 import java.util.Map;
125 import java.util.Objects;
126 import java.util.Random;
127 import java.util.concurrent.BlockingQueue;
128 import java.util.concurrent.CountDownLatch;
129 import java.util.concurrent.LinkedBlockingQueue;
130 import java.util.concurrent.TimeUnit;
131 import java.util.function.Function;
132 import java.util.function.Supplier;
133 
134 /**
135  * Test the UsageStats API. It is difficult to test the entire surface area
136  * of the API, as a lot of the testing depends on what data is already present
137  * on the device and for how long that data has been aggregating.
138  *
139  * These tests perform simple checks that each interval is of the correct duration,
140  * and that events do appear in the event log.
141  *
142  * Tests to add that are difficult to add now:
143  * - Invoking a device configuration change and then watching for it in the event log.
144  * - Changing the system time and verifying that all data has been correctly shifted
145  *   along with the new time.
146  * - Proper eviction of old data.
147  */
148 @RunWith(UsageStatsTestRunner.class)
149 public class UsageStatsTest extends StsExtraBusinessLogicTestCase {
150     private static final boolean DEBUG = false;
151     static final String TAG = "UsageStatsTest";
152 
153     private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} " +
154             AppOpsManager.OPSTR_GET_USAGE_STATS + " {1}";
155     private static final String APPOPS_RESET_SHELL_COMMAND = "appops reset {0}";
156 
157     private static final String PRUNE_PACKAGE_DATA_SHELL_COMMAND =
158             "cmd usagestats delete-package-data {0} -u {1}";
159 
160     private static final String GET_SHELL_COMMAND = "settings get global ";
161 
162     private static final String SET_SHELL_COMMAND = "settings put global ";
163 
164     private static final String DELETE_SHELL_COMMAND = "settings delete global ";
165 
166     private static final String JOBSCHEDULER_RUN_SHELL_COMMAND = "cmd jobscheduler run";
167 
168     static final String TEST_APP_PKG = "android.app.usage.cts.test1";
169 
170     static final String TEST_APP_CLASS = "android.app.usage.cts.test1.SomeActivity";
171     private static final String TEST_APP_CLASS_LOCUS
172             = "android.app.usage.cts.test1.SomeActivityWithLocus";
173     static final String TEST_APP_CLASS_SERVICE
174             = "android.app.usage.cts.test1.TestService";
175     static final String TEST_APP_CLASS_BROADCAST_RECEIVER
176             = "android.app.usage.cts.test1.TestBroadcastReceiver";
177     private static final String TEST_APP_CLASS_FINISH_SELF_ON_RESUME =
178             "android.app.usage.cts.test1.FinishOnResumeActivity";
179     private static final String TEST_AUTHORITY = "android.app.usage.cts.test1.provider";
180     private static final String TEST_APP_CONTENT_URI_STRING = "content://" + TEST_AUTHORITY;
181     private static final String TEST_APP2_PKG = "android.app.usage.cts.test2";
182     private static final String TEST_APP2_CLASS_FINISHING_TASK_ROOT =
183             "android.app.usage.cts.test2.FinishingTaskRootActivity";
184     private static final String TEST_APP2_CLASS_PIP =
185             "android.app.usage.cts.test2.PipActivity";
186     private static final ComponentName TEST_APP2_PIP_COMPONENT = new ComponentName(TEST_APP2_PKG,
187             TEST_APP2_CLASS_PIP);
188 
189     private static final String TEST_APP_API_32_PKG = "android.app.usage.cts.testapi32";
190 
191     // TODO(206518483): Define these constants in UsageStatsManager to avoid hardcoding here.
192     private static final String KEY_NOTIFICATION_SEEN_HOLD_DURATION =
193             "notification_seen_duration";
194     private static final String KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET =
195             "notification_seen_promoted_bucket";
196     private static final String KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS =
197             "retain_notification_seen_impact_for_pre_t_apps";
198 
199     private static final int DEFAULT_TIMEOUT_MS = 10_000;
200 
201     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
202     private static final long MINUTE = TimeUnit.MINUTES.toMillis(1);
203     private static final long DAY = TimeUnit.DAYS.toMillis(1);
204     private static final long WEEK = 7 * DAY;
205     private static final long MONTH = 30 * DAY;
206     private static final long YEAR = 365 * DAY;
207     private static final long TIME_DIFF_THRESHOLD = 200;
208     private static final String CHANNEL_ID = "my_channel";
209 
210     private static final long TIMEOUT_BINDER_SERVICE_SEC = 2;
211 
212     private static final String TEST_NOTIFICATION_CHANNEL_ID = "test-channel-id";
213     private static final String TEST_NOTIFICATION_CHANNEL_NAME = "test-channel-name";
214     private static final String TEST_NOTIFICATION_CHANNEL_DESC = "test-channel-description";
215 
216     private static final int TEST_NOTIFICATION_ID_1 = 10;
217     private static final int TEST_NOTIFICATION_ID_2 = 20;
218     private static final String TEST_NOTIFICATION_TITLE_FMT = "Test title; id=%s";
219     private static final String TEST_NOTIFICATION_TEXT_1 = "Test content 1";
220     private static final String TEST_NOTIFICATION_TEXT_2 = "Test content 2";
221 
222     @Rule
223     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
224 
225     private Context mContext;
226     private UiDevice mUiDevice;
227     private UiAutomation mUiAutomation;
228     private ActivityManager mAm;
229     private UsageStatsManager mUsageStatsManager;
230     private KeyguardManager mKeyguardManager;
231     private String mTargetPackage;
232     private String mCachedUsageSourceSetting;
233     private int mOtherUser;
234     private Context mOtherUserContext;
235     private UsageStatsManager mOtherUsageStats;
236     private WindowManagerStateHelper mWMStateHelper;
237 
238     @Before
setUp()239     public void setUp() throws Exception {
240         final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
241         mContext = instrumentation.getContext();
242         mUiDevice = UiDevice.getInstance(instrumentation);
243         mUiAutomation = instrumentation.getUiAutomation();
244         mAm = mContext.getSystemService(ActivityManager.class);
245         mUsageStatsManager = (UsageStatsManager) mContext.getSystemService(
246                 Context.USAGE_STATS_SERVICE);
247         mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
248         mTargetPackage = mContext.getPackageName();
249         PermissionUtils.grantPermission(mTargetPackage, POST_NOTIFICATIONS);
250 
251         mWMStateHelper = new WindowManagerStateHelper();
252 
253         assumeTrue("App Standby not enabled on device", AppStandbyUtils.isAppStandbyEnabled());
254         setAppOpsMode("allow");
255         mCachedUsageSourceSetting = getSetting(Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE);
256     }
257 
258     @After
cleanUp()259     public void cleanUp() throws Exception {
260         if (mCachedUsageSourceSetting != null &&
261                 !mCachedUsageSourceSetting.equals(
262                     getSetting(Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE))) {
263             setUsageSourceSetting(mCachedUsageSourceSetting);
264         }
265         // Force stop test package to avoid any running test code from carrying over to the next run
266         if (mAm != null) {
267             SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
268             SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP2_PKG));
269         }
270 
271         if (mUiDevice != null) {
272             mUiDevice.pressHome();
273         }
274 
275         // delete any usagestats data that was created for the test packages
276         if (mContext != null) {
277             clearTestPackagesData(mContext.getUserId());
278         }
279 
280         // Destroy the other user if created
281         if (mOtherUser != 0) {
282             clearTestPackagesData(mOtherUser);
283             stopUser(mOtherUser, true, true);
284             removeUser(mOtherUser);
285             mOtherUser = 0;
286         }
287         // Use test API to prevent PermissionManager from killing the test process when revoking
288         // permission.
289         if (mContext != null && mTargetPackage != null) {
290             SystemUtil.runWithShellPermissionIdentity(
291                     () -> mContext.getSystemService(PermissionManager.class)
292                             .revokePostNotificationPermissionWithoutKillForTest(
293                                     mTargetPackage,
294                                     Process.myUserHandle().getIdentifier()),
295                     REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL,
296                     REVOKE_RUNTIME_PERMISSIONS);
297         }
298 
299         if (mUiAutomation != null) {
300             mUiAutomation.dropShellPermissionIdentity();
301         }
302     }
303 
assertLessThan(long left, long right)304     private static void assertLessThan(long left, long right) {
305         assertTrue("Expected " + left + " to be less than " + right, left < right);
306     }
307 
assertLessThanOrEqual(long left, long right)308     private static void assertLessThanOrEqual(long left, long right) {
309         assertTrue("Expected " + left + " to be less than " + right, left <= right);
310     }
311 
setAppOpsMode(String mode)312     private void setAppOpsMode(String mode) throws Exception {
313         executeShellCmd(MessageFormat.format(APPOPS_SET_SHELL_COMMAND, mTargetPackage, mode));
314     }
315 
resetAppOpsMode()316     private void resetAppOpsMode() throws Exception {
317         executeShellCmd(MessageFormat.format(APPOPS_RESET_SHELL_COMMAND, mTargetPackage));
318     }
319 
clearTestPackagesData(int userId)320     private void clearTestPackagesData(int userId) throws Exception {
321         if (mTargetPackage != null) {
322             executeShellCmd(MessageFormat.format(PRUNE_PACKAGE_DATA_SHELL_COMMAND, mTargetPackage,
323                     userId));
324         }
325         executeShellCmd(MessageFormat.format(PRUNE_PACKAGE_DATA_SHELL_COMMAND, TEST_APP_PKG,
326                 userId));
327         executeShellCmd(MessageFormat.format(PRUNE_PACKAGE_DATA_SHELL_COMMAND, TEST_APP2_PKG,
328                 userId));
329         executeShellCmd(MessageFormat.format(PRUNE_PACKAGE_DATA_SHELL_COMMAND, TEST_APP_API_32_PKG,
330                 userId));
331     }
332 
getSetting(String name)333     private String getSetting(String name) throws Exception {
334         return executeShellCmd(GET_SHELL_COMMAND + name);
335     }
336 
setSetting(String name, String setting)337     private void setSetting(String name, String setting) throws Exception {
338         if (setting == null || setting.equals("null")) {
339             executeShellCmd(DELETE_SHELL_COMMAND + name);
340         } else {
341             executeShellCmd(SET_SHELL_COMMAND + name + " " + setting);
342         }
343     }
344 
setUsageSourceSetting(String value)345     private void setUsageSourceSetting(String value) throws Exception {
346         setSetting(Settings.Global.APP_TIME_LIMIT_USAGE_SOURCE, value);
347         mUsageStatsManager.forceUsageSourceSettingRead();
348     }
349 
launchSubActivity(Class<? extends Activity> clazz)350     private void launchSubActivity(Class<? extends Activity> clazz) {
351         launchSubActivity(clazz, WINDOWING_MODE_UNDEFINED);
352     }
353 
launchSubActivity(Class<? extends Activity> clazz, int windowingMode)354     private void launchSubActivity(Class<? extends Activity> clazz, int windowingMode) {
355         final Intent intent = new Intent(Intent.ACTION_MAIN);
356         intent.setClassName(mTargetPackage, clazz.getName());
357         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
358         final ActivityOptions options = ActivityOptions.makeBasic();
359         options.setLaunchWindowingMode(windowingMode);
360         mContext.startActivity(intent, options.toBundle());
361         mUiDevice.wait(Until.hasObject(By.clazz(clazz)), TIMEOUT);
362     }
363 
createTestActivityIntent(String pkgName, String className)364     private Intent createTestActivityIntent(String pkgName, String className) {
365         final Intent intent = new Intent();
366         intent.setClassName(pkgName, className);
367         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
368         return intent;
369     }
370 
launchTestActivity(String pkgName, String className)371     private void launchTestActivity(String pkgName, String className) {
372         launchTestActivity(pkgName, className, WINDOWING_MODE_UNDEFINED);
373     }
374 
launchTestActivity(String pkgName, String className, int windowingMode)375     private void launchTestActivity(String pkgName, String className, int windowingMode) {
376         final ActivityOptions options = ActivityOptions.makeBasic();
377         options.setLaunchWindowingMode(windowingMode);
378         mContext.startActivity(createTestActivityIntent(pkgName, className), options.toBundle());
379         mUiDevice.wait(Until.hasObject(By.clazz(pkgName, className)), TIMEOUT);
380     }
381 
launchSubActivities(Class<? extends Activity>[] activityClasses)382     private void launchSubActivities(Class<? extends Activity>[] activityClasses) {
383         for (Class<? extends Activity> clazz : activityClasses) {
384             launchSubActivity(clazz);
385         }
386     }
387 
388     @Test
testTogglingViaSettings()389     public void testTogglingViaSettings() throws Exception {
390         final String initialAppStandbyEnabled = getSetting(Settings.Global.APP_STANDBY_ENABLED);
391         final String initialAdaptiveBatteryManagementEnabled =
392                 getSetting(Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED);
393         try {
394             // Right now, this test only runs when we've already confirmed that app standby is
395             // enabled via the command-line.
396             assertTrue(mUsageStatsManager.isAppStandbyEnabled());
397 
398             setSetting(Settings.Global.APP_STANDBY_ENABLED, "0");
399             // Need to wait a bit for the setting change to propagate
400             waitUntil(() -> mUsageStatsManager.isAppStandbyEnabled(), false);
401             assertFalse(AppStandbyUtils.isAppStandbyEnabled());
402 
403             setSetting(Settings.Global.APP_STANDBY_ENABLED, "1");
404             setSetting(Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, "0");
405             waitUntil(() -> mUsageStatsManager.isAppStandbyEnabled(), false);
406             assertFalse(AppStandbyUtils.isAppStandbyEnabled());
407 
408             setSetting(Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, "1");
409             waitUntil(() -> mUsageStatsManager.isAppStandbyEnabled(), true);
410             assertTrue(AppStandbyUtils.isAppStandbyEnabled());
411         } finally {
412             setSetting(Settings.Global.APP_STANDBY_ENABLED, initialAppStandbyEnabled);
413             setSetting(Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
414                     initialAdaptiveBatteryManagementEnabled);
415         }
416     }
417 
418     @AppModeFull(reason = "No usage events access in instant apps")
419     @Test
testLastTimeVisible_launchActivityShouldBeDetected()420     public void testLastTimeVisible_launchActivityShouldBeDetected() throws Exception {
421         wakeDevice();
422         dismissKeyguard(); // also want to start out with the keyguard dismissed.
423 
424         final long startTime = System.currentTimeMillis();
425         launchSubActivity(Activities.ActivityOne.class);
426         final long endTime = System.currentTimeMillis();
427 
428         verifyLastTimeVisibleWithinRange(startTime, endTime, mTargetPackage);
429     }
430 
431     @AppModeFull(reason = "No usage events access in instant apps")
432     @Test
testLastTimeAnyComponentUsed_launchActivityShouldBeDetected()433     public void testLastTimeAnyComponentUsed_launchActivityShouldBeDetected() throws Exception {
434         wakeDevice();
435         dismissKeyguard(); // also want to start out with the keyguard dismissed.
436 
437         final long startTime = System.currentTimeMillis();
438         launchSubActivity(Activities.ActivityOne.class);
439         final long endTime = System.currentTimeMillis();
440 
441         verifyLastTimeAnyComponentUsedWithinRange(startTime, endTime, mTargetPackage);
442     }
443 
444     @AppModeFull(reason = "No usage events access in instant apps")
445     @Test
testLastTimeAnyComponentUsed_bindServiceShouldBeDetected()446     public void testLastTimeAnyComponentUsed_bindServiceShouldBeDetected() throws Exception {
447         wakeDevice();
448         dismissKeyguard(); // also want to start out with the keyguard dismissed.
449 
450         final long startTime = System.currentTimeMillis();
451         bindToTestService();
452         final long endTime = System.currentTimeMillis();
453 
454         verifyLastTimeAnyComponentUsedWithinRange(startTime, endTime, TEST_APP_PKG);
455     }
456 
457     @AppModeFull(reason = "No usage events access in instant apps")
458     @Test
testLastTimeAnyComponentUsed_bindExplicitBroadcastReceiverShouldBeDetected()459     public void testLastTimeAnyComponentUsed_bindExplicitBroadcastReceiverShouldBeDetected()
460             throws Exception {
461         wakeDevice();
462         dismissKeyguard(); // also want to start out with the keyguard dismissed.
463 
464         final long startTime = System.currentTimeMillis();
465         bindToTestBroadcastReceiver();
466         final long endTime = System.currentTimeMillis();
467 
468         verifyLastTimeAnyComponentUsedWithinRange(startTime, endTime, TEST_APP_PKG);
469     }
470 
471     @AppModeFull(reason = "No usage events access in instant apps")
472     @Test
testLastTimeAnyComponentUsed_bindContentProviderShouldBeDetected()473     public void testLastTimeAnyComponentUsed_bindContentProviderShouldBeDetected()
474             throws Exception {
475         wakeDevice();
476         dismissKeyguard(); // also want to start out with the keyguard dismissed.
477 
478         final long startTime = System.currentTimeMillis();
479         bindToTestContentProvider();
480         final long endTime = System.currentTimeMillis();
481 
482         verifyLastTimeAnyComponentUsedWithinRange(startTime, endTime, TEST_APP_PKG);
483     }
484 
verifyLastTimeVisibleWithinRange( long startTime, long endTime, String targetPackage)485     private void verifyLastTimeVisibleWithinRange(
486             long startTime, long endTime, String targetPackage) {
487         UsageStats stats = getAggregateUsageStats(startTime, endTime, targetPackage);
488         assertNotNull(stats);
489         long lastTimeVisible = stats.getLastTimeVisible();
490         if (lastTimeVisible < startTime) {
491             // There is a slight possibility that the returned stats do not include the latest data,
492             // so query usage stats again after a 1s wait for the most recent data
493             SystemClock.sleep(1000);
494             endTime += 1000;
495             stats = getAggregateUsageStats(startTime, endTime, targetPackage);
496             assertNotNull(stats);
497             lastTimeVisible = stats.getLastTimeVisible();
498         }
499         assertLessThanOrEqual(startTime, lastTimeVisible);
500         assertLessThanOrEqual(lastTimeVisible, endTime);
501     }
502 
verifyLastTimeAnyComponentUsedWithinRange( long startTime, long endTime, String targetPackage)503     private void verifyLastTimeAnyComponentUsedWithinRange(
504             long startTime, long endTime, String targetPackage) {
505 
506         UsageStats stats = getAggregateUsageStats(startTime, endTime, targetPackage);
507         assertNotNull(stats);
508         long lastTimeAnyComponentUsed = stats.getLastTimeAnyComponentUsed();
509         if (lastTimeAnyComponentUsed < startTime) {
510             // There is a slight possibility that the returned stats do not include the latest data,
511             // so query usage stats again after a 1s wait for the most recent data
512             SystemClock.sleep(1000);
513             endTime += 1000;
514             stats = getAggregateUsageStats(startTime, endTime, targetPackage);
515             assertNotNull(stats);
516             lastTimeAnyComponentUsed = stats.getLastTimeAnyComponentUsed();
517         }
518         assertLessThanOrEqual(startTime, lastTimeAnyComponentUsed);
519         assertLessThanOrEqual(lastTimeAnyComponentUsed, endTime);
520 
521         final long lastDayLowerBound = startTime / DAY;
522         final long lastDayUpperBound = endTime / DAY;
523         SystemUtil.runWithShellPermissionIdentity(()-> {
524             final long lastDayAnyComponentUsedGlobal =
525                     mUsageStatsManager.getLastTimeAnyComponentUsed(targetPackage) / DAY;
526             assertLessThanOrEqual(lastDayLowerBound, lastDayAnyComponentUsedGlobal);
527             assertLessThanOrEqual(lastDayAnyComponentUsedGlobal, lastDayUpperBound);
528         });
529     }
530 
getAggregateUsageStats(long startTime, long endTime, String targetPackage)531     private UsageStats getAggregateUsageStats(long startTime, long endTime, String targetPackage) {
532         UsageStats stats;
533         // Query for up to 5 seconds in case the handler is busy.
534         for (int i = 0; i < 10; i++) {
535             final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
536                     startTime, endTime + 1000);
537             stats = map.get(targetPackage);
538             if (stats != null) {
539                 return stats;
540             }
541             SystemClock.sleep(500);
542         }
543         return null;
544     }
545 
546     @AppModeFull(reason = "No usage events access in instant apps")
547     @Test
testLastTimeAnyComponentUsed_JobServiceShouldBeIgnored()548     public void testLastTimeAnyComponentUsed_JobServiceShouldBeIgnored() throws Exception {
549         wakeDevice();
550         dismissKeyguard(); // also want to start out with the keyguard dismissed.
551 
552         final long startTime = System.currentTimeMillis();
553         runJobImmediately();
554         waitUntil(TestJob.hasJobStarted, /* expected */ true);
555 
556         final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
557                 startTime, System.currentTimeMillis());
558         final UsageStats stats = map.get(mTargetPackage);
559         if (stats != null) {
560             final long lastTimeAnyComponentUsed = stats.getLastTimeAnyComponentUsed();
561             // Check that the usage is NOT detected.
562             assertLessThanOrEqual(lastTimeAnyComponentUsed, startTime);
563         }
564 
565         SystemUtil.runWithShellPermissionIdentity(()-> {
566             final long lastDayAnyComponentUsedGlobal =
567                     mUsageStatsManager.getLastTimeAnyComponentUsed(mTargetPackage) / DAY;
568             // Check that the usage is NOT detected.
569             assertLessThanOrEqual(lastDayAnyComponentUsedGlobal, startTime / DAY);
570         });
571     }
572 
573     @AppModeFull(reason = "No usage events access in instant apps")
574     @Test
testLastTimeAnyComponentUsedGlobal_withoutPermission()575     public void testLastTimeAnyComponentUsedGlobal_withoutPermission() throws Exception {
576         try{
577             mUsageStatsManager.getLastTimeAnyComponentUsed(mTargetPackage);
578             fail("Query across users should require INTERACT_ACROSS_USERS permission");
579         } catch (SecurityException se) {
580             // Expected
581         }
582     }
583 
584     @AppModeFull(reason = "No usage events access in instant apps")
585     @Test
testOrderedActivityLaunchSequenceInEventLog()586     public void testOrderedActivityLaunchSequenceInEventLog() throws Exception {
587         @SuppressWarnings("unchecked")
588         Class<? extends Activity>[] activitySequence = new Class[] {
589                 Activities.ActivityOne.class,
590                 Activities.ActivityTwo.class,
591                 Activities.ActivityThree.class,
592         };
593         wakeDevice();
594         dismissKeyguard(); // also want to start out with the keyguard dismissed.
595 
596         final long startTime = System.currentTimeMillis();
597         // Launch the series of Activities.
598         launchSubActivities(activitySequence);
599         final long endTime = System.currentTimeMillis();
600         UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
601 
602         // Only look at events belongs to mTargetPackage.
603         ArrayList<UsageEvents.Event> eventList = new ArrayList<>();
604         while (events.hasNextEvent()) {
605             UsageEvents.Event event = new UsageEvents.Event();
606             assertTrue(events.getNextEvent(event));
607             if (mTargetPackage.equals(event.getPackageName())) {
608                 eventList.add(event);
609             }
610         }
611 
612         final int activityCount = activitySequence.length;
613         for (int i = 0; i < activityCount; i++) {
614             String className = activitySequence[i].getName();
615             ArrayList<UsageEvents.Event> activityEvents = new ArrayList<>();
616             final int size = eventList.size();
617             for (int j = 0; j < size; j++) {
618                 Event evt = eventList.get(j);
619                 if (className.equals(evt.getClassName())) {
620                     activityEvents.add(evt);
621                 }
622             }
623             // We expect 3 events per Activity launched (ACTIVITY_RESUMED + ACTIVITY_PAUSED
624             // + ACTIVITY_STOPPED) except for the last Activity, which only has
625             // ACTIVITY_RESUMED event.
626             if (i < activityCount - 1) {
627                 assertEquals(3, activityEvents.size());
628                 assertEquals(Event.ACTIVITY_RESUMED, activityEvents.get(0).getEventType());
629                 assertEquals(Event.ACTIVITY_PAUSED, activityEvents.get(1).getEventType());
630                 assertEquals(Event.ACTIVITY_STOPPED, activityEvents.get(2).getEventType());
631             } else {
632                 // The last activity
633                 assertEquals(1, activityEvents.size());
634                 assertEquals(Event.ACTIVITY_RESUMED, activityEvents.get(0).getEventType());
635             }
636         }
637     }
638 
639     @AppModeFull(reason = "No usage events access in instant apps")
640     @Test
testActivityOnBackButton()641     public void testActivityOnBackButton() throws Exception {
642         testActivityOnButton(mUiDevice::pressBack);
643     }
644 
645     @AppModeFull(reason = "No usage events access in instant apps")
646     @Test
testActivityOnHomeButton()647     public void testActivityOnHomeButton() throws Exception {
648         testActivityOnButton(mUiDevice::pressHome);
649     }
650 
testActivityOnButton(Runnable pressButton)651     private void testActivityOnButton(Runnable pressButton) throws Exception {
652         wakeDevice();
653         final long startTime = System.currentTimeMillis();
654         final Class clazz = Activities.ActivityOne.class;
655         launchSubActivity(clazz);
656         pressButton.run();
657         Thread.sleep(1000);
658         final long endTime = System.currentTimeMillis();
659         UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
660 
661         ArrayList<UsageEvents.Event> eventList = new ArrayList<>();
662         while (events.hasNextEvent()) {
663             UsageEvents.Event event = new UsageEvents.Event();
664             assertTrue(events.getNextEvent(event));
665             if (mTargetPackage.equals(event.getPackageName())
666                 && clazz.getName().equals(event.getClassName())) {
667                 eventList.add(event);
668             }
669         }
670         assertEquals(3, eventList.size());
671         assertEquals(Event.ACTIVITY_RESUMED, eventList.get(0).getEventType());
672         assertEquals(Event.ACTIVITY_PAUSED, eventList.get(1).getEventType());
673         assertEquals(Event.ACTIVITY_STOPPED, eventList.get(2).getEventType());
674     }
675 
676     @AppModeFull(reason = "No usage events access in instant apps")
677     @Test
testAppLaunchCount()678     public void testAppLaunchCount() throws Exception {
679         long endTime = System.currentTimeMillis();
680         long startTime = endTime - DateUtils.DAY_IN_MILLIS;
681         Map<String,UsageStats> events = mUsageStatsManager.queryAndAggregateUsageStats(
682                 startTime, endTime);
683         UsageStats stats = events.get(mTargetPackage);
684         if (stats == null) {
685             fail("Querying UsageStats for " + mTargetPackage + " returned empty; list of packages "
686                  + "with events: " + Arrays.toString(events.keySet().toArray(new String[0])));
687         }
688         int startingCount = stats.getAppLaunchCount();
689         // Launch count is updated by UsageStatsService depending on last background package.
690         // When running this test on single screen device (where tasks are launched in the same
691         // TaskDisplayArea), the last background package is updated when the HOME activity is
692         // paused. In a hierarchy with multiple TaskDisplayArea there is no guarantee the Home
693         // Activity will be paused as the activities we launch might be placed on a different
694         // TaskDisplayArea. Starting an activity and finishing it immediately will update the last
695         // background package of the UsageStatsService regardless of the HOME Activity state.
696         // To ensure that the test is not affected by the display windowing mode, all activities are
697         // forced to launch in fullscreen mode in this test.
698         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS_FINISH_SELF_ON_RESUME,
699                 WINDOWING_MODE_FULLSCREEN);
700         launchSubActivity(Activities.ActivityOne.class, WINDOWING_MODE_FULLSCREEN);
701         launchSubActivity(Activities.ActivityTwo.class, WINDOWING_MODE_FULLSCREEN);
702         endTime = System.currentTimeMillis();
703         events = mUsageStatsManager.queryAndAggregateUsageStats(
704                 startTime, endTime);
705         stats = events.get(mTargetPackage);
706         assertEquals(startingCount + 1, stats.getAppLaunchCount());
707 
708         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS_FINISH_SELF_ON_RESUME,
709                 WINDOWING_MODE_FULLSCREEN);
710         launchSubActivity(Activities.ActivityOne.class, WINDOWING_MODE_FULLSCREEN);
711         launchSubActivity(Activities.ActivityTwo.class, WINDOWING_MODE_FULLSCREEN);
712         launchSubActivity(Activities.ActivityThree.class, WINDOWING_MODE_FULLSCREEN);
713         endTime = System.currentTimeMillis();
714         events = mUsageStatsManager.queryAndAggregateUsageStats(
715                 startTime, endTime);
716         stats = events.get(mTargetPackage);
717 
718         final ComponentName activityThree = new ComponentName(mTargetPackage,
719                 Activities.ActivityThree.class.getName());
720         mWMStateHelper.waitAndAssertActivityState(activityThree, WindowManagerState.STATE_RESUMED);
721 
722         // If the app is launching in freeform instead of the requested FULLSCREEN, then the
723         // target package was never stopped.
724         if (mWMStateHelper.getTaskByActivity(activityThree).getWindowingMode()
725                 == WINDOWING_MODE_FREEFORM) {
726             assertEquals(startingCount + 1, stats.getAppLaunchCount());
727         } else {
728             assertEquals(startingCount + 2, stats.getAppLaunchCount());
729         }
730     }
731 
732     @AppModeFull(reason = "No usage events access in instant apps")
733     @Test
testStandbyBucketChangeLog()734     public void testStandbyBucketChangeLog() throws Exception {
735         final long startTime = System.currentTimeMillis();
736         setStandByBucket(mTargetPackage, "rare");
737 
738         final long endTime = System.currentTimeMillis();
739         UsageEvents events = mUsageStatsManager.queryEvents(startTime - 1_000, endTime + 1_000);
740 
741         boolean found = false;
742         // Check all the events.
743         while (events.hasNextEvent()) {
744             UsageEvents.Event event = new UsageEvents.Event();
745             assertTrue(events.getNextEvent(event));
746             if (event.getEventType() == UsageEvents.Event.STANDBY_BUCKET_CHANGED) {
747                 found |= event.getAppStandbyBucket() == STANDBY_BUCKET_RARE;
748             }
749         }
750 
751         assertTrue(found);
752     }
753 
754     @Test
testGetAppStandbyBuckets()755     public void testGetAppStandbyBuckets() throws Exception {
756         final boolean origValue = AppStandbyUtils.isAppStandbyEnabledAtRuntime();
757         AppStandbyUtils.setAppStandbyEnabledAtRuntime(true);
758         try {
759             assumeTrue("Skip GetAppStandby test: app standby is disabled.",
760                     AppStandbyUtils.isAppStandbyEnabled());
761 
762             setStandByBucket(mTargetPackage, "rare");
763             Map<String, Integer> bucketMap = mUsageStatsManager.getAppStandbyBuckets();
764             assertTrue("No bucket data returned", bucketMap.size() > 0);
765             final int bucket = bucketMap.getOrDefault(mTargetPackage, -1);
766             assertEquals("Incorrect bucket returned for " + mTargetPackage, bucket,
767                     STANDBY_BUCKET_RARE);
768         } finally {
769             AppStandbyUtils.setAppStandbyEnabledAtRuntime(origValue);
770         }
771     }
772 
773     @Test
testGetAppStandbyBucket()774     public void testGetAppStandbyBucket() throws Exception {
775         // App should be at least active, since it's running instrumentation tests
776         assertLessThanOrEqual(UsageStatsManager.STANDBY_BUCKET_ACTIVE,
777                 mUsageStatsManager.getAppStandbyBucket());
778     }
779 
780     @Test
testQueryEventsForSelf()781     public void testQueryEventsForSelf() throws Exception {
782         setAppOpsMode("ignore"); // To ensure permission is not required
783         // Time drifts of 2s are expected inside usage stats
784         final long start = System.currentTimeMillis() - 2_000;
785         setStandByBucket(mTargetPackage, "rare");
786         Thread.sleep(100);
787         setStandByBucket(mTargetPackage, "working_set");
788         Thread.sleep(100);
789         final long end = System.currentTimeMillis() + 2_000;
790         final UsageEvents events = mUsageStatsManager.queryEventsForSelf(start, end);
791         long rareTimeStamp = end + 1; // Initializing as rareTimeStamp > workingTimeStamp
792         long workingTimeStamp = start - 1;
793         int numEvents = 0;
794         while (events.hasNextEvent()) {
795             UsageEvents.Event event = new UsageEvents.Event();
796             assertTrue(events.getNextEvent(event));
797             numEvents++;
798             assertEquals("Event for a different package", mTargetPackage, event.getPackageName());
799             if (event.getEventType() == Event.STANDBY_BUCKET_CHANGED) {
800                 if (event.getAppStandbyBucket() == STANDBY_BUCKET_RARE) {
801                     rareTimeStamp = event.getTimeStamp();
802                 }
803                 else if (event.getAppStandbyBucket() == UsageStatsManager
804                         .STANDBY_BUCKET_WORKING_SET) {
805                     workingTimeStamp = event.getTimeStamp();
806                 }
807             }
808         }
809         assertTrue("Only " + numEvents + " events returned", numEvents >= 2);
810         assertLessThan(rareTimeStamp, workingTimeStamp);
811     }
812 
813     /**
814      * We can't run this test because we are unable to change the system time.
815      * It would be nice to add a shell command or other to allow the shell user
816      * to set the time, thereby allowing this test to set the time using the UIAutomator.
817      */
818     @Ignore
819     @Test
ignore_testStatsAreShiftedInTimeWhenSystemTimeChanges()820     public void ignore_testStatsAreShiftedInTimeWhenSystemTimeChanges() throws Exception {
821         launchSubActivity(Activities.ActivityOne.class);
822         launchSubActivity(Activities.ActivityThree.class);
823 
824         long endTime = System.currentTimeMillis();
825         long startTime = endTime - MINUTE;
826         Map<String, UsageStats> statsMap = mUsageStatsManager.queryAndAggregateUsageStats(startTime,
827                 endTime);
828         assertFalse(statsMap.isEmpty());
829         assertTrue(statsMap.containsKey(mTargetPackage));
830         final UsageStats before = statsMap.get(mTargetPackage);
831 
832         SystemClock.setCurrentTimeMillis(System.currentTimeMillis() - (DAY / 2));
833         try {
834             endTime = System.currentTimeMillis();
835             startTime = endTime - MINUTE;
836             statsMap = mUsageStatsManager.queryAndAggregateUsageStats(startTime, endTime);
837             assertFalse(statsMap.isEmpty());
838             assertTrue(statsMap.containsKey(mTargetPackage));
839             final UsageStats after = statsMap.get(mTargetPackage);
840             assertEquals(before.getPackageName(), after.getPackageName());
841 
842             long diff = before.getFirstTimeStamp() - after.getFirstTimeStamp();
843             assertLessThan(Math.abs(diff - (DAY / 2)), TIME_DIFF_THRESHOLD);
844 
845             assertEquals(before.getLastTimeStamp() - before.getFirstTimeStamp(),
846                     after.getLastTimeStamp() - after.getFirstTimeStamp());
847             assertEquals(before.getLastTimeUsed() - before.getFirstTimeStamp(),
848                     after.getLastTimeUsed() - after.getFirstTimeStamp());
849             assertEquals(before.getTotalTimeInForeground(), after.getTotalTimeInForeground());
850         } finally {
851             SystemClock.setCurrentTimeMillis(System.currentTimeMillis() + (DAY / 2));
852         }
853     }
854 
855     @Test
testUsageEventsParceling()856     public void testUsageEventsParceling() throws Exception {
857         final long startTime = System.currentTimeMillis() - MINUTE;
858 
859         // Ensure some data is in the UsageStats log.
860         @SuppressWarnings("unchecked")
861         Class<? extends Activity>[] activityClasses = new Class[] {
862                 Activities.ActivityTwo.class,
863                 Activities.ActivityOne.class,
864                 Activities.ActivityThree.class,
865         };
866         launchSubActivities(activityClasses);
867 
868         final long endTime = System.currentTimeMillis();
869         UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
870         assertTrue(events.getNextEvent(new UsageEvents.Event()));
871 
872         Parcel p = Parcel.obtain();
873         p.setDataPosition(0);
874         events.writeToParcel(p, 0);
875         p.setDataPosition(0);
876 
877         UsageEvents reparceledEvents = UsageEvents.CREATOR.createFromParcel(p);
878 
879         UsageEvents.Event e1 = new UsageEvents.Event();
880         UsageEvents.Event e2 = new UsageEvents.Event();
881         while (events.hasNextEvent() && reparceledEvents.hasNextEvent()) {
882             events.getNextEvent(e1);
883             reparceledEvents.getNextEvent(e2);
884             assertEquals(e1.getPackageName(), e2.getPackageName());
885             assertEquals(e1.getClassName(), e2.getClassName());
886             assertEquals(e1.getConfiguration(), e2.getConfiguration());
887             assertEquals(e1.getEventType(), e2.getEventType());
888             assertEquals(e1.getTimeStamp(), e2.getTimeStamp());
889         }
890 
891         assertEquals(events.hasNextEvent(), reparceledEvents.hasNextEvent());
892     }
893 
894     @AppModeFull(reason = "No usage events access in instant apps")
895     @Test
testPackageUsageStatsIntervals()896     public void testPackageUsageStatsIntervals() throws Exception {
897         final long beforeTime = System.currentTimeMillis();
898 
899         // Launch an Activity.
900         launchSubActivity(Activities.ActivityFour.class);
901         launchSubActivity(Activities.ActivityThree.class);
902 
903         final long endTime = System.currentTimeMillis();
904 
905         final SparseLongArray intervalLengths = new SparseLongArray();
906         intervalLengths.put(UsageStatsManager.INTERVAL_DAILY, DAY);
907         intervalLengths.put(UsageStatsManager.INTERVAL_WEEKLY, WEEK);
908         intervalLengths.put(UsageStatsManager.INTERVAL_MONTHLY, MONTH);
909         intervalLengths.put(UsageStatsManager.INTERVAL_YEARLY, YEAR);
910 
911         final int intervalCount = intervalLengths.size();
912         for (int i = 0; i < intervalCount; i++) {
913             final int intervalType = intervalLengths.keyAt(i);
914             final long intervalDuration = intervalLengths.valueAt(i);
915             final long startTime = endTime - (2 * intervalDuration);
916             final List<UsageStats> statsList = mUsageStatsManager.queryUsageStats(intervalType,
917                     startTime, endTime);
918             assertFalse(statsList.isEmpty());
919 
920             boolean foundPackage = false;
921             for (UsageStats stats : statsList) {
922                 // Verify that each period is a day long.
923                 assertLessThanOrEqual(stats.getLastTimeStamp() - stats.getFirstTimeStamp(),
924                         intervalDuration);
925                 if (stats.getPackageName().equals(mTargetPackage) &&
926                         stats.getLastTimeUsed() >= beforeTime - TIME_DIFF_THRESHOLD) {
927                     foundPackage = true;
928                 }
929             }
930 
931             assertTrue("Did not find package " + mTargetPackage + " in interval " + intervalType,
932                     foundPackage);
933         }
934     }
935 
936     @Test
testNoAccessSilentlyFails()937     public void testNoAccessSilentlyFails() throws Exception {
938         final long startTime = System.currentTimeMillis() - MINUTE;
939 
940         launchSubActivity(android.app.usage.cts.Activities.ActivityOne.class);
941         launchSubActivity(android.app.usage.cts.Activities.ActivityThree.class);
942 
943         final long endTime = System.currentTimeMillis();
944         List<UsageStats> stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST,
945                 startTime, endTime);
946         assertFalse(stats.isEmpty());
947 
948         // We set the mode to ignore because our package has the PACKAGE_USAGE_STATS permission,
949         // and default would allow in this case.
950         setAppOpsMode("ignore");
951 
952         stats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST,
953                 startTime, endTime);
954         assertTrue(stats.isEmpty());
955     }
956 
generateAndSendNotification()957     private void generateAndSendNotification() throws Exception {
958         final NotificationManager mNotificationManager =
959                 (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
960         final NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, "Channel",
961                 NotificationManager.IMPORTANCE_DEFAULT);
962         // Configure the notification channel.
963         mChannel.setDescription("Test channel");
964         mNotificationManager.createNotificationChannel(mChannel);
965         final Notification.Builder mBuilder =
966                 new Notification.Builder(mContext, CHANNEL_ID)
967                         .setSmallIcon(R.drawable.ic_notification)
968                         .setContentTitle("My notification")
969                         .setContentText("Hello World!");
970         final PendingIntent pi = PendingIntent.getActivity(mContext, 1,
971                 new Intent(Settings.ACTION_SETTINGS), PendingIntent.FLAG_IMMUTABLE);
972         mBuilder.setContentIntent(pi);
973         mNotificationManager.notify(1, mBuilder.build());
974         Thread.sleep(500);
975     }
976 
977     @AppModeFull(reason = "No usage events access in instant apps")
978     @Test
testNotificationSeen()979     public void testNotificationSeen() throws Exception {
980         final long startTime = System.currentTimeMillis();
981 
982         // Skip the test for wearable devices, televisions and automotives; none of them have
983         // a notification shade, as notifications are shown via a different path than phones
984         assumeFalse("Test cannot run on a watch- notification shade is not shown",
985                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
986         assumeFalse("Test cannot run on a television- notifications are not shown",
987                 mContext.getPackageManager().hasSystemFeature(
988                         PackageManager.FEATURE_LEANBACK_ONLY));
989         assumeFalse("Test cannot run on an automotive - notification shade is not shown",
990                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
991 
992         generateAndSendNotification();
993 
994         long endTime = System.currentTimeMillis();
995         UsageEvents events = queryEventsAsShell(startTime, endTime);
996         boolean found = false;
997         Event event = new Event();
998         while (events.hasNextEvent()) {
999             events.getNextEvent(event);
1000             if (event.getEventType() == Event.NOTIFICATION_SEEN) {
1001                 found = true;
1002             }
1003         }
1004         assertFalse(found);
1005         // Pull down shade
1006         mUiDevice.openNotification();
1007         outer:
1008         for (int i = 0; i < 5; i++) {
1009             Thread.sleep(500);
1010             endTime = System.currentTimeMillis();
1011             events = queryEventsAsShell(startTime, endTime);
1012             found = false;
1013             while (events.hasNextEvent()) {
1014                 events.getNextEvent(event);
1015                 if (event.getEventType() == Event.NOTIFICATION_SEEN) {
1016                     found = true;
1017                     break outer;
1018                 }
1019             }
1020         }
1021         assertTrue(found);
1022         mUiDevice.pressBack();
1023     }
1024 
1025     @AppModeFull(reason = "No usage events access in instant apps")
1026     @MediumTest
1027     @Test
testNotificationSeen_verifyBucket()1028     public void testNotificationSeen_verifyBucket() throws Exception {
1029         // Skip the test for wearable devices, televisions and automotives; none of them have
1030         // a notification shade, as notifications are shown via a different path than phones
1031         assumeFalse("Test cannot run on a watch- notification shade is not shown",
1032                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
1033         assumeFalse("Test cannot run on a television- notifications are not shown",
1034                 mContext.getPackageManager().hasSystemFeature(
1035                         PackageManager.FEATURE_LEANBACK_ONLY));
1036         assumeFalse("Test cannot run on an automotive - notification shade is not shown",
1037                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
1038 
1039         final long promotedBucketHoldDurationMs = TimeUnit.MINUTES.toMillis(2);
1040         try (DeviceConfigStateHelper deviceConfigStateHelper =
1041                      new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
1042             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET,
1043                     String.valueOf(STANDBY_BUCKET_FREQUENT));
1044             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_HOLD_DURATION,
1045                     String.valueOf(promotedBucketHoldDurationMs));
1046 
1047             wakeDevice();
1048             dismissKeyguard();
1049             final TestServiceConnection connection = bindToTestServiceAndGetConnection();
1050             final TestServiceConnection connection2 = bindToTestServiceAndGetConnection(
1051                     TEST_APP_API_32_PKG);
1052             try {
1053                 ITestReceiver testReceiver = connection.getITestReceiver();
1054                 ITestReceiver testReceiver2 = connection2.getITestReceiver();
1055                 for (ITestReceiver receiver : new ITestReceiver[] {
1056                         testReceiver,
1057                         testReceiver2
1058                 }) {
1059                     receiver.cancelAll();
1060                     receiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
1061                             TEST_NOTIFICATION_CHANNEL_NAME,
1062                             TEST_NOTIFICATION_CHANNEL_DESC);
1063                     receiver.postNotification(TEST_NOTIFICATION_ID_1,
1064                             buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
1065                                     TEST_NOTIFICATION_TEXT_1));
1066                 }
1067             } finally {
1068                 connection.unbind();
1069                 connection2.unbind();
1070             }
1071             for (String pkg : new String[] {TEST_APP_PKG, TEST_APP_API_32_PKG}) {
1072                 setStandByBucket(pkg, "rare");
1073                 executeShellCmd("cmd usagestats clear-last-used-timestamps " + pkg);
1074                 waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(pkg),
1075                         STANDBY_BUCKET_RARE);
1076             }
1077             mUiDevice.openNotification();
1078             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1079                     STANDBY_BUCKET_FREQUENT);
1080             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_API_32_PKG),
1081                     STANDBY_BUCKET_FREQUENT);
1082             SystemClock.sleep(promotedBucketHoldDurationMs);
1083             // Verify that after the promoted duration expires, the app drops into a
1084             // lower standby bucket.
1085             // Note: "set-standby-bucket" command only updates the bucket of the app and not
1086             // it's last used timestamps. So, it is possible when the standby bucket is calculated
1087             // the app is not going to be back in RARE bucket we set earlier. So, just verify
1088             // the app gets demoted to some lower bucket.
1089             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1090                     result -> result > STANDBY_BUCKET_FREQUENT,
1091                     "bucket should be > FREQUENT");
1092             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_API_32_PKG),
1093                     result -> result > STANDBY_BUCKET_FREQUENT,
1094                     "bucket should be > FREQUENT");
1095             mUiDevice.pressHome();
1096         }
1097     }
1098 
1099     @AppModeFull(reason = "No usage events access in instant apps")
1100     @MediumTest
1101     @Test
testNotificationSeen_verifyBucket_retainPreTImpact()1102     public void testNotificationSeen_verifyBucket_retainPreTImpact() throws Exception {
1103         // Skip the test for wearable devices, televisions and automotives; none of them have
1104         // a notification shade, as notifications are shown via a different path than phones
1105         assumeFalse("Test cannot run on a watch- notification shade is not shown",
1106                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
1107         assumeFalse("Test cannot run on a television- notifications are not shown",
1108                 mContext.getPackageManager().hasSystemFeature(
1109                         PackageManager.FEATURE_LEANBACK_ONLY));
1110         assumeFalse("Test cannot run on an automotive - notification shade is not shown",
1111                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
1112 
1113         final long promotedBucketHoldDurationMs = TimeUnit.SECONDS.toMillis(10);
1114         try (DeviceConfigStateHelper deviceConfigStateHelper =
1115                      new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
1116             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET,
1117                     String.valueOf(STANDBY_BUCKET_FREQUENT));
1118             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_HOLD_DURATION,
1119                     String.valueOf(promotedBucketHoldDurationMs));
1120             deviceConfigStateHelper.set(KEY_RETAIN_NOTIFICATION_SEEN_IMPACT_FOR_PRE_T_APPS,
1121                     String.valueOf(true));
1122 
1123             wakeDevice();
1124             dismissKeyguard();
1125             final TestServiceConnection connection = bindToTestServiceAndGetConnection();
1126             final TestServiceConnection connection2 = bindToTestServiceAndGetConnection(
1127                     TEST_APP_API_32_PKG);
1128             try {
1129                 ITestReceiver testReceiver = connection.getITestReceiver();
1130                 ITestReceiver testReceiver2 = connection2.getITestReceiver();
1131                 for (ITestReceiver receiver : new ITestReceiver[] {
1132                         testReceiver,
1133                         testReceiver2
1134                 }) {
1135                     receiver.cancelAll();
1136                     receiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
1137                             TEST_NOTIFICATION_CHANNEL_NAME,
1138                             TEST_NOTIFICATION_CHANNEL_DESC);
1139                     receiver.postNotification(TEST_NOTIFICATION_ID_1,
1140                             buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
1141                                     TEST_NOTIFICATION_TEXT_1));
1142                 }
1143             } finally {
1144                 connection.unbind();
1145                 connection2.unbind();
1146             }
1147             for (String pkg : new String[] {TEST_APP_PKG, TEST_APP_API_32_PKG}) {
1148                 setStandByBucket(pkg, "rare");
1149                 executeShellCmd("cmd usagestats clear-last-used-timestamps " + pkg);
1150                 waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(pkg),
1151                         STANDBY_BUCKET_RARE);
1152             }
1153             mUiDevice.openNotification();
1154             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1155                     STANDBY_BUCKET_FREQUENT);
1156             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_API_32_PKG),
1157                     STANDBY_BUCKET_WORKING_SET);
1158             SystemClock.sleep(promotedBucketHoldDurationMs);
1159             // Verify that after the promoted duration expires, the app drops into a
1160             // lower standby bucket.
1161             // Note: "set-standby-bucket" command only updates the bucket of the app and not
1162             // it's last used timestamps. So, it is possible when the standby bucket is calculated
1163             // the app is not going to be back in RARE bucket we set earlier. So, just verify
1164             // the app gets demoted to some lower bucket.
1165             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1166                     result -> result > STANDBY_BUCKET_FREQUENT,
1167                     "bucket should be > FREQUENT");
1168             // App targeting api level 32 should still be in the working set bucket after a few
1169             // minutes.
1170             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_API_32_PKG),
1171                     STANDBY_BUCKET_WORKING_SET);
1172             mUiDevice.pressHome();
1173         }
1174     }
1175 
1176     @AppModeFull(reason = "No usage events access in instant apps")
1177     @MediumTest
1178     @Test
testNotificationSeen_noImpact()1179     public void testNotificationSeen_noImpact() throws Exception {
1180         // Skip the test for wearable devices, televisions and automotives; none of them have
1181         // a notification shade, as notifications are shown via a different path than phones
1182         assumeFalse("Test cannot run on a watch- notification shade is not shown",
1183                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
1184         assumeFalse("Test cannot run on a television- notifications are not shown",
1185                 mContext.getPackageManager().hasSystemFeature(
1186                         PackageManager.FEATURE_LEANBACK_ONLY));
1187         assumeFalse("Test cannot run on an automotive - notification shade is not shown",
1188                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
1189 
1190         final long promotedBucketHoldDurationMs = TimeUnit.SECONDS.toMillis(10);
1191         try (DeviceConfigStateHelper deviceConfigStateHelper =
1192                      new DeviceConfigStateHelper(NAMESPACE_APP_STANDBY)) {
1193             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_PROMOTED_BUCKET,
1194                     String.valueOf(STANDBY_BUCKET_NEVER));
1195             deviceConfigStateHelper.set(KEY_NOTIFICATION_SEEN_HOLD_DURATION,
1196                     String.valueOf(promotedBucketHoldDurationMs));
1197 
1198             wakeDevice();
1199             dismissKeyguard();
1200             final TestServiceConnection connection = bindToTestServiceAndGetConnection();
1201             try {
1202                 ITestReceiver testReceiver = connection.getITestReceiver();
1203                 testReceiver.cancelAll();
1204                 testReceiver.createNotificationChannel(TEST_NOTIFICATION_CHANNEL_ID,
1205                         TEST_NOTIFICATION_CHANNEL_NAME,
1206                         TEST_NOTIFICATION_CHANNEL_DESC);
1207                 testReceiver.postNotification(TEST_NOTIFICATION_ID_1,
1208                         buildNotification(TEST_NOTIFICATION_CHANNEL_ID, TEST_NOTIFICATION_ID_1,
1209                                 TEST_NOTIFICATION_TEXT_1));
1210             } finally {
1211                 connection.unbind();
1212             }
1213             setStandByBucket(TEST_APP_PKG, "rare");
1214             executeShellCmd("cmd usagestats clear-last-used-timestamps " + TEST_APP_PKG);
1215             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1216                     STANDBY_BUCKET_RARE);
1217             mUiDevice.openNotification();
1218             // Verify there is no change in the standby bucket
1219             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1220                     STANDBY_BUCKET_RARE);
1221             SystemClock.sleep(promotedBucketHoldDurationMs);
1222             // Verify there is no change in the standby bucket even after the hold duration
1223             // is elapsed.
1224             waitUntil(() -> mUsageStatsManager.getAppStandbyBucket(TEST_APP_PKG),
1225                     STANDBY_BUCKET_RARE);
1226             mUiDevice.pressHome();
1227         }
1228     }
1229 
buildNotification(String channelId, int notificationId, String notificationText)1230     private Notification buildNotification(String channelId, int notificationId,
1231             String notificationText) {
1232         return new Notification.Builder(mContext, channelId)
1233                 .setSmallIcon(android.R.drawable.ic_info)
1234                 .setContentTitle(String.format(TEST_NOTIFICATION_TITLE_FMT, notificationId))
1235                 .setContentText(notificationText)
1236                 .build();
1237     }
1238 
1239     @AppModeFull(reason = "No usage events access in instant apps")
1240     @Test
testNotificationInterruptionEventsObfuscation()1241     public void testNotificationInterruptionEventsObfuscation() throws Exception {
1242         final long startTime = System.currentTimeMillis();
1243 
1244         // Skip the test for wearable devices and televisions; none of them have a
1245         // notification shade.
1246         assumeFalse("Test cannot run on a watch- notification shade is not shown",
1247                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
1248         assumeFalse("Test cannot run on a television- notifications are not shown",
1249                 mContext.getPackageManager().hasSystemFeature(
1250                         PackageManager.FEATURE_LEANBACK_ONLY));
1251 
1252         generateAndSendNotification();
1253         final long endTime = System.currentTimeMillis();
1254 
1255         final UsageEvents obfuscatedEvents = mUsageStatsManager.queryEvents(startTime, endTime);
1256         final UsageEvents unobfuscatedEvents = queryEventsAsShell(startTime, endTime);
1257         verifyNotificationInterruptionEvent(obfuscatedEvents, true);
1258         verifyNotificationInterruptionEvent(unobfuscatedEvents, false);
1259     }
1260 
verifyNotificationInterruptionEvent(UsageEvents events, boolean obfuscated)1261     private void verifyNotificationInterruptionEvent(UsageEvents events, boolean obfuscated) {
1262         boolean found = false;
1263         Event event = new Event();
1264         while (events.hasNextEvent()) {
1265             events.getNextEvent(event);
1266             if (event.getEventType() == Event.NOTIFICATION_INTERRUPTION) {
1267                 found = true;
1268                 break;
1269             }
1270         }
1271         assertTrue(found);
1272         if (obfuscated) {
1273             assertEquals("Notification channel id was not obfuscated.",
1274                     UsageEvents.OBFUSCATED_NOTIFICATION_CHANNEL_ID, event.mNotificationChannelId);
1275         } else {
1276             assertEquals("Failed to verify notification channel id.",
1277                     CHANNEL_ID, event.mNotificationChannelId);
1278         }
1279     }
1280 
1281     @AppModeFull(reason = "No usage events access in instant apps")
1282     @Test
testUserUnlockedEventExists()1283     public void testUserUnlockedEventExists() throws Exception {
1284         final UsageEvents events = mUsageStatsManager.queryEvents(0, System.currentTimeMillis());
1285         while (events.hasNextEvent()) {
1286             final Event event = new Event();
1287             events.getNextEvent(event);
1288             if (event.mEventType == Event.USER_UNLOCKED) {
1289                 return;
1290             }
1291         }
1292         fail("Couldn't find a user unlocked event.");
1293     }
1294 
1295     @AppModeFull(reason = "No usage stats access in instant apps")
1296     @Test
testCrossUserQuery_withPermission()1297     public void testCrossUserQuery_withPermission() throws Exception {
1298         assumeTrue(UserManager.supportsMultipleUsers());
1299         final long startTime = System.currentTimeMillis();
1300         // Create user
1301         final int userId = createUser("Test User");
1302         startUser(userId, true);
1303         installExistingPackageAsUser(mContext.getPackageName(), userId);
1304 
1305         // Query as Shell
1306         SystemUtil.runWithShellPermissionIdentity(() -> {
1307             final UserHandle otherUser = UserHandle.of(userId);
1308             final Context userContext = mContext.createContextAsUser(otherUser, 0);
1309 
1310             final UsageStatsManager usmOther = userContext.getSystemService(
1311                     UsageStatsManager.class);
1312 
1313             waitUntil(() -> {
1314                 final List<UsageStats> stats = usmOther.queryUsageStats(
1315                         UsageStatsManager.INTERVAL_DAILY, startTime, System.currentTimeMillis());
1316                 return stats.isEmpty();
1317             }, false);
1318         });
1319         // user cleanup done in @After
1320     }
1321 
1322     @AppModeFull(reason = "No usage stats access in instant apps")
1323     @Test
testCrossUserQuery_withoutPermission()1324     public void testCrossUserQuery_withoutPermission() throws Exception {
1325         assumeTrue(UserManager.supportsMultipleUsers());
1326         final long startTime = System.currentTimeMillis();
1327         // Create user
1328         final int userId = createUser("Test User");
1329         startUser(userId, true);
1330         installExistingPackageAsUser(mContext.getPackageName(), userId);
1331 
1332         SystemUtil.runWithShellPermissionIdentity(() -> {
1333             mOtherUserContext = mContext.createContextAsUser(UserHandle.of(userId), 0);
1334             mOtherUsageStats = mOtherUserContext.getSystemService(UsageStatsManager.class);
1335         });
1336 
1337         try {
1338             mOtherUsageStats.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, startTime,
1339                     System.currentTimeMillis());
1340             fail("Query across users should require INTERACT_ACROSS_USERS permission");
1341         } catch (SecurityException se) {
1342             // Expected
1343         }
1344 
1345         // user cleanup done in @After
1346     }
1347 
1348     // TODO(148887416): get this test to work for instant apps
1349     @AppModeFull(reason = "Test APK Activity not found when installed as an instant app")
1350     @Test
testUserForceIntoRestricted()1351     public void testUserForceIntoRestricted() throws Exception {
1352         launchSubActivity(TaskRootActivity.class);
1353         assertEquals("Activity launch didn't bring app up to ACTIVE bucket",
1354                 UsageStatsManager.STANDBY_BUCKET_ACTIVE,
1355                 mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
1356 
1357         // User force shouldn't have to deal with the timeout.
1358         setStandByBucket(mTargetPackage, "restricted");
1359         assertEquals("User was unable to force an ACTIVE app down into RESTRICTED bucket",
1360                 UsageStatsManager.STANDBY_BUCKET_RESTRICTED,
1361                 mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
1362 
1363     }
1364 
1365     // TODO(148887416): get this test to work for instant apps
1366     @AppModeFull(reason = "Test APK Activity not found when installed as an instant app")
1367     @Test
testUserLaunchRemovesFromRestricted()1368     public void testUserLaunchRemovesFromRestricted() throws Exception {
1369         setStandByBucket(mTargetPackage, "restricted");
1370         assertEquals("User was unable to force an app into RESTRICTED bucket",
1371                 UsageStatsManager.STANDBY_BUCKET_RESTRICTED,
1372                 mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
1373 
1374         launchSubActivity(TaskRootActivity.class);
1375         assertEquals("Activity launch didn't bring RESTRICTED app into ACTIVE bucket",
1376                 UsageStatsManager.STANDBY_BUCKET_ACTIVE,
1377                 mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
1378     }
1379 
1380     // TODO(148887416): get this test to work for instant apps
1381     @AppModeFull(reason = "Test APK Activity not found when installed as an instant app")
1382     @Test
testIsAppInactive()1383     public void testIsAppInactive() throws Exception {
1384         assumeTrue("Test only works on devices with a battery", BatteryUtils.hasBattery());
1385 
1386         setStandByBucket(mTargetPackage, "rare");
1387 
1388         try {
1389             BatteryUtils.runDumpsysBatteryUnplug();
1390 
1391             waitUntil(() -> mUsageStatsManager.isAppInactive(mTargetPackage), true);
1392             assertFalse(
1393                     "App without PACKAGE_USAGE_STATS permission should always receive false for "
1394                             + "isAppInactive",
1395                     isAppInactiveAsPermissionlessApp(mTargetPackage));
1396 
1397             launchSubActivity(Activities.ActivityOne.class);
1398 
1399             waitUntil(() -> mUsageStatsManager.isAppInactive(mTargetPackage), false);
1400             assertFalse(
1401                     "App without PACKAGE_USAGE_STATS permission should always receive false for "
1402                             + "isAppInactive",
1403                     isAppInactiveAsPermissionlessApp(mTargetPackage));
1404 
1405             mUiDevice.pressHome();
1406             setStandByBucket(TEST_APP_PKG, "rare");
1407             // Querying for self does not require the PACKAGE_USAGE_STATS
1408             waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), true);
1409             assertTrue(
1410                     "App without PACKAGE_USAGE_STATS permission should be able to call "
1411                             + "isAppInactive for itself",
1412                     isAppInactiveAsPermissionlessApp(TEST_APP_PKG));
1413 
1414             launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
1415 
1416             waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), false);
1417             assertFalse(
1418                     "App without PACKAGE_USAGE_STATS permission should be able to call "
1419                             + "isAppInactive for itself",
1420                     isAppInactiveAsPermissionlessApp(TEST_APP_PKG));
1421 
1422         } finally {
1423             BatteryUtils.runDumpsysBatteryReset();
1424         }
1425     }
1426 
1427     // TODO(148887416): get this test to work for instant apps
1428     @AppModeFull(reason = "Test APK Activity not found when installed as an instant app")
1429     @Test
testIsAppInactive_Charging()1430     public void testIsAppInactive_Charging() throws Exception {
1431         assumeTrue("Test only works on devices with a battery", BatteryUtils.hasBattery());
1432 
1433         setStandByBucket(TEST_APP_PKG, "rare");
1434 
1435         try {
1436             BatteryUtils.runDumpsysBatteryUnplug();
1437             // Plug/unplug change takes a while to propagate inside the system.
1438             waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), true);
1439 
1440             BatteryUtils.runDumpsysBatterySetPluggedIn(true);
1441             BatteryUtils.runDumpsysBatterySetLevel(100);
1442             // Plug/unplug change takes a while to propagate inside the system.
1443             waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), false);
1444         } finally {
1445             BatteryUtils.runDumpsysBatteryReset();
1446         }
1447     }
1448 
1449     @Test
testSetEstimatedLaunchTime_NotUsableByShell()1450     public void testSetEstimatedLaunchTime_NotUsableByShell() {
1451         SystemUtil.runWithShellPermissionIdentity(() -> {
1452             try {
1453                 mUsageStatsManager.setEstimatedLaunchTimeMillis(TEST_APP_PKG,
1454                         System.currentTimeMillis() + 1000);
1455                 fail("Shell was able to set an app's estimated launch time");
1456             } catch (SecurityException expected) {
1457                 // Success
1458             }
1459 
1460             try {
1461                 Map<String, Long> estimatedLaunchTime = new ArrayMap<>();
1462                 estimatedLaunchTime.put(TEST_APP_PKG, System.currentTimeMillis() + 10_000);
1463                 mUsageStatsManager.setEstimatedLaunchTimesMillis(estimatedLaunchTime);
1464                 fail("Shell was able to set an app's estimated launch time");
1465             } catch (SecurityException expected) {
1466                 // Success
1467             }
1468         }, Manifest.permission.CHANGE_APP_LAUNCH_TIME_ESTIMATE);
1469     }
1470 
1471     private static final int[] INTERACTIVE_EVENTS = new int[] {
1472             Event.SCREEN_INTERACTIVE,
1473             Event.SCREEN_NON_INTERACTIVE
1474     };
1475 
1476     private static final int[] KEYGUARD_EVENTS = new int[] {
1477             Event.KEYGUARD_SHOWN,
1478             Event.KEYGUARD_HIDDEN
1479     };
1480 
1481     private static final int[] ALL_EVENTS = new int[] {
1482             Event.SCREEN_INTERACTIVE,
1483             Event.SCREEN_NON_INTERACTIVE,
1484             Event.KEYGUARD_SHOWN,
1485             Event.KEYGUARD_HIDDEN
1486     };
1487 
1488     private static final int[] PAUSED_EVENT = new int[] {
1489             Event.ACTIVITY_PAUSED
1490     };
1491 
1492     private static final int[] STOPPED_EVENT = new int[] {
1493             Event.ACTIVITY_STOPPED
1494     };
1495 
getEvents(int[] whichEvents, long startTime, List<Event> out, String packageName)1496     private long getEvents(int[] whichEvents, long startTime, List<Event> out, String packageName) {
1497         final long endTime = System.currentTimeMillis();
1498         if (DEBUG) {
1499             Log.i(TAG, "Looking for events " + Arrays.toString(whichEvents)
1500                     + " between " + startTime + " and " + endTime);
1501         }
1502         UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
1503 
1504         long latestTime = 0;
1505 
1506         // Find events.
1507         while (events.hasNextEvent()) {
1508             UsageEvents.Event event = new UsageEvents.Event();
1509             assertTrue(events.getNextEvent(event));
1510             final int ev = event.getEventType();
1511             for (int which : whichEvents) {
1512                 if (ev == which) {
1513                     if (packageName != null && !packageName.equals(event.getPackageName())) {
1514                         break;
1515                     }
1516 
1517                     if (out != null) {
1518                         out.add(event);
1519                     }
1520                     if (DEBUG) Log.i(TAG, "Next event type " + event.getEventType()
1521                             + " time=" + event.getTimeStamp());
1522                     if (latestTime < event.getTimeStamp()) {
1523                         latestTime = event.getTimeStamp();
1524                     }
1525                     break;
1526                 }
1527             }
1528         }
1529 
1530         return latestTime;
1531     }
1532 
waitForEventCount(int[] whichEvents, long startTime, int count)1533     private ArrayList<Event> waitForEventCount(int[] whichEvents, long startTime, int count) {
1534         return waitForEventCount(whichEvents, startTime, count, null);
1535     }
1536 
waitForEventCount(int[] whichEvents, long startTime, int count, String packageName)1537     private ArrayList<Event> waitForEventCount(int[] whichEvents, long startTime, int count,
1538             String packageName) {
1539         final ArrayList<Event> events = new ArrayList<>();
1540         final long endTime = SystemClock.uptimeMillis() + TIMEOUT;
1541         do {
1542             events.clear();
1543             getEvents(whichEvents, startTime, events, packageName);
1544             if (events.size() == count) {
1545                 return events;
1546             }
1547             if (events.size() > count) {
1548                 fail("Found too many events: got " + events.size() + ", expected " + count);
1549                 return events;
1550             }
1551             SystemClock.sleep(10);
1552         } while (SystemClock.uptimeMillis() < endTime);
1553 
1554         fail("Timed out waiting for " + count + " events, only reached " + events.size());
1555         return events;
1556     }
1557 
waitUntil(Supplier<T> resultSupplier, T expectedResult)1558     private <T> void waitUntil(Supplier<T> resultSupplier, T expectedResult) {
1559         final T actualResult = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS, resultSupplier,
1560                 result -> Objects.equals(expectedResult, result));
1561         assertEquals(expectedResult, actualResult);
1562     }
1563 
waitUntil(Supplier<T> resultSupplier, Function<T, Boolean> condition, String conditionDesc)1564     private <T> void waitUntil(Supplier<T> resultSupplier, Function<T, Boolean> condition,
1565             String conditionDesc) {
1566         final T actualResult = PollingCheck.waitFor(DEFAULT_TIMEOUT_MS, resultSupplier,
1567                 condition);
1568         Log.d(TAG, "Expecting '" + conditionDesc + "'; actual result=" + actualResult);
1569         assertTrue("Timed out waiting for '" + conditionDesc + "', actual=" + actualResult,
1570                 condition.apply(actualResult));
1571     }
1572 
1573     static class AggrEventData {
1574         final String label;
1575         int count;
1576         long duration;
1577         long lastEventTime;
1578 
AggrEventData(String label)1579         AggrEventData(String label) {
1580             this.label = label;
1581         }
1582     }
1583 
1584     static class AggrAllEventsData {
1585         final AggrEventData interactive = new AggrEventData("Interactive");
1586         final AggrEventData nonInteractive = new AggrEventData("Non-interactive");
1587         final AggrEventData keyguardShown = new AggrEventData("Keyguard shown");
1588         final AggrEventData keyguardHidden = new AggrEventData("Keyguard hidden");
1589     }
1590 
getAggrEventData()1591     private SparseArray<AggrAllEventsData> getAggrEventData() {
1592         final long endTime = System.currentTimeMillis();
1593 
1594         final SparseLongArray intervalLengths = new SparseLongArray();
1595         intervalLengths.put(UsageStatsManager.INTERVAL_DAILY, DAY);
1596         intervalLengths.put(UsageStatsManager.INTERVAL_WEEKLY, WEEK);
1597         intervalLengths.put(UsageStatsManager.INTERVAL_MONTHLY, MONTH);
1598         intervalLengths.put(UsageStatsManager.INTERVAL_YEARLY, YEAR);
1599 
1600         final SparseArray<AggrAllEventsData> allAggr = new SparseArray<>();
1601 
1602         final int intervalCount = intervalLengths.size();
1603         for (int i = 0; i < intervalCount; i++) {
1604             final int intervalType = intervalLengths.keyAt(i);
1605             final long intervalDuration = intervalLengths.valueAt(i);
1606             final long startTime = endTime - (2 * intervalDuration);
1607             List<EventStats> statsList = mUsageStatsManager.queryEventStats(intervalType,
1608                     startTime, endTime);
1609             assertFalse(statsList.isEmpty());
1610 
1611             final AggrAllEventsData aggr = new AggrAllEventsData();
1612             allAggr.put(intervalType, aggr);
1613 
1614             boolean foundEvent = false;
1615             for (EventStats stats : statsList) {
1616                 // Verify that each period is a day long.
1617                 //assertLessThanOrEqual(stats.getLastTimeStamp() - stats.getFirstTimeStamp(),
1618                 //        intervalDuration);
1619                 AggrEventData data = null;
1620                 switch (stats.getEventType()) {
1621                     case Event.SCREEN_INTERACTIVE:
1622                         data = aggr.interactive;
1623                         break;
1624                     case Event.SCREEN_NON_INTERACTIVE:
1625                         data = aggr.nonInteractive;
1626                         break;
1627                     case Event.KEYGUARD_HIDDEN:
1628                         data = aggr.keyguardHidden;
1629                         break;
1630                     case Event.KEYGUARD_SHOWN:
1631                         data = aggr.keyguardShown;
1632                         break;
1633                 }
1634                 if (data != null) {
1635                     foundEvent = true;
1636                     data.count += stats.getCount();
1637                     data.duration += stats.getTotalTime();
1638                     if (data.lastEventTime < stats.getLastEventTime()) {
1639                         data.lastEventTime = stats.getLastEventTime();
1640                     }
1641                 }
1642             }
1643 
1644             assertTrue("Did not find event data in interval " + intervalType,
1645                     foundEvent);
1646         }
1647 
1648         return allAggr;
1649     }
1650 
verifyCount(int oldCount, int newCount, boolean larger, String label, int interval)1651     private void verifyCount(int oldCount, int newCount, boolean larger, String label,
1652             int interval) {
1653         if (larger) {
1654             if (newCount <= oldCount) {
1655                 fail(label + " count newer " + newCount
1656                         + " expected to be larger than older " + oldCount
1657                         + " @ interval " + interval);
1658             }
1659         } else {
1660             if (newCount != oldCount) {
1661                 fail(label + " count newer " + newCount
1662                         + " expected to be same as older " + oldCount
1663                         + " @ interval " + interval);
1664             }
1665         }
1666     }
1667 
verifyDuration(long oldDur, long newDur, boolean larger, String label, int interval)1668     private void verifyDuration(long oldDur, long newDur, boolean larger, String label,
1669             int interval) {
1670         if (larger) {
1671             if (newDur <= oldDur) {
1672                 fail(label + " duration newer " + newDur
1673                         + " expected to be larger than older " + oldDur
1674                         + " @ interval " + interval);
1675             }
1676         } else {
1677             if (newDur != oldDur) {
1678                 fail(label + " duration newer " + newDur
1679                         + " expected to be same as older " + oldDur
1680                         + " @ interval " + interval);
1681             }
1682         }
1683     }
1684 
verifyAggrEventData(AggrEventData older, AggrEventData newer, boolean countLarger, boolean durationLarger, int interval)1685     private void verifyAggrEventData(AggrEventData older, AggrEventData newer,
1686             boolean countLarger, boolean durationLarger, int interval) {
1687         verifyCount(older.count, newer.count, countLarger, older.label, interval);
1688         verifyDuration(older.duration, newer.duration, durationLarger, older.label, interval);
1689     }
1690 
verifyAggrInteractiveEventData(SparseArray<AggrAllEventsData> older, SparseArray<AggrAllEventsData> newer, boolean interactiveLarger, boolean nonInteractiveLarger)1691     private void verifyAggrInteractiveEventData(SparseArray<AggrAllEventsData> older,
1692             SparseArray<AggrAllEventsData> newer, boolean interactiveLarger,
1693             boolean nonInteractiveLarger) {
1694         for (int i = 0; i < older.size(); i++) {
1695             AggrAllEventsData o = older.valueAt(i);
1696             AggrAllEventsData n = newer.valueAt(i);
1697             // When we are told something is larger, that means we have transitioned
1698             // *out* of that state -- so the duration of that state is expected to
1699             // increase, but the count should stay the same (and the count of the state
1700             // we transition to is increased).
1701             final int interval = older.keyAt(i);
1702             verifyAggrEventData(o.interactive, n.interactive, nonInteractiveLarger,
1703                     interactiveLarger, interval);
1704             verifyAggrEventData(o.nonInteractive, n.nonInteractive, interactiveLarger,
1705                     nonInteractiveLarger, interval);
1706         }
1707     }
1708 
verifyAggrKeyguardEventData(SparseArray<AggrAllEventsData> older, SparseArray<AggrAllEventsData> newer, boolean hiddenLarger, boolean shownLarger)1709     private void verifyAggrKeyguardEventData(SparseArray<AggrAllEventsData> older,
1710             SparseArray<AggrAllEventsData> newer, boolean hiddenLarger,
1711             boolean shownLarger) {
1712         for (int i = 0; i < older.size(); i++) {
1713             AggrAllEventsData o = older.valueAt(i);
1714             AggrAllEventsData n = newer.valueAt(i);
1715             // When we are told something is larger, that means we have transitioned
1716             // *out* of that state -- so the duration of that state is expected to
1717             // increase, but the count should stay the same (and the count of the state
1718             // we transition to is increased).
1719             final int interval = older.keyAt(i);
1720             verifyAggrEventData(o.keyguardHidden, n.keyguardHidden, shownLarger,
1721                     hiddenLarger, interval);
1722             verifyAggrEventData(o.keyguardShown, n.keyguardShown, hiddenLarger,
1723                     shownLarger, interval);
1724         }
1725     }
1726 
1727     @AppModeFull(reason = "No usage events access in instant apps")
1728     @Test
testInteractiveEvents()1729     public void testInteractiveEvents() throws Exception {
1730         // We need to start out with the screen on.
1731         wakeDevice();
1732         dismissKeyguard(); // also want to start out with the keyguard dismissed.
1733         SystemClock.sleep(500);
1734 
1735 
1736         try {
1737             ArrayList<Event> events;
1738 
1739             // Determine time to start looking for events.
1740             final long startTime = getEvents(ALL_EVENTS, 0, null, null) + 1;
1741             SparseArray<AggrAllEventsData> baseAggr = getAggrEventData();
1742             SystemClock.sleep(500);
1743 
1744             // First test -- put device to sleep and make sure we see this event.
1745             sleepDevice();
1746             SystemClock.sleep(500);
1747 
1748             // Do we have one event, going in to non-interactive mode?
1749             events = waitForEventCount(INTERACTIVE_EVENTS, startTime, 1);
1750             assertEquals(Event.SCREEN_NON_INTERACTIVE, events.get(0).getEventType());
1751             SparseArray<AggrAllEventsData> offAggr = getAggrEventData();
1752             verifyAggrInteractiveEventData(baseAggr, offAggr, true, false);
1753 
1754             // Next test -- turn screen on and make sure we have a second event.
1755             // XXX need to wait a bit so we don't accidentally trigger double-power
1756             // to launch camera.  (SHOULD FIX HOW WE WAKEUP / SLEEP TO NOT USE POWER KEY)
1757             SystemClock.sleep(500);
1758             wakeDevice();
1759             events = waitForEventCount(INTERACTIVE_EVENTS, startTime, 2);
1760             assertEquals(Event.SCREEN_NON_INTERACTIVE, events.get(0).getEventType());
1761             assertEquals(Event.SCREEN_INTERACTIVE, events.get(1).getEventType());
1762             SparseArray<AggrAllEventsData> onAggr = getAggrEventData();
1763             verifyAggrInteractiveEventData(offAggr, onAggr, false, true);
1764 
1765             // If the device is doing a lock screen, verify that we are also seeing the
1766             // appropriate keyguard behavior.  We don't know the timing from when the screen
1767             // will go off until the keyguard is shown, so we will do this all after turning
1768             // the screen back on (at which point it must be shown).
1769             // XXX CTS seems to be preventing the keyguard from showing, so this path is
1770             // never being tested.
1771             if (mKeyguardManager.isKeyguardLocked()) {
1772                 events = waitForEventCount(KEYGUARD_EVENTS, startTime, 1);
1773                 assertEquals(Event.KEYGUARD_SHOWN, events.get(0).getEventType());
1774                 SparseArray<AggrAllEventsData> shownAggr = getAggrEventData();
1775                 verifyAggrKeyguardEventData(offAggr, shownAggr, true, false);
1776 
1777                 // Now dismiss the keyguard and verify the resulting events.
1778                 executeShellCmd("wm dismiss-keyguard");
1779                 events = waitForEventCount(KEYGUARD_EVENTS, startTime, 2);
1780                 assertEquals(Event.KEYGUARD_SHOWN, events.get(0).getEventType());
1781                 assertEquals(Event.KEYGUARD_HIDDEN, events.get(1).getEventType());
1782                 SparseArray<AggrAllEventsData> hiddenAggr = getAggrEventData();
1783                 verifyAggrKeyguardEventData(shownAggr, hiddenAggr, false, true);
1784             }
1785 
1786         } finally {
1787             // Dismiss keyguard to get device back in its normal state.
1788             wakeDevice();
1789             executeShellCmd("wm dismiss-keyguard");
1790         }
1791     }
1792 
1793     @Test
testIgnoreNonexistentPackage()1794     public void testIgnoreNonexistentPackage() throws Exception {
1795         final String fakePackageName = "android.fake.package.name";
1796         final int defaultValue = -1;
1797 
1798         setStandByBucket(fakePackageName, "rare");
1799         // Verify the above does not add a new entry to the App Standby bucket map
1800         Map<String, Integer> bucketMap = mUsageStatsManager.getAppStandbyBuckets();
1801         int bucket = bucketMap.getOrDefault(fakePackageName, defaultValue);
1802         assertFalse("Meaningful bucket value " + bucket + " returned for " + fakePackageName
1803                 + " after set-standby-bucket", bucket > 0);
1804 
1805         executeShellCmd("am get-standby-bucket " + fakePackageName);
1806         // Verify the above does not add a new entry to the App Standby bucket map
1807         bucketMap = mUsageStatsManager.getAppStandbyBuckets();
1808         bucket = bucketMap.getOrDefault(fakePackageName, defaultValue);
1809         assertFalse("Meaningful bucket value " + bucket + " returned for " + fakePackageName
1810                 + " after get-standby-bucket", bucket > 0);
1811     }
1812 
1813     @Test
testObserveUsagePermissionForRegisterObserver()1814     public void testObserveUsagePermissionForRegisterObserver() {
1815         final int observerId = 0;
1816         final String[] packages = new String[] {"com.android.settings"};
1817 
1818         try {
1819             mUsageStatsManager.registerAppUsageObserver(observerId, packages,
1820                     1, java.util.concurrent.TimeUnit.HOURS, null);
1821             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1822         } catch (SecurityException e) {
1823             // Exception expected
1824         }
1825 
1826         try {
1827             mUsageStatsManager.registerUsageSessionObserver(observerId, packages,
1828                     Duration.ofHours(1), Duration.ofSeconds(10), null, null);
1829             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1830         } catch (SecurityException e) {
1831             // Exception expected
1832         }
1833 
1834         try {
1835             mUsageStatsManager.registerAppUsageLimitObserver(observerId, packages,
1836                     Duration.ofHours(1), Duration.ofHours(0), null);
1837             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1838         } catch (SecurityException e) {
1839             // Exception expected
1840         }
1841     }
1842 
1843     @Test
testObserveUsagePermissionForUnregisterObserver()1844     public void testObserveUsagePermissionForUnregisterObserver() {
1845         final int observerId = 0;
1846 
1847         try {
1848             mUsageStatsManager.unregisterAppUsageObserver(observerId);
1849             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1850         } catch (SecurityException e) {
1851             // Exception expected
1852         }
1853 
1854         try {
1855             mUsageStatsManager.unregisterUsageSessionObserver(observerId);
1856             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1857         } catch (SecurityException e) {
1858             // Exception expected
1859         }
1860 
1861         try {
1862             mUsageStatsManager.unregisterAppUsageLimitObserver(observerId);
1863             fail("Expected SecurityException for an app not holding OBSERVE_APP_USAGE permission.");
1864         } catch (SecurityException e) {
1865             // Exception expected
1866         }
1867     }
1868 
1869     @AppModeFull(reason = "No usage events access in instant apps")
1870     @RequiresFlagsDisabled(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API)
1871     @Test
testForegroundService()1872     public void testForegroundService() throws Exception {
1873         testForegroundServiceHelper(/* filteredEvents= */ false);
1874     }
1875 
1876     @AppModeFull(reason = "No usage events access in instant apps")
1877     @RequiresFlagsEnabled(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API)
1878     @Test
testForegroundService_withQueryFilter()1879     public void testForegroundService_withQueryFilter() throws Exception {
1880         testForegroundServiceHelper(/* filteredEvents= */ true);
1881     }
1882 
testForegroundServiceHelper(boolean filteredEvents)1883     private void testForegroundServiceHelper(boolean filteredEvents) {
1884         // This test start a foreground service then stop it. The event list should have one
1885         // FOREGROUND_SERVICE_START and one FOREGROUND_SERVICE_STOP event.
1886         final long startTime = System.currentTimeMillis();
1887         mContext.startService(new Intent(mContext, TestService.class));
1888         mUiDevice.wait(Until.hasObject(By.clazz(TestService.class)), TIMEOUT);
1889         final long sleepTime = 500;
1890         SystemClock.sleep(sleepTime);
1891         mContext.stopService(new Intent(mContext, TestService.class));
1892         mUiDevice.wait(Until.gone(By.clazz(TestService.class)), TIMEOUT);
1893         final long endTime = System.currentTimeMillis();
1894         UsageEvents events = null;
1895         if (filteredEvents) {
1896             UsageEventsQuery query = new UsageEventsQuery.Builder(startTime, endTime)
1897                     .setEventTypes(Event.FOREGROUND_SERVICE_START,
1898                             Event.FOREGROUND_SERVICE_STOP)
1899                     .build();
1900             events = mUsageStatsManager.queryEvents(query);
1901         } else {
1902             events = mUsageStatsManager.queryEvents(startTime, endTime);
1903         }
1904 
1905         int numStarts = 0;
1906         int numStops = 0;
1907         int startIdx = -1;
1908         int stopIdx = -1;
1909         int i = 0;
1910         while (events.hasNextEvent()) {
1911             UsageEvents.Event event = new UsageEvents.Event();
1912             assertTrue(events.getNextEvent(event));
1913             assertTrue(!filteredEvents
1914                     || (event.getEventType() == Event.FOREGROUND_SERVICE_START
1915                             || event.getEventType() == Event.FOREGROUND_SERVICE_STOP));
1916             if (mTargetPackage.equals(event.getPackageName())
1917                     || TestService.class.getName().equals(event.getClassName())) {
1918                 if (event.getEventType() == Event.FOREGROUND_SERVICE_START) {
1919                     numStarts++;
1920                     startIdx = i;
1921                 } else if (event.getEventType() == Event.FOREGROUND_SERVICE_STOP) {
1922                     numStops++;
1923                     stopIdx = i;
1924                 }
1925                 i++;
1926             }
1927         }
1928         // One FOREGROUND_SERVICE_START event followed by one FOREGROUND_SERVICE_STOP event.
1929         assertEquals(numStarts, 1);
1930         assertEquals(numStops, 1);
1931         assertLessThan(startIdx, stopIdx);
1932 
1933         final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
1934                 startTime, endTime);
1935         final UsageStats stats = map.get(mTargetPackage);
1936         assertNotNull(stats);
1937         final long lastTimeUsed = stats.getLastTimeForegroundServiceUsed();
1938         // lastTimeUsed should be falling between startTime and endTime.
1939         assertLessThan(startTime, lastTimeUsed);
1940         assertLessThan(lastTimeUsed, endTime);
1941         final long totalTimeUsed = stats.getTotalTimeForegroundServiceUsed();
1942         // because we slept for 500 milliseconds earlier, we know the totalTimeUsed must be more
1943         // more than 500 milliseconds.
1944         assertLessThan(sleepTime, totalTimeUsed);
1945     }
1946 
1947     @AppModeFull(reason = "No usage events access in instant apps")
1948     @Test
testTaskRootEventField()1949     public void testTaskRootEventField() throws Exception {
1950         wakeDevice();
1951         dismissKeyguard(); // also want to start out with the keyguard dismissed.
1952 
1953         final long startTime = System.currentTimeMillis();
1954         launchSubActivity(TaskRootActivity.class);
1955         final long endTime = System.currentTimeMillis();
1956         UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
1957 
1958         while (events.hasNextEvent()) {
1959             UsageEvents.Event event = new UsageEvents.Event();
1960             assertTrue(events.getNextEvent(event));
1961             if (TaskRootActivity.TEST_APP_PKG.equals(event.getPackageName())
1962                     && TaskRootActivity.TEST_APP_CLASS.equals(event.getClassName())) {
1963                 assertEquals(mTargetPackage, event.getTaskRootPackageName());
1964                 assertEquals(TaskRootActivity.class.getCanonicalName(),
1965                         event.getTaskRootClassName());
1966                 return;
1967             }
1968         }
1969         fail("Did not find nested activity name in usage events");
1970     }
1971 
1972     @AppModeFull(reason = "No usage events access in instant apps")
1973     @Test
testUsageSourceAttribution()1974     public void testUsageSourceAttribution() throws Exception {
1975         wakeDevice();
1976         dismissKeyguard(); // also want to start out with the keyguard dismissed.
1977         mUiDevice.pressHome();
1978 
1979         setUsageSourceSetting(Integer.toString(UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY));
1980         launchSubActivity(TaskRootActivity.class);
1981         // Usage should be attributed to the test app package
1982         assertAppOrTokenUsed(TaskRootActivity.TEST_APP_PKG, true, TIMEOUT);
1983 
1984         SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
1985 
1986         setUsageSourceSetting(Integer.toString(UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY));
1987         launchSubActivity(TaskRootActivity.class);
1988         // Usage should be attributed to this package
1989         assertAppOrTokenUsed(mTargetPackage, true, TIMEOUT);
1990     }
1991 
1992     @AppModeFull(reason = "No usage events access in instant apps")
1993     @Test
testTaskRootAttribution_finishingTaskRoot()1994     public void testTaskRootAttribution_finishingTaskRoot() throws Exception {
1995         setUsageSourceSetting(Integer.toString(UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY));
1996         wakeDevice();
1997         dismissKeyguard(); // also want to start out with the keyguard dismissed.
1998 
1999         launchTestActivity(TEST_APP2_PKG, TEST_APP2_CLASS_FINISHING_TASK_ROOT);
2000         // Wait until the nested activity gets started
2001         mUiDevice.wait(Until.hasObject(By.clazz(TEST_APP_PKG, TEST_APP_CLASS)), TIMEOUT);
2002 
2003         // Usage should be attributed to the task root app package
2004         assertAppOrTokenUsed(TEST_APP_PKG, false, TIMEOUT);
2005         assertAppOrTokenUsed(TEST_APP2_PKG, true, TIMEOUT);
2006         SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
2007         mUiDevice.wait(Until.gone(By.clazz(TEST_APP_PKG, TEST_APP_CLASS)), TIMEOUT);
2008 
2009         // Usage should no longer be tracked
2010         assertAppOrTokenUsed(TEST_APP_PKG, false, TIMEOUT);
2011         assertAppOrTokenUsed(TEST_APP2_PKG, false, TIMEOUT);
2012     }
2013 
2014     @AppModeInstant
2015     @Test
testInstantAppUsageEventsObfuscated()2016     public void testInstantAppUsageEventsObfuscated() throws Exception {
2017         @SuppressWarnings("unchecked")
2018         final Class<? extends Activity>[] activitySequence = new Class[] {
2019                 Activities.ActivityOne.class,
2020                 Activities.ActivityTwo.class,
2021                 Activities.ActivityThree.class,
2022         };
2023         wakeDevice();
2024         mUiDevice.pressHome();
2025 
2026         final long startTime = System.currentTimeMillis();
2027         // Launch the series of Activities.
2028         launchSubActivities(activitySequence);
2029         SystemClock.sleep(250);
2030 
2031         final long endTime = System.currentTimeMillis();
2032         final UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
2033 
2034         int resumes = 0;
2035         int pauses = 0;
2036         int stops = 0;
2037 
2038         // Only look at events belongs to mTargetPackage.
2039         while (events.hasNextEvent()) {
2040             final UsageEvents.Event event = new UsageEvents.Event();
2041             assertTrue(events.getNextEvent(event));
2042             // There should be no events with this packages name
2043             assertNotEquals("Instant app package name found in usage event list",
2044                     mTargetPackage, event.getPackageName());
2045 
2046             // Look for the obfuscated instant app string instead
2047             if(UsageEvents.INSTANT_APP_PACKAGE_NAME.equals(event.getPackageName())) {
2048                 switch (event.mEventType) {
2049                     case Event.ACTIVITY_RESUMED:
2050                         resumes++;
2051                         break;
2052                     case Event.ACTIVITY_PAUSED:
2053                         pauses++;
2054                         break;
2055                     case Event.ACTIVITY_STOPPED:
2056                         stops++;
2057                         break;
2058                 }
2059             }
2060         }
2061         assertEquals("Unexpected number of activity resumes", 3, resumes);
2062         assertEquals("Unexpected number of activity pauses", 2, pauses);
2063         assertEquals("Unexpected number of activity stops", 2, stops);
2064     }
2065 
2066     @AppModeFull(reason = "No usage events access in instant apps")
2067     @Test
testSuddenDestroy()2068     public void testSuddenDestroy() throws Exception {
2069         wakeDevice();
2070         dismissKeyguard(); // also want to start out with the keyguard dismissed.
2071         mUiDevice.pressHome();
2072 
2073         final long startTime = System.currentTimeMillis();
2074 
2075         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
2076         SystemClock.sleep(500);
2077 
2078         // Destroy the activity
2079         SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
2080         mUiDevice.wait(Until.gone(By.clazz(TEST_APP_PKG, TEST_APP_CLASS)), TIMEOUT);
2081         SystemClock.sleep(500);
2082 
2083         final long endTime = System.currentTimeMillis();
2084         final UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
2085 
2086         int resumes = 0;
2087         int stops = 0;
2088 
2089         while (events.hasNextEvent()) {
2090             final UsageEvents.Event event = new UsageEvents.Event();
2091             assertTrue(events.getNextEvent(event));
2092 
2093             if(TEST_APP_PKG.equals(event.getPackageName())) {
2094                 switch (event.mEventType) {
2095                     case Event.ACTIVITY_RESUMED:
2096                         assertNotNull("ACTIVITY_RESUMED event Task Root should not be null",
2097                                 event.getTaskRootPackageName());
2098                         resumes++;
2099                         break;
2100                     case Event.ACTIVITY_STOPPED:
2101                         assertNotNull("ACTIVITY_STOPPED event Task Root should not be null",
2102                                 event.getTaskRootPackageName());
2103                         stops++;
2104                         break;
2105                 }
2106             }
2107         }
2108         assertEquals("Unexpected number of activity resumes", 1, resumes);
2109         assertEquals("Unexpected number of activity stops", 1, stops);
2110     }
2111 
2112     @AppModeFull(reason = "No usage events access in instant apps")
2113     @Test
testPipActivity()2114     public void testPipActivity() throws Exception {
2115         assumeTrue("Test cannot run without Picture in Picture support",
2116                 mContext.getPackageManager().hasSystemFeature(
2117                         PackageManager.FEATURE_PICTURE_IN_PICTURE));
2118         wakeDevice();
2119         dismissKeyguard(); // also want to start out with the keyguard dismissed.
2120         mUiDevice.pressHome();
2121 
2122         final long startTime = System.currentTimeMillis();
2123 
2124         launchTestActivity(TEST_APP2_PKG, TEST_APP2_CLASS_PIP);
2125         SystemClock.sleep(500);
2126 
2127         // TEST_APP_PKG should take focus, pausing the TEST_APP2_CLASS_PIP activity.
2128         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
2129         SystemClock.sleep(500);
2130 
2131         mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
2132                 WindowManagerState.STATE_PAUSED);
2133 
2134         mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
2135         mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
2136                 TEST_APP2_PIP_COMPONENT);
2137 
2138         final long endTime = System.currentTimeMillis();
2139         final UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
2140 
2141         int resumes = 0;
2142         int pauses = 0;
2143         int stops = 0;
2144 
2145         while (events.hasNextEvent()) {
2146             final UsageEvents.Event event = new UsageEvents.Event();
2147             assertTrue(events.getNextEvent(event));
2148 
2149             if(TEST_APP2_PKG.equals(event.getPackageName())) {
2150                 switch (event.mEventType) {
2151                     case Event.ACTIVITY_RESUMED:
2152                         assertNotNull("ACTIVITY_RESUMED event Task Root should not be null",
2153                                 event.getTaskRootPackageName());
2154                         resumes++;
2155                         break;
2156                     case Event.ACTIVITY_PAUSED:
2157                         assertNotNull("ACTIVITY_PAUSED event Task Root should not be null",
2158                                 event.getTaskRootPackageName());
2159                         pauses++;
2160                         break;
2161                     case Event.ACTIVITY_STOPPED:
2162                         assertNotNull("ACTIVITY_STOPPED event Task Root should not be null",
2163                                 event.getTaskRootPackageName());
2164                         stops++;
2165                         break;
2166                 }
2167             }
2168         }
2169         assertEquals("Unexpected number of activity resumes", 1, resumes);
2170         assertEquals("Unexpected number of activity pauses", 1, pauses);
2171         assertEquals("Unexpected number of activity stops", 0, stops);
2172 
2173         final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
2174                 startTime, endTime);
2175         final UsageStats stats = map.get(TEST_APP2_PKG);
2176         assertNotNull(stats);
2177         final long totalTimeVisible = stats.getTotalTimeVisible();
2178         assertLessThan(0, totalTimeVisible);
2179     }
2180 
2181     @AppModeFull(reason = "No usage events access in instant apps")
2182     @Test
testPipActivity_StopToPause()2183     public void testPipActivity_StopToPause() throws Exception {
2184         assumeTrue("Test cannot run without Picture in Picture support",
2185                 mContext.getPackageManager().hasSystemFeature(
2186                         PackageManager.FEATURE_PICTURE_IN_PICTURE));
2187         wakeDevice();
2188         dismissKeyguard(); // also want to start out with the keyguard dismissed.
2189         mUiDevice.pressHome();
2190 
2191         launchTestActivity(TEST_APP2_PKG, TEST_APP2_CLASS_PIP);
2192         SystemClock.sleep(500);
2193 
2194         // TEST_APP_PKG should take focus, pausing the TEST_APP2_CLASS_PIP activity.
2195         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS);
2196         SystemClock.sleep(500);
2197 
2198         mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
2199         mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
2200                 TEST_APP2_PIP_COMPONENT);
2201 
2202         // Sleeping the device should cause the Pip activity to stop.
2203         final long sleepTime = System.currentTimeMillis();
2204         sleepDevice();
2205         mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
2206                 WindowManagerState.STATE_STOPPED);
2207 
2208         // Pip activity stop should show up in UsageStats.
2209         final ArrayList<Event> stoppedEvent = waitForEventCount(STOPPED_EVENT, sleepTime, 1,
2210                 TEST_APP2_PKG);
2211         assertEquals(Event.ACTIVITY_STOPPED, stoppedEvent.get(0).getEventType());
2212 
2213         // Waking the device should cause the stopped Pip to return to the paused state.
2214         final long wakeTime = System.currentTimeMillis();
2215         wakeDevice();
2216         dismissKeyguard();
2217         mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
2218                 WindowManagerState.STATE_PAUSED);
2219 
2220         mWMStateHelper.assertActivityDisplayed(TEST_APP2_PIP_COMPONENT);
2221         mWMStateHelper.assertNotFocusedActivity("Pip activity should not be in focus",
2222                 TEST_APP2_PIP_COMPONENT);
2223 
2224         // Sleeping the device should cause the Pip activity to stop again.
2225         final long secondSleepTime = System.currentTimeMillis();
2226         sleepDevice();
2227         mWMStateHelper.waitForActivityState(TEST_APP2_PIP_COMPONENT,
2228                 WindowManagerState.STATE_STOPPED);
2229 
2230         // Pip activity stop should show up in UsageStats again.
2231         final ArrayList<Event> secondStoppedEvent = waitForEventCount(STOPPED_EVENT,
2232                 secondSleepTime, 1,
2233                 TEST_APP2_PKG);
2234         assertEquals(Event.ACTIVITY_STOPPED, secondStoppedEvent.get(0).getEventType());
2235     }
2236 
2237     @AppModeFull(reason = "No usage events access in instant apps")
2238     @RequiresFlagsDisabled(Flags.FLAG_REPORT_USAGE_STATS_PERMISSION)
2239     @Test
2240     @AsbSecurityTest(cveBugId = 229633537)
testReportChooserSelection()2241     public void testReportChooserSelection() throws Exception {
2242         testReportChooserSelectionNoPermissionCheck();
2243     }
2244 
2245     @AppModeFull(reason = "No usage events access in instant apps")
2246     @RequiresFlagsEnabled(Flags.FLAG_REPORT_USAGE_STATS_PERMISSION)
2247     @Test
2248     @AsbSecurityTest(cveBugId = 229633537)
testReportChooserSelectionWithPermission()2249     public void testReportChooserSelectionWithPermission() throws Exception {
2250         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2251         testReportChooserSelectionNoPermissionCheck();
2252     }
2253 
testReportChooserSelectionNoPermissionCheck()2254     private void testReportChooserSelectionNoPermissionCheck() throws Exception {
2255         // attempt to report an event with a null package, should fail.
2256         try {
2257             mUsageStatsManager.reportChooserSelection(
2258                     null,
2259                     /* userId= */ mContext.getUserId(),
2260                     "text/plain",
2261                     null,
2262                     "android.intent.action.SEND");
2263             fail("Able to report a chooser selection with a null package");
2264         } catch (IllegalArgumentException expected) { }
2265 
2266         // attempt to report an event with a non-existent package, should fail.
2267         long startTime = System.currentTimeMillis();
2268         mUsageStatsManager.reportChooserSelection("android.app.usage.cts.nonexistent.pkg", 0,
2269                 "text/plain", null, "android.intent.action.SEND");
2270         UsageEvents events = mUsageStatsManager.queryEvents(
2271                 startTime - 1000, System.currentTimeMillis() + 1000);
2272         while (events.hasNextEvent()) {
2273             final Event event = new Event();
2274             events.getNextEvent(event);
2275             if (event.mEventType == Event.CHOOSER_ACTION) {
2276                 fail("Able to report a chooser action event with a non-existent package.");
2277             }
2278         }
2279 
2280         // attempt to report an event with a null/empty contentType, should fail.
2281         startTime = System.currentTimeMillis();
2282         mUsageStatsManager.reportChooserSelection(
2283                 TEST_APP_PKG,
2284                 /* userId= */ mContext.getUserId(),
2285                 null,
2286                 null,
2287                 "android.intent.action.SEND");
2288         mUsageStatsManager.reportChooserSelection(
2289                 TEST_APP_PKG,
2290                 /* userId= */ mContext.getUserId(),
2291                 " ",
2292                 null,
2293                 "android.intent.action.SEND");
2294         events = mUsageStatsManager.queryEvents(
2295                 startTime - 1000, System.currentTimeMillis() + 1000);
2296         while (events.hasNextEvent()) {
2297             final Event event = new Event();
2298             events.getNextEvent(event);
2299             if (event.mEventType == Event.CHOOSER_ACTION) {
2300                 fail("Able to report a chooser action event with a null/empty contentType.");
2301             }
2302         }
2303 
2304         // attempt to report an event with a null/empty action, should fail.
2305         startTime = System.currentTimeMillis();
2306         mUsageStatsManager.reportChooserSelection(
2307                 TEST_APP_PKG, /* userId= */ mContext.getUserId(), "text/plain", null, null);
2308         mUsageStatsManager.reportChooserSelection(
2309                 TEST_APP_PKG, /* userId= */ mContext.getUserId(), "text/plain", null, " ");
2310         events = mUsageStatsManager.queryEvents(
2311                 startTime - 1000, System.currentTimeMillis() + 1000);
2312         while (events.hasNextEvent()) {
2313             final Event event = new Event();
2314             events.getNextEvent(event);
2315             if (event.mEventType == Event.CHOOSER_ACTION) {
2316                 fail("Able to report a chooser action event with a null/empty action.");
2317             }
2318         }
2319 
2320         // report an event with valid args - event should be found.
2321         startTime = System.currentTimeMillis();
2322         mUsageStatsManager.reportChooserSelection(
2323                 TEST_APP_PKG,
2324                 /* userId= */ mContext.getUserId(),
2325                 "text/plain",
2326                 null,
2327                 "android.intent.action.SEND");
2328         Thread.sleep(500); // wait a little for the event to report via the handler.
2329         events = mUsageStatsManager.queryEvents(
2330                 startTime - 1000, System.currentTimeMillis() + 1000);
2331         boolean foundEvent = false;
2332         while (events.hasNextEvent()) {
2333             final Event event = new Event();
2334             events.getNextEvent(event);
2335             if (event.mEventType == Event.CHOOSER_ACTION) {
2336                 foundEvent = true;
2337                 break;
2338             }
2339         }
2340         assertTrue("Couldn't find the reported chooser action event.", foundEvent);
2341     }
2342 
2343     @AppModeFull(reason = "No usage events access in instant apps")
2344     @RequiresFlagsEnabled(Flags.FLAG_REPORT_USAGE_STATS_PERMISSION)
2345     @Test
testReportChooserSelectionAccess()2346     public void testReportChooserSelectionAccess() throws Exception {
2347         try {
2348             // only system uid or holders of the REPORT_USAGE_EVENTS should be able to report events
2349             mUsageStatsManager.reportChooserSelection(
2350                     TEST_APP_PKG,
2351                     /* userId= */ mContext.getUserId(),
2352                     "text/plain",
2353                     null,
2354                     "android.intent.action.SEND");
2355             fail("Able to report a chooser selection from CTS test");
2356         } catch (SecurityException expected) { }
2357 
2358         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2359         mUsageStatsManager.reportChooserSelection(
2360                 TEST_APP_PKG,
2361                 /* userId= */ mContext.getUserId(),
2362                 "text/plain",
2363                 null,
2364                 "android.intent.action.SEND");
2365     }
2366 
2367     @AppModeFull(reason = "No usage events access in instant apps")
2368     @RequiresFlagsEnabled(Flags.FLAG_REPORT_USAGE_STATS_PERMISSION)
2369     @Test
testReportUserInteractionAccess()2370     public void testReportUserInteractionAccess() throws Exception {
2371         try {
2372             // only system uid or holders of the REPORT_USAGE_EVENTS should be able to report events
2373             mUsageStatsManager.reportUserInteraction(TEST_APP_PKG, mContext.getUserId());
2374             fail("Able to report a user interaction from CTS test");
2375         } catch (SecurityException expected) { }
2376 
2377         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2378         mUsageStatsManager.reportUserInteraction(TEST_APP_PKG, mContext.getUserId());
2379     }
2380 
2381     @AppModeFull(reason = "No usage events access in instant apps")
2382     @RequiresFlagsEnabled(Flags.FLAG_REPORT_USAGE_STATS_PERMISSION)
2383     @Test
testCrossUserReportUserInteractionAccess()2384     public void testCrossUserReportUserInteractionAccess() throws Exception {
2385         assumeTrue(UserManager.supportsMultipleUsers());
2386         // Create user
2387         final int userId = createUser("Test User");
2388         startUser(userId, true);
2389         installExistingPackageAsUser(mContext.getPackageName(), userId);
2390         installExistingPackageAsUser(TEST_APP_PKG, userId);
2391 
2392         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2393         try {
2394             mUsageStatsManager.reportUserInteraction(TEST_APP_PKG, /* userId= */ userId);
2395             fail("Able to report cross user interaction without INTERACT_ACROSS_USERS_FULLi"
2396                     + " permission from CTS test");
2397         } catch (SecurityException expected) {
2398             // Do nothing.
2399         }
2400 
2401         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS,
2402                 Manifest.permission.INTERACT_ACROSS_USERS_FULL);
2403         mUsageStatsManager.reportUserInteraction(TEST_APP_PKG, userId);
2404         // user cleanup done in @After.
2405     }
2406 
2407     /**
2408      * Test to ensure the {@link UsageStatsManager#reportUserInteraction(String, int, Bundle)}
2409      * is enforce with {@link android.Manifest.permission#REPORT_USAGE_STATS}
2410      */
2411     @AppModeFull(reason = "No usage events access in instant apps")
2412     @Test
2413     @RequiresFlagsEnabled(Flags.FLAG_USER_INTERACTION_TYPE_API)
testReportUserInteractionWithTypeAccess()2414     public void testReportUserInteractionWithTypeAccess() throws Exception {
2415         final PersistableBundle extras = new PersistableBundle();
2416         extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "fake.namespace.category");
2417         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, "fakeaction");
2418         try {
2419             // only system uid or holders of the REPORT_USAGE_EVENTS should be able to report events
2420             mUsageStatsManager.reportUserInteraction(
2421                     TEST_APP_PKG, /* userId= */ mContext.getUserId(), extras);
2422             fail("Able to report a user interaction from CTS test");
2423         } catch (SecurityException expected) { }
2424 
2425         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2426         mUsageStatsManager.reportUserInteraction(TEST_APP_PKG, mContext.getUserId(), extras);
2427     }
2428 
2429     /**
2430      * Tests to ensure {@link UsageStatsManager#reportUserInteraction(String, int, Bundle)}
2431      * with valid package and user interaction event type is able to report the user
2432      * interaction events.
2433      */
2434     @AppModeFull(reason = "No usage events access in instant apps")
2435     @Test
2436     @RequiresFlagsEnabled({Flags.FLAG_USER_INTERACTION_TYPE_API,
2437             Flags.FLAG_REPORT_USAGE_STATS_PERMISSION})
testReportUserInteraction()2438     public void testReportUserInteraction() throws Exception {
2439         mUiAutomation.adoptShellPermissionIdentity(Manifest.permission.REPORT_USAGE_STATS);
2440         // attempt to report an event with a null package, should fail.
2441         try {
2442             mUsageStatsManager.reportUserInteraction(
2443                     null,
2444                     /* userId= */ mContext.getUserId(),
2445                     /* extras= */ PersistableBundle.EMPTY);
2446             fail("able to report a user interaction with a null package");
2447         } catch (NullPointerException expected) { }
2448 
2449         // attempt to report an event with non-existent package, should fail.
2450         final PersistableBundle extras = new PersistableBundle();
2451         final String interactionCategoryValue = "android.app.notification";
2452         final String interactionActionValue = "click";
2453         extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, interactionCategoryValue);
2454         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, interactionActionValue);
2455         try {
2456             mUsageStatsManager.reportUserInteraction(
2457                     "android.app.usage.cts.nonexistent.pkg",
2458                     /* userId= */ mContext.getUserId(),
2459                     extras);
2460             fail("able to report a user interaction with non-existent package name");
2461         } catch (IllegalArgumentException expected) { }
2462 
2463         // attempt to report an event with an empty extras, should fail.
2464         try {
2465             mUsageStatsManager.reportUserInteraction(
2466                     TEST_APP_PKG,
2467                     /* userId= */ mContext.getUserId(),
2468                     /* extras= */ PersistableBundle.EMPTY);
2469             fail("able to report a user interaction with empty extras");
2470         } catch (IllegalArgumentException expected) { }
2471 
2472         // attempt to report an event with empty category or action, should fail.
2473         extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, "");
2474         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, interactionActionValue);
2475         try {
2476             mUsageStatsManager.reportUserInteraction(
2477                     TEST_APP_PKG, /* userId= */ mContext.getUserId(), /* extras= */ extras);
2478             fail("able to report a user interaction with empty category");
2479         } catch (IllegalArgumentException expected) { }
2480 
2481         extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, interactionCategoryValue);
2482         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, "");
2483         try {
2484             mUsageStatsManager.reportUserInteraction(
2485                     TEST_APP_PKG, /* userId= */ mContext.getUserId(), /* extras= */ extras);
2486             fail("able to report a user interaction with empty action");
2487         } catch (IllegalArgumentException expected) { }
2488 
2489         // report a valid user interaction event - should be found.
2490         extras.putString(UsageStatsManager.EXTRA_EVENT_CATEGORY, interactionCategoryValue);
2491         extras.putString(UsageStatsManager.EXTRA_EVENT_ACTION, interactionActionValue);
2492         long startTime = System.currentTimeMillis();
2493         mUsageStatsManager.reportUserInteraction(
2494                 TEST_APP_PKG, /* userId */ mContext.getUserId(), extras);
2495         Thread.sleep(500); // wait for a while for the event to report via the handler.
2496         UsageEvents userInteractionEvents = mUsageStatsManager.queryEvents(
2497                 startTime - 1000, System.currentTimeMillis() + 1000);
2498         boolean found = false;
2499         while (userInteractionEvents.hasNextEvent()) {
2500             final Event ev = new Event();
2501             userInteractionEvents.getNextEvent(ev);
2502             if (ev.getEventType() != Event.USER_INTERACTION) {
2503                 continue;
2504             }
2505             PersistableBundle interactionExtras = ev.getExtras();
2506             assertEquals(interactionCategoryValue,
2507                     interactionExtras.getString(UsageStatsManager.EXTRA_EVENT_CATEGORY));
2508             assertEquals(interactionActionValue,
2509                     interactionExtras.getString(UsageStatsManager.EXTRA_EVENT_ACTION));
2510             found = true;
2511             break;
2512         }
2513         assertTrue("Couldn't find the reported user interaction event.", found);
2514     }
2515 
2516     @AppModeFull(reason = "No usage events access in instant apps")
2517     @Test
testLocusIdEventsVisibility()2518     public void testLocusIdEventsVisibility() throws Exception {
2519         final long startTime = System.currentTimeMillis();
2520         startAndDestroyActivityWithLocus();
2521         final long endTime = System.currentTimeMillis();
2522 
2523         final UsageEvents restrictedEvents = mUsageStatsManager.queryEvents(startTime, endTime);
2524         final UsageEvents allEvents = queryEventsAsShell(startTime, endTime);
2525         verifyLocusIdEventVisibility(restrictedEvents, false);
2526         verifyLocusIdEventVisibility(allEvents, true);
2527     }
2528 
2529     @AppModeFull(reason = "No usage events access in instant apps")
2530     @RequiresFlagsEnabled(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API)
2531     @Test
testUsageEventsQueryParceling()2532     public void testUsageEventsQueryParceling() throws Exception {
2533         final String fakePackageName = "android.fake.package.name";
2534         final long endTime = System.currentTimeMillis();
2535         final long startTime = endTime - MINUTE_IN_MILLIS;
2536         Random rnd = new Random();
2537         UsageEventsQuery.Builder queryBuilder = new UsageEventsQuery.Builder(startTime, endTime);
2538         queryBuilder.setEventTypes(rnd.nextInt(Event.MAX_EVENT_TYPE + 1),
2539                 rnd.nextInt(Event.MAX_EVENT_TYPE + 1), rnd.nextInt(Event.MAX_EVENT_TYPE + 1));
2540         queryBuilder.setPackageNames(fakePackageName + "2",
2541                 fakePackageName + "7", fakePackageName + "11");
2542         UsageEventsQuery query = queryBuilder.build();
2543         Parcel p = Parcel.obtain();
2544         p.setDataPosition(0);
2545         query.writeToParcel(p, 0);
2546         p.setDataPosition(0);
2547 
2548         UsageEventsQuery queryFromParcel = UsageEventsQuery.CREATOR.createFromParcel(p);
2549         assertEquals(queryFromParcel.getBeginTimeMillis(), query.getBeginTimeMillis());
2550         assertEquals(queryFromParcel.getEndTimeMillis(), query.getEndTimeMillis());
2551         assertArrayEquals(query.getEventTypes(), queryFromParcel.getEventTypes());
2552         assertEquals(queryFromParcel.getPackageNames(), query.getPackageNames());
2553     }
2554 
2555     @AppModeFull(reason = "No usage events access in instant apps")
2556     @RequiresFlagsEnabled(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API)
2557     @Test
testQueryEventsWithEventTypeFilter()2558     public void testQueryEventsWithEventTypeFilter() throws Exception {
2559         final long endTime = System.currentTimeMillis() - MINUTE_IN_MILLIS;
2560         final long startTime = Math.max(0, endTime - HOUR_IN_MILLIS); // 1 hour
2561 
2562         UsageEvents unfilteredEvents = mUsageStatsManager.queryEvents(startTime, endTime);
2563         UsageEventsQuery query = new UsageEventsQuery.Builder(startTime, endTime)
2564                 .setEventTypes(Event.ACTIVITY_RESUMED, Event.ACTIVITY_PAUSED)
2565                 .build();
2566         UsageEvents filteredEvents = mUsageStatsManager.queryEvents(query);
2567         ArrayList<Event> filteredEventList = new ArrayList<>();
2568         ArrayList<Event> unfilteredEventList = new ArrayList<>();
2569         while (unfilteredEvents.hasNextEvent()) {
2570             final Event event = new Event();
2571             unfilteredEvents.getNextEvent(event);
2572             if (event.getEventType() == Event.ACTIVITY_RESUMED
2573                     || event.getEventType() == Event.ACTIVITY_PAUSED) {
2574                 unfilteredEventList.add(event);
2575             }
2576         }
2577 
2578         while (filteredEvents.hasNextEvent()) {
2579             final Event event = new Event();
2580             filteredEvents.getNextEvent(event);
2581             assertTrue(event.getEventType() == Event.ACTIVITY_RESUMED
2582                     || event.getEventType() == Event.ACTIVITY_PAUSED);
2583             filteredEventList.add(event);
2584         }
2585 
2586         compareUsageEventList(unfilteredEventList, filteredEventList);
2587 
2588         // Test with empty event types, it should behave the same with the non-filter one
2589         unfilteredEvents = mUsageStatsManager.queryEvents(startTime, endTime);
2590         query = new UsageEventsQuery.Builder(startTime, endTime).build();
2591         filteredEvents = mUsageStatsManager.queryEvents(query);
2592         unfilteredEventList = new ArrayList<>();
2593         filteredEventList = new ArrayList<>();
2594         while (unfilteredEvents.hasNextEvent()) {
2595             final Event event = new Event();
2596             unfilteredEvents.getNextEvent(event);
2597             unfilteredEventList.add(event);
2598         }
2599 
2600         while (filteredEvents.hasNextEvent()) {
2601             final Event event = new Event();
2602             filteredEvents.getNextEvent(event);
2603             filteredEventList.add(event);
2604         }
2605 
2606         // Two query results should be the same.
2607         compareUsageEventList(unfilteredEventList, filteredEventList);
2608     }
2609 
2610     @AppModeFull(reason = "No usage events access in instant apps")
2611     @RequiresFlagsEnabled(Flags.FLAG_FILTER_BASED_EVENT_QUERY_API)
2612     @Test
testQueryEventsWithPackageFilter()2613     public void testQueryEventsWithPackageFilter() throws Exception {
2614         final String fakePackageName = "android.fake.package.name";
2615         final long endTime = System.currentTimeMillis() - MINUTE_IN_MILLIS;
2616         final long startTime = Math.max(0, endTime - HOUR_IN_MILLIS); // 1 hour
2617 
2618         UsageEventsQuery query = new UsageEventsQuery.Builder(startTime, endTime)
2619                 .setPackageNames(fakePackageName)
2620                 .build();
2621         UsageEvents filteredEvents = mUsageStatsManager.queryEvents(query);
2622         // Query for a fake package should get no usage event.
2623         assertFalse(filteredEvents.hasNextEvent());
2624 
2625         UsageEvents unfilteredEvents = mUsageStatsManager.queryEvents(startTime, endTime);
2626         query = new UsageEventsQuery.Builder(startTime, endTime)
2627                 .setEventTypes(Event.ACTIVITY_RESUMED, Event.ACTIVITY_PAUSED)
2628                 .setPackageNames(TEST_APP_PKG, TEST_APP2_PKG)
2629                 .build();
2630         filteredEvents = mUsageStatsManager.queryEvents(query);
2631         ArrayList<Event> filteredEventList = new ArrayList<>();
2632         ArrayList<Event> unfilteredEventList = new ArrayList<>();
2633         while (unfilteredEvents.hasNextEvent()) {
2634             final Event event = new Event();
2635             unfilteredEvents.getNextEvent(event);
2636             if (event.getEventType() != Event.ACTIVITY_RESUMED
2637                     && event.getEventType() != Event.ACTIVITY_PAUSED) {
2638                 continue;
2639             }
2640             final String pkgName = event.getPackageName();
2641             if (!TEST_APP_PKG.equals(pkgName)
2642                     && !TEST_APP2_PKG.equals(pkgName)) {
2643                 continue;
2644             }
2645             unfilteredEventList.add(event);
2646         }
2647 
2648         while (filteredEvents.hasNextEvent()) {
2649             final Event event = new Event();
2650             filteredEvents.getNextEvent(event);
2651             assertTrue(event.getEventType() == Event.ACTIVITY_RESUMED
2652                     || event.getEventType() == Event.ACTIVITY_PAUSED);
2653             final String pkgName = event.getPackageName();
2654             assertTrue(TEST_APP_PKG.equals(pkgName) || TEST_APP2_PKG.equals(pkgName));
2655             filteredEventList.add(event);
2656         }
2657 
2658         compareUsageEventList(unfilteredEventList, filteredEventList);
2659     }
2660 
compareUsageEventList(List<Event> unfilteredEventList, List<Event> filteredEventList)2661     private static void compareUsageEventList(List<Event> unfilteredEventList,
2662             List<Event> filteredEventList) {
2663         // There should be same number of usage events.
2664         assertEquals(unfilteredEventList.size(), filteredEventList.size());
2665 
2666         for (Event event : filteredEventList) {
2667             // Each event should be appeared in both query results.
2668             boolean found = false;
2669             for (int i = 0; i < unfilteredEventList.size(); i++) {
2670                 if (compareEvent(event, unfilteredEventList.get(i))) {
2671                     found = true;
2672                     break;
2673                 }
2674             }
2675             assertTrue(found);
2676         }
2677     }
2678 
compareEvent(Event ue1, Event ue2)2679     private static boolean compareEvent(Event ue1, Event ue2) {
2680         boolean result = (ue1.mEventType == ue2.mEventType)
2681                 && (ue1.mTimeStamp ==  ue2.mTimeStamp)
2682                 && (ue1.mInstanceId == ue2.mInstanceId)
2683                 && Objects.equals(ue1.mPackage, ue2.mPackage)
2684                 && Objects.equals(ue1.mClass, ue2.mClass)
2685                 && Objects.equals(ue1.mTaskRootPackage, ue2.mTaskRootPackage)
2686                 && Objects.equals(ue1.mTaskRootClass, ue2.mTaskRootClass)
2687                 && (ue1.mFlags == ue2.mFlags);
2688 
2689         switch (ue1.mEventType) {
2690             case Event.CONFIGURATION_CHANGE:
2691                 result &= Objects.equals(ue1.mConfiguration, ue2.mConfiguration);
2692                 break;
2693             case Event.SHORTCUT_INVOCATION:
2694                 result &= Objects.equals(ue1.mShortcutId, ue2.mShortcutId);
2695                 break;
2696             case Event.CHOOSER_ACTION:
2697                 result &= Objects.equals(ue1.mAction, ue2.mAction);
2698                 result &= Objects.equals(ue1.mContentType, ue2.mContentType);
2699                 result &= Arrays.equals(ue1.mContentAnnotations, ue2.mContentAnnotations);
2700                 break;
2701             case Event.STANDBY_BUCKET_CHANGED:
2702                 result &= (ue1.mBucketAndReason == ue2.mBucketAndReason);
2703                 break;
2704             case Event.NOTIFICATION_INTERRUPTION:
2705                 result &= Objects.equals(ue1.mNotificationChannelId, ue2.mNotificationChannelId);
2706                 break;
2707             case Event.LOCUS_ID_SET:
2708                 result &= Objects.equals(ue1.mLocusId, ue2.mLocusId);
2709                 break;
2710         }
2711 
2712         return result;
2713     }
2714 
startAndDestroyActivityWithLocus()2715     private void startAndDestroyActivityWithLocus() {
2716         launchTestActivity(TEST_APP_PKG, TEST_APP_CLASS_LOCUS);
2717         SystemClock.sleep(500);
2718 
2719         // Destroy the activity
2720         SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
2721         mUiDevice.wait(Until.gone(By.clazz(TEST_APP_PKG, TEST_APP_CLASS_LOCUS)), TIMEOUT);
2722         SystemClock.sleep(500);
2723     }
2724 
verifyLocusIdEventVisibility(UsageEvents events, boolean hasPermission)2725     private void verifyLocusIdEventVisibility(UsageEvents events, boolean hasPermission) {
2726         int locuses = 0;
2727         while (events.hasNextEvent()) {
2728             final Event event = new UsageEvents.Event();
2729             assertTrue(events.getNextEvent(event));
2730 
2731             if (TEST_APP_PKG.equals(event.getPackageName())
2732                     && event.mEventType == Event.LOCUS_ID_SET) {
2733                 locuses++;
2734             }
2735         }
2736 
2737         if (hasPermission) {
2738             assertEquals("LOCUS_ID_SET events were not visible.", 2, locuses);
2739         } else {
2740             assertEquals("LOCUS_ID_SET events were visible.", 0, locuses);
2741         }
2742     }
2743 
2744     /**
2745      * Assert on an app or token's usage state.
2746      *
2747      * @param entity name of the app or token
2748      * @param expected expected usage state, true for in use, false for not in use
2749      */
assertAppOrTokenUsed(String entity, boolean expected, long timeout)2750     private void assertAppOrTokenUsed(String entity, boolean expected, long timeout)
2751             throws IOException {
2752         final long realtimeTimeout = SystemClock.elapsedRealtime() + timeout;
2753         String activeUsages;
2754         boolean found;
2755         do {
2756             activeUsages = executeShellCmd("dumpsys usagestats apptimelimit actives");
2757             final String[] actives = activeUsages.split("\n");
2758             found = Arrays.asList(actives).contains(entity);
2759         } while (found != expected && SystemClock.elapsedRealtime() <= realtimeTimeout);
2760 
2761         if (expected) {
2762             assertTrue(entity + " not found in list of active activities and tokens\n"
2763                     + activeUsages, found);
2764         } else {
2765             assertFalse(entity + " found in list of active activities and tokens\n"
2766                     + activeUsages, found);
2767         }
2768     }
2769 
dismissKeyguard()2770     private void dismissKeyguard() throws Exception {
2771         if (mKeyguardManager.isKeyguardLocked()) {
2772             final long startTime = getEvents(KEYGUARD_EVENTS, 0, null, null) + 1;
2773             executeShellCmd("wm dismiss-keyguard");
2774             final ArrayList<Event> events = waitForEventCount(KEYGUARD_EVENTS, startTime, 1);
2775             assertEquals(Event.KEYGUARD_HIDDEN, events.get(0).getEventType());
2776             SystemClock.sleep(500);
2777         }
2778     }
2779 
setStandByBucket(String packageName, String bucket)2780     private void setStandByBucket(String packageName, String bucket) throws IOException {
2781         executeShellCmd("am set-standby-bucket " + packageName + " " + bucket);
2782     }
2783 
executeShellCmd(String command)2784     private String executeShellCmd(String command) throws IOException {
2785         return mUiDevice.executeShellCommand(command);
2786     }
2787 
queryEventsAsShell(long start, long end)2788     private UsageEvents queryEventsAsShell(long start, long end) {
2789         return SystemUtil.runWithShellPermissionIdentity(() ->
2790                 mUsageStatsManager.queryEvents(start, end));
2791     }
2792 
bindToTestService()2793     private ITestReceiver bindToTestService() throws Exception {
2794         final TestServiceConnection connection = bindToTestServiceAndGetConnection();
2795         return connection.getITestReceiver();
2796     }
2797 
bindToTestServiceAndGetConnection(String packageName)2798     private TestServiceConnection bindToTestServiceAndGetConnection(String packageName)
2799             throws Exception {
2800         final TestServiceConnection connection = new TestServiceConnection(mContext);
2801         final Intent intent = new Intent().setComponent(
2802                 new ComponentName(packageName, TEST_APP_CLASS_SERVICE));
2803         mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
2804         return connection;
2805     }
2806 
bindToTestServiceAndGetConnection()2807     private TestServiceConnection bindToTestServiceAndGetConnection() throws Exception {
2808         return bindToTestServiceAndGetConnection(TEST_APP_PKG);
2809     }
2810 
2811     /**
2812      * Send broadcast to test app's receiver and wait for it to be received.
2813      */
bindToTestBroadcastReceiver()2814     private void bindToTestBroadcastReceiver() {
2815         final Intent intent = new Intent().setComponent(
2816                 new ComponentName(TEST_APP_PKG, TEST_APP_CLASS_BROADCAST_RECEIVER));
2817         CountDownLatch latch = new CountDownLatch(1);
2818         mContext.sendOrderedBroadcast(
2819                 intent,
2820                 null /* receiverPermission */,
2821                 new BroadcastReceiver() {
2822                     @Override public void onReceive(Context context, Intent intent) {
2823                         latch.countDown();
2824                     }
2825                 },
2826                 null /* scheduler */,
2827                 Activity.RESULT_OK,
2828                 null /* initialData */,
2829                 null /* initialExtras */);
2830         try {
2831             assertTrue("Timed out waiting for test broadcast to be received",
2832                     latch.await(TIMEOUT, TimeUnit.MILLISECONDS));
2833         } catch (InterruptedException e) {
2834             throw new IllegalStateException("Interrupted", e);
2835         }
2836     }
2837 
2838     /**
2839      * Bind to the test app's content provider.
2840      */
bindToTestContentProvider()2841     private void bindToTestContentProvider() throws Exception {
2842         // Acquire unstable content provider so that test process isn't killed when content
2843         // provider app is killed.
2844         final Uri testUri = Uri.parse(TEST_APP_CONTENT_URI_STRING);
2845         ContentProviderClient client =
2846                 mContext.getContentResolver().acquireUnstableContentProviderClient(testUri);
2847         try (Cursor cursor = client.query(
2848                 testUri,
2849                 null /* projection */,
2850                 null /* selection */,
2851                 null /* selectionArgs */,
2852                 null /* sortOrder */)) {
2853             assertNotNull(cursor);
2854         }
2855     }
2856 
2857     static class TestServiceConnection implements ServiceConnection {
2858         private BlockingQueue<IBinder> mBlockingQueue = new LinkedBlockingQueue<>();
2859         private Context mContext;
2860 
TestServiceConnection(Context context)2861         TestServiceConnection(Context context) {
2862             mContext = context;
2863         }
2864 
onServiceConnected(ComponentName componentName, IBinder service)2865         public void onServiceConnected(ComponentName componentName, IBinder service) {
2866             mBlockingQueue.offer(service);
2867         }
2868 
onServiceDisconnected(ComponentName componentName)2869         public void onServiceDisconnected(ComponentName componentName) {
2870         }
2871 
getService()2872         public IBinder getService() throws Exception {
2873             final IBinder service = mBlockingQueue.poll(TIMEOUT_BINDER_SERVICE_SEC,
2874                     TimeUnit.SECONDS);
2875             return service;
2876         }
2877 
getITestReceiver()2878         public ITestReceiver getITestReceiver() throws Exception {
2879             return ITestReceiver.Stub.asInterface(getService());
2880         }
2881 
unbind()2882         public void unbind() {
2883             mContext.unbindService(this);
2884         }
2885     }
2886 
runJobImmediately()2887     private void runJobImmediately() throws Exception {
2888         TestJob.schedule(mContext);
2889         executeShellCmd(JOBSCHEDULER_RUN_SHELL_COMMAND
2890                 + " " + mContext.getPackageName()
2891                 + " " + TestJob.TEST_JOB_ID);
2892     }
2893 
isAppInactiveAsPermissionlessApp(String pkg)2894     private boolean isAppInactiveAsPermissionlessApp(String pkg) throws Exception {
2895         final ITestReceiver testService = bindToTestService();
2896         return testService.isAppInactive(pkg);
2897     }
2898 
createUser(String name)2899     private int createUser(String name) throws Exception {
2900         final String output = executeShellCmd(
2901                 "pm create-user " + name);
2902         if (output.startsWith("Success")) {
2903             return mOtherUser = Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
2904         }
2905         throw new IllegalStateException(String.format("Failed to create user: %s", output));
2906     }
2907 
removeUser(final int userId)2908     private boolean removeUser(final int userId) throws Exception {
2909         final String output = executeShellCmd(String.format("pm remove-user %s", userId));
2910         if (output.startsWith("Error")) {
2911             return false;
2912         }
2913         return true;
2914     }
2915 
startUser(int userId, boolean waitFlag)2916     private boolean startUser(int userId, boolean waitFlag) throws Exception {
2917         String cmd = "am start-user " + (waitFlag ? "-w " : "") + userId;
2918 
2919         final String output = executeShellCmd(cmd);
2920         if (output.startsWith("Error")) {
2921             return false;
2922         }
2923         if (waitFlag) {
2924             String state = executeShellCmd("am get-started-user-state " + userId);
2925             if (!state.contains("RUNNING_UNLOCKED")) {
2926                 return false;
2927             }
2928         }
2929         return true;
2930     }
2931 
stopUser(int userId, boolean waitFlag, boolean forceFlag)2932     private boolean stopUser(int userId, boolean waitFlag, boolean forceFlag)
2933             throws Exception {
2934         StringBuilder cmd = new StringBuilder("am stop-user ");
2935         if (waitFlag) {
2936             cmd.append("-w ");
2937         }
2938         if (forceFlag) {
2939             cmd.append("-f ");
2940         }
2941         cmd.append(userId);
2942 
2943         final String output = executeShellCmd(cmd.toString());
2944         if (output.contains("Error: Can't stop system user")) {
2945             return false;
2946         }
2947         return true;
2948     }
2949 
installExistingPackageAsUser(String packageName, int userId)2950     private void installExistingPackageAsUser(String packageName, int userId)
2951             throws Exception {
2952         executeShellCmd(
2953                 String.format("pm install-existing --user %d --wait %s", userId, packageName));
2954     }
2955 
sleepDevice()2956     private void sleepDevice() throws Exception {
2957         if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
2958             mUiDevice.pressKeyCode(KeyEvent.KEYCODE_SLEEP);
2959         } else {
2960             mUiDevice.sleep();
2961         }
2962 
2963         waitUntil(() -> {
2964             try {
2965                 return mUiDevice.isScreenOn();
2966             } catch (Exception e) {
2967                 return true;
2968             }
2969         }, false);
2970     }
2971 
wakeDevice()2972     private void wakeDevice() throws Exception {
2973         mUiDevice.wakeUp();
2974 
2975         waitUntil(() -> {
2976             try {
2977                 return mUiDevice.isScreenOn();
2978             } catch (Exception e) {
2979                 return false;
2980             }
2981         }, true);
2982     }
2983 }
2984