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