• 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 package android.app.usage;
17 
18 import android.annotation.IntDef;
19 import android.annotation.Nullable;
20 import android.annotation.SystemApi;
21 import android.compat.annotation.UnsupportedAppUsage;
22 import android.content.res.Configuration;
23 import android.os.Build;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.Arrays;
30 import java.util.List;
31 
32 /**
33  * A result returned from {@link android.app.usage.UsageStatsManager#queryEvents(long, long)}
34  * from which to read {@link android.app.usage.UsageEvents.Event} objects.
35  */
36 public final class UsageEvents implements Parcelable {
37 
38     /** @hide */
39     public static final String INSTANT_APP_PACKAGE_NAME = "android.instant_app";
40 
41     /** @hide */
42     public static final String INSTANT_APP_CLASS_NAME = "android.instant_class";
43 
44     /** @hide */
45     public static final String OBFUSCATED_NOTIFICATION_CHANNEL_ID = "unknown_channel_id";
46 
47     /**
48      * Flag: indicates to not obfuscate or hide any usage event data when being queried.
49      * @hide
50      */
51     public static final int SHOW_ALL_EVENT_DATA = 0x00000000;
52 
53     /**
54      * Flag: indicates to obfuscate package and class names for instant apps when querying usage
55      * events.
56      * @hide
57      */
58     public static final int OBFUSCATE_INSTANT_APPS = 0x00000001;
59 
60     /**
61      * Flag: indicates to hide all {@link Event#SHORTCUT_INVOCATION} events when querying usage
62      * events.
63      * @hide
64      */
65     public static final int HIDE_SHORTCUT_EVENTS = 0x00000002;
66 
67     /**
68      * Flag: indicates to obfuscate the notification channel id for all notification events,
69      * such as {@link Event#NOTIFICATION_SEEN} and {@link Event#NOTIFICATION_INTERRUPTION} events,
70      * when querying usage events.
71      * @hide
72      */
73     public static final int OBFUSCATE_NOTIFICATION_EVENTS = 0x00000004;
74 
75     /**
76      * Flag: indicates to hide all {@link Event#LOCUS_ID_SET} events when querying usage events.
77      * @hide
78      */
79     public static final int HIDE_LOCUS_EVENTS = 0x00000008;
80 
81     /**
82      * An event representing a state change for a component.
83      */
84     public static final class Event {
85 
86         /**
87          * No event type.
88          */
89         public static final int NONE = 0;
90 
91         /**
92          * A device level event like {@link #DEVICE_SHUTDOWN} does not have package name, but some
93          * user code always expect a non-null {@link #mPackage} for every event. Use
94          * {@link #DEVICE_EVENT_PACKAGE_NAME} as packageName for these device level events.
95          * @hide
96          */
97         public static final String DEVICE_EVENT_PACKAGE_NAME = "android";
98 
99         /**
100          * @deprecated by {@link #ACTIVITY_RESUMED}
101          */
102         @Deprecated
103         public static final int MOVE_TO_FOREGROUND = 1;
104 
105         /**
106          * An event type denoting that an {@link android.app.Activity} moved to the foreground.
107          * This event has a package name and class name associated with it and can be retrieved
108          * using {@link #getPackageName()} and {@link #getClassName()}.
109          * If a package has multiple activities, this event is reported for each activity that moves
110          * to foreground.
111          * This event is corresponding to {@link android.app.Activity#onResume()} of the
112          * activity's lifecycle.
113          */
114         public static final int ACTIVITY_RESUMED = MOVE_TO_FOREGROUND;
115 
116         /**
117          * @deprecated by {@link #ACTIVITY_PAUSED}
118          */
119         @Deprecated
120         public static final int MOVE_TO_BACKGROUND = 2;
121 
122         /**
123          * An event type denoting that an {@link android.app.Activity} moved to the background.
124          * This event has a package name and class name associated with it and can be retrieved
125          * using {@link #getPackageName()} and {@link #getClassName()}.
126          * If a package has multiple activities, this event is reported for each activity that moves
127          * to background.
128          * This event is corresponding to {@link android.app.Activity#onPause()} of the activity's
129          * lifecycle.
130          */
131         public static final int ACTIVITY_PAUSED = MOVE_TO_BACKGROUND;
132 
133         /**
134          * An event type denoting that a component was in the foreground when the stats
135          * rolled-over. This is effectively treated as a {@link #ACTIVITY_PAUSED}.
136          * This event has a non-null packageName, and a null className.
137          * {@hide}
138          */
139         public static final int END_OF_DAY = 3;
140 
141         /**
142          * An event type denoting that a component was in the foreground the previous day.
143          * This is effectively treated as a {@link #ACTIVITY_RESUMED}.
144          * {@hide}
145          */
146         public static final int CONTINUE_PREVIOUS_DAY = 4;
147 
148         /**
149          * An event type denoting that the device configuration has changed.
150          */
151         public static final int CONFIGURATION_CHANGE = 5;
152 
153         /**
154          * An event type denoting that a package was interacted with in some way by the system.
155          * @hide
156          */
157         @SystemApi
158         public static final int SYSTEM_INTERACTION = 6;
159 
160         /**
161          * An event type denoting that a package was interacted with in some way by the user.
162          */
163         public static final int USER_INTERACTION = 7;
164 
165         /**
166          * An event type denoting that an action equivalent to a ShortcutInfo is taken by the user.
167          *
168          * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
169          */
170         public static final int SHORTCUT_INVOCATION = 8;
171 
172         /**
173          * An event type denoting that a package was selected by the user for ChooserActivity.
174          * @hide
175          */
176         public static final int CHOOSER_ACTION = 9;
177 
178         /**
179          * An event type denoting that a notification was viewed by the user.
180          * @hide
181          */
182         @SystemApi
183         public static final int NOTIFICATION_SEEN = 10;
184 
185         /**
186          * An event type denoting a change in App Standby Bucket. The new bucket can be
187          * retrieved by calling {@link #getAppStandbyBucket()}.
188          *
189          * @see UsageStatsManager#getAppStandbyBucket()
190          */
191         public static final int STANDBY_BUCKET_CHANGED = 11;
192 
193         /**
194          * An event type denoting that an app posted an interruptive notification. Visual and
195          * audible interruptions are included.
196          * @hide
197          */
198         @SystemApi
199         public static final int NOTIFICATION_INTERRUPTION = 12;
200 
201         /**
202          * A Slice was pinned by the default launcher or the default assistant.
203          * @hide
204          */
205         @SystemApi
206         public static final int SLICE_PINNED_PRIV = 13;
207 
208         /**
209          * A Slice was pinned by an app.
210          * @hide
211          */
212         @SystemApi
213         public static final int SLICE_PINNED = 14;
214 
215         /**
216          * An event type denoting that the screen has gone in to an interactive state (turned
217          * on for full user interaction, not ambient display or other non-interactive state).
218          */
219         public static final int SCREEN_INTERACTIVE = 15;
220 
221         /**
222          * An event type denoting that the screen has gone in to a non-interactive state
223          * (completely turned off or turned on only in a non-interactive state like ambient
224          * display).
225          */
226         public static final int SCREEN_NON_INTERACTIVE = 16;
227 
228         /**
229          * An event type denoting that the screen's keyguard has been shown, whether or not
230          * the screen is off.
231          */
232         public static final int KEYGUARD_SHOWN = 17;
233 
234         /**
235          * An event type denoting that the screen's keyguard has been hidden.  This typically
236          * happens when the user unlocks their phone after turning it on.
237          */
238         public static final int KEYGUARD_HIDDEN = 18;
239 
240         /**
241          * An event type denoting start of a foreground service.
242          * This event has a package name and class name associated with it and can be retrieved
243          * using {@link #getPackageName()} and {@link #getClassName()}.
244          * If a package has multiple foreground services, this event is reported for each service
245          * that is started.
246          */
247         public static final int FOREGROUND_SERVICE_START = 19;
248 
249         /**
250          * An event type denoting stop of a foreground service.
251          * This event has a package name and class name associated with it and can be retrieved
252          * using {@link #getPackageName()} and {@link #getClassName()}.
253          * If a package has multiple foreground services, this event is reported for each service
254          * that is stopped.
255          */
256         public static final int FOREGROUND_SERVICE_STOP = 20;
257 
258         /**
259          * An event type denoting that a foreground service is at started state at beginning of a
260          * time interval.
261          * This is effectively treated as a {@link #FOREGROUND_SERVICE_START}.
262          * {@hide}
263          */
264         public static final int CONTINUING_FOREGROUND_SERVICE = 21;
265 
266         /**
267          * An event type denoting that a foreground service is at started state when the stats
268          * rolled-over at the end of a time interval.
269          * {@hide}
270          */
271         public static final int ROLLOVER_FOREGROUND_SERVICE = 22;
272 
273         /**
274          * An activity becomes invisible on the UI, corresponding to
275          * {@link android.app.Activity#onStop()} of the activity's lifecycle.
276          */
277         public static final int ACTIVITY_STOPPED = 23;
278 
279         /**
280          * An activity object is destroyed, corresponding to
281          * {@link android.app.Activity#onDestroy()} of the activity's lifecycle.
282          * {@hide}
283          */
284         public static final int ACTIVITY_DESTROYED = 24;
285 
286         /**
287          * The event type demoting that a flush of UsageStatsDatabase to file system. Before the
288          * flush all usage stats need to be updated to latest timestamp to make sure the most
289          * up to date stats are persisted.
290          * @hide
291          */
292         public static final int FLUSH_TO_DISK = 25;
293 
294         /**
295          * An event type denoting that the Android runtime underwent a shutdown process.
296          * A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
297          * services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
298          * {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
299          *
300          * <p>The DEVICE_SHUTDOWN timestamp is actually the last time UsageStats database is
301          * persisted before the actual shutdown. Events (if there are any) between this timestamp
302          * and the actual shutdown is not persisted in the database. So any open events without
303          * matching close events between DEVICE_SHUTDOWN and {@link #DEVICE_STARTUP} should be
304          * ignored because the closing time is unknown.</p>
305          */
306         public static final int DEVICE_SHUTDOWN = 26;
307 
308         /**
309          * An event type denoting that the Android runtime started up. This could be after a
310          * shutdown or a runtime restart. Any open events without matching close events between
311          * {@link #DEVICE_SHUTDOWN} and DEVICE_STARTUP should be ignored because the closing time is
312          * unknown.
313          */
314         public static final int DEVICE_STARTUP = 27;
315 
316         /**
317          * An event type denoting that a user has been unlocked for the first time. This event
318          * mainly indicates when the user's credential encrypted storage was first accessible.
319          * @hide
320          */
321         public static final int USER_UNLOCKED = 28;
322 
323         /**
324          * An event type denoting that a user has been stopped. This typically happens when the
325          * system is being turned off or when users are being switched.
326          * @hide
327          */
328         public static final int USER_STOPPED = 29;
329 
330         /**
331          * An event type denoting that new locusId has been set for a given activity.
332          * @hide
333          */
334         public static final int LOCUS_ID_SET = 30;
335 
336         /**
337          * An event type denoting that a component in the package has been used (e.g. broadcast
338          * receiver, service, content provider). This generally matches up with usage that would
339          * cause an app to leave force stop. The component itself is not provided as we are only
340          * interested in whether the package is used, not the component itself.
341          * @hide
342          */
343         public static final int APP_COMPONENT_USED = 31;
344 
345         /**
346          * Keep in sync with the greatest event type value.
347          * @hide
348          */
349         public static final int MAX_EVENT_TYPE = 31;
350 
351         /** @hide */
352         public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
353 
354         /** @hide */
355         @IntDef(flag = true, prefix = { "FLAG_" }, value = {
356                 FLAG_IS_PACKAGE_INSTANT_APP,
357         })
358         @Retention(RetentionPolicy.SOURCE)
359         public @interface EventFlags {}
360 
361         /**
362          * Bitwise OR all valid flag constants to create this constant.
363          * @hide
364          */
365         public static final int VALID_FLAG_BITS = FLAG_IS_PACKAGE_INSTANT_APP;
366 
367         /**
368          * @hide
369          */
370         private static final int UNASSIGNED_TOKEN = -1;
371 
372         /**
373          * {@hide}
374          */
375         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
376         public String mPackage;
377 
378         /**
379          * {@hide}
380          */
381         public int mPackageToken = UNASSIGNED_TOKEN;
382 
383         /**
384          * {@hide}
385          */
386         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
387         public String mClass;
388 
389         /**
390          * {@hide}
391          */
392         public int mClassToken = UNASSIGNED_TOKEN;
393 
394         /**
395          * Uniquely identifies an activity. It's possible for two activities with the same
396          * pkg/class name to be in lifecycle at the same time. The mInstanceId is guaranteed to be
397          * unique per activity across all apps (not just within a single app).
398          *
399          * {@hide}
400          */
401         public int mInstanceId;
402 
403         /**
404          * {@hide}
405          */
406         public String mTaskRootPackage;
407 
408         /**
409          * {@hide}
410          */
411         public int mTaskRootPackageToken = UNASSIGNED_TOKEN;
412 
413         /**
414          * {@hide}
415          */
416         public String mTaskRootClass;
417 
418         /**
419          * {@hide}
420          */
421         public int mTaskRootClassToken = UNASSIGNED_TOKEN;
422 
423         /**
424          * {@hide}
425          */
426         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
427         public long mTimeStamp;
428 
429         /**
430          * {@hide}
431          */
432         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
433         public int mEventType;
434 
435         /**
436          * Only present for {@link #CONFIGURATION_CHANGE} event types.
437          * {@hide}
438          */
439         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
440         public Configuration mConfiguration;
441 
442         /**
443          * ID of the shortcut.
444          * Only present for {@link #SHORTCUT_INVOCATION} event types.
445          * {@hide}
446          */
447         public String mShortcutId;
448 
449         /**
450          * {@hide}
451          */
452         public int mShortcutIdToken = UNASSIGNED_TOKEN;
453 
454         /**
455          * Action type passed to ChooserActivity
456          * Only present for {@link #CHOOSER_ACTION} event types.
457          * {@hide}
458          */
459         public String mAction;
460 
461         /**
462          * Content type passed to ChooserActivity.
463          * Only present for {@link #CHOOSER_ACTION} event types.
464          * {@hide}
465          */
466         public String mContentType;
467 
468         /**
469          * Content annotations passed to ChooserActivity.
470          * Only present for {@link #CHOOSER_ACTION} event types.
471          * {@hide}
472          */
473         public String[] mContentAnnotations;
474 
475         /**
476          * The app standby bucket assigned and reason. Bucket is the high order 16 bits, reason
477          * is the low order 16 bits.
478          * Only present for {@link #STANDBY_BUCKET_CHANGED} event types
479          * {@hide}
480          */
481         public int mBucketAndReason;
482 
483         /**
484          * The id of the {@link android.app.NotificationChannel} to which an interruptive
485          * notification was posted.
486          * Only present for {@link #NOTIFICATION_INTERRUPTION} event types.
487          * {@hide}
488          */
489         public String mNotificationChannelId;
490 
491         /**
492          * {@hide}
493          */
494         public int mNotificationChannelIdToken = UNASSIGNED_TOKEN;
495 
496         /**
497          * LocusId.
498          * Currently LocusId only present for {@link #LOCUS_ID_SET} event types.
499          * {@hide}
500          */
501         public String mLocusId;
502 
503         /**
504          * {@hide}
505          */
506         public int mLocusIdToken = UNASSIGNED_TOKEN;
507 
508         /** @hide */
509         @EventFlags
510         public int mFlags;
511 
Event()512         public Event() {
513         }
514 
515         /** @hide */
Event(int type, long timeStamp)516         public Event(int type,  long timeStamp) {
517             mEventType = type;
518             mTimeStamp = timeStamp;
519         }
520 
521         /** @hide */
Event(Event orig)522         public Event(Event orig) {
523             copyFrom(orig);
524         }
525 
526         /**
527          * The package name of the source of this event.
528          */
getPackageName()529         public String getPackageName() {
530             return mPackage;
531         }
532 
533         /**
534          * Indicates whether it is an instant app.
535          * @hide
536          */
537         @SystemApi
isInstantApp()538         public boolean isInstantApp() {
539             return (mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == FLAG_IS_PACKAGE_INSTANT_APP;
540         }
541 
542         /**
543          * The class name of the source of this event. This may be null for
544          * certain events.
545          */
getClassName()546         public String getClassName() {
547             return mClass;
548         }
549 
550         /**
551          *  An activity can be instantiated multiple times, this is the unique activity instance ID.
552          *  For non-activity class, instance ID is always zero.
553          *  @hide
554          */
555         @SystemApi
getInstanceId()556         public int getInstanceId() {
557             return mInstanceId;
558         }
559 
560         /**
561          * The package name of the task root when this event was reported.
562          * Or {@code null} for queries from apps without {@link
563          * android.Manifest.permission#PACKAGE_USAGE_STATS}
564          * @hide
565          */
566         @SystemApi
getTaskRootPackageName()567         public @Nullable String getTaskRootPackageName() {
568             return mTaskRootPackage;
569         }
570 
571         /**
572          * The class name of the task root when this event was reported.
573          * Or {@code null} for queries from apps without {@link
574          * android.Manifest.permission#PACKAGE_USAGE_STATS}
575          * @hide
576          */
577         @SystemApi
getTaskRootClassName()578         public @Nullable String getTaskRootClassName() {
579             return mTaskRootClass;
580         }
581 
582         /**
583          * The time at which this event occurred, measured in milliseconds since the epoch.
584          * <p/>
585          * See {@link System#currentTimeMillis()}.
586          */
getTimeStamp()587         public long getTimeStamp() {
588             return mTimeStamp;
589         }
590 
591         /**
592          * The event type.
593          * @see #ACTIVITY_PAUSED
594          * @see #ACTIVITY_RESUMED
595          * @see #CONFIGURATION_CHANGE
596          * @see #USER_INTERACTION
597          * @see #STANDBY_BUCKET_CHANGED
598          * @see #FOREGROUND_SERVICE_START
599          * @see #FOREGROUND_SERVICE_STOP
600          * @see #ACTIVITY_STOPPED
601          */
getEventType()602         public int getEventType() {
603             return mEventType;
604         }
605 
606         /**
607          * Returns a {@link Configuration} for this event if the event is of type
608          * {@link #CONFIGURATION_CHANGE}, otherwise it returns null.
609          */
getConfiguration()610         public Configuration getConfiguration() {
611             return mConfiguration;
612         }
613 
614         /**
615          * Returns the ID of a {@link android.content.pm.ShortcutInfo} for this event
616          * if the event is of type {@link #SHORTCUT_INVOCATION}, otherwise it returns null.
617          *
618          * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
619          */
getShortcutId()620         public String getShortcutId() {
621             return mShortcutId;
622         }
623 
624         /**
625          * Returns the standby bucket of the app, if the event is of type
626          * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
627          * @return the standby bucket associated with the event.
628          * @hide
629          */
getStandbyBucket()630         public int getStandbyBucket() {
631             return (mBucketAndReason & 0xFFFF0000) >>> 16;
632         }
633 
634         /**
635          * Returns the standby bucket of the app, if the event is of type
636          * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
637          * @return the standby bucket associated with the event.
638          *
639          */
getAppStandbyBucket()640         public int getAppStandbyBucket() {
641             return (mBucketAndReason & 0xFFFF0000) >>> 16;
642         }
643 
644         /**
645          * Returns the reason for the bucketing, if the event is of type
646          * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0. Reason values include
647          * the main reason which is one of REASON_MAIN_*, OR'ed with REASON_SUB_*, if there
648          * are sub-reasons for the main reason, such as REASON_SUB_USAGE_* when the main reason
649          * is REASON_MAIN_USAGE.
650          * @hide
651          */
getStandbyReason()652         public int getStandbyReason() {
653             return mBucketAndReason & 0x0000FFFF;
654         }
655 
656         /**
657          * Returns the ID of the {@link android.app.NotificationChannel} for this event if the
658          * event is of type {@link #NOTIFICATION_INTERRUPTION}, otherwise it returns null;
659          * @hide
660          */
661         @Nullable
662         @SystemApi
getNotificationChannelId()663         public String getNotificationChannelId() {
664             return mNotificationChannelId;
665         }
666 
667         /** @hide */
getObfuscatedIfInstantApp()668         public Event getObfuscatedIfInstantApp() {
669             if (!isInstantApp()) {
670                 return this;
671             }
672             final Event ret = new Event(this);
673             ret.mPackage = INSTANT_APP_PACKAGE_NAME;
674             ret.mClass = INSTANT_APP_CLASS_NAME;
675 
676             // Note there are other string fields too, but they're for app shortcuts and choosers,
677             // which instant apps can't use anyway, so there's no need to hide them.
678             return ret;
679         }
680 
681         /** @hide */
getObfuscatedNotificationEvent()682         public Event getObfuscatedNotificationEvent() {
683             final Event ret = new Event(this);
684             ret.mNotificationChannelId = OBFUSCATED_NOTIFICATION_CHANNEL_ID;
685             return ret;
686         }
687 
688         /**
689          * Returns the locusId for this event if the event is of type {@link #LOCUS_ID_SET},
690          * otherwise it returns null.
691          * @hide
692          */
693         @Nullable
getLocusId()694         public String getLocusId() {
695             return mLocusId;
696         }
697 
copyFrom(Event orig)698         private void copyFrom(Event orig) {
699             mPackage = orig.mPackage;
700             mClass = orig.mClass;
701             mInstanceId = orig.mInstanceId;
702             mTaskRootPackage = orig.mTaskRootPackage;
703             mTaskRootClass = orig.mTaskRootClass;
704             mTimeStamp = orig.mTimeStamp;
705             mEventType = orig.mEventType;
706             mConfiguration = orig.mConfiguration;
707             mShortcutId = orig.mShortcutId;
708             mAction = orig.mAction;
709             mContentType = orig.mContentType;
710             mContentAnnotations = orig.mContentAnnotations;
711             mFlags = orig.mFlags;
712             mBucketAndReason = orig.mBucketAndReason;
713             mNotificationChannelId = orig.mNotificationChannelId;
714             mLocusId = orig.mLocusId;
715         }
716     }
717 
718     // Only used when creating the resulting events. Not used for reading/unparceling.
719     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
720     private List<Event> mEventsToWrite = null;
721 
722     // Only used for reading/unparceling events.
723     @UnsupportedAppUsage
724     private Parcel mParcel = null;
725     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
726     private final int mEventCount;
727 
728     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
729     private int mIndex = 0;
730 
731     // Only used when parceling events. If false, task roots will be omitted from the parcel
732     private final boolean mIncludeTaskRoots;
733 
734     /*
735      * In order to save space, since ComponentNames will be duplicated everywhere,
736      * we use a map and index into it.
737      */
738     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
739     private String[] mStringPool;
740 
741     /**
742      * Construct the iterator from a parcel.
743      * {@hide}
744      */
745     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
UsageEvents(Parcel in)746     public UsageEvents(Parcel in) {
747         byte[] bytes = in.readBlob();
748         Parcel data = Parcel.obtain();
749         data.unmarshall(bytes, 0, bytes.length);
750         data.setDataPosition(0);
751         mEventCount = data.readInt();
752         mIndex = data.readInt();
753         if (mEventCount > 0) {
754             mStringPool = data.createStringArray();
755 
756             final int listByteLength = data.readInt();
757             final int positionInParcel = data.readInt();
758             mParcel = Parcel.obtain();
759             mParcel.setDataPosition(0);
760             mParcel.appendFrom(data, data.dataPosition(), listByteLength);
761             mParcel.setDataSize(mParcel.dataPosition());
762             mParcel.setDataPosition(positionInParcel);
763         }
764         mIncludeTaskRoots = true;
765     }
766 
767     /**
768      * Create an empty iterator.
769      * {@hide}
770      */
UsageEvents()771     UsageEvents() {
772         mEventCount = 0;
773         mIncludeTaskRoots = true;
774     }
775 
776     /**
777      * Construct the iterator in preparation for writing it to a parcel.
778      * Defaults to excluding task roots from the parcel.
779      * {@hide}
780      */
UsageEvents(List<Event> events, String[] stringPool)781     public UsageEvents(List<Event> events, String[] stringPool) {
782         this(events, stringPool, false);
783     }
784 
785     /**
786      * Construct the iterator in preparation for writing it to a parcel.
787      * {@hide}
788      */
UsageEvents(List<Event> events, String[] stringPool, boolean includeTaskRoots)789     public UsageEvents(List<Event> events, String[] stringPool, boolean includeTaskRoots) {
790         mStringPool = stringPool;
791         mEventCount = events.size();
792         mEventsToWrite = events;
793         mIncludeTaskRoots = includeTaskRoots;
794     }
795 
796     /**
797      * Returns whether or not there are more events to read using
798      * {@link #getNextEvent(android.app.usage.UsageEvents.Event)}.
799      *
800      * @return true if there are more events, false otherwise.
801      */
hasNextEvent()802     public boolean hasNextEvent() {
803         return mIndex < mEventCount;
804     }
805 
806     /**
807      * Retrieve the next {@link android.app.usage.UsageEvents.Event} from the collection and put the
808      * resulting data into {@code eventOut}.
809      *
810      * @param eventOut The {@link android.app.usage.UsageEvents.Event} object that will receive the
811      *                 next event data.
812      * @return true if an event was available, false if there are no more events.
813      */
getNextEvent(Event eventOut)814     public boolean getNextEvent(Event eventOut) {
815         if (mIndex >= mEventCount) {
816             return false;
817         }
818 
819         if (mParcel != null) {
820             readEventFromParcel(mParcel, eventOut);
821         } else {
822             eventOut.copyFrom(mEventsToWrite.get(mIndex));
823         }
824 
825         mIndex++;
826         if (mIndex >= mEventCount && mParcel != null) {
827             mParcel.recycle();
828             mParcel = null;
829         }
830         return true;
831     }
832 
833     /**
834      * Resets the collection so that it can be iterated over from the beginning.
835      *
836      * @hide When this object is iterated to completion, the parcel is destroyed and
837      * so resetToStart doesn't work.
838      */
resetToStart()839     public void resetToStart() {
840         mIndex = 0;
841         if (mParcel != null) {
842             mParcel.setDataPosition(0);
843         }
844     }
845 
846     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
findStringIndex(String str)847     private int findStringIndex(String str) {
848         final int index = Arrays.binarySearch(mStringPool, str);
849         if (index < 0) {
850             throw new IllegalStateException("String '" + str + "' is not in the string pool");
851         }
852         return index;
853     }
854 
855     /**
856      * Writes a single event to the parcel. Modify this when updating {@link Event}.
857      */
858     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
writeEventToParcel(Event event, Parcel p, int flags)859     private void writeEventToParcel(Event event, Parcel p, int flags) {
860         final int packageIndex;
861         if (event.mPackage != null) {
862             packageIndex = findStringIndex(event.mPackage);
863         } else {
864             packageIndex = -1;
865         }
866 
867         final int classIndex;
868         if (event.mClass != null) {
869             classIndex = findStringIndex(event.mClass);
870         } else {
871             classIndex = -1;
872         }
873 
874         final int taskRootPackageIndex;
875         if (mIncludeTaskRoots && event.mTaskRootPackage != null) {
876             taskRootPackageIndex = findStringIndex(event.mTaskRootPackage);
877         } else {
878             taskRootPackageIndex = -1;
879         }
880 
881         final int taskRootClassIndex;
882         if (mIncludeTaskRoots && event.mTaskRootClass != null) {
883             taskRootClassIndex = findStringIndex(event.mTaskRootClass);
884         } else {
885             taskRootClassIndex = -1;
886         }
887         p.writeInt(packageIndex);
888         p.writeInt(classIndex);
889         p.writeInt(event.mInstanceId);
890         p.writeInt(taskRootPackageIndex);
891         p.writeInt(taskRootClassIndex);
892         p.writeInt(event.mEventType);
893         p.writeLong(event.mTimeStamp);
894 
895         switch (event.mEventType) {
896             case Event.CONFIGURATION_CHANGE:
897                 event.mConfiguration.writeToParcel(p, flags);
898                 break;
899             case Event.SHORTCUT_INVOCATION:
900                 p.writeString(event.mShortcutId);
901                 break;
902             case Event.CHOOSER_ACTION:
903                 p.writeString(event.mAction);
904                 p.writeString(event.mContentType);
905                 p.writeStringArray(event.mContentAnnotations);
906                 break;
907             case Event.STANDBY_BUCKET_CHANGED:
908                 p.writeInt(event.mBucketAndReason);
909                 break;
910             case Event.NOTIFICATION_INTERRUPTION:
911                 p.writeString(event.mNotificationChannelId);
912                 break;
913             case Event.LOCUS_ID_SET:
914                 p.writeString(event.mLocusId);
915                 break;
916         }
917         p.writeInt(event.mFlags);
918     }
919 
920     /**
921      * Reads a single event from the parcel. Modify this when updating {@link Event}.
922      */
923     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
readEventFromParcel(Parcel p, Event eventOut)924     private void readEventFromParcel(Parcel p, Event eventOut) {
925         final int packageIndex = p.readInt();
926         if (packageIndex >= 0) {
927             eventOut.mPackage = mStringPool[packageIndex];
928         } else {
929             eventOut.mPackage = null;
930         }
931 
932         final int classIndex = p.readInt();
933         if (classIndex >= 0) {
934             eventOut.mClass = mStringPool[classIndex];
935         } else {
936             eventOut.mClass = null;
937         }
938         eventOut.mInstanceId = p.readInt();
939 
940         final int taskRootPackageIndex = p.readInt();
941         if (taskRootPackageIndex >= 0) {
942             eventOut.mTaskRootPackage = mStringPool[taskRootPackageIndex];
943         } else {
944             eventOut.mTaskRootPackage = null;
945         }
946 
947         final int taskRootClassIndex = p.readInt();
948         if (taskRootClassIndex >= 0) {
949             eventOut.mTaskRootClass = mStringPool[taskRootClassIndex];
950         } else {
951             eventOut.mTaskRootClass = null;
952         }
953 
954         eventOut.mEventType = p.readInt();
955         eventOut.mTimeStamp = p.readLong();
956 
957         // Fill out the event-dependant fields.
958         eventOut.mConfiguration = null;
959         eventOut.mShortcutId = null;
960         eventOut.mAction = null;
961         eventOut.mContentType = null;
962         eventOut.mContentAnnotations = null;
963         eventOut.mNotificationChannelId = null;
964         eventOut.mLocusId = null;
965 
966         switch (eventOut.mEventType) {
967             case Event.CONFIGURATION_CHANGE:
968                 // Extract the configuration for configuration change events.
969                 eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p);
970                 break;
971             case Event.SHORTCUT_INVOCATION:
972                 eventOut.mShortcutId = p.readString();
973                 break;
974             case Event.CHOOSER_ACTION:
975                 eventOut.mAction = p.readString();
976                 eventOut.mContentType = p.readString();
977                 eventOut.mContentAnnotations = p.createStringArray();
978                 break;
979             case Event.STANDBY_BUCKET_CHANGED:
980                 eventOut.mBucketAndReason = p.readInt();
981                 break;
982             case Event.NOTIFICATION_INTERRUPTION:
983                 eventOut.mNotificationChannelId = p.readString();
984                 break;
985             case Event.LOCUS_ID_SET:
986                 eventOut.mLocusId = p.readString();
987                 break;
988         }
989         eventOut.mFlags = p.readInt();
990     }
991 
992     @Override
describeContents()993     public int describeContents() {
994         return 0;
995     }
996 
997     @Override
writeToParcel(Parcel dest, int flags)998     public void writeToParcel(Parcel dest, int flags) {
999         Parcel data = Parcel.obtain();
1000         data.writeInt(mEventCount);
1001         data.writeInt(mIndex);
1002         if (mEventCount > 0) {
1003             data.writeStringArray(mStringPool);
1004 
1005             if (mEventsToWrite != null) {
1006                 // Write out the events
1007                 Parcel p = Parcel.obtain();
1008                 try {
1009                     p.setDataPosition(0);
1010                     for (int i = 0; i < mEventCount; i++) {
1011                         final Event event = mEventsToWrite.get(i);
1012                         writeEventToParcel(event, p, flags);
1013                     }
1014 
1015                     final int listByteLength = p.dataPosition();
1016 
1017                     // Write the total length of the data.
1018                     data.writeInt(listByteLength);
1019 
1020                     // Write our current position into the data.
1021                     data.writeInt(0);
1022 
1023                     // Write the data.
1024                     data.appendFrom(p, 0, listByteLength);
1025                 } finally {
1026                     p.recycle();
1027                 }
1028 
1029             } else if (mParcel != null) {
1030                 // Write the total length of the data.
1031                 data.writeInt(mParcel.dataSize());
1032 
1033                 // Write out current position into the data.
1034                 data.writeInt(mParcel.dataPosition());
1035 
1036                 // Write the data.
1037                 data.appendFrom(mParcel, 0, mParcel.dataSize());
1038             } else {
1039                 throw new IllegalStateException(
1040                         "Either mParcel or mEventsToWrite must not be null");
1041             }
1042         }
1043         // Data can be too large for a transact. Write the data as a Blob, which will be written to
1044         // ashmem if too large.
1045         dest.writeBlob(data.marshall());
1046     }
1047 
1048     public static final @android.annotation.NonNull Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() {
1049         @Override
1050         public UsageEvents createFromParcel(Parcel source) {
1051             return new UsageEvents(source);
1052         }
1053 
1054         @Override
1055         public UsageEvents[] newArray(int size) {
1056             return new UsageEvents[size];
1057         }
1058     };
1059 }
1060