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

Commit 737b6984 authored by Jiaming Liu's avatar Jiaming Liu
Browse files

Cancel state override request when app goes into background

Automatically cancel the state override request when the requesting app
goes into background or the screen is turned off.

Bug: 264557324
Test: Manually tested with the demo app.
atest com.android.server.devicestate.DeviceStateManagerServiceTest

Change-Id: I9d3208475d2a6231cde1d80f6886391e4f01cae2
parent cda60c24
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -64,10 +64,20 @@ public final class DeviceState {
     */
    public static final int FLAG_EMULATED_ONLY = 1 << 2;

    /**
     * This flag indicates that the corresponding state should be automatically canceled when the
     * requesting app is no longer on top. The app is considered not on top when (1) the top
     * activity in the system is from a different app, (2) the device is in sleep mode, or
     * (3) the keyguard shows up.
     */
    public static final int FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP = 1 << 3;

    /** @hide */
    @IntDef(prefix = {"FLAG_"}, flag = true, value = {
            FLAG_CANCEL_OVERRIDE_REQUESTS,
            FLAG_APP_INACCESSIBLE
            FLAG_APP_INACCESSIBLE,
            FLAG_EMULATED_ONLY,
            FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DeviceStateFlags {}
+65 −5
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.TaskStackListener;
import android.content.Context;
import android.hardware.devicestate.DeviceStateInfo;
import android.hardware.devicestate.DeviceStateManager;
@@ -176,6 +177,12 @@ public final class DeviceStateManagerService extends SystemService {
    @NonNull
    private final SystemPropertySetter mSystemPropertySetter;

    @VisibleForTesting
    TaskStackListener mOverrideRequestTaskStackListener = new OverrideRequestTaskStackListener();
    @VisibleForTesting
    ActivityTaskManagerInternal.ScreenObserver mOverrideRequestScreenObserver =
            new OverrideRequestScreenObserver();

    public DeviceStateManagerService(@NonNull Context context) {
        this(context, DeviceStatePolicy.Provider
                .fromResources(context.getResources())
@@ -215,6 +222,9 @@ public final class DeviceStateManagerService extends SystemService {
            readStatesAvailableForRequestFromApps();
            mFoldedDeviceStates = readFoldedStates();
        }

        mActivityTaskManagerInternal.registerTaskStackListener(mOverrideRequestTaskStackListener);
        mActivityTaskManagerInternal.registerScreenObserver(mOverrideRequestScreenObserver);
    }

    @VisibleForTesting
@@ -842,9 +852,7 @@ public final class DeviceStateManagerService extends SystemService {
     * @param state state that is being requested.
     */
    private void assertCanRequestDeviceState(int callingPid, int state) {
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        if (topApp == null || topApp.getPid() != callingPid
                || !isStateAvailableForAppRequests(state)) {
        if (!isTopApp(callingPid) || !isStateAvailableForAppRequests(state)) {
            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                    "Permission required to request device state, "
                            + "or the call must come from the top app "
@@ -859,14 +867,18 @@ public final class DeviceStateManagerService extends SystemService {
     * @param callingPid Process ID that is requesting this state change
     */
    private void assertCanControlDeviceState(int callingPid) {
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        if (topApp == null || topApp.getPid() != callingPid) {
        if (!isTopApp(callingPid)) {
            getContext().enforceCallingOrSelfPermission(CONTROL_DEVICE_STATE,
                    "Permission required to request device state, "
                            + "or the call must come from the top app.");
        }
    }

    private boolean isTopApp(int callingPid) {
        final WindowProcessController topApp = mActivityTaskManagerInternal.getTopApp();
        return topApp != null && topApp.getPid() == callingPid;
    }

    private boolean isStateAvailableForAppRequests(int state) {
        synchronized (mLock) {
            return mDeviceStatesAvailableForAppRequests.contains(state);
@@ -1185,4 +1197,52 @@ public final class DeviceStateManagerService extends SystemService {
            }
        }
    }

    @GuardedBy("mLock")
    private boolean shouldCancelOverrideRequestWhenRequesterNotOnTop() {
        if (mActiveOverride.isEmpty()) {
            return false;
        }
        int identifier = mActiveOverride.get().getRequestedState();
        DeviceState deviceState = mDeviceStates.get(identifier);
        return deviceState.hasFlag(DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP);
    }

    private class OverrideRequestTaskStackListener extends TaskStackListener {
        @Override
        public void onTaskStackChanged() throws RemoteException {
            synchronized (mLock) {
                if (!shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
                    return;
                }

                OverrideRequest request = mActiveOverride.get();
                if (!isTopApp(request.getPid())) {
                    mOverrideRequestController.cancelRequest(request);
                }
            }
        }
    }

    private class OverrideRequestScreenObserver implements
            ActivityTaskManagerInternal.ScreenObserver {

        @Override
        public void onAwakeStateChanged(boolean isAwake) {
            synchronized (mLock) {
                if (!isAwake && shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
                    mOverrideRequestController.cancelRequest(mActiveOverride.get());
                }
            }
        }

        @Override
        public void onKeyguardStateChanged(boolean isShowing) {
            synchronized (mLock) {
                if (isShowing && shouldCancelOverrideRequestWhenRequesterNotOnTop()) {
                    mOverrideRequestController.cancelRequest(mActiveOverride.get());
                }
            }
        }
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -97,6 +97,8 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
    private static final String FLAG_CANCEL_OVERRIDE_REQUESTS = "FLAG_CANCEL_OVERRIDE_REQUESTS";
    private static final String FLAG_APP_INACCESSIBLE = "FLAG_APP_INACCESSIBLE";
    private static final String FLAG_EMULATED_ONLY = "FLAG_EMULATED_ONLY";
    private static final String FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP =
            "FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP";

    /** Interface that allows reading the device state configuration. */
    interface ReadableConfig {
@@ -152,6 +154,10 @@ public final class DeviceStateProviderImpl implements DeviceStateProvider,
                                    break;
                                case FLAG_EMULATED_ONLY:
                                    flags |= DeviceState.FLAG_EMULATED_ONLY;
                                    break;
                                case FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP:
                                    flags |= DeviceState.FLAG_CANCEL_WHEN_REQUESTER_NOT_ON_TOP;
                                    break;
                                default:
                                    Slog.w(TAG, "Parsed unknown flag with name: "
                                            + configFlagString);
+7 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.app.ActivityManager;
import android.app.AppProtoEnums;
import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.ITaskStackListener;
import android.app.ProfilerInfo;
import android.content.ComponentName;
import android.content.IIntentSender;
@@ -739,4 +740,10 @@ public abstract class ActivityTaskManagerInternal {
     */
    public abstract void restartTaskActivityProcessIfVisible(
            int taskId, @NonNull String packageName);

    /** Sets the task stack listener that gets callbacks when a task stack changes. */
    public abstract void registerTaskStackListener(ITaskStackListener listener);

    /** Unregister a task stack listener so that it stops receiving callbacks. */;
    public abstract void unregisterTaskStackListener(ITaskStackListener listener);
}
+12 −0
Original line number Diff line number Diff line
@@ -6912,5 +6912,17 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
                activity.restartProcessIfVisible();
            }
        }

        /** Sets the task stack listener that gets callbacks when a task stack changes. */
        @Override
        public void registerTaskStackListener(ITaskStackListener listener) {
            ActivityTaskManagerService.this.registerTaskStackListener(listener);
        }

        /** Unregister a task stack listener so that it stops receiving callbacks. */
        @Override
        public void unregisterTaskStackListener(ITaskStackListener listener) {
            ActivityTaskManagerService.this.unregisterTaskStackListener(listener);
        }
    }
}
Loading