1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.policy; 18 19 import static android.os.PowerManager.WAKE_REASON_CAMERA_LAUNCH; 20 import static android.os.PowerManager.WAKE_REASON_GESTURE; 21 import static android.os.PowerManager.WAKE_REASON_LID; 22 import static android.os.PowerManager.WAKE_REASON_POWER_BUTTON; 23 import static android.os.PowerManager.WAKE_REASON_WAKE_KEY; 24 import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION; 25 import static android.view.KeyEvent.KEYCODE_POWER; 26 27 import static com.android.server.policy.Flags.supportInputWakeupDelegate; 28 29 import android.annotation.Nullable; 30 import android.content.Context; 31 import android.content.res.Resources; 32 import android.os.PowerManager; 33 import android.os.PowerManager.WakeReason; 34 import android.os.SystemClock; 35 import android.provider.Settings; 36 import android.util.Slog; 37 import android.view.Display; 38 import android.view.KeyEvent; 39 import android.view.WindowManager; 40 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.internal.os.Clock; 43 import com.android.server.LocalServices; 44 45 /** Policy controlling the decision and execution of window-related wake ups. */ 46 class WindowWakeUpPolicy { 47 private static final String TAG = "WindowWakeUpPolicy"; 48 49 private static final boolean DEBUG = false; 50 51 private final Context mContext; 52 private final PowerManager mPowerManager; 53 private final WindowManager mWindowManager; 54 private final Clock mClock; 55 56 private final boolean mAllowTheaterModeWakeFromKey; 57 private final boolean mAllowTheaterModeWakeFromPowerKey; 58 private final boolean mAllowTheaterModeWakeFromMotion; 59 private final boolean mAllowTheaterModeWakeFromCameraLens; 60 private final boolean mAllowTheaterModeWakeFromLidSwitch; 61 private final boolean mAllowTheaterModeWakeFromWakeGesture; 62 63 // The policy will handle input-based wake ups if this delegate is null. 64 @Nullable private WindowWakeUpPolicyInternal.InputWakeUpDelegate mInputWakeUpDelegate; 65 WindowWakeUpPolicy(Context context)66 WindowWakeUpPolicy(Context context) { 67 this(context, Clock.SYSTEM_CLOCK); 68 } 69 70 @VisibleForTesting WindowWakeUpPolicy(Context context, Clock clock)71 WindowWakeUpPolicy(Context context, Clock clock) { 72 mContext = context; 73 mPowerManager = context.getSystemService(PowerManager.class); 74 mWindowManager = context.getSystemService(WindowManager.class); 75 mClock = clock; 76 77 final Resources res = context.getResources(); 78 mAllowTheaterModeWakeFromKey = res.getBoolean( 79 com.android.internal.R.bool.config_allowTheaterModeWakeFromKey); 80 mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey 81 || res.getBoolean( 82 com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey); 83 mAllowTheaterModeWakeFromMotion = res.getBoolean( 84 com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion); 85 mAllowTheaterModeWakeFromCameraLens = res.getBoolean( 86 com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens); 87 mAllowTheaterModeWakeFromLidSwitch = res.getBoolean( 88 com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch); 89 mAllowTheaterModeWakeFromWakeGesture = res.getBoolean( 90 com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture); 91 if (supportInputWakeupDelegate()) { 92 LocalServices.addService(WindowWakeUpPolicyInternal.class, new LocalService()); 93 } 94 } 95 96 private final class LocalService implements WindowWakeUpPolicyInternal { 97 @Override setInputWakeUpDelegate(@ullable InputWakeUpDelegate delegate)98 public void setInputWakeUpDelegate(@Nullable InputWakeUpDelegate delegate) { 99 if (!supportInputWakeupDelegate()) { 100 Slog.w(TAG, "Input wake up delegates not supported."); 101 return; 102 } 103 mInputWakeUpDelegate = delegate; 104 } 105 } 106 107 /** 108 * Wakes up from a key event. 109 * 110 * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}. 111 * @param keyCode the {@link android.view.KeyEvent} key code of the key event. 112 * @param isDown {@code true} if the event's action is {@link KeyEvent#ACTION_DOWN}. 113 * @return {@code true} if the policy allows the requested wake up and the request has been 114 * executed; {@code false} otherwise. 115 */ wakeUpFromKey(long eventTime, int keyCode, boolean isDown)116 boolean wakeUpFromKey(long eventTime, int keyCode, boolean isDown) { 117 final boolean wakeAllowedDuringTheaterMode = 118 keyCode == KEYCODE_POWER 119 ? mAllowTheaterModeWakeFromPowerKey 120 : mAllowTheaterModeWakeFromKey; 121 if (!canWakeUp(wakeAllowedDuringTheaterMode)) { 122 if (DEBUG) Slog.d(TAG, "Unable to wake up from " + KeyEvent.keyCodeToString(keyCode)); 123 return false; 124 } 125 if (mInputWakeUpDelegate != null 126 && mInputWakeUpDelegate.wakeUpFromKey(eventTime, keyCode, isDown)) { 127 return true; 128 } 129 wakeUp( 130 eventTime, 131 keyCode == KEYCODE_POWER ? WAKE_REASON_POWER_BUTTON : WAKE_REASON_WAKE_KEY, 132 keyCode == KEYCODE_POWER ? "POWER" : "KEY"); 133 return true; 134 } 135 136 /** 137 * Wakes up from a motion event. 138 * 139 * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}. 140 * @param isDown {@code true} if the event's action is {@link MotionEvent#ACTION_DOWN}. 141 * @return {@code true} if the policy allows the requested wake up and the request has been 142 * executed; {@code false} otherwise. 143 */ wakeUpFromMotion(long eventTime, int source, boolean isDown)144 boolean wakeUpFromMotion(long eventTime, int source, boolean isDown) { 145 if (!canWakeUp(mAllowTheaterModeWakeFromMotion)) { 146 if (DEBUG) Slog.d(TAG, "Unable to wake up from motion."); 147 return false; 148 } 149 if (mInputWakeUpDelegate != null 150 && mInputWakeUpDelegate.wakeUpFromMotion(eventTime, source, isDown)) { 151 return true; 152 } 153 wakeUp(eventTime, WAKE_REASON_WAKE_MOTION, "MOTION"); 154 return true; 155 } 156 157 /** 158 * Wakes up due to an opened camera cover. 159 * 160 * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}. 161 * @return {@code true} if the policy allows the requested wake up and the request has been 162 * executed; {@code false} otherwise. 163 */ wakeUpFromCameraCover(long eventTime)164 boolean wakeUpFromCameraCover(long eventTime) { 165 if (!canWakeUp(mAllowTheaterModeWakeFromCameraLens)) { 166 if (DEBUG) Slog.d(TAG, "Unable to wake up from camera cover."); 167 return false; 168 } 169 wakeUp(eventTime, WAKE_REASON_CAMERA_LAUNCH, "CAMERA_COVER"); 170 return true; 171 } 172 173 /** 174 * Wakes up due to an opened lid. 175 * 176 * @return {@code true} if the policy allows the requested wake up and the request has been 177 * executed; {@code false} otherwise. 178 */ wakeUpFromLid()179 boolean wakeUpFromLid() { 180 if (!canWakeUp(mAllowTheaterModeWakeFromLidSwitch)) { 181 if (DEBUG) Slog.d(TAG, "Unable to wake up from lid."); 182 return false; 183 } 184 wakeUp(mClock.uptimeMillis(), WAKE_REASON_LID, "LID"); 185 return true; 186 } 187 188 /** 189 * Wakes up to prevent sleeping when opening camera through power button. 190 * 191 * @return {@code true} if the policy allows the requested wake up and the request has been 192 * executed; {@code false} otherwise. 193 */ wakeUpFromPowerKeyCameraGesture()194 boolean wakeUpFromPowerKeyCameraGesture() { 195 if (!canWakeUp(mAllowTheaterModeWakeFromPowerKey)) { 196 if (DEBUG) Slog.d(TAG, "Unable to wake up from power key camera gesture."); 197 return false; 198 } 199 wakeUp(mClock.uptimeMillis(), WAKE_REASON_CAMERA_LAUNCH, "CAMERA_GESTURE_PREVENT_LOCK"); 200 return true; 201 } 202 203 /** 204 * Wake up from a wake gesture. 205 * 206 * @return {@code true} if the policy allows the requested wake up and the request has been 207 * executed; {@code false} otherwise. 208 */ wakeUpFromWakeGesture()209 boolean wakeUpFromWakeGesture() { 210 if (!canWakeUp(mAllowTheaterModeWakeFromWakeGesture)) { 211 if (DEBUG) Slog.d(TAG, "Unable to wake up from gesture."); 212 return false; 213 } 214 wakeUp(mClock.uptimeMillis(), WAKE_REASON_GESTURE, "GESTURE"); 215 return true; 216 } 217 canWakeUp(boolean wakeInTheaterMode)218 private boolean canWakeUp(boolean wakeInTheaterMode) { 219 if (supportInputWakeupDelegate() && isDefaultDisplayOn()) { 220 // If the default display is on, theater mode should not influence whether or not 221 // waking up is allowed. This is because the theater mode checks are there to block 222 // the display from being on in situations where the user may not want it to be 223 // on (so if the display is already on, no need to check for theater mode at all). 224 return true; 225 } 226 final boolean isTheaterModeEnabled = 227 Settings.Global.getInt( 228 mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0) == 1; 229 return wakeInTheaterMode || !isTheaterModeEnabled; 230 } 231 isDefaultDisplayOn()232 private boolean isDefaultDisplayOn() { 233 return Display.isOnState(mWindowManager.getDefaultDisplay().getState()); 234 } 235 236 /** Wakes up {@link PowerManager}. */ wakeUp(long wakeTime, @WakeReason int reason, String details)237 private void wakeUp(long wakeTime, @WakeReason int reason, String details) { 238 mPowerManager.wakeUp(wakeTime, reason, "android.policy:" + details); 239 } 240 } 241