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

Commit c3b973d9 authored by Yeabkal Wubshit's avatar Yeabkal Wubshit
Browse files

Allow input wake up delegation

This change allows system server components to inject a delegate that
controls wake up requests generated from input events. As part of this,
the WindowWakeUpPolicy is published as a system server local service.

Bug: 317432315
Test: atest WindowWakeUpPolicyTests

Change-Id: If8e65e045cc8aa64589ae050b1c364b641d15b21
parent f41e1e48
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ java_library_static {
        "com_android_wm_shell_flags_lib",
        "com.android.server.utils_aconfig-java",
        "service-jobscheduler-deviceidle.flags-aconfig-java",
        "policy_flags_lib",
    ],
    javac_shard_size: 50,
    javacflags: [
+10 −0
Original line number Diff line number Diff line
aconfig_declarations {
    name: "policy_flags",
    package: "com.android.server.policy",
    srcs: ["*.aconfig"],
}

java_aconfig_library {
    name: "policy_flags_lib",
    aconfig_declarations: "policy_flags",
}
+12 −7
Original line number Diff line number Diff line
@@ -1301,7 +1301,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    Settings.Global.putInt(mContext.getContentResolver(),
                            Settings.Global.THEATER_MODE_ON, 0);
                    if (!interactive) {
                        wakeUpFromWakeKey(eventTime, KEYCODE_POWER);
                        wakeUpFromWakeKey(eventTime, KEYCODE_POWER, /* isDown= */ false);
                    }
                } else {
                    Slog.i(TAG, "Toggling theater mode on.");
@@ -1317,7 +1317,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
                Slog.i(TAG, "Starting brightness boost.");
                if (!interactive) {
                    wakeUpFromWakeKey(eventTime, KEYCODE_POWER);
                    wakeUpFromWakeKey(eventTime, KEYCODE_POWER, /* isDown= */ false);
                }
                mPowerManager.boostScreenBrightness(eventTime);
                break;
@@ -5185,7 +5185,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    public int interceptMotionBeforeQueueingNonInteractive(int displayId, int source, int action,
            long whenNanos, int policyFlags) {
        if ((policyFlags & FLAG_WAKE) != 0) {
            if (mWindowWakeUpPolicy.wakeUpFromMotion(whenNanos / 1000000)) {
            if (mWindowWakeUpPolicy.wakeUpFromMotion(
                        whenNanos / 1000000, source, action == MotionEvent.ACTION_DOWN)) {
                // Woke up. Pass motion events to user.
                return ACTION_PASS_TO_USER;
            }
@@ -5199,7 +5200,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        // there will be no dream to intercept the touch and wake into ambient.  The device should
        // wake up in this case.
        if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
            if (mWindowWakeUpPolicy.wakeUpFromMotion(whenNanos / 1000000)) {
            if (mWindowWakeUpPolicy.wakeUpFromMotion(
                        whenNanos / 1000000, source, action == MotionEvent.ACTION_DOWN)) {
                // Woke up. Pass motion events to user.
                return ACTION_PASS_TO_USER;
            }
@@ -5534,11 +5536,14 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    }

    private void wakeUpFromWakeKey(KeyEvent event) {
        wakeUpFromWakeKey(event.getEventTime(), event.getKeyCode());
        wakeUpFromWakeKey(
                event.getEventTime(),
                event.getKeyCode(),
                event.getAction() == KeyEvent.ACTION_DOWN);
    }

    private void wakeUpFromWakeKey(long eventTime, int keyCode) {
        if (mWindowWakeUpPolicy.wakeUpFromKey(eventTime, keyCode)) {
    private void wakeUpFromWakeKey(long eventTime, int keyCode, boolean isDown) {
        if (mWindowWakeUpPolicy.wakeUpFromKey(eventTime, keyCode, isDown)) {
            final boolean keyCanLaunchHome = keyCode == KEYCODE_HOME || keyCode == KEYCODE_POWER;
            // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
            if (shouldWakeUpWithHomeIntent() &&  keyCanLaunchHome) {
+85 −36
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import static android.os.PowerManager.WAKE_REASON_WAKE_KEY;
import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION;
import static android.view.KeyEvent.KEYCODE_POWER;

import static com.android.server.policy.Flags.supportInputWakeupDelegate;

import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.os.PowerManager;
@@ -31,7 +34,11 @@ import android.os.PowerManager.WakeReason;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Slog;
import android.view.KeyEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.Clock;
import com.android.server.LocalServices;

/** Policy controlling the decision and execution of window-related wake ups. */
class WindowWakeUpPolicy {
@@ -41,18 +48,27 @@ class WindowWakeUpPolicy {

    private final Context mContext;
    private final PowerManager mPowerManager;
    private final Clock mClock;

    private final boolean mAllowTheaterModeWakeFromKey;
    private final boolean mAllowTheaterModeWakeFromPowerKey;
    private final boolean mAllowTheaterModeWakeFromMotion;
    private final boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming;
    private final boolean mAllowTheaterModeWakeFromCameraLens;
    private final boolean mAllowTheaterModeWakeFromLidSwitch;
    private final boolean mAllowTheaterModeWakeFromWakeGesture;

    // The policy will handle input-based wake ups if this delegate is null.
    @Nullable private WindowWakeUpPolicyInternal.InputWakeUpDelegate mInputWakeUpDelegate;

    WindowWakeUpPolicy(Context context) {
        this(context, Clock.SYSTEM_CLOCK);
    }

    @VisibleForTesting
    WindowWakeUpPolicy(Context context, Clock clock) {
        mContext = context;
        mPowerManager = context.getSystemService(PowerManager.class);
        mClock = clock;

        final Resources res = context.getResources();
        mAllowTheaterModeWakeFromKey = res.getBoolean(
@@ -62,14 +78,26 @@ class WindowWakeUpPolicy {
                    com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
        mAllowTheaterModeWakeFromMotion = res.getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
        mAllowTheaterModeWakeFromMotionWhenNotDreaming = res.getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming);
        mAllowTheaterModeWakeFromCameraLens = res.getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
        mAllowTheaterModeWakeFromLidSwitch = res.getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
        mAllowTheaterModeWakeFromWakeGesture = res.getBoolean(
                com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
        if (supportInputWakeupDelegate()) {
            LocalServices.addService(WindowWakeUpPolicyInternal.class, new LocalService());
        }
    }

    private final class LocalService implements WindowWakeUpPolicyInternal {
        @Override
        public void setInputWakeUpDelegate(@Nullable InputWakeUpDelegate delegate) {
            if (!supportInputWakeupDelegate()) {
                Slog.w(TAG, "Input wake up delegates not supported.");
                return;
            }
            mInputWakeUpDelegate = delegate;
        }
    }

    /**
@@ -77,31 +105,49 @@ class WindowWakeUpPolicy {
     *
     * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
     * @param keyCode the {@link android.view.KeyEvent} key code of the key event.
     * @param isDown {@code true} if the event's action is {@link KeyEvent#ACTION_DOWN}.
     * @return {@code true} if the policy allows the requested wake up and the request has been
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromKey(long eventTime, int keyCode) {
    boolean wakeUpFromKey(long eventTime, int keyCode, boolean isDown) {
        final boolean wakeAllowedDuringTheaterMode =
                keyCode == KEYCODE_POWER
                        ? mAllowTheaterModeWakeFromPowerKey
                        : mAllowTheaterModeWakeFromKey;
        return wakeUp(
        if (!canWakeUp(wakeAllowedDuringTheaterMode)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from " + KeyEvent.keyCodeToString(keyCode));
            return false;
        }
        if (mInputWakeUpDelegate != null
                && mInputWakeUpDelegate.wakeUpFromKey(eventTime, keyCode, isDown)) {
            return true;
        }
        wakeUp(
                eventTime,
                wakeAllowedDuringTheaterMode,
                keyCode == KEYCODE_POWER ? WAKE_REASON_POWER_BUTTON : WAKE_REASON_WAKE_KEY,
                keyCode == KEYCODE_POWER ? "POWER" : "KEY");
        return true;
    }

    /**
     * Wakes up from a motion event.
     *
     * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
     * @param isDown {@code true} if the event's action is {@link MotionEvent#ACTION_DOWN}.
     * @return {@code true} if the policy allows the requested wake up and the request has been
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromMotion(long eventTime) {
        return wakeUp(
                eventTime, mAllowTheaterModeWakeFromMotion, WAKE_REASON_WAKE_MOTION, "MOTION");
    boolean wakeUpFromMotion(long eventTime, int source, boolean isDown) {
        if (!canWakeUp(mAllowTheaterModeWakeFromMotion)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from motion.");
            return false;
        }
        if (mInputWakeUpDelegate != null
                && mInputWakeUpDelegate.wakeUpFromMotion(eventTime, source, isDown)) {
            return true;
        }
        wakeUp(eventTime, WAKE_REASON_WAKE_MOTION, "MOTION");
        return true;
    }

    /**
@@ -112,11 +158,12 @@ class WindowWakeUpPolicy {
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromCameraCover(long eventTime) {
        return wakeUp(
                eventTime,
                mAllowTheaterModeWakeFromCameraLens,
                WAKE_REASON_CAMERA_LAUNCH,
                "CAMERA_COVER");
        if (!canWakeUp(mAllowTheaterModeWakeFromCameraLens)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from camera cover.");
            return false;
        }
        wakeUp(eventTime, WAKE_REASON_CAMERA_LAUNCH, "CAMERA_COVER");
        return true;
    }

    /**
@@ -126,11 +173,12 @@ class WindowWakeUpPolicy {
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromLid() {
        return wakeUp(
                SystemClock.uptimeMillis(),
                mAllowTheaterModeWakeFromLidSwitch,
                WAKE_REASON_LID,
                "LID");
        if (!canWakeUp(mAllowTheaterModeWakeFromLidSwitch)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from lid.");
            return false;
        }
        wakeUp(mClock.uptimeMillis(), WAKE_REASON_LID, "LID");
        return true;
    }

    /**
@@ -140,11 +188,12 @@ class WindowWakeUpPolicy {
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromPowerKeyCameraGesture() {
        return wakeUp(
                SystemClock.uptimeMillis(),
                mAllowTheaterModeWakeFromPowerKey,
                WAKE_REASON_CAMERA_LAUNCH,
                "CAMERA_GESTURE_PREVENT_LOCK");
        if (!canWakeUp(mAllowTheaterModeWakeFromPowerKey)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from power key camera gesture.");
            return false;
        }
        wakeUp(mClock.uptimeMillis(), WAKE_REASON_CAMERA_LAUNCH, "CAMERA_GESTURE_PREVENT_LOCK");
        return true;
    }

    /**
@@ -154,23 +203,23 @@ class WindowWakeUpPolicy {
     *      executed; {@code false} otherwise.
     */
    boolean wakeUpFromWakeGesture() {
        return wakeUp(
                SystemClock.uptimeMillis(),
                mAllowTheaterModeWakeFromWakeGesture,
                WAKE_REASON_GESTURE,
                "GESTURE");
        if (!canWakeUp(mAllowTheaterModeWakeFromWakeGesture)) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from gesture.");
            return false;
        }
        wakeUp(mClock.uptimeMillis(), WAKE_REASON_GESTURE, "GESTURE");
        return true;
    }

    private boolean wakeUp(
            long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason, String details) {
    private boolean canWakeUp(boolean wakeInTheaterMode) {
        final boolean isTheaterModeEnabled =
                Settings.Global.getInt(
                        mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0) == 1;
        if (!wakeInTheaterMode && isTheaterModeEnabled) {
            if (DEBUG) Slog.d(TAG, "Unable to wake up from " + details);
            return false;
        return wakeInTheaterMode || !isTheaterModeEnabled;
    }

    /** Wakes up {@link PowerManager}. */
    private void wakeUp(long wakeTime, @WakeReason int reason, String details) {
        mPowerManager.wakeUp(wakeTime, reason, "android.policy:" + details);
        return true;
    }
}
+75 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.android.server.policy;

import android.annotation.Nullable;
import android.os.SystemClock;

import com.android.internal.annotations.Keep;
import com.android.server.LocalServices;

/** Policy controlling the decision and execution of window-related wake ups. */
@Keep
public interface WindowWakeUpPolicyInternal {

    /**
     * A delegate that can choose to intercept Input-related wake ups.
     *
     * <p>This delegate is not meant to control policy decisions on whether or not to wake up. The
     * policy makes that decision, and forwards the wake up request to the delegate as necessary.
     * Therefore, the role of the delegate is to handle the actual "waking" of the device in
     * response to the respective input event.
     */
    @Keep
    interface InputWakeUpDelegate {
        /**
         * Wakes up the device in response to a key event.
         *
         * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
         * @param keyCode the {@link android.view.KeyEvent} key code of the key event.
         * @param isDown {@code true} if the event's action is {@link KeyEvent#ACTION_DOWN}.
         * @return {@code true} if the delegate handled the wake up. {@code false} if the delegate
         *      decided not to handle the wake up. The policy will execute the wake up in this case.
         */
        boolean wakeUpFromKey(long eventTime, int keyCode, boolean isDown);
        /**
         * Wakes up the device in response to a motion event.
         *
         * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
         * @param source the {@link android.view.InputDevice} source that caused the event.
         * @param isDown {@code true} if the event's action is {@link MotionEvent#ACTION_DOWN}.
         * @return {@code true} if the delegate handled the wake up. {@code false} if the delegate
         *      decided not to handle the wake up. The policy will execute the wake up in this case.
         */
        boolean wakeUpFromMotion(long eventTime, int source, boolean isDown);
    }

    /**
     * Allows injecting a delegate for controlling input-based wake ups.
     *
     * <p>A delegate can be injected to the policy by system_server components only, and should be
     * done via the {@link LocalServices} interface.
     *
     * <p>There can at most be one active delegate. If there's no delegate set (or if a {@code null}
     * delegate is set), the policy will handle waking up the device in response to input events.
     *
     * @param delegate an implementation of {@link InputWakeUpDelegate} that handles input-based
     *      wake up requests. {@code null} to let the policy handle these wake ups.
     */
    @Keep
    void setInputWakeUpDelegate(@Nullable InputWakeUpDelegate delegate);
}
Loading