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