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