diff options
| author | Dianne Hackborn <hackbod@google.com> | 2018-02-26 13:07:42 -0800 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2018-03-27 13:27:20 -0700 |
| commit | ced54398cc0dfd2f782153560c2ffd0eb8743045 (patch) | |
| tree | d5e6a868ec1b33c2fd8e91287c9e8eed6e3b47a0 /core/java | |
| parent | d52c532df7c7c481bf6e482c37f4e0ee02618fce (diff) | |
Work on issue #74404949: Screen state usage API
Add usage stats tracking of screen time. There are two new
events, one for when the device is an interactive state, the
other for when it is non-interactive. Also add a whole new
usage stats API for retrieving aggregated data that is associated
with general events, not particular packages. In this case
it allows you to find the time the device spent interactive
and non-interactive and the count of the transitions in to
each of those states.
Bug: 74404949
Test: atest CtsUsageStatsTestCases:UsageStatsTest\#testInteractiveEvents
Change-Id: Ibe6d55e2aecb0c8519b1358644378ec5c7a4250d
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/usage/EventStats.java | 182 | ||||
| -rw-r--r-- | core/java/android/app/usage/IUsageStatsManager.aidl | 2 | ||||
| -rw-r--r-- | core/java/android/app/usage/UsageEvents.java | 13 | ||||
| -rw-r--r-- | core/java/android/app/usage/UsageStatsManager.java | 38 | ||||
| -rw-r--r-- | core/java/android/os/Parcel.java | 4 |
5 files changed, 237 insertions, 2 deletions
diff --git a/core/java/android/app/usage/EventStats.java b/core/java/android/app/usage/EventStats.java new file mode 100644 index 000000000000..b799de9410a3 --- /dev/null +++ b/core/java/android/app/usage/EventStats.java @@ -0,0 +1,182 @@ +/** + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.app.usage; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Contains usage statistics for an event type for a specific + * time range. + */ +public final class EventStats implements Parcelable { + + /** + * {@hide} + */ + public int mEventType; + + /** + * {@hide} + */ + public long mBeginTimeStamp; + + /** + * {@hide} + */ + public long mEndTimeStamp; + + /** + * Last time used by the user with an explicit action (notification, activity launch). + * {@hide} + */ + public long mLastTimeUsed; + + /** + * {@hide} + */ + public long mTotalTime; + + /** + * {@hide} + */ + public int mCount; + + /** + * {@hide} + */ + public EventStats() { + } + + public EventStats(EventStats stats) { + mEventType = stats.mEventType; + mBeginTimeStamp = stats.mBeginTimeStamp; + mEndTimeStamp = stats.mEndTimeStamp; + mLastTimeUsed = stats.mLastTimeUsed; + mTotalTime = stats.mTotalTime; + mCount = stats.mCount; + } + + /** + * Return the type of event this is usage for. May be one of the event + * constants in {@link UsageEvents.Event}. + */ + public int getEventType() { + return mEventType; + } + + /** + * Get the beginning of the time range this {@link android.app.usage.EventStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getFirstTimeStamp() { + return mBeginTimeStamp; + } + + /** + * Get the end of the time range this {@link android.app.usage.EventStats} represents, + * measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeStamp() { + return mEndTimeStamp; + } + + /** + * Get the last time this event was used, measured in milliseconds since the epoch. + * <p/> + * See {@link System#currentTimeMillis()}. + */ + public long getLastTimeUsed() { + return mLastTimeUsed; + } + + /** + * Return the number of times that this event occurred over the interval. + */ + public int getCount() { + return mCount; + } + + /** + * Get the total time this event was active, measured in milliseconds. + */ + public long getTotalTime() { + return mTotalTime; + } + + /** + * Add the statistics from the right {@link EventStats} to the left. The event type for + * both {@link UsageStats} objects must be the same. + * @param right The {@link EventStats} object to merge into this one. + * @throws java.lang.IllegalArgumentException if the event types of the two + * {@link UsageStats} objects are different. + */ + public void add(EventStats right) { + if (mEventType != right.mEventType) { + throw new IllegalArgumentException("Can't merge EventStats for event #" + + mEventType + " with EventStats for event #" + right.mEventType); + } + + // We use the mBeginTimeStamp due to a bug where UsageStats files can overlap with + // regards to their mEndTimeStamp. + if (right.mBeginTimeStamp > mBeginTimeStamp) { + mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed); + } + mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp); + mEndTimeStamp = Math.max(mEndTimeStamp, right.mEndTimeStamp); + mTotalTime += right.mTotalTime; + mCount += right.mCount; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mEventType); + dest.writeLong(mBeginTimeStamp); + dest.writeLong(mEndTimeStamp); + dest.writeLong(mLastTimeUsed); + dest.writeLong(mTotalTime); + dest.writeInt(mCount); + } + + public static final Creator<EventStats> CREATOR = new Creator<EventStats>() { + @Override + public EventStats createFromParcel(Parcel in) { + EventStats stats = new EventStats(); + stats.mEventType = in.readInt(); + stats.mBeginTimeStamp = in.readLong(); + stats.mEndTimeStamp = in.readLong(); + stats.mLastTimeUsed = in.readLong(); + stats.mTotalTime = in.readLong(); + stats.mCount = in.readInt(); + return stats; + } + + @Override + public EventStats[] newArray(int size) { + return new EventStats[size]; + } + }; +} diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index d52bd3764101..00d8711c7baa 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -32,6 +32,8 @@ interface IUsageStatsManager { String callingPackage); ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, String callingPackage); + ParceledListSlice queryEventStats(int bucketType, long beginTime, long endTime, + String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index b354e8122a98..a66565212000 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -139,6 +139,19 @@ public final class UsageEvents implements Parcelable { @SystemApi public static final int SLICE_PINNED = 14; + /** + * An event type denoting that the screen has gone in to an interactive state (turned + * on for full user interaction, not ambient display or other non-interactive state). + */ + public static final int SCREEN_INTERACTIVE = 15; + + /** + * An event type denoting that the screen has gone in to a non-interactive state + * (completely turned off or turned on only in a non-interactive state like ambient + * display). + */ + public static final int SCREEN_NON_INTERACTIVE = 16; + /** @hide */ public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0; diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 47441476f95b..6feb5278a48c 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -301,6 +301,44 @@ public final class UsageStatsManager { } /** + * Gets aggregated event stats for the given time range, aggregated by the specified interval. + * <p>The returned list will contain a {@link EventStats} object for each event type that + * is being aggregated and has data for an interval that is a subset of the time range given. + * + * <p>The current event types that will be aggregated here are:</p> + * <ul> + * <li>{@link UsageEvents.Event#SCREEN_INTERACTIVE}</li> + * <li>{@link UsageEvents.Event#SCREEN_NON_INTERACTIVE}</li> + * </ul> + * + * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> + * + * @param intervalType The time interval by which the stats are aggregated. + * @param beginTime The inclusive beginning of the range of stats to include in the results. + * @param endTime The exclusive end of the range of stats to include in the results. + * @return A list of {@link EventStats} + * + * @see #INTERVAL_DAILY + * @see #INTERVAL_WEEKLY + * @see #INTERVAL_MONTHLY + * @see #INTERVAL_YEARLY + * @see #INTERVAL_BEST + */ + public List<EventStats> queryEventStats(int intervalType, long beginTime, long endTime) { + try { + @SuppressWarnings("unchecked") + ParceledListSlice<EventStats> slice = mService.queryEventStats(intervalType, beginTime, + endTime, mContext.getOpPackageName()); + if (slice != null) { + return slice.getList(); + } + } catch (RemoteException e) { + // fallthrough and return the empty list. + } + return Collections.emptyList(); + } + + /** * Query for events in the given time range. Events are only kept by the system for a few * days. * <p> The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS} </p> diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 62bb38540e44..e3c48700b4c0 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -2803,8 +2803,8 @@ public final class Parcel { Class<?> parcelableClass = Class.forName(name, false /* initialize */, parcelableClassLoader); if (!Parcelable.class.isAssignableFrom(parcelableClass)) { - throw new BadParcelableException("Parcelable protocol requires that the " - + "class implements Parcelable"); + throw new BadParcelableException("Parcelable protocol requires subclassing " + + "from Parcelable on class " + name); } Field f = parcelableClass.getField("CREATOR"); if ((f.getModifiers() & Modifier.STATIC) == 0) { |
