blob: d34e6d3836b8e612e58bc22a230f80c4802f1d62 [file] [log] [blame]
Adam Lesinski0debc9a2014-07-16 19:09:13 -07001/**
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
17package android.app.usage;
18
Amith Yamasaniafbccb72017-11-27 10:44:24 -080019import android.annotation.IntDef;
Amith Yamasanibc813eb2018-03-20 19:37:46 -070020import android.annotation.NonNull;
Michael Wachenschwanz641e3382018-10-23 23:21:48 -070021import android.annotation.Nullable;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060022import android.annotation.RequiresPermission;
Amith Yamasaniaf575b92015-05-29 15:35:26 -070023import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060024import android.annotation.SystemService;
Michael Wachenschwanz0b4ab1f2019-01-07 13:59:10 -080025import android.annotation.TestApi;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010026import android.annotation.UnsupportedAppUsage;
Michael Wachenschwanz36778522018-11-12 11:06:19 -080027import android.app.Activity;
Amith Yamasani62ec27e92018-03-11 14:42:06 -070028import android.app.PendingIntent;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070029import android.content.Context;
Adam Lesinski35168002014-07-21 15:25:30 -070030import android.content.pm.ParceledListSlice;
Mathew Inwood8c854f82018-09-14 12:35:36 +010031import android.os.Build;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070032import android.os.RemoteException;
Amith Yamasanicf768722015-04-23 20:36:41 -070033import android.os.UserHandle;
Adam Lesinski35168002014-07-21 15:25:30 -070034import android.util.ArrayMap;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070035
Amith Yamasaniafbccb72017-11-27 10:44:24 -080036import java.lang.annotation.Retention;
37import java.lang.annotation.RetentionPolicy;
Suprabh Shukla868bde22018-02-20 20:59:52 -080038import java.util.ArrayList;
Adam Lesinski35168002014-07-21 15:25:30 -070039import java.util.Collections;
40import java.util.List;
Adam Lesinskicc562a82014-08-27 11:52:52 -070041import java.util.Map;
Amith Yamasani62ec27e92018-03-11 14:42:06 -070042import java.util.concurrent.TimeUnit;
Adam Lesinski35168002014-07-21 15:25:30 -070043
44/**
45 * Provides access to device usage history and statistics. Usage data is aggregated into
46 * time intervals: days, weeks, months, and years.
47 * <p />
48 * When requesting usage data since a particular time, the request might look something like this:
49 * <pre>
50 * PAST REQUEST_TIME TODAY FUTURE
51 * ————————————————————————————||———————————————————————————¦-----------------------|
52 * YEAR || ¦ |
53 * ————————————————————————————||———————————————————————————¦-----------------------|
54 * MONTH | || MONTH ¦ |
55 * ——————————————————|—————————||———————————————————————————¦-----------------------|
56 * | WEEK | WEEK|| | WEEK | WE¦EK | WEEK |
57 * ————————————————————————————||———————————————————|———————¦-----------------------|
58 * || |DAY|DAY|DAY|DAY¦DAY|DAY|DAY|DAY|DAY|DAY|
59 * ————————————————————————————||———————————————————————————¦-----------------------|
60 * </pre>
61 * A request for data in the middle of a time interval will include that interval.
62 * <p/>
Suprabh Shukla217ccda2018-02-23 17:57:12 -080063 * <b>NOTE:</b> Most methods on this API require the permission
64 * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to
65 * use the API and the user of the device still needs to grant permission through the Settings
66 * application.
67 * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}.
68 * Methods which only return the information for the calling package do not require this permission.
69 * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}.
Adam Lesinski35168002014-07-21 15:25:30 -070070 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060071@SystemService(Context.USAGE_STATS_SERVICE)
Adam Lesinski0debc9a2014-07-16 19:09:13 -070072public final class UsageStatsManager {
Adam Lesinski0debc9a2014-07-16 19:09:13 -070073
74 /**
Adam Lesinski35168002014-07-21 15:25:30 -070075 * An interval type that spans a day. See {@link #queryUsageStats(int, long, long)}.
Adam Lesinski0debc9a2014-07-16 19:09:13 -070076 */
Adam Lesinski35168002014-07-21 15:25:30 -070077 public static final int INTERVAL_DAILY = 0;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070078
79 /**
Adam Lesinski35168002014-07-21 15:25:30 -070080 * An interval type that spans a week. See {@link #queryUsageStats(int, long, long)}.
Adam Lesinski0debc9a2014-07-16 19:09:13 -070081 */
Adam Lesinski35168002014-07-21 15:25:30 -070082 public static final int INTERVAL_WEEKLY = 1;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070083
84 /**
Adam Lesinski35168002014-07-21 15:25:30 -070085 * An interval type that spans a month. See {@link #queryUsageStats(int, long, long)}.
Adam Lesinski0debc9a2014-07-16 19:09:13 -070086 */
Adam Lesinski35168002014-07-21 15:25:30 -070087 public static final int INTERVAL_MONTHLY = 2;
Adam Lesinski0debc9a2014-07-16 19:09:13 -070088
89 /**
Adam Lesinski35168002014-07-21 15:25:30 -070090 * An interval type that spans a year. See {@link #queryUsageStats(int, long, long)}.
91 */
92 public static final int INTERVAL_YEARLY = 3;
93
94 /**
95 * An interval type that will use the best fit interval for the given time range.
96 * See {@link #queryUsageStats(int, long, long)}.
97 */
98 public static final int INTERVAL_BEST = 4;
99
100 /**
101 * The number of available intervals. Does not include {@link #INTERVAL_BEST}, since it
102 * is a pseudo interval (it actually selects a real interval).
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700103 * {@hide}
104 */
Adam Lesinski35168002014-07-21 15:25:30 -0700105 public static final int INTERVAL_COUNT = 4;
106
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800107
108 /**
109 * The app is whitelisted for some reason and the bucket cannot be changed.
110 * {@hide}
111 */
112 @SystemApi
113 public static final int STANDBY_BUCKET_EXEMPTED = 5;
114
115 /**
Amith Yamasani853e53f2018-03-16 16:08:57 -0700116 * The app was used very recently, currently in use or likely to be used very soon. Standby
117 * bucket values that are &le; {@link #STANDBY_BUCKET_ACTIVE} will not be throttled by the
118 * system while they are in this bucket. Buckets &gt; {@link #STANDBY_BUCKET_ACTIVE} will most
119 * likely be restricted in some way. For instance, jobs and alarms may be deferred.
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800120 * @see #getAppStandbyBucket()
121 */
122 public static final int STANDBY_BUCKET_ACTIVE = 10;
123
124 /**
Amith Yamasani853e53f2018-03-16 16:08:57 -0700125 * The app was used recently and/or likely to be used in the next few hours. Restrictions will
126 * apply to these apps, such as deferral of jobs and alarms.
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800127 * @see #getAppStandbyBucket()
128 */
129 public static final int STANDBY_BUCKET_WORKING_SET = 20;
130
131 /**
132 * The app was used in the last few days and/or likely to be used in the next few days.
Amith Yamasani853e53f2018-03-16 16:08:57 -0700133 * Restrictions will apply to these apps, such as deferral of jobs and alarms. The delays may be
134 * greater than for apps in higher buckets (lower bucket value). Bucket values &gt;
135 * {@link #STANDBY_BUCKET_FREQUENT} may additionally have network access limited.
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800136 * @see #getAppStandbyBucket()
137 */
138 public static final int STANDBY_BUCKET_FREQUENT = 30;
139
140 /**
141 * The app has not be used for several days and/or is unlikely to be used for several days.
Amith Yamasani853e53f2018-03-16 16:08:57 -0700142 * Apps in this bucket will have the most restrictions, including network restrictions, except
143 * during certain short periods (at a minimum, once a day) when they are allowed to execute
144 * jobs, access the network, etc.
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800145 * @see #getAppStandbyBucket()
146 */
147 public static final int STANDBY_BUCKET_RARE = 40;
148
149 /**
150 * The app has never been used.
151 * {@hide}
152 */
153 @SystemApi
154 public static final int STANDBY_BUCKET_NEVER = 50;
155
Amith Yamasani119be9a2018-02-18 22:23:00 -0800156 /** @hide */
157 public static final int REASON_MAIN_MASK = 0xFF00;
158 /** @hide */
159 public static final int REASON_MAIN_DEFAULT = 0x0100;
160 /** @hide */
161 public static final int REASON_MAIN_TIMEOUT = 0x0200;
162 /** @hide */
163 public static final int REASON_MAIN_USAGE = 0x0300;
164 /** @hide */
165 public static final int REASON_MAIN_FORCED = 0x0400;
166 /** @hide */
167 public static final int REASON_MAIN_PREDICTED = 0x0500;
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800168
Amith Yamasani119be9a2018-02-18 22:23:00 -0800169 /** @hide */
170 public static final int REASON_SUB_MASK = 0x00FF;
171 /** @hide */
172 public static final int REASON_SUB_USAGE_SYSTEM_INTERACTION = 0x0001;
173 /** @hide */
174 public static final int REASON_SUB_USAGE_NOTIFICATION_SEEN = 0x0002;
175 /** @hide */
176 public static final int REASON_SUB_USAGE_USER_INTERACTION = 0x0003;
177 /** @hide */
178 public static final int REASON_SUB_USAGE_MOVE_TO_FOREGROUND = 0x0004;
179 /** @hide */
180 public static final int REASON_SUB_USAGE_MOVE_TO_BACKGROUND = 0x0005;
181 /** @hide */
182 public static final int REASON_SUB_USAGE_SYSTEM_UPDATE = 0x0006;
183 /** @hide */
184 public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT = 0x0007;
185 /** @hide */
186 public static final int REASON_SUB_USAGE_SYNC_ADAPTER = 0x0008;
Amith Yamasani80c4be82018-03-26 10:54:04 -0700187 /** @hide */
188 public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009;
189 /** @hide */
190 public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A;
Makoto Onuki75ad2492018-03-28 14:42:42 -0700191 /** @hide */
Makoto Onukid5f25d22018-05-22 16:02:17 -0700192 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B;
193 /** @hide */
194 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
195 /** @hide */
196 public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
Hui Yue361a232018-10-04 15:05:21 -0700197 /** @hide */
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800198 public static final int REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED = 0x000E;
199 /** @hide */
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700200 public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001;
201
Makoto Onuki75ad2492018-03-28 14:42:42 -0700202
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700203 /** @hide */
Jeff Sharkeyce8db992017-12-13 20:05:05 -0700204 @IntDef(flag = false, prefix = { "STANDBY_BUCKET_" }, value = {
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800205 STANDBY_BUCKET_EXEMPTED,
206 STANDBY_BUCKET_ACTIVE,
207 STANDBY_BUCKET_WORKING_SET,
208 STANDBY_BUCKET_FREQUENT,
209 STANDBY_BUCKET_RARE,
210 STANDBY_BUCKET_NEVER,
211 })
212 @Retention(RetentionPolicy.SOURCE)
213 public @interface StandbyBuckets {}
214
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700215 /**
216 * Observer id of the registered observer for the group of packages that reached the usage
217 * time limit. Included as an extra in the PendingIntent that was registered.
218 * @hide
219 */
220 @SystemApi
221 public static final String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
222
223 /**
224 * Original time limit in milliseconds specified by the registered observer for the group of
225 * packages that reached the usage time limit. Included as an extra in the PendingIntent that
226 * was registered.
227 * @hide
228 */
229 @SystemApi
230 public static final String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
231
232 /**
233 * Actual usage time in milliseconds for the group of packages that reached the specified time
234 * limit. Included as an extra in the PendingIntent that was registered.
235 * @hide
236 */
237 @SystemApi
238 public static final String EXTRA_TIME_USED = "android.app.usage.extra.TIME_USED";
239
Michael Wachenschwanz0b4ab1f2019-01-07 13:59:10 -0800240
241 /**
242 * App usage observers will consider the task root package the source of usage.
243 * @hide
244 */
245 @SystemApi
246 public static final int USAGE_SOURCE_TASK_ROOT_ACTIVITY = 1;
247
248 /**
249 * App usage observers will consider the visible activity's package the source of usage.
250 * @hide
251 */
252 @SystemApi
253 public static final int USAGE_SOURCE_CURRENT_ACTIVITY = 2;
254
255 /** @hide */
256 @IntDef(prefix = { "USAGE_SOURCE_" }, value = {
257 USAGE_SOURCE_TASK_ROOT_ACTIVITY,
258 USAGE_SOURCE_CURRENT_ACTIVITY,
259 })
260 @Retention(RetentionPolicy.SOURCE)
261 public @interface UsageSource {}
262
Mathew Inwood31755f92018-12-20 13:53:36 +0000263 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Adam Lesinski35168002014-07-21 15:25:30 -0700264 private static final UsageEvents sEmptyResults = new UsageEvents();
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700265
Mathew Inwood8c854f82018-09-14 12:35:36 +0100266 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700267 private final Context mContext;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100268 @UnsupportedAppUsage
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700269 private final IUsageStatsManager mService;
270
271 /**
272 * {@hide}
273 */
274 public UsageStatsManager(Context context, IUsageStatsManager service) {
275 mContext = context;
276 mService = service;
277 }
278
Adam Lesinski35168002014-07-21 15:25:30 -0700279 /**
280 * Gets application usage stats for the given time range, aggregated by the specified interval.
281 * <p>The returned list will contain a {@link UsageStats} object for each package that
282 * has data for an interval that is a subset of the time range given. To illustrate:</p>
283 * <pre>
284 * intervalType = INTERVAL_YEARLY
285 * beginTime = 2013
286 * endTime = 2015 (exclusive)
287 *
288 * Results:
289 * 2013 - com.example.alpha
290 * 2013 - com.example.beta
291 * 2014 - com.example.alpha
292 * 2014 - com.example.beta
293 * 2014 - com.example.charlie
294 * </pre>
295 *
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800296 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
297 *
Adam Lesinski35168002014-07-21 15:25:30 -0700298 * @param intervalType The time interval by which the stats are aggregated.
299 * @param beginTime The inclusive beginning of the range of stats to include in the results.
300 * @param endTime The exclusive end of the range of stats to include in the results.
Esteban Talaverafa962312017-10-09 14:58:28 +0100301 * @return A list of {@link UsageStats}
Adam Lesinski35168002014-07-21 15:25:30 -0700302 *
303 * @see #INTERVAL_DAILY
304 * @see #INTERVAL_WEEKLY
305 * @see #INTERVAL_MONTHLY
306 * @see #INTERVAL_YEARLY
307 * @see #INTERVAL_BEST
308 */
Adam Lesinski35168002014-07-21 15:25:30 -0700309 public List<UsageStats> queryUsageStats(int intervalType, long beginTime, long endTime) {
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700310 try {
Adam Lesinski7f61e962014-09-02 16:43:52 -0700311 @SuppressWarnings("unchecked")
Adam Lesinski35168002014-07-21 15:25:30 -0700312 ParceledListSlice<UsageStats> slice = mService.queryUsageStats(intervalType, beginTime,
313 endTime, mContext.getOpPackageName());
314 if (slice != null) {
315 return slice.getList();
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700316 }
Adam Lesinski35168002014-07-21 15:25:30 -0700317 } catch (RemoteException e) {
Esteban Talaverafa962312017-10-09 14:58:28 +0100318 // fallthrough and return the empty list.
Adam Lesinski35168002014-07-21 15:25:30 -0700319 }
Adam Lesinski7f61e962014-09-02 16:43:52 -0700320 return Collections.emptyList();
321 }
322
323 /**
324 * Gets the hardware configurations the device was in for the given time range, aggregated by
325 * the specified interval. The results are ordered as in
326 * {@link #queryUsageStats(int, long, long)}.
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800327 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
Adam Lesinski7f61e962014-09-02 16:43:52 -0700328 *
329 * @param intervalType The time interval by which the stats are aggregated.
330 * @param beginTime The inclusive beginning of the range of stats to include in the results.
331 * @param endTime The exclusive end of the range of stats to include in the results.
Esteban Talaverafa962312017-10-09 14:58:28 +0100332 * @return A list of {@link ConfigurationStats}
Adam Lesinski7f61e962014-09-02 16:43:52 -0700333 */
334 public List<ConfigurationStats> queryConfigurations(int intervalType, long beginTime,
335 long endTime) {
336 try {
337 @SuppressWarnings("unchecked")
338 ParceledListSlice<ConfigurationStats> slice = mService.queryConfigurationStats(
339 intervalType, beginTime, endTime, mContext.getOpPackageName());
340 if (slice != null) {
341 return slice.getList();
342 }
343 } catch (RemoteException e) {
344 // fallthrough and return the empty list.
345 }
346 return Collections.emptyList();
Adam Lesinski35168002014-07-21 15:25:30 -0700347 }
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700348
Adam Lesinski35168002014-07-21 15:25:30 -0700349 /**
Dianne Hackbornced54392018-02-26 13:07:42 -0800350 * Gets aggregated event stats for the given time range, aggregated by the specified interval.
351 * <p>The returned list will contain a {@link EventStats} object for each event type that
352 * is being aggregated and has data for an interval that is a subset of the time range given.
353 *
354 * <p>The current event types that will be aggregated here are:</p>
355 * <ul>
356 * <li>{@link UsageEvents.Event#SCREEN_INTERACTIVE}</li>
357 * <li>{@link UsageEvents.Event#SCREEN_NON_INTERACTIVE}</li>
Dianne Hackborn3378aa92018-03-30 17:43:49 -0700358 * <li>{@link UsageEvents.Event#KEYGUARD_SHOWN}</li>
359 * <li>{@link UsageEvents.Event#KEYGUARD_HIDDEN}</li>
Dianne Hackbornced54392018-02-26 13:07:42 -0800360 * </ul>
361 *
362 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
363 *
364 * @param intervalType The time interval by which the stats are aggregated.
365 * @param beginTime The inclusive beginning of the range of stats to include in the results.
366 * @param endTime The exclusive end of the range of stats to include in the results.
367 * @return A list of {@link EventStats}
368 *
369 * @see #INTERVAL_DAILY
370 * @see #INTERVAL_WEEKLY
371 * @see #INTERVAL_MONTHLY
372 * @see #INTERVAL_YEARLY
373 * @see #INTERVAL_BEST
374 */
375 public List<EventStats> queryEventStats(int intervalType, long beginTime, long endTime) {
376 try {
377 @SuppressWarnings("unchecked")
378 ParceledListSlice<EventStats> slice = mService.queryEventStats(intervalType, beginTime,
379 endTime, mContext.getOpPackageName());
380 if (slice != null) {
381 return slice.getList();
382 }
383 } catch (RemoteException e) {
384 // fallthrough and return the empty list.
385 }
386 return Collections.emptyList();
387 }
388
389 /**
Adam Lesinski35168002014-07-21 15:25:30 -0700390 * Query for events in the given time range. Events are only kept by the system for a few
391 * days.
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800392 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
Adam Lesinski35168002014-07-21 15:25:30 -0700393 *
394 * @param beginTime The inclusive beginning of the range of events to include in the results.
395 * @param endTime The exclusive end of the range of events to include in the results.
396 * @return A {@link UsageEvents}.
397 */
Adam Lesinski35168002014-07-21 15:25:30 -0700398 public UsageEvents queryEvents(long beginTime, long endTime) {
399 try {
400 UsageEvents iter = mService.queryEvents(beginTime, endTime,
401 mContext.getOpPackageName());
402 if (iter != null) {
403 return iter;
404 }
405 } catch (RemoteException e) {
Esteban Talaverafa962312017-10-09 14:58:28 +0100406 // fallthrough and return empty result.
Adam Lesinski35168002014-07-21 15:25:30 -0700407 }
408 return sEmptyResults;
409 }
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700410
Adam Lesinski35168002014-07-21 15:25:30 -0700411 /**
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800412 * Like {@link #queryEvents(long, long)}, but only returns events for the calling package.
413 *
414 * @param beginTime The inclusive beginning of the range of events to include in the results.
415 * @param endTime The exclusive end of the range of events to include in the results.
416 * @return A {@link UsageEvents} object.
417 *
418 * @see #queryEvents(long, long)
419 */
420 public UsageEvents queryEventsForSelf(long beginTime, long endTime) {
421 try {
422 final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime,
423 mContext.getOpPackageName());
424 if (events != null) {
425 return events;
426 }
427 } catch (RemoteException e) {
428 // fallthrough
429 }
430 return sEmptyResults;
431 }
432
433 /**
Adam Lesinski35168002014-07-21 15:25:30 -0700434 * A convenience method that queries for all stats in the given range (using the best interval
435 * for that range), merges the resulting data, and keys it by package name.
436 * See {@link #queryUsageStats(int, long, long)}.
Suprabh Shukla217ccda2018-02-23 17:57:12 -0800437 * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p>
Adam Lesinski35168002014-07-21 15:25:30 -0700438 *
439 * @param beginTime The inclusive beginning of the range of stats to include in the results.
440 * @param endTime The exclusive end of the range of stats to include in the results.
Esteban Talaverafa962312017-10-09 14:58:28 +0100441 * @return A {@link java.util.Map} keyed by package name
Adam Lesinski35168002014-07-21 15:25:30 -0700442 */
Adam Lesinskicc562a82014-08-27 11:52:52 -0700443 public Map<String, UsageStats> queryAndAggregateUsageStats(long beginTime, long endTime) {
Adam Lesinski35168002014-07-21 15:25:30 -0700444 List<UsageStats> stats = queryUsageStats(INTERVAL_BEST, beginTime, endTime);
445 if (stats.isEmpty()) {
Adam Lesinskicc562a82014-08-27 11:52:52 -0700446 return Collections.emptyMap();
Adam Lesinski35168002014-07-21 15:25:30 -0700447 }
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700448
Adam Lesinski35168002014-07-21 15:25:30 -0700449 ArrayMap<String, UsageStats> aggregatedStats = new ArrayMap<>();
450 final int statCount = stats.size();
451 for (int i = 0; i < statCount; i++) {
452 UsageStats newStat = stats.get(i);
453 UsageStats existingStat = aggregatedStats.get(newStat.getPackageName());
454 if (existingStat == null) {
455 aggregatedStats.put(newStat.mPackageName, newStat);
456 } else {
457 existingStat.add(newStat);
Adam Lesinski0debc9a2014-07-16 19:09:13 -0700458 }
459 }
460 return aggregatedStats;
461 }
Amith Yamasanicf768722015-04-23 20:36:41 -0700462
463 /**
Amith Yamasanie5f33042015-05-08 13:20:22 -0700464 * Returns whether the specified app is currently considered inactive. This will be true if the
Amith Yamasanicf768722015-04-23 20:36:41 -0700465 * app hasn't been used directly or indirectly for a period of time defined by the system. This
466 * could be of the order of several hours or days.
467 * @param packageName The package name of the app to query
Amith Yamasanie5f33042015-05-08 13:20:22 -0700468 * @return whether the app is currently considered inactive
Amith Yamasanicf768722015-04-23 20:36:41 -0700469 */
Amith Yamasanie5f33042015-05-08 13:20:22 -0700470 public boolean isAppInactive(String packageName) {
Amith Yamasanicf768722015-04-23 20:36:41 -0700471 try {
Jeff Sharkeyad357d12018-02-02 13:25:31 -0700472 return mService.isAppInactive(packageName, mContext.getUserId());
Amith Yamasanicf768722015-04-23 20:36:41 -0700473 } catch (RemoteException e) {
474 // fall through and return default
475 }
476 return false;
477 }
Amith Yamasani901e9242015-05-13 18:21:09 -0700478
479 /**
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800480 * {@hide}
Amith Yamasani901e9242015-05-13 18:21:09 -0700481 */
482 public void setAppInactive(String packageName, boolean inactive) {
483 try {
Jeff Sharkeyad357d12018-02-02 13:25:31 -0700484 mService.setAppInactive(packageName, inactive, mContext.getUserId());
Amith Yamasani901e9242015-05-13 18:21:09 -0700485 } catch (RemoteException e) {
486 // fall through
487 }
488 }
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700489
490 /**
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800491 * Returns the current standby bucket of the calling app. The system determines the standby
492 * state of the app based on app usage patterns. Standby buckets determine how much an app will
Amith Yamasani853e53f2018-03-16 16:08:57 -0700493 * be restricted from running background tasks such as jobs and alarms.
Amith Yamasanie8789312017-12-10 14:34:26 -0800494 * <p>Restrictions increase progressively from {@link #STANDBY_BUCKET_ACTIVE} to
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800495 * {@link #STANDBY_BUCKET_RARE}, with {@link #STANDBY_BUCKET_ACTIVE} being the least
496 * restrictive. The battery level of the device might also affect the restrictions.
Amith Yamasani853e53f2018-03-16 16:08:57 -0700497 * <p>Apps in buckets &le; {@link #STANDBY_BUCKET_ACTIVE} have no standby restrictions imposed.
498 * Apps in buckets &gt; {@link #STANDBY_BUCKET_FREQUENT} may have network access restricted when
499 * running in the background.
500 * <p>The standby state of an app can change at any time either due to a user interaction or a
501 * system interaction or some algorithm determining that the app can be restricted for a period
502 * of time before the user has a need for it.
503 * <p>You can also query the recent history of standby bucket changes by calling
504 * {@link #queryEventsForSelf(long, long)} and searching for
505 * {@link UsageEvents.Event#STANDBY_BUCKET_CHANGED}.
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800506 *
Amith Yamasanie8789312017-12-10 14:34:26 -0800507 * @return the current standby bucket of the calling app. One of STANDBY_BUCKET_* constants.
Amith Yamasani17fffee2017-09-29 13:17:43 -0700508 */
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800509 public @StandbyBuckets int getAppStandbyBucket() {
510 try {
511 return mService.getAppStandbyBucket(mContext.getOpPackageName(),
512 mContext.getOpPackageName(),
513 mContext.getUserId());
514 } catch (RemoteException e) {
515 }
516 return STANDBY_BUCKET_ACTIVE;
517 }
518
519 /**
520 * {@hide}
521 * Returns the current standby bucket of the specified app. The caller must hold the permission
522 * android.permission.PACKAGE_USAGE_STATS.
523 * @param packageName the package for which to fetch the current standby bucket.
524 */
525 @SystemApi
526 @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
Amith Yamasani17fffee2017-09-29 13:17:43 -0700527 public @StandbyBuckets int getAppStandbyBucket(String packageName) {
528 try {
529 return mService.getAppStandbyBucket(packageName, mContext.getOpPackageName(),
530 mContext.getUserId());
531 } catch (RemoteException e) {
532 }
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800533 return STANDBY_BUCKET_ACTIVE;
Amith Yamasani17fffee2017-09-29 13:17:43 -0700534 }
535
536 /**
Amith Yamasaniafbccb72017-11-27 10:44:24 -0800537 * {@hide}
Amith Yamasanie8789312017-12-10 14:34:26 -0800538 * Changes an app's standby bucket to the provided value. The caller can only set the standby
539 * bucket for a different app than itself.
540 * @param packageName the package name of the app to set the bucket for. A SecurityException
541 * will be thrown if the package name is that of the caller.
542 * @param bucket the standby bucket to set it to, which should be one of STANDBY_BUCKET_*.
543 * Setting a standby bucket outside of the range of STANDBY_BUCKET_ACTIVE to
544 * STANDBY_BUCKET_NEVER will result in a SecurityException.
Amith Yamasani17fffee2017-09-29 13:17:43 -0700545 */
Amith Yamasani4470ab92017-10-31 13:29:00 -0700546 @SystemApi
547 @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
Amith Yamasani17fffee2017-09-29 13:17:43 -0700548 public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) {
549 try {
550 mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId());
551 } catch (RemoteException e) {
Amith Yamasanifd44f272018-05-14 14:47:19 -0700552 throw e.rethrowFromSystemServer();
Amith Yamasani17fffee2017-09-29 13:17:43 -0700553 }
554 }
555
556 /**
Amith Yamasaniaf575b92015-05-29 15:35:26 -0700557 * {@hide}
Amith Yamasanie8789312017-12-10 14:34:26 -0800558 * Returns the current standby bucket of every app that has a bucket assigned to it.
559 * The caller must hold the permission android.permission.PACKAGE_USAGE_STATS. The key of the
560 * returned Map is the package name and the value is the bucket assigned to the package.
561 * @see #getAppStandbyBucket()
562 */
563 @SystemApi
564 @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS)
565 public Map<String, Integer> getAppStandbyBuckets() {
566 try {
Suprabh Shukla868bde22018-02-20 20:59:52 -0800567 final ParceledListSlice<AppStandbyInfo> slice = mService.getAppStandbyBuckets(
Amith Yamasanie8789312017-12-10 14:34:26 -0800568 mContext.getOpPackageName(), mContext.getUserId());
Suprabh Shukla868bde22018-02-20 20:59:52 -0800569 final List<AppStandbyInfo> bucketList = slice.getList();
570 final ArrayMap<String, Integer> bucketMap = new ArrayMap<>();
571 final int n = bucketList.size();
572 for (int i = 0; i < n; i++) {
573 final AppStandbyInfo bucketInfo = bucketList.get(i);
574 bucketMap.put(bucketInfo.mPackageName, bucketInfo.mStandbyBucket);
575 }
576 return bucketMap;
Amith Yamasanie8789312017-12-10 14:34:26 -0800577 } catch (RemoteException e) {
Amith Yamasanifd44f272018-05-14 14:47:19 -0700578 throw e.rethrowFromSystemServer();
Amith Yamasanie8789312017-12-10 14:34:26 -0800579 }
Amith Yamasanie8789312017-12-10 14:34:26 -0800580 }
581
582 /**
583 * {@hide}
584 * Changes the app standby bucket for multiple apps at once. The Map is keyed by the package
585 * name and the value is one of STANDBY_BUCKET_*.
586 * @param appBuckets a map of package name to bucket value.
587 */
588 @SystemApi
589 @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
590 public void setAppStandbyBuckets(Map<String, Integer> appBuckets) {
Suprabh Shukla868bde22018-02-20 20:59:52 -0800591 if (appBuckets == null) {
592 return;
593 }
594 final List<AppStandbyInfo> bucketInfoList = new ArrayList<>(appBuckets.size());
595 for (Map.Entry<String, Integer> bucketEntry : appBuckets.entrySet()) {
596 bucketInfoList.add(new AppStandbyInfo(bucketEntry.getKey(), bucketEntry.getValue()));
597 }
598 final ParceledListSlice<AppStandbyInfo> slice = new ParceledListSlice<>(bucketInfoList);
Amith Yamasanie8789312017-12-10 14:34:26 -0800599 try {
Suprabh Shukla868bde22018-02-20 20:59:52 -0800600 mService.setAppStandbyBuckets(slice, mContext.getUserId());
Amith Yamasanie8789312017-12-10 14:34:26 -0800601 } catch (RemoteException e) {
Amith Yamasanifd44f272018-05-14 14:47:19 -0700602 throw e.rethrowFromSystemServer();
Amith Yamasanie8789312017-12-10 14:34:26 -0800603 }
604 }
605
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700606 /**
607 * @hide
608 * Register an app usage limit observer that receives a callback on the provided intent when
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800609 * the sum of usages of apps and tokens in the {@code observed} array exceeds the
610 * {@code timeLimit} specified. The structure of a token is a String with the reporting
611 * package's name and a token the reporting app will use, separated by the forward slash
612 * character. Example: com.reporting.package/5OM3*0P4QU3-7OK3N
613 * The observer will automatically be unregistered when the time limit is reached and the
614 * intent is delivered. Registering an {@code observerId} that was already registered will
615 * override the previous one. No more than 1000 unique {@code observerId} may be registered by
616 * a single uid at any one time.
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700617 * @param observerId A unique id associated with the group of apps to be monitored. There can
618 * be multiple groups with common packages and different time limits.
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800619 * @param observedEntities The list of packages and token to observe for usage time. Cannot be
620 * null and must include at least one package or token.
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700621 * @param timeLimit The total time the set of apps can be in the foreground before the
Michael Wachenschwanzc8703092018-05-01 16:02:45 -0700622 * callbackIntent is delivered. Must be at least one minute.
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700623 * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
Varun Shah2546cef2019-01-11 15:50:54 -0800624 * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700625 * exceeded by the group of apps. The delivered Intent will also contain
626 * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700627 * {@link #EXTRA_TIME_USED}. Cannot be null.
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700628 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700629 * is not the profile owner of this user.
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700630 */
631 @SystemApi
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700632 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800633 public void registerAppUsageObserver(int observerId, @NonNull String[] observedEntities,
634 long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700635 try {
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800636 mService.registerAppUsageObserver(observerId, observedEntities,
637 timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700638 } catch (RemoteException e) {
Amith Yamasanifd44f272018-05-14 14:47:19 -0700639 throw e.rethrowFromSystemServer();
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700640 }
641 }
642
643 /**
644 * @hide
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700645 * Unregister the app usage observer specified by the {@code observerId}. This will only apply
646 * to any observer registered by this application. Unregistering an observer that was already
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700647 * unregistered or never registered will have no effect.
648 * @param observerId The id of the observer that was previously registered.
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700649 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and is
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700650 * not the profile owner of this user.
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700651 */
652 @SystemApi
Amith Yamasanibc813eb2018-03-20 19:37:46 -0700653 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700654 public void unregisterAppUsageObserver(int observerId) {
655 try {
656 mService.unregisterAppUsageObserver(observerId, mContext.getOpPackageName());
657 } catch (RemoteException e) {
Amith Yamasanifd44f272018-05-14 14:47:19 -0700658 throw e.rethrowFromSystemServer();
Amith Yamasani62ec27e92018-03-11 14:42:06 -0700659 }
660 }
661
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700662 /**
663 * Register a usage session observer that receives a callback on the provided {@code
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800664 * limitReachedCallbackIntent} when the sum of usages of apps and tokens in the {@code
665 * observed} array exceeds the {@code timeLimit} specified within a usage session. The
666 * structure of a token is a String with the reporting packages' name and a token the
667 * reporting app will use, separated by the forward slash character.
668 * Example: com.reporting.package/5OM3*0P4QU3-7OK3N
669 * After the {@code timeLimit} has been reached, the usage session observer will receive a
670 * callback on the provided {@code sessionEndCallbackIntent} when the usage session ends.
671 * Registering another session observer against a {@code sessionObserverId} that has already
672 * been registered will override the previous session observer.
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700673 *
674 * @param sessionObserverId A unique id associated with the group of apps to be
675 * monitored. There can be multiple groups with common
676 * packages and different time limits.
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800677 * @param observedEntities The list of packages and token to observe for usage time. Cannot be
678 * null and must include at least one package or token.
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700679 * @param timeLimit The total time the set of apps can be used continuously before the {@code
680 * limitReachedCallbackIntent} is delivered. Must be at least one minute.
681 * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
682 * @param sessionThresholdTime The time that can take place between usage sessions before the
683 * next session is considered a new session. Must be non-negative.
684 * @param sessionThresholdTimeUnit The unit for time specified in {@code sessionThreshold}.
685 * Cannot be null.
686 * @param limitReachedCallbackIntent The {@link PendingIntent} that will be dispatched when the
Varun Shah2546cef2019-01-11 15:50:54 -0800687 * usage limit is exceeded by the group of apps. The
688 * delivered Intent will also contain the extras {@link
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700689 * #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and {@link
690 * #EXTRA_TIME_USED}. Cannot be null.
691 * @param sessionEndCallbackIntent The {@link PendingIntent} that will be dispatched when the
Varun Shah2546cef2019-01-11 15:50:54 -0800692 * session has ended after the usage limit has been exceeded.
693 * The session is considered at its end after the {@code
694 * observed} usage has stopped and an additional {@code
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700695 * sessionThresholdTime} has passed. The delivered Intent will
696 * also contain the extras {@link #EXTRA_OBSERVER_ID} and {@link
697 * #EXTRA_TIME_USED}. Can be null.
698 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
699 * is not the profile owner of this user.
700 * @hide
701 */
702 @SystemApi
703 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800704 public void registerUsageSessionObserver(int sessionObserverId,
705 @NonNull String[] observedEntities, long timeLimit, @NonNull TimeUnit timeUnit,
706 long sessionThresholdTime, @NonNull TimeUnit sessionThresholdTimeUnit,
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700707 @NonNull PendingIntent limitReachedCallbackIntent,
708 @Nullable PendingIntent sessionEndCallbackIntent) {
709 try {
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800710 mService.registerUsageSessionObserver(sessionObserverId, observedEntities,
Michael Wachenschwanz641e3382018-10-23 23:21:48 -0700711 timeUnit.toMillis(timeLimit),
712 sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
713 limitReachedCallbackIntent, sessionEndCallbackIntent,
714 mContext.getOpPackageName());
715 } catch (RemoteException e) {
716 throw e.rethrowFromSystemServer();
717 }
718 }
719
720 /**
721 * Unregister the usage session observer specified by the {@code sessionObserverId}. This will
722 * only apply to any app session observer registered by this application. Unregistering an
723 * observer that was already unregistered or never registered will have no effect.
724 *
725 * @param sessionObserverId The id of the observer that was previously registered.
726 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
727 * is not the profile owner of this user.
728 * @hide
729 */
730 @SystemApi
731 @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
732 public void unregisterUsageSessionObserver(int sessionObserverId) {
733 try {
734 mService.unregisterUsageSessionObserver(sessionObserverId, mContext.getOpPackageName());
735 } catch (RemoteException e) {
736 throw e.rethrowFromSystemServer();
737 }
738 }
739
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800740 /**
Varun Shah2546cef2019-01-11 15:50:54 -0800741 * Register a usage limit observer that receives a callback on the provided intent when the
742 * sum of usages of apps and tokens in the provided {@code observedEntities} array exceeds the
743 * {@code timeLimit} specified. The structure of a token is a {@link String} with the reporting
744 * package's name and a token that the calling app will use, separated by the forward slash
745 * character. Example: com.reporting.package/5OM3*0P4QU3-7OK3N
746 * <p>
747 * Registering an {@code observerId} that was already registered will override the previous one.
748 * No more than 1000 unique {@code observerId} may be registered by a single uid
749 * at any one time.
Varun Shah54f7f7f2019-02-07 10:21:17 -0800750 * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via
751 * {@link #unregisterAppUsageLimitObserver}.
752 * <p>
753 * Note: usage limits are not persisted in the system and are cleared on reboots. Callers
754 * must reset any limits that they need on reboots.
Varun Shah2546cef2019-01-11 15:50:54 -0800755 * <p>
756 * This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here
757 * will be visible to the launcher so that it can report the limit to the user and how much
758 * of it is remaining.
759 * @see android.content.pm.LauncherApps#getAppUsageLimit
760 *
761 * @param observerId A unique id associated with the group of apps to be monitored. There can
762 * be multiple groups with common packages and different time limits.
763 * @param observedEntities The list of packages and token to observe for usage time. Cannot be
764 * null and must include at least one package or token.
765 * @param timeLimit The total time the set of apps can be in the foreground before the
Varun Shah54f7f7f2019-02-07 10:21:17 -0800766 * callbackIntent is delivered. Must be at least one minute. Note: a limit of
767 * 0 can be set to indicate that the user has already exhausted the limit for
768 * a group, in which case, the given {@code callbackIntent} will be ignored.
Varun Shah2546cef2019-01-11 15:50:54 -0800769 * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
Varun Shah54f7f7f2019-02-07 10:21:17 -0800770 * @param callbackIntent The PendingIntent that will be dispatched when the usage limit is
Varun Shah2546cef2019-01-11 15:50:54 -0800771 * exceeded by the group of apps. The delivered Intent will also contain
772 * the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
Varun Shah54f7f7f2019-02-07 10:21:17 -0800773 * {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
774 * being registered with a {@code timeLimit} of 0.
Varun Shah2546cef2019-01-11 15:50:54 -0800775 * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
776 * permissions.
777 * @hide
778 */
779 @SystemApi
780 @RequiresPermission(allOf = {
781 android.Manifest.permission.SUSPEND_APPS,
782 android.Manifest.permission.OBSERVE_APP_USAGE})
783 public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
Varun Shah9c169892019-02-15 10:21:27 -0800784 long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) {
Varun Shah2546cef2019-01-11 15:50:54 -0800785 try {
786 mService.registerAppUsageLimitObserver(observerId, observedEntities,
787 timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
788 } catch (RemoteException e) {
789 throw e.rethrowFromSystemServer();
790 }
791 }
792
793 /**
794 * Unregister the app usage limit observer specified by the {@code observerId}.
795 * This will only apply to any observer registered by this application. Unregistering
796 * an observer that was already unregistered or never registered will have no effect.
797 *
798 * @param observerId The id of the observer that was previously registered.
799 * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
800 * permissions.
801 * @hide
802 */
803 @SystemApi
804 @RequiresPermission(allOf = {
805 android.Manifest.permission.SUSPEND_APPS,
806 android.Manifest.permission.OBSERVE_APP_USAGE})
807 public void unregisterAppUsageLimitObserver(int observerId) {
808 try {
809 mService.unregisterAppUsageLimitObserver(observerId, mContext.getOpPackageName());
810 } catch (RemoteException e) {
811 throw e.rethrowFromSystemServer();
812 }
813 }
814
815 /**
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800816 * Report usage associated with a particular {@code token} has started. Tokens are app defined
817 * strings used to represent usage of in-app features. Apps with the {@link
818 * android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time limit observers
819 * to monitor the usage of a token. In app usage can only associated with an {@code activity}
820 * and usage will be considered stopped if the activity stops or crashes.
821 * @see #registerAppUsageObserver
822 * @see #registerUsageSessionObserver
Varun Shah2546cef2019-01-11 15:50:54 -0800823 * @see #registerAppUsageLimitObserver
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800824 *
825 * @param activity The activity {@code token} is associated with.
826 * @param token The token to report usage against.
827 * @hide
828 */
829 @SystemApi
830 public void reportUsageStart(@NonNull Activity activity, @NonNull String token) {
831 try {
832 mService.reportUsageStart(activity.getActivityToken(), token,
833 mContext.getOpPackageName());
834 } catch (RemoteException e) {
835 throw e.rethrowFromSystemServer();
836 }
837 }
838
839 /**
840 * Report usage associated with a particular {@code token} had started some amount of time in
841 * the past. Tokens are app defined strings used to represent usage of in-app features. Apps
842 * with the {@link android.Manifest.permission#OBSERVE_APP_USAGE} permission can register time
843 * limit observers to monitor the usage of a token. In app usage can only associated with an
844 * {@code activity} and usage will be considered stopped if the activity stops or crashes.
845 * @see #registerAppUsageObserver
846 * @see #registerUsageSessionObserver
Varun Shah2546cef2019-01-11 15:50:54 -0800847 * @see #registerAppUsageLimitObserver
Michael Wachenschwanz36778522018-11-12 11:06:19 -0800848 *
849 * @param activity The activity {@code token} is associated with.
850 * @param token The token to report usage against.
851 * @param timeAgoMs How long ago the start of usage took place
852 * @hide
853 */
854 @SystemApi
855 public void reportUsageStart(@NonNull Activity activity, @NonNull String token,
856 long timeAgoMs) {
857 try {
858 mService.reportPastUsageStart(activity.getActivityToken(), token, timeAgoMs,
859 mContext.getOpPackageName());
860 } catch (RemoteException e) {
861 throw e.rethrowFromSystemServer();
862 }
863 }
864
865 /**
866 * Report the usage associated with a particular {@code token} has stopped.
867 *
868 * @param activity The activity {@code token} is associated with.
869 * @param token The token to report usage against.
870 * @hide
871 */
872 @SystemApi
873 public void reportUsageStop(@NonNull Activity activity, @NonNull String token) {
874 try {
875 mService.reportUsageStop(activity.getActivityToken(), token,
876 mContext.getOpPackageName());
877 } catch (RemoteException e) {
878 throw e.rethrowFromSystemServer();
879 }
880 }
881
Michael Wachenschwanz0b4ab1f2019-01-07 13:59:10 -0800882 /**
883 * Get what App Usage Observers will consider the source of usage for an activity. Usage Source
884 * is decided at boot and will not change until next boot.
885 * @see #USAGE_SOURCE_TASK_ROOT_ACTIVITY
886 * @see #USAGE_SOURCE_CURRENT_ACTIVITY
887 *
888 * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
889 * is not the profile owner of this user.
890 * @hide
891 */
892 @SystemApi
893 public @UsageSource int getUsageSource() {
894 try {
895 return mService.getUsageSource();
896 } catch (RemoteException e) {
897 throw e.rethrowFromSystemServer();
898 }
899 }
900
901 /**
902 * Force the Usage Source be reread from global settings.
903 * @hide
904 */
905 @TestApi
906 public void forceUsageSourceSettingRead() {
907 try {
908 mService.forceUsageSourceSettingRead();
909 } catch (RemoteException e) {
910 throw e.rethrowFromSystemServer();
911 }
912 }
913
Amith Yamasani119be9a2018-02-18 22:23:00 -0800914 /** @hide */
915 public static String reasonToString(int standbyReason) {
916 StringBuilder sb = new StringBuilder();
917 switch (standbyReason & REASON_MAIN_MASK) {
918 case REASON_MAIN_DEFAULT:
919 sb.append("d");
920 break;
921 case REASON_MAIN_FORCED:
922 sb.append("f");
923 break;
924 case REASON_MAIN_PREDICTED:
925 sb.append("p");
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700926 switch (standbyReason & REASON_SUB_MASK) {
927 case REASON_SUB_PREDICTED_RESTORED:
928 sb.append("-r");
929 break;
930 }
Amith Yamasani119be9a2018-02-18 22:23:00 -0800931 break;
932 case REASON_MAIN_TIMEOUT:
933 sb.append("t");
934 break;
935 case REASON_MAIN_USAGE:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700936 sb.append("u");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800937 switch (standbyReason & REASON_SUB_MASK) {
938 case REASON_SUB_USAGE_SYSTEM_INTERACTION:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700939 sb.append("-si");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800940 break;
941 case REASON_SUB_USAGE_NOTIFICATION_SEEN:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700942 sb.append("-ns");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800943 break;
944 case REASON_SUB_USAGE_USER_INTERACTION:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700945 sb.append("-ui");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800946 break;
947 case REASON_SUB_USAGE_MOVE_TO_FOREGROUND:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700948 sb.append("-mf");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800949 break;
950 case REASON_SUB_USAGE_MOVE_TO_BACKGROUND:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700951 sb.append("-mb");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800952 break;
953 case REASON_SUB_USAGE_SYSTEM_UPDATE:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700954 sb.append("-su");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800955 break;
956 case REASON_SUB_USAGE_ACTIVE_TIMEOUT:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700957 sb.append("-at");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800958 break;
959 case REASON_SUB_USAGE_SYNC_ADAPTER:
Amith Yamasani3154dcf2018-03-27 18:24:04 -0700960 sb.append("-sa");
Amith Yamasani119be9a2018-02-18 22:23:00 -0800961 break;
Amith Yamasani80c4be82018-03-26 10:54:04 -0700962 case REASON_SUB_USAGE_SLICE_PINNED:
Makoto Onukid5f25d22018-05-22 16:02:17 -0700963 sb.append("-lp");
Amith Yamasani80c4be82018-03-26 10:54:04 -0700964 break;
965 case REASON_SUB_USAGE_SLICE_PINNED_PRIV:
Makoto Onukid5f25d22018-05-22 16:02:17 -0700966 sb.append("-lv");
967 break;
968 case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE:
969 sb.append("-en");
970 break;
971 case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE:
972 sb.append("-ed");
Amith Yamasani80c4be82018-03-26 10:54:04 -0700973 break;
Makoto Onuki75ad2492018-03-28 14:42:42 -0700974 case REASON_SUB_USAGE_EXEMPTED_SYNC_START:
Makoto Onukid5f25d22018-05-22 16:02:17 -0700975 sb.append("-es");
Makoto Onuki75ad2492018-03-28 14:42:42 -0700976 break;
Michael Wachenschwanzc3295202019-02-20 17:19:52 -0800977 case REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED:
978 sb.append("-uss");
979 break;
Amith Yamasani119be9a2018-02-18 22:23:00 -0800980 }
981 break;
982 }
983 return sb.toString();
984 }
985
Michael Wachenschwanz0b4ab1f2019-01-07 13:59:10 -0800986 /** @hide */
987 public static String usageSourceToString(int usageSource) {
988 switch (usageSource) {
989 case USAGE_SOURCE_TASK_ROOT_ACTIVITY:
990 return "TASK_ROOT_ACTIVITY";
991 case USAGE_SOURCE_CURRENT_ACTIVITY:
992 return "CURRENT_ACTIVITY";
993 default:
994 StringBuilder sb = new StringBuilder();
995 sb.append("UNKNOWN(");
996 sb.append(usageSource);
997 sb.append(")");
998 return sb.toString();
999 }
1000 }
1001
Amith Yamasanie8789312017-12-10 14:34:26 -08001002 /**
1003 * {@hide}
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001004 * Temporarily whitelist the specified app for a short duration. This is to allow an app
1005 * receiving a high priority message to be able to access the network and acquire wakelocks
1006 * even if the device is in power-save mode or the app is currently considered inactive.
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001007 * @param packageName The package name of the app to whitelist.
1008 * @param duration Duration to whitelist the app for, in milliseconds. It is recommended that
1009 * this be limited to 10s of seconds. Requested duration will be clamped to a few minutes.
1010 * @param user The user for whom the package should be whitelisted. Passing in a user that is
1011 * not the same as the caller's process will require the INTERACT_ACROSS_USERS permission.
1012 * @see #isAppInactive(String)
1013 */
1014 @SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001015 @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001016 public void whitelistAppTemporarily(String packageName, long duration, UserHandle user) {
1017 try {
1018 mService.whitelistAppTemporarily(packageName, duration, user.getIdentifier());
1019 } catch (RemoteException re) {
Amith Yamasanifd44f272018-05-14 14:47:19 -07001020 throw re.rethrowFromSystemServer();
Amith Yamasaniaf575b92015-05-29 15:35:26 -07001021 }
1022 }
Amith Yamasani4ec63682016-02-19 12:55:27 -08001023
1024 /**
1025 * Inform usage stats that the carrier privileged apps access rules have changed.
1026 * @hide
1027 */
1028 public void onCarrierPrivilegedAppsChanged() {
1029 try {
1030 mService.onCarrierPrivilegedAppsChanged();
1031 } catch (RemoteException re) {
Amith Yamasanifd44f272018-05-14 14:47:19 -07001032 throw re.rethrowFromSystemServer();
Amith Yamasani4ec63682016-02-19 12:55:27 -08001033 }
1034 }
Kang Li53b43142016-11-14 14:38:25 -08001035
1036 /**
1037 * Reports a Chooser action to the UsageStatsManager.
1038 *
1039 * @param packageName The package name of the app that is selected.
1040 * @param userId The user id of who makes the selection.
1041 * @param contentType The type of the content, e.g., Image, Video, App.
1042 * @param annotations The annotations of the content, e.g., Game, Selfie.
1043 * @param action The action type of Intent that invokes ChooserActivity.
1044 * {@link UsageEvents}
1045 * @hide
1046 */
1047 public void reportChooserSelection(String packageName, int userId, String contentType,
1048 String[] annotations, String action) {
1049 try {
1050 mService.reportChooserSelection(packageName, userId, contentType, annotations, action);
1051 } catch (RemoteException re) {
1052 }
1053 }
Adam Lesinski0debc9a2014-07-16 19:09:13 -07001054}