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 /** 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 @Nullable 558 @SystemApi getNotificationChannelId()559 public String getNotificationChannelId() { 560 return mNotificationChannelId; 561 } 562 563 /** @hide */ getObfuscatedIfInstantApp()564 public Event getObfuscatedIfInstantApp() { 565 if (!isInstantApp()) { 566 return this; 567 } 568 final Event ret = new Event(this); 569 ret.mPackage = INSTANT_APP_PACKAGE_NAME; 570 ret.mClass = INSTANT_APP_CLASS_NAME; 571 572 // Note there are other string fields too, but they're for app shortcuts and choosers, 573 // which instant apps can't use anyway, so there's no need to hide them. 574 return ret; 575 } 576 } 577 578 // Only used when creating the resulting events. Not used for reading/unparceling. 579 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 580 private List<Event> mEventsToWrite = null; 581 582 // Only used for reading/unparceling events. 583 @UnsupportedAppUsage 584 private Parcel mParcel = null; 585 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 586 private final int mEventCount; 587 588 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 589 private int mIndex = 0; 590 591 // Only used when parceling events. If false, task roots will be omitted from the parcel 592 private final boolean mIncludeTaskRoots; 593 594 /* 595 * In order to save space, since ComponentNames will be duplicated everywhere, 596 * we use a map and index into it. 597 */ 598 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 599 private String[] mStringPool; 600 601 /** 602 * Construct the iterator from a parcel. 603 * {@hide} 604 */ 605 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) UsageEvents(Parcel in)606 public UsageEvents(Parcel in) { 607 byte[] bytes = in.readBlob(); 608 Parcel data = Parcel.obtain(); 609 data.unmarshall(bytes, 0, bytes.length); 610 data.setDataPosition(0); 611 mEventCount = data.readInt(); 612 mIndex = data.readInt(); 613 if (mEventCount > 0) { 614 mStringPool = data.createStringArray(); 615 616 final int listByteLength = data.readInt(); 617 final int positionInParcel = data.readInt(); 618 mParcel = Parcel.obtain(); 619 mParcel.setDataPosition(0); 620 mParcel.appendFrom(data, data.dataPosition(), listByteLength); 621 mParcel.setDataSize(mParcel.dataPosition()); 622 mParcel.setDataPosition(positionInParcel); 623 } 624 mIncludeTaskRoots = true; 625 } 626 627 /** 628 * Create an empty iterator. 629 * {@hide} 630 */ UsageEvents()631 UsageEvents() { 632 mEventCount = 0; 633 mIncludeTaskRoots = true; 634 } 635 636 /** 637 * Construct the iterator in preparation for writing it to a parcel. 638 * Defaults to excluding task roots from the parcel. 639 * {@hide} 640 */ UsageEvents(List<Event> events, String[] stringPool)641 public UsageEvents(List<Event> events, String[] stringPool) { 642 this(events, stringPool, false); 643 } 644 645 /** 646 * Construct the iterator in preparation for writing it to a parcel. 647 * {@hide} 648 */ UsageEvents(List<Event> events, String[] stringPool, boolean includeTaskRoots)649 public UsageEvents(List<Event> events, String[] stringPool, boolean includeTaskRoots) { 650 mStringPool = stringPool; 651 mEventCount = events.size(); 652 mEventsToWrite = events; 653 mIncludeTaskRoots = includeTaskRoots; 654 } 655 656 /** 657 * Returns whether or not there are more events to read using 658 * {@link #getNextEvent(android.app.usage.UsageEvents.Event)}. 659 * 660 * @return true if there are more events, false otherwise. 661 */ hasNextEvent()662 public boolean hasNextEvent() { 663 return mIndex < mEventCount; 664 } 665 666 /** 667 * Retrieve the next {@link android.app.usage.UsageEvents.Event} from the collection and put the 668 * resulting data into {@code eventOut}. 669 * 670 * @param eventOut The {@link android.app.usage.UsageEvents.Event} object that will receive the 671 * next event data. 672 * @return true if an event was available, false if there are no more events. 673 */ getNextEvent(Event eventOut)674 public boolean getNextEvent(Event eventOut) { 675 if (mIndex >= mEventCount) { 676 return false; 677 } 678 679 readEventFromParcel(mParcel, eventOut); 680 681 mIndex++; 682 if (mIndex >= mEventCount) { 683 mParcel.recycle(); 684 mParcel = null; 685 } 686 return true; 687 } 688 689 /** 690 * Resets the collection so that it can be iterated over from the beginning. 691 * 692 * @hide When this object is iterated to completion, the parcel is destroyed and 693 * so resetToStart doesn't work. 694 */ resetToStart()695 public void resetToStart() { 696 mIndex = 0; 697 if (mParcel != null) { 698 mParcel.setDataPosition(0); 699 } 700 } 701 702 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) findStringIndex(String str)703 private int findStringIndex(String str) { 704 final int index = Arrays.binarySearch(mStringPool, str); 705 if (index < 0) { 706 throw new IllegalStateException("String '" + str + "' is not in the string pool"); 707 } 708 return index; 709 } 710 711 /** 712 * Writes a single event to the parcel. Modify this when updating {@link Event}. 713 */ 714 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) writeEventToParcel(Event event, Parcel p, int flags)715 private void writeEventToParcel(Event event, Parcel p, int flags) { 716 final int packageIndex; 717 if (event.mPackage != null) { 718 packageIndex = findStringIndex(event.mPackage); 719 } else { 720 packageIndex = -1; 721 } 722 723 final int classIndex; 724 if (event.mClass != null) { 725 classIndex = findStringIndex(event.mClass); 726 } else { 727 classIndex = -1; 728 } 729 730 final int taskRootPackageIndex; 731 if (mIncludeTaskRoots && event.mTaskRootPackage != null) { 732 taskRootPackageIndex = findStringIndex(event.mTaskRootPackage); 733 } else { 734 taskRootPackageIndex = -1; 735 } 736 737 final int taskRootClassIndex; 738 if (mIncludeTaskRoots && event.mTaskRootClass != null) { 739 taskRootClassIndex = findStringIndex(event.mTaskRootClass); 740 } else { 741 taskRootClassIndex = -1; 742 } 743 p.writeInt(packageIndex); 744 p.writeInt(classIndex); 745 p.writeInt(event.mInstanceId); 746 p.writeInt(taskRootPackageIndex); 747 p.writeInt(taskRootClassIndex); 748 p.writeInt(event.mEventType); 749 p.writeLong(event.mTimeStamp); 750 751 switch (event.mEventType) { 752 case Event.CONFIGURATION_CHANGE: 753 event.mConfiguration.writeToParcel(p, flags); 754 break; 755 case Event.SHORTCUT_INVOCATION: 756 p.writeString(event.mShortcutId); 757 break; 758 case Event.CHOOSER_ACTION: 759 p.writeString(event.mAction); 760 p.writeString(event.mContentType); 761 p.writeStringArray(event.mContentAnnotations); 762 break; 763 case Event.STANDBY_BUCKET_CHANGED: 764 p.writeInt(event.mBucketAndReason); 765 break; 766 case Event.NOTIFICATION_INTERRUPTION: 767 p.writeString(event.mNotificationChannelId); 768 break; 769 } 770 p.writeInt(event.mFlags); 771 } 772 773 /** 774 * Reads a single event from the parcel. Modify this when updating {@link Event}. 775 */ 776 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) readEventFromParcel(Parcel p, Event eventOut)777 private void readEventFromParcel(Parcel p, Event eventOut) { 778 final int packageIndex = p.readInt(); 779 if (packageIndex >= 0) { 780 eventOut.mPackage = mStringPool[packageIndex]; 781 } else { 782 eventOut.mPackage = null; 783 } 784 785 final int classIndex = p.readInt(); 786 if (classIndex >= 0) { 787 eventOut.mClass = mStringPool[classIndex]; 788 } else { 789 eventOut.mClass = null; 790 } 791 eventOut.mInstanceId = p.readInt(); 792 793 final int taskRootPackageIndex = p.readInt(); 794 if (taskRootPackageIndex >= 0) { 795 eventOut.mTaskRootPackage = mStringPool[taskRootPackageIndex]; 796 } else { 797 eventOut.mTaskRootPackage = null; 798 } 799 800 final int taskRootClassIndex = p.readInt(); 801 if (taskRootClassIndex >= 0) { 802 eventOut.mTaskRootClass = mStringPool[taskRootClassIndex]; 803 } else { 804 eventOut.mTaskRootClass = null; 805 } 806 807 eventOut.mEventType = p.readInt(); 808 eventOut.mTimeStamp = p.readLong(); 809 810 // Fill out the event-dependant fields. 811 eventOut.mConfiguration = null; 812 eventOut.mShortcutId = null; 813 eventOut.mAction = null; 814 eventOut.mContentType = null; 815 eventOut.mContentAnnotations = null; 816 eventOut.mNotificationChannelId = null; 817 818 switch (eventOut.mEventType) { 819 case Event.CONFIGURATION_CHANGE: 820 // Extract the configuration for configuration change events. 821 eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p); 822 break; 823 case Event.SHORTCUT_INVOCATION: 824 eventOut.mShortcutId = p.readString(); 825 break; 826 case Event.CHOOSER_ACTION: 827 eventOut.mAction = p.readString(); 828 eventOut.mContentType = p.readString(); 829 eventOut.mContentAnnotations = p.createStringArray(); 830 break; 831 case Event.STANDBY_BUCKET_CHANGED: 832 eventOut.mBucketAndReason = p.readInt(); 833 break; 834 case Event.NOTIFICATION_INTERRUPTION: 835 eventOut.mNotificationChannelId = p.readString(); 836 break; 837 } 838 eventOut.mFlags = p.readInt(); 839 } 840 841 @Override describeContents()842 public int describeContents() { 843 return 0; 844 } 845 846 @Override writeToParcel(Parcel dest, int flags)847 public void writeToParcel(Parcel dest, int flags) { 848 Parcel data = Parcel.obtain(); 849 data.writeInt(mEventCount); 850 data.writeInt(mIndex); 851 if (mEventCount > 0) { 852 data.writeStringArray(mStringPool); 853 854 if (mEventsToWrite != null) { 855 // Write out the events 856 Parcel p = Parcel.obtain(); 857 try { 858 p.setDataPosition(0); 859 for (int i = 0; i < mEventCount; i++) { 860 final Event event = mEventsToWrite.get(i); 861 writeEventToParcel(event, p, flags); 862 } 863 864 final int listByteLength = p.dataPosition(); 865 866 // Write the total length of the data. 867 data.writeInt(listByteLength); 868 869 // Write our current position into the data. 870 data.writeInt(0); 871 872 // Write the data. 873 data.appendFrom(p, 0, listByteLength); 874 } finally { 875 p.recycle(); 876 } 877 878 } else if (mParcel != null) { 879 // Write the total length of the data. 880 data.writeInt(mParcel.dataSize()); 881 882 // Write out current position into the data. 883 data.writeInt(mParcel.dataPosition()); 884 885 // Write the data. 886 data.appendFrom(mParcel, 0, mParcel.dataSize()); 887 } else { 888 throw new IllegalStateException( 889 "Either mParcel or mEventsToWrite must not be null"); 890 } 891 } 892 // Data can be too large for a transact. Write the data as a Blob, which will be written to 893 // ashmem if too large. 894 dest.writeBlob(data.marshall()); 895 } 896 897 public static final @android.annotation.NonNull Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() { 898 @Override 899 public UsageEvents createFromParcel(Parcel source) { 900 return new UsageEvents(source); 901 } 902 903 @Override 904 public UsageEvents[] newArray(int size) { 905 return new UsageEvents[size]; 906 } 907 }; 908 } 909