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

Commit 54f7f7f9 authored by Varun Shah's avatar Varun Shah
Browse files

Allow registration of AppUsageLimitObservers with 0 time limit.

A wellbeing app can now register AppUsageLimit observers with a time
limit of 0 seconds. There will be no callback intent fired in this case.

Bug: 123899673
Test: atest FrameworksServicesTests:AppTimeLimitControllerTests#testAppUsageLimitObserver_ZeroTimeLimitIsAllowed
Test: atest android.content.pm.cts.LauncherAppsTest#testGetAppUsageLimit_allowsZeroLimit
Change-Id: I9cdff21bcfa72f202699cea288e703f35a4f158f
parent f28075bf
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1145,7 +1145,7 @@ package android.app.usage {
    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getAppStandbyBucket(String);
    method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public java.util.Map<java.lang.String,java.lang.Integer> getAppStandbyBuckets();
    method public int getUsageSource();
    method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
    method @RequiresPermission(allOf={android.Manifest.permission.SUSPEND_APPS, android.Manifest.permission.OBSERVE_APP_USAGE}) public void registerAppUsageLimitObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, android.app.PendingIntent);
    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerAppUsageObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent);
    method @RequiresPermission(android.Manifest.permission.OBSERVE_APP_USAGE) public void registerUsageSessionObserver(int, @NonNull String[], long, @NonNull java.util.concurrent.TimeUnit, long, @NonNull java.util.concurrent.TimeUnit, @NonNull android.app.PendingIntent, @Nullable android.app.PendingIntent);
    method public void reportUsageStart(@NonNull android.app.Activity, @NonNull String);
+12 −5
Original line number Diff line number Diff line
@@ -745,7 +745,11 @@ public final class UsageStatsManager {
     * Registering an {@code observerId} that was already registered will override the previous one.
     * No more than 1000 unique {@code observerId} may be registered by a single uid
     * at any one time.
     * A limit may be unregistered via {@link #unregisterAppUsageLimitObserver}
     * A limit is not cleared when the usage time is exceeded. It needs to be unregistered via
     * {@link #unregisterAppUsageLimitObserver}.
     * <p>
     * Note: usage limits are not persisted in the system and are cleared on reboots. Callers
     * must reset any limits that they need on reboots.
     * <p>
     * This method is similar to {@link #registerAppUsageObserver}, but the usage limit set here
     * will be visible to the launcher so that it can report the limit to the user and how much
@@ -757,12 +761,15 @@ public final class UsageStatsManager {
     * @param observedEntities The list of packages and token to observe for usage time. Cannot be
     *                         null and must include at least one package or token.
     * @param timeLimit The total time the set of apps can be in the foreground before the
     *                  callbackIntent is delivered. Must be at least one minute.
     *                  callbackIntent is delivered. Must be at least one minute. Note: a limit of
     *                  0 can be set to indicate that the user has already exhausted the limit for
     *                  a group, in which case, the given {@code callbackIntent} will be ignored.
     * @param timeUnit The unit for time specified in {@code timeLimit}. Cannot be null.
     * @param callbackIntent The PendingIntent that will be dispatched when the usage 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.
     *                       {@link #EXTRA_TIME_USED}. Cannot be {@code null} unless the observer is
     *                       being registered with a {@code timeLimit} of 0.
     * @throws SecurityException if the caller doesn't have both SUSPEND_APPS and OBSERVE_APP_USAGE
     *                           permissions.
     * @hide
@@ -772,7 +779,7 @@ public final class UsageStatsManager {
            android.Manifest.permission.SUSPEND_APPS,
            android.Manifest.permission.OBSERVE_APP_USAGE})
    public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities,
            long timeLimit, @NonNull TimeUnit timeUnit, @NonNull PendingIntent callbackIntent) {
            long timeLimit, @NonNull TimeUnit timeUnit, PendingIntent callbackIntent) {
        try {
            mService.registerAppUsageLimitObserver(observerId, observedEntities,
                    timeUnit.toMillis(timeLimit), callbackIntent, mContext.getOpPackageName());
+9 −0
Original line number Diff line number Diff line
@@ -1035,6 +1035,15 @@ public class AppTimeLimitControllerTests {
                0L, group.getUsageRemaining());
    }

    /** Verify that a limit of 0 is allowed for the special case of re-registering an observer. */
    @Test
    public void testAppUsageLimitObserver_ZeroTimeLimitIsAllowed() {
        addAppUsageLimitObserver(OBS_ID1, GROUP1, 0);
        AppTimeLimitController.AppUsageLimitGroup group = getAppUsageLimitObserver(UID, OBS_ID1);
        assertNotNull("Observer wasn't added", group);
        assertEquals("Usage remaining was not 0.", 0, group.getUsageRemaining());
    }

    private void startUsage(String packageName) {
        mController.noteUsageStart(packageName, USER_ID);
    }
+3 −2
Original line number Diff line number Diff line
@@ -840,7 +840,8 @@ public class AppTimeLimitController {
     */
    public void addAppUsageLimitObserver(int requestingUid, int observerId, String[] observed,
            long timeLimit, PendingIntent callbackIntent, @UserIdInt int userId) {
        if (timeLimit < getMinTimeLimit()) {
        // Allow the special case of the limit being 0, but with no callback.
        if (timeLimit != 0L && timeLimit < getMinTimeLimit()) {
            throw new IllegalArgumentException("Time limit must be >= " + getMinTimeLimit());
        }
        synchronized (mLock) {
@@ -858,7 +859,7 @@ public class AppTimeLimitController {
                        "Too many app usage observers added by uid " + requestingUid);
            }
            group = new AppUsageLimitGroup(user, observerApp, observerId, observed, timeLimit,
                    callbackIntent);
                    timeLimit == 0L ? null : callbackIntent);
            observerApp.appUsageLimitGroups.append(observerId, group);

            if (DEBUG) {
+1 −1
Original line number Diff line number Diff line
@@ -1375,7 +1375,7 @@ public class UsageStatsService extends SystemService implements
            if (packages == null || packages.length == 0) {
                throw new IllegalArgumentException("Must specify at least one package");
            }
            if (callbackIntent == null) {
            if (callbackIntent == null && timeLimitMs != 0L) {
                throw new NullPointerException("callbackIntent can't be null");
            }
            final int callingUid = Binder.getCallingUid();