Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ced54398 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

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
parent d52c532d
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -7327,6 +7327,20 @@ package android.app.usage {
    field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR;
  }
  public final class EventStats implements android.os.Parcelable {
    ctor public EventStats(android.app.usage.EventStats);
    method public void add(android.app.usage.EventStats);
    method public int describeContents();
    method public int getCount();
    method public int getEventType();
    method public long getFirstTimeStamp();
    method public long getLastTimeStamp();
    method public long getLastTimeUsed();
    method public long getTotalTime();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.app.usage.EventStats> CREATOR;
  }
  public final class ExternalStorageStats implements android.os.Parcelable {
    method public int describeContents();
    method public long getAppBytes();
@@ -7432,6 +7446,8 @@ package android.app.usage {
    field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
    field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
    field public static final int NONE = 0; // 0x0
    field public static final int SCREEN_INTERACTIVE = 15; // 0xf
    field public static final int SCREEN_NON_INTERACTIVE = 16; // 0x10
    field public static final int SHORTCUT_INVOCATION = 8; // 0x8
    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
    field public static final int USER_INTERACTION = 7; // 0x7
@@ -7455,6 +7471,7 @@ package android.app.usage {
    method public boolean isAppInactive(java.lang.String);
    method public java.util.Map<java.lang.String, android.app.usage.UsageStats> queryAndAggregateUsageStats(long, long);
    method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
    method public java.util.List<android.app.usage.EventStats> queryEventStats(int, long, long);
    method public android.app.usage.UsageEvents queryEvents(long, long);
    method public android.app.usage.UsageEvents queryEventsForSelf(long, long);
    method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
+182 −0
Original line number Diff line number Diff line
/**
 * 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];
        }
    };
}
+2 −0
Original line number Diff line number Diff line
@@ -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);
+13 −0
Original line number Diff line number Diff line
@@ -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;

+38 −0
Original line number Diff line number Diff line
@@ -300,6 +300,44 @@ public final class UsageStatsManager {
        return Collections.emptyList();
    }

    /**
     * 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.
Loading