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

Commit 641e338f authored by Michael Wachenschwanz's avatar Michael Wachenschwanz
Browse files

Add SystemApi for registering Usage Session Observers in UsageStats

Test: atest cts/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ProfileOwnerTest.java#testAppUsageObserver
Test: atest android.app.usage.cts.UsageStatsTest#testObserveUsagePermission
Bug: 111465038
Change-Id: I70a7a5729117f8e9651a2e4ea732156537d2f3c1
parent 0f47284a
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -850,9 +850,11 @@ package android.app.usage {
    method public int getAppStandbyBucket(java.lang.String);
    method public java.util.Map<java.lang.String, java.lang.Integer> getAppStandbyBuckets();
    method public void registerAppUsageObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, android.app.PendingIntent);
    method public void registerUsageSessionObserver(int, java.lang.String[], long, java.util.concurrent.TimeUnit, long, java.util.concurrent.TimeUnit, android.app.PendingIntent, android.app.PendingIntent);
    method public void setAppStandbyBucket(java.lang.String, int);
    method public void setAppStandbyBuckets(java.util.Map<java.lang.String, java.lang.Integer>);
    method public void unregisterAppUsageObserver(int);
    method public void unregisterUsageSessionObserver(int);
    method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
    field public static final java.lang.String EXTRA_OBSERVER_ID = "android.app.usage.extra.OBSERVER_ID";
    field public static final java.lang.String EXTRA_TIME_LIMIT = "android.app.usage.extra.TIME_LIMIT";
+78 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.app.usage;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
@@ -595,7 +596,7 @@ public final class UsageStatsManager {
     *                       exceeded by the group of apps. The delivered Intent will also contain
     *                       the extras {@link #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and
     *                       {@link #EXTRA_TIME_USED}. Cannot be null.
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission or
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
     *                           is not the profile owner of this user.
     */
    @SystemApi
@@ -616,7 +617,7 @@ public final class UsageStatsManager {
     * to any observer registered by this application. Unregistering an observer that was already
     * unregistered or never registered will have no effect.
     * @param observerId The id of the observer that was previously registered.
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission or is
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and is
     *                           not the profile owner of this user.
     */
    @SystemApi
@@ -629,6 +630,81 @@ public final class UsageStatsManager {
        }
    }

    /**
     * Register a usage session observer that receives a callback on the provided {@code
     * limitReachedCallbackIntent} when the sum of usages of apps in the packages array exceeds
     * the {@code timeLimit} specified within a usage session. After the {@code timeLimit} has
     * been reached, the usage session observer will receive a callback on the provided {@code
     * sessionEndCallbackIntent} when the usage session ends. Registering another session
     * observer against a {@code sessionObserverId} that has already been registered will
     * override the previous session observer.
     *
     * @param sessionObserverId A unique id associated with the group of apps to be
     *                          monitored. There can be multiple groups with common
     *                          packages and different time limits.
     * @param packages The list of packages to observe for foreground activity time. Cannot be null
     *                 and must include at least one package.
     * @param timeLimit The total time the set of apps can be used continuously before the {@code
     *                  limitReachedCallbackIntent} is delivered. Must be at least one minute.
     * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
     * @param sessionThresholdTime The time that can take place between usage sessions before the
     *                             next session is considered a new session. Must be non-negative.
     * @param sessionThresholdTimeUnit The unit for time specified in {@code sessionThreshold}.
     *                                 Cannot be null.
     * @param limitReachedCallbackIntent The {@link PendingIntent} that will be dispatched when the
     *                                   time limit is exceeded by the group of apps. The delivered
     *                                   Intent will also contain the extras {@link
     *                                   #EXTRA_OBSERVER_ID}, {@link #EXTRA_TIME_LIMIT} and {@link
     *                                   #EXTRA_TIME_USED}. Cannot be null.
     * @param sessionEndCallbackIntent The {@link PendingIntent}  that will be dispatched when the
     *                                 session has ended after the time limit has been exceeded. The
     *                                 session is considered at its end after the {@code observed}
     *                                 usage has stopped and an additional {@code
     *                                 sessionThresholdTime} has passed. The delivered Intent will
     *                                 also contain the extras {@link #EXTRA_OBSERVER_ID} and {@link
     *                                 #EXTRA_TIME_USED}. Can be null.
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
     *                           is not the profile owner of this user.
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
    public void registerUsageSessionObserver(int sessionObserverId, @NonNull String[] packages,
            long timeLimit, @NonNull TimeUnit timeUnit, long sessionThresholdTime,
            @NonNull TimeUnit sessionThresholdTimeUnit,
            @NonNull PendingIntent limitReachedCallbackIntent,
            @Nullable PendingIntent sessionEndCallbackIntent) {
        try {
            mService.registerUsageSessionObserver(sessionObserverId, packages,
                    timeUnit.toMillis(timeLimit),
                    sessionThresholdTimeUnit.toMillis(sessionThresholdTime),
                    limitReachedCallbackIntent, sessionEndCallbackIntent,
                    mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Unregister the usage session observer specified by the {@code sessionObserverId}. This will
     * only apply to any app session observer registered by this application. Unregistering an
     * observer that was already unregistered or never registered will have no effect.
     *
     * @param sessionObserverId The id of the observer that was previously registered.
     * @throws SecurityException if the caller doesn't have the OBSERVE_APP_USAGE permission and
     *                           is not the profile owner of this user.
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE)
    public void unregisterUsageSessionObserver(int sessionObserverId) {
        try {
            mService.unregisterUsageSessionObserver(sessionObserverId, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /** @hide */
    public static String reasonToString(int standbyReason) {
        StringBuilder sb = new StringBuilder();