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; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.RequiresPermission; 22 import android.annotation.SystemApi; 23 import android.annotation.SystemService; 24 import android.app.PendingIntent; 25 import android.content.Context; 26 import android.content.pm.ParceledListSlice; 27 import android.os.RemoteException; 28 import android.os.UserHandle; 29 import android.util.ArrayMap; 30 31 import java.lang.annotation.Retention; 32 import java.lang.annotation.RetentionPolicy; 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * Provides access to device usage history and statistics. Usage data is aggregated into 41 * time intervals: days, weeks, months, and years. 42 * <p /> 43 * When requesting usage data since a particular time, the request might look something like this: 44 * <pre> 45 * PAST REQUEST_TIME TODAY FUTURE 46 * ————————————————————————————||———————————————————————————¦-----------------------| 47 * YEAR || ¦ | 48 * ————————————————————————————||———————————————————————————¦-----------------------| 49 * MONTH | || MONTH ¦ | 50 * ——————————————————|—————————||———————————————————————————¦-----------------------| 51 * | WEEK | WEEK|| | WEEK | WE¦EK | WEEK | 52 * ————————————————————————————||———————————————————|———————¦-----------------------| 53 * || |DAY|DAY|DAY|DAY¦DAY|DAY|DAY|DAY|DAY|DAY| 54 * ————————————————————————————||———————————————————————————¦-----------------------| 55 * </pre> 56 * A request for data in the middle of a time interval will include that interval. 57 * <p/> 58 * <b>NOTE:</b> Most methods on this API require the permission 59 * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to 60 * use the API and the user of the device still needs to grant permission through the Settings 61 * application. 62 * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}. 63 * Methods which only return the information for the calling package do not require this permission. 64 * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}. 65 */ 66 @SystemService(Context.USAGE_STATS_SERVICE) 67 public final class UsageStatsManager { 68 69 /** 70 * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}. 71 */ 72 public static final int INTERVAL_DAILY = 0; 73 74 /** 75 * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}. 76 */ 77 public static final int INTERVAL_WEEKLY = 1; 78 79 /** 80 * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}. 81 */ 82 public static final int INTERVAL_MONTHLY = 2; 83 84 /** 85 * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}. 86 */ 87 public static final int INTERVAL_YEARLY = 3; 88 89 /** 90 * An interval type that will use the best fit interval for the given time range. 91 * See {@link #queryUsageStats(int, long, long)}. 92 */ 93 public static final int INTERVAL_BEST = 4; 94 95 /** 96 * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it 97 * is a pseudo interval (it actually selects a real interval). 98 * {@hide} 99 */ 100 public static final int INTERVAL_COUNT = 4; 101 102 103 /** 104 * The app is whitelisted for some reason and the bucket cannot be changed. 105 * {@hide} 106 */ 107 @SystemApi 108 public static final int STANDBY_BUCKET_EXEMPTED = 5; 109 110 /** 111 * The app was used very recently, currently in use or likely to be used very soon. Standby 112 * bucket values that are ≤ {@link #STANDBY_BUCKET_ACTIVE} will not be throttled by the 113 * system while they are in this bucket. Buckets > {@link #STANDBY_BUCKET_ACTIVE} will most 114 * likely be restricted in some way. For instance, jobs and alarms may be deferred. 115 * @see #getAppStandbyBucket() 116 */ 117 public static final int STANDBY_BUCKET_ACTIVE = 10; 118 119 /** 120 * The app was used recently and/or likely to be used in the next few hours. Restrictions will 121 * apply to these apps, such as deferral of jobs and alarms. 122 * @see #getAppStandbyBucket() 123 */ 124 public static final int STANDBY_BUCKET_WORKING_SET = 20; 125 126 /** 127 * The app was used in the last few days and/or likely to be used in the next few days. 128 * Restrictions will apply to these apps, such as deferral of jobs and alarms. The delays may be 129 * greater than for apps in higher buckets (lower bucket value). Bucket values > 130 * {@link #STANDBY_BUCKET_FREQUENT} may additionally have network access limited. 131 * @see #getAppStandbyBucket() 132 */ 133 public static final int STANDBY_BUCKET_FREQUENT = 30; 134 135 /** 136 * The app has not be used for several days and/or is unlikely to be used for several days. 137 * Apps in this bucket will have the most restrictions, including network restrictions, except 138 * during certain short periods (at a minimum, once a day) when they are allowed to execute 139 * jobs, access the network, etc. 140 * @see #getAppStandbyBucket() 141 */ 142 public static final int STANDBY_BUCKET_RARE = 40; 143 144 /** 145 * The app has never been used. 146 * {@hide} 147 */ 148 @SystemApi 149 public static final int STANDBY_BUCKET_NEVER = 50; 150 151 /** @hide */ 152 public static final int REASON_MAIN_MASK = 0xFF00; 153 /** @hide */ 154 public static final int REASON_MAIN_DEFAULT = 0x0100; 155 /** @hide */ 156 public static final int REASON_MAIN_TIMEOUT = 0x0200; 157 /** @hide */ 158 public static final int REASON_MAIN_USAGE = 0x0300; 159 /** @hide */ 160 public static final int REASON_MAIN_FORCED = 0x0400; 161 /** @hide */ 162 public static final int REASON_MAIN_PREDICTED = 0x0500; 163 164 /** @hide */ 165 public static final int REASON_SUB_MASK = 0x00FF; 166 /** @hide */ 167 public static final int REASON_SUB_USAGE_SYSTEM_INTERACTION = 0x0001; 168 /** @hide */ 169 public static final int REASON_SUB_USAGE_NOTIFICATION_SEEN = 0x0002; 170 /** @hide */ 171 public static final int REASON_SUB_USAGE_USER_INTERACTION = 0x0003; 172 /** @hide */ 173 public static final int REASON_SUB_USAGE_MOVE_TO_FOREGROUND = 0x0004; 174 /** @hide */ 175 public static final int REASON_SUB_USAGE_MOVE_TO_BACKGROUND = 0x0005; 176 /** @hide */ 177 public static final int REASON_SUB_USAGE_SYSTEM_UPDATE = 0x0006; 178 /** @hide */ 179 public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT = 0x0007; 180 /** @hide */ 181 public static final int REASON_SUB_USAGE_SYNC_ADAPTER = 0x0008; 182 /** @hide */ 183 public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009; 184 /** @hide */ 185 public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A; 186 /** @hide */ 187 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B; 188 /** @hide */ 189 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C; 190 /** @hide */ 191 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D; 192 193 /** @hide */ 194 public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001; 195 196 197 /** @hide */ 198 @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = { 199 STANDBY_BUCKET_EXEMPTED, 200 STANDBY_BUCKET_ACTIVE, 201 STANDBY_BUCKET_WORKING_SET, 202 STANDBY_BUCKET_FREQUENT, 203 STANDBY_BUCKET_RARE, 204 STANDBY_BUCKET_NEVER, 205 }) 206 @Retention(RetentionPolicy.SOURCE) 207 public @interface StandbyBuckets {} 208 209 /** 210 * Observer id of the registered observer for the group of packages that reached the usage 211 * time limit. Included as an extra in the PendingIntent that was registered. 212 * @hide 213 */ 214 @SystemApi 215 public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID"; 216 217 /** 218 * Original time limit in milliseconds specified by the registered observer for the group of 219 * packages that reached the usage time limit. Included as an extra in the PendingIntent that 220 * was registered. 221 * @hide 222 */ 223 @SystemApi 224 public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT"; 225 226 /** 227 * Actual usage time in milliseconds for the group of packages that reached the specified time 228 * limit. Included as an extra in the PendingIntent that was registered. 229 * @hide 230 */ 231 @SystemApi 232 public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED"; 233 234 private static final UsageEvents sEmptyResults = new UsageEvents(); 235 236 private final Context mContext; 237 private final IUsageStatsManager mService; 238 239 /** 240 * {@hide} 241 */ UsageStatsManager(Context context, IUsageStatsManager service)242 public UsageStatsManager(Context context, IUsageStatsManager service) { 243 mContext = context; 244 mService = service; 245 } 246 247 /** 248 * Gets application usage stats for the given time range, aggregated by the specified interval. 249 * <p>The returned list will contain a {@link UsageStats} object for each package that 250 * has data for an interval that is a subset of the time range given. To illustrate:</p> 251 * <pre> 252 * intervalType = INTERVAL_YEARLY 253 * beginTime = 2013 254 * endTime = 2015 (exclusive) 255 * 256 * Results: 257 * 2013 - com.example.alpha 258 * 2013 - com.example.beta 259 * 2014 - com.example.alpha 260 * 2014 - com.example.beta 261 * 2014 - com.example.charlie 262 * </pre> 263 * 264 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> 265 * 266 * @param intervalType The time interval by which the stats are aggregated. 267 * @param beginTime The inclusive beginning of the range of stats to include in the results. 268 * @param endTime The exclusive end of the range of stats to include in the results. 269 * @return A list of {@link UsageStats} 270 * 271 * @see #INTERVAL_DAILY 272 * @see #INTERVAL_WEEKLY 273 * @see #INTERVAL_MONTHLY 274 * @see #INTERVAL_YEARLY 275 * @see #INTERVAL_BEST 276 */ queryUsageStats(int intervalType, long beginTime, long endTime)277 public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) { 278 try { 279 @SuppressWarnings("unchecked") 280 ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime, 281 endTime, mContext.getOpPackageName()); 282 if (slice != null) { 283 return slice.getList(); 284 } 285 } catch (RemoteException e) { 286 // fallthrough and return the empty list. 287 } 288 return Collections.emptyList(); 289 } 290 291 /** 292 * Gets the hardware configurations the device was in for the given time range, aggregated by 293 * the specified interval. The results are ordered as in 294 * {@link #queryUsageStats(int, long, long)}. 295 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> 296 * 297 * @param intervalType The time interval by which the stats are aggregated. 298 * @param beginTime The inclusive beginning of the range of stats to include in the results. 299 * @param endTime The exclusive end of the range of stats to include in the results. 300 * @return A list of {@link ConfigurationStats} 301 */ queryConfigurations(int intervalType, long beginTime, long endTime)302 public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime, 303 long endTime) { 304 try { 305 @SuppressWarnings("unchecked") 306 ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats( 307 intervalType, beginTime, endTime, mContext.getOpPackageName()); 308 if (slice != null) { 309 return slice.getList(); 310 } 311 } catch (RemoteException e) { 312 // fallthrough and return the empty list. 313 } 314 return Collections.emptyList(); 315 } 316 317 /** 318 * Gets aggregated event stats for the given time range, aggregated by the specified interval. 319 * <p>The returned list will contain a {@link EventStats} object for each event type that 320 * is being aggregated and has data for an interval that is a subset of the time range given. 321 * 322 * <p>The current event types that will be aggregated here are:</p> 323 * <ul> 324 * <li>{@link UsageEvents.Event#SCREEN_INTERACTIVE}</li> 325 * <li>{@link UsageEvents.Event#SCREEN_NON_INTERACTIVE}</li> 326 * <li>{@link UsageEvents.Event#KEYGUARD_SHOWN}</li> 327 * <li>{@link UsageEvents.Event#KEYGUARD_HIDDEN}</li> 328 * </ul> 329 * 330 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> 331 * 332 * @param intervalType The time interval by which the stats are aggregated. 333 * @param beginTime The inclusive beginning of the range of stats to include in the results. 334 * @param endTime The exclusive end of the range of stats to include in the results. 335 * @return A list of {@link EventStats} 336 * 337 * @see #INTERVAL_DAILY 338 * @see #INTERVAL_WEEKLY 339 * @see #INTERVAL_MONTHLY 340 * @see #INTERVAL_YEARLY 341 * @see #INTERVAL_BEST 342 */ queryEventStats(int intervalType, long beginTime, long endTime)343 public List<EventStats> queryEventStats(int intervalType, long beginTime, long endTime) { 344 try { 345 @SuppressWarnings("unchecked") 346 ParceledListSlice<EventStats> slice = mService.queryEventStats(intervalType, beginTime, 347 endTime, mContext.getOpPackageName()); 348 if (slice != null) { 349 return slice.getList(); 350 } 351 } catch (RemoteException e) { 352 // fallthrough and return the empty list. 353 } 354 return Collections.emptyList(); 355 } 356 357 /** 358 * Query for events in the given time range. Events are only kept by the system for a few 359 * days. 360 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> 361 * 362 * @param beginTime The inclusive beginning of the range of events to include in the results. 363 * @param endTime The exclusive end of the range of events to include in the results. 364 * @return A {@link UsageEvents}. 365 */ queryEvents(long beginTime, long endTime)366 public UsageEvents queryEvents(long beginTime, long endTime) { 367 try { 368 UsageEvents iter = mService.queryEvents(beginTime, endTime, 369 mContext.getOpPackageName()); 370 if (iter != null) { 371 return iter; 372 } 373 } catch (RemoteException e) { 374 // fallthrough and return empty result. 375 } 376 return sEmptyResults; 377 } 378 379 /** 380 * Like {@link #queryEvents(long, long)}, but only returns events for the calling package. 381 * 382 * @param beginTime The inclusive beginning of the range of events to include in the results. 383 * @param endTime The exclusive end of the range of events to include in the results. 384 * @return A {@link UsageEvents} object. 385 * 386 * @see #queryEvents(long, long) 387 */ queryEventsForSelf(long beginTime, long endTime)388 public UsageEvents queryEventsForSelf(long beginTime, long endTime) { 389 try { 390 final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime, 391 mContext.getOpPackageName()); 392 if (events != null) { 393 return events; 394 } 395 } catch (RemoteException e) { 396 // fallthrough 397 } 398 return sEmptyResults; 399 } 400 401 /** 402 * A convenience method that queries for all stats in the given range (using the best interval 403 * for that range), merges the resulting data, and keys it by package name. 404 * See {@link #queryUsageStats(int, long, long)}. 405 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> 406 * 407 * @param beginTime The inclusive beginning of the range of stats to include in the results. 408 * @param endTime The exclusive end of the range of stats to include in the results. 409 * @return A {@link java.util.Map} keyed by package name 410 */ queryAndAggregateUsageStats(long beginTime, long endTime)411 public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) { 412 List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime); 413 if (stats.isEmpty()) { 414 return Collections.emptyMap(); 415 } 416 417 ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>(); 418 final int statCount = stats.size(); 419 for (int i = 0; i < statCount; i++) { 420 UsageStats newStat = stats.get(i); 421 UsageStats existingStat = aggregatedStats.get(newStat.getPackageName()); 422 if (existingStat == null) { 423 aggregatedStats.put(newStat.mPackageName, newStat); 424 } else { 425 existingStat.add(newStat); 426 } 427 } 428 return aggregatedStats; 429 } 430 431 /** 432 * Returns whether the specified app is currently considered inactive. This will be true if the 433 * app hasn't been used directly or indirectly for a period of time defined by the system. This 434 * could be of the order of several hours or days. 435 * @param packageName The package name of the app to query 436 * @return whether the app is currently considered inactive 437 */ isAppInactive(String packageName)438 public boolean isAppInactive(String packageName) { 439 try { 440 return mService.isAppInactive(packageName, mContext.getUserId()); 441 } catch (RemoteException e) { 442 // fall through and return default 443 } 444 return false; 445 } 446 447 /** 448 * {@hide} 449 */ setAppInactive(String packageName, boolean inactive)450 public void setAppInactive(String packageName, boolean inactive) { 451 try { 452 mService.setAppInactive(packageName, inactive, mContext.getUserId()); 453 } catch (RemoteException e) { 454 // fall through 455 } 456 } 457 458 /** 459 * Returns the current standby bucket of the calling app. The system determines the standby 460 * state of the app based on app usage patterns. Standby buckets determine how much an app will 461 * be restricted from running background tasks such as jobs and alarms. 462 * <p>Restrictions increase progressively from {@link #STANDBY_BUCKET_ACTIVE} to 463 * {@link #STANDBY_BUCKET_RARE}, with {@link #STANDBY_BUCKET_ACTIVE} being the least 464 * restrictive. The battery level of the device might also affect the restrictions. 465 * <p>Apps in buckets ≤ {@link #STANDBY_BUCKET_ACTIVE} have no standby restrictions imposed. 466 * Apps in buckets > {@link #STANDBY_BUCKET_FREQUENT} may have network access restricted when 467 * running in the background. 468 * <p>The standby state of an app can change at any time either due to a user interaction or a 469 * system interaction or some algorithm determining that the app can be restricted for a period 470 * of time before the user has a need for it. 471 * <p>You can also query the recent history of standby bucket changes by calling 472 * {@link #queryEventsForSelf(long, long)} and searching for 473 * {@link UsageEvents.Event#STANDBY_BUCKET_CHANGED}. 474 * 475 * @return the current standby bucket of the calling app. One of STANDBY_BUCKET_* constants. 476 */ getAppStandbyBucket()477 public @StandbyBuckets int getAppStandbyBucket() { 478 try { 479 return mService.getAppStandbyBucket(mContext.getOpPackageName(), 480 mContext.getOpPackageName(), 481 mContext.getUserId()); 482 } catch (RemoteException e) { 483 } 484 return STANDBY_BUCKET_ACTIVE; 485 } 486 487 /** 488 * {@hide} 489 * Returns the current standby bucket of the specified app. The caller must hold the permission 490 * android.permission.PACKAGE_USAGE_STATS. 491 * @param packageName the package for which to fetch the current standby bucket. 492 */ 493 @SystemApi 494 @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) getAppStandbyBucket(String packageName)495 public @StandbyBuckets int getAppStandbyBucket(String packageName) { 496 try { 497 return mService.getAppStandbyBucket(packageName, mContext.getOpPackageName(), 498 mContext.getUserId()); 499 } catch (RemoteException e) { 500 } 501 return STANDBY_BUCKET_ACTIVE; 502 } 503 504 /** 505 * {@hide} 506 * Changes an app's standby bucket to the provided value. The caller can only set the standby 507 * bucket for a different app than itself. 508 * @param packageName the package name of the app to set the bucket for. A SecurityException 509 * will be thrown if the package name is that of the caller. 510 * @param bucket the standby bucket to set it to, which should be one of STANDBY_BUCKET_*. 511 * Setting a standby bucket outside of the range of STANDBY_BUCKET_ACTIVE to 512 * STANDBY_BUCKET_NEVER will result in a SecurityException. 513 */ 514 @SystemApi 515 @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) setAppStandbyBucket(String packageName, @StandbyBuckets int bucket)516 public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) { 517 try { 518 mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId()); 519 } catch (RemoteException e) { 520 throw e.rethrowFromSystemServer(); 521 } 522 } 523 524 /** 525 * {@hide} 526 * Returns the current standby bucket of every app that has a bucket assigned to it. 527 * The caller must hold the permission android.permission.PACKAGE_USAGE_STATS. The key of the 528 * returned Map is the package name and the value is the bucket assigned to the package. 529 * @see #getAppStandbyBucket() 530 */ 531 @SystemApi 532 @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) getAppStandbyBuckets()533 public Map<String, Integer> getAppStandbyBuckets() { 534 try { 535 final ParceledListSlice<AppStandbyInfo> slice = mService.getAppStandbyBuckets( 536 mContext.getOpPackageName(), mContext.getUserId()); 537 final List<AppStandbyInfo> bucketList = slice.getList(); 538 final ArrayMap<String, Integer> bucketMap = new ArrayMap<>(); 539 final int n = bucketList.size(); 540 for (int i = 0; i < n; i++) { 541 final AppStandbyInfo bucketInfo = bucketList.get(i); 542 bucketMap.put(bucketInfo.mPackageName, bucketInfo.mStandbyBucket); 543 } 544 return bucketMap; 545 } catch (RemoteException e) { 546 throw e.rethrowFromSystemServer(); 547 } 548 } 549 550 /** 551 * {@hide} 552 * Changes the app standby bucket for multiple apps at once. The Map is keyed by the package 553 * name and the value is one of STANDBY_BUCKET_*. 554 * @param appBuckets a map of package name to bucket value. 555 */ 556 @SystemApi 557 @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE) setAppStandbyBuckets(Map<String, Integer> appBuckets)558 public void setAppStandbyBuckets(Map<String, Integer> appBuckets) { 559 if (appBuckets == null) { 560 return; 561 } 562 final List<AppStandbyInfo> bucketInfoList = new ArrayList<>(appBuckets.size()); 563 for (Map.Entry<String, Integer> bucketEntry : appBuckets.entrySet()) { 564 bucketInfoList.add(new AppStandbyInfo(bucketEntry.getKey(), bucketEntry.getValue())); 565 } 566 final ParceledListSlice<AppStandbyInfo> slice = new ParceledListSlice<>(bucketInfoList); 567 try { 568 mService.setAppStandbyBuckets(slice, mContext.getUserId()); 569 } catch (RemoteException e) { 570 throw e.rethrowFromSystemServer(); 571 } 572 } 573 574 /** 575 * @hide 576 * Register an app usage limit observer that receives a callback on the provided intent when 577 * the sum of usages of apps in the packages array exceeds the {@code timeLimit} specified. The 578 * observer will automatically be unregistered when the time limit is reached and the intent 579 * is delivered. Registering an {@code observerId} that was already registered will override 580 * the previous one. No more than 1000 unique {@code observerId} may be registered by a single 581 * uid at any one time. 582 * @param observerId A unique id associated with the group of apps to be monitored. There can 583 * be multiple groups with common packages and different time limits. 584 * @param packages The list of packages to observe for foreground activity time. Cannot be null 585 * and must include at least one package. 586 * @param timeLimit The total time the set of apps can be in the foreground before the 587 * callbackIntent is delivered. Must be at least one minute. 588 * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null. 589 * @param callbackIntent The PendingIntent that will be dispatched when the time limit is 590 * exceeded by the group of apps. The delivered Intent will also contain 591 * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and 592 * {@link #EXTRA_TIME_USED}. Cannot be null. 593 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission or 594 * is not the profile owner of this user. 595 */ 596 @SystemApi 597 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent)598 public void registerAppUsageObserver(int observerId, @NonNull String[] packages, long timeLimit, 599 @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) { 600 try { 601 mService.registerAppUsageObserver(observerId, packages, timeUnit.toMillis(timeLimit), 602 callbackIntent, mContext.getOpPackageName()); 603 } catch (RemoteException e) { 604 throw e.rethrowFromSystemServer(); 605 } 606 } 607 608 /** 609 * @hide 610 * Unregister the app usage observer specified by the {@code observerId}. This will only apply 611 * to any observer registered by this application. Unregistering an observer that was already 612 * unregistered or never registered will have no effect. 613 * @param observerId The id of the observer that was previously registered. 614 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission or is 615 * not the profile owner of this user. 616 */ 617 @SystemApi 618 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) unregisterAppUsageObserver(int observerId)619 public void unregisterAppUsageObserver(int observerId) { 620 try { 621 mService.unregisterAppUsageObserver(observerId, mContext.getOpPackageName()); 622 } catch (RemoteException e) { 623 throw e.rethrowFromSystemServer(); 624 } 625 } 626 627 /** @hide */ reasonToString(int standbyReason)628 public static String reasonToString(int standbyReason) { 629 StringBuilder sb = new StringBuilder(); 630 switch (standbyReason & REASON_MAIN_MASK) { 631 case REASON_MAIN_DEFAULT: 632 sb.append("d"); 633 break; 634 case REASON_MAIN_FORCED: 635 sb.append("f"); 636 break; 637 case REASON_MAIN_PREDICTED: 638 sb.append("p"); 639 switch (standbyReason & REASON_SUB_MASK) { 640 case REASON_SUB_PREDICTED_RESTORED: 641 sb.append("-r"); 642 break; 643 } 644 break; 645 case REASON_MAIN_TIMEOUT: 646 sb.append("t"); 647 break; 648 case REASON_MAIN_USAGE: 649 sb.append("u"); 650 switch (standbyReason & REASON_SUB_MASK) { 651 case REASON_SUB_USAGE_SYSTEM_INTERACTION: 652 sb.append("-si"); 653 break; 654 case REASON_SUB_USAGE_NOTIFICATION_SEEN: 655 sb.append("-ns"); 656 break; 657 case REASON_SUB_USAGE_USER_INTERACTION: 658 sb.append("-ui"); 659 break; 660 case REASON_SUB_USAGE_MOVE_TO_FOREGROUND: 661 sb.append("-mf"); 662 break; 663 case REASON_SUB_USAGE_MOVE_TO_BACKGROUND: 664 sb.append("-mb"); 665 break; 666 case REASON_SUB_USAGE_SYSTEM_UPDATE: 667 sb.append("-su"); 668 break; 669 case REASON_SUB_USAGE_ACTIVE_TIMEOUT: 670 sb.append("-at"); 671 break; 672 case REASON_SUB_USAGE_SYNC_ADAPTER: 673 sb.append("-sa"); 674 break; 675 case REASON_SUB_USAGE_SLICE_PINNED: 676 sb.append("-lp"); 677 break; 678 case REASON_SUB_USAGE_SLICE_PINNED_PRIV: 679 sb.append("-lv"); 680 break; 681 case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE: 682 sb.append("-en"); 683 break; 684 case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE: 685 sb.append("-ed"); 686 break; 687 case REASON_SUB_USAGE_EXEMPTED_SYNC_START: 688 sb.append("-es"); 689 break; 690 } 691 break; 692 } 693 return sb.toString(); 694 } 695 696 /** 697 * {@hide} 698 * Temporarily whitelist the specified app for a short duration. This is to allow an app 699 * receiving a high priority message to be able to access the network and acquire wakelocks 700 * even if the device is in power-save mode or the app is currently considered inactive. 701 * @param packageName The package name of the app to whitelist. 702 * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that 703 * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes. 704 * @param user The user for whom the package should be whitelisted. Passing in a user that is 705 * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission. 706 * @see #isAppInactive(String) 707 */ 708 @SystemApi 709 @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST) whitelistAppTemporarily(String packageName, long duration, UserHandle user)710 public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) { 711 try { 712 mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier()); 713 } catch (RemoteException re) { 714 throw re.rethrowFromSystemServer(); 715 } 716 } 717 718 /** 719 * Inform usage stats that the carrier privileged apps access rules have changed. 720 * @hide 721 */ onCarrierPrivilegedAppsChanged()722 public void onCarrierPrivilegedAppsChanged() { 723 try { 724 mService.onCarrierPrivilegedAppsChanged(); 725 } catch (RemoteException re) { 726 throw re.rethrowFromSystemServer(); 727 } 728 } 729 730 /** 731 * Reports a Chooser action to the UsageStatsManager. 732 * 733 * @param packageName The package name of the app that is selected. 734 * @param userId The user id of who makes the selection. 735 * @param contentType The type of the content, e.g., Image, Video, App. 736 * @param annotations The annotations of the content, e.g., Game, Selfie. 737 * @param action The action type of Intent that invokes ChooserActivity. 738 * {@link UsageEvents} 739 * @hide 740 */ reportChooserSelection(String packageName, int userId, String contentType, String[] annotations, String action)741 public void reportChooserSelection(String packageName, int userId, String contentType, 742 String[] annotations, String action) { 743 try { 744 mService.reportChooserSelection(packageName, userId, contentType, annotations, action); 745 } catch (RemoteException re) { 746 } 747 } 748 } 749