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_LID; 21 import static android.os.PowerManager.WAKE_REASON_GESTURE; 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.InputDevice.SOURCE_ROTARY_ENCODER; 26 import static android.view.InputDevice.SOURCE_TOUCHSCREEN; 27 import static android.view.KeyEvent.KEYCODE_HOME; 28 import static android.view.KeyEvent.KEYCODE_POWER; 29 import static android.view.KeyEvent.KEYCODE_STEM_PRIMARY; 30 31 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromKey; 32 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey; 33 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion; 34 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens; 35 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch; 36 import static com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture; 37 import static com.android.server.policy.Flags.FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE; 38 39 import static com.google.common.truth.Truth.assertThat; 40 import static com.google.common.truth.Truth.assertWithMessage; 41 42 import static org.mockito.ArgumentMatchers.anyBoolean; 43 import static org.mockito.ArgumentMatchers.anyInt; 44 import static org.mockito.ArgumentMatchers.anyLong; 45 import static org.mockito.ArgumentMatchers.anyString; 46 import static org.mockito.Mockito.never; 47 import static org.mockito.Mockito.spy; 48 import static org.mockito.Mockito.verify; 49 import static org.mockito.Mockito.when; 50 51 import android.content.Context; 52 import android.content.ContextWrapper; 53 import android.content.res.Resources; 54 import android.os.PowerManager; 55 import android.platform.test.flag.junit.SetFlagsRule; 56 import android.provider.Settings; 57 import android.view.Display; 58 import android.view.WindowManager; 59 60 import androidx.test.InstrumentationRegistry; 61 62 import com.android.internal.os.Clock; 63 import com.android.internal.util.test.FakeSettingsProvider; 64 import com.android.internal.util.test.FakeSettingsProviderRule; 65 import com.android.server.LocalServices; 66 67 import org.junit.Before; 68 import org.junit.Rule; 69 import org.junit.Test; 70 import org.mockito.Mock; 71 import org.mockito.Mockito; 72 import org.mockito.junit.MockitoJUnit; 73 import org.mockito.junit.MockitoRule; 74 75 import java.util.function.BooleanSupplier; 76 /** 77 * Test class for {@link WindowWakeUpPolicy}. 78 * 79 * <p>Build/Install/Run: atest WmTests:WindowWakeUpPolicyTests 80 */ 81 public final class WindowWakeUpPolicyTests { 82 @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule(); 83 @Rule public FakeSettingsProviderRule mSettingsProviderRule = FakeSettingsProvider.rule(); 84 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 85 86 @Mock PowerManager mPowerManager; 87 @Mock WindowManager mWindowManager; 88 @Mock Display mDefaultDisplay; 89 @Mock Clock mClock; 90 @Mock WindowWakeUpPolicyInternal.InputWakeUpDelegate mInputWakeUpDelegate; 91 92 private Context mContextSpy; 93 private Resources mResourcesSpy; 94 95 private WindowWakeUpPolicy mPolicy; 96 97 @Before setUp()98 public void setUp() { 99 mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext())); 100 mResourcesSpy = spy(mContextSpy.getResources()); 101 when(mContextSpy.getResources()).thenReturn(mResourcesSpy); 102 when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(mPowerManager); 103 when(mContextSpy.getSystemService(WindowManager.class)).thenReturn(mWindowManager); 104 when(mWindowManager.getDefaultDisplay()).thenReturn(mDefaultDisplay); 105 LocalServices.removeServiceForTest(WindowWakeUpPolicyInternal.class); 106 setDefaultDisplayState(Display.STATE_OFF); 107 } 108 109 @Test testSupportsInputWakeDelegatse_publishesLocalService()110 public void testSupportsInputWakeDelegatse_publishesLocalService() { 111 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 112 113 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 114 115 assertThat(LocalServices.getService(WindowWakeUpPolicyInternal.class)).isNotNull(); 116 } 117 118 @Test testDoesNotSupportInputWakeDelegatse_doesNotPublishLocalService()119 public void testDoesNotSupportInputWakeDelegatse_doesNotPublishLocalService() { 120 mSetFlagsRule.disableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 121 122 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 123 124 assertThat(LocalServices.getService(WindowWakeUpPolicyInternal.class)).isNull(); 125 } 126 127 @Test testMotionWakeUpDelegation_wakePowerManagerIfDelegateDoesNotHandleWake()128 public void testMotionWakeUpDelegation_wakePowerManagerIfDelegateDoesNotHandleWake() { 129 setTheaterModeEnabled(false); 130 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 131 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 132 LocalServices.getService(WindowWakeUpPolicyInternal.class) 133 .setInputWakeUpDelegate(mInputWakeUpDelegate); 134 135 setDelegatedMotionWakeUpResult(true); 136 137 // Verify the policy wake up call succeeds because of the call on the delegate, and not 138 // because of a PowerManager wake up. 139 assertThat(mPolicy.wakeUpFromMotion(200, SOURCE_TOUCHSCREEN, true)).isTrue(); 140 verify(mInputWakeUpDelegate).wakeUpFromMotion(200, SOURCE_TOUCHSCREEN, true); 141 verifyNoPowerManagerWakeUp(); 142 143 setDelegatedMotionWakeUpResult(false); 144 145 // Verify the policy wake up call succeeds because of the PowerManager wake up, since the 146 // delegate would not handle the wake up request. 147 assertThat(mPolicy.wakeUpFromMotion(300, SOURCE_ROTARY_ENCODER, false)).isTrue(); 148 verify(mInputWakeUpDelegate).wakeUpFromMotion(300, SOURCE_ROTARY_ENCODER, false); 149 verify(mPowerManager).wakeUp(300, WAKE_REASON_WAKE_MOTION, "android.policy:MOTION"); 150 } 151 152 @Test testKeyWakeUpDelegation_wakePowerManagerIfDelegateDoesNotHandleWake()153 public void testKeyWakeUpDelegation_wakePowerManagerIfDelegateDoesNotHandleWake() { 154 setTheaterModeEnabled(false); 155 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 156 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 157 LocalServices.getService(WindowWakeUpPolicyInternal.class) 158 .setInputWakeUpDelegate(mInputWakeUpDelegate); 159 160 setDelegatedKeyWakeUpResult(true); 161 162 // Verify the policy wake up call succeeds because of the call on the delegate, and not 163 // because of a PowerManager wake up. 164 assertThat(mPolicy.wakeUpFromKey(200, KEYCODE_POWER, true)).isTrue(); 165 verify(mInputWakeUpDelegate).wakeUpFromKey(200, KEYCODE_POWER, true); 166 verifyNoPowerManagerWakeUp(); 167 168 setDelegatedKeyWakeUpResult(false); 169 170 // Verify the policy wake up call succeeds because of the PowerManager wake up, since the 171 // delegate would not handle the wake up request. 172 assertThat(mPolicy.wakeUpFromKey(300, KEYCODE_STEM_PRIMARY, false)).isTrue(); 173 verify(mInputWakeUpDelegate).wakeUpFromKey(300, KEYCODE_STEM_PRIMARY, false); 174 verify(mPowerManager).wakeUp(300, WAKE_REASON_WAKE_KEY, "android.policy:KEY"); 175 } 176 177 @Test testDelegatedKeyWakeIsSubjectToPolicyChecks()178 public void testDelegatedKeyWakeIsSubjectToPolicyChecks() { 179 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 180 setDelegatedKeyWakeUpResult(true); 181 setTheaterModeEnabled(true); 182 setBooleanRes(config_allowTheaterModeWakeFromKey, false); 183 setBooleanRes(config_allowTheaterModeWakeFromPowerKey, false); 184 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 185 LocalServices.getService(WindowWakeUpPolicyInternal.class) 186 .setInputWakeUpDelegate(mInputWakeUpDelegate); 187 188 // Check that the wake up does not happen because the theater mode policy check fails. 189 assertThat(mPolicy.wakeUpFromKey(200, KEYCODE_POWER, true)).isFalse(); 190 verify(mInputWakeUpDelegate, never()).wakeUpFromKey(anyLong(), anyInt(), anyBoolean()); 191 } 192 193 @Test testDelegatedMotionWakeIsSubjectToPolicyChecks()194 public void testDelegatedMotionWakeIsSubjectToPolicyChecks() { 195 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 196 setDelegatedMotionWakeUpResult(true); 197 setTheaterModeEnabled(true); 198 setBooleanRes(config_allowTheaterModeWakeFromMotion, false); 199 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 200 LocalServices.getService(WindowWakeUpPolicyInternal.class) 201 .setInputWakeUpDelegate(mInputWakeUpDelegate); 202 203 // Check that the wake up does not happen because the theater mode policy check fails. 204 assertThat(mPolicy.wakeUpFromMotion(200, SOURCE_TOUCHSCREEN, true)).isFalse(); 205 verify(mInputWakeUpDelegate, never()).wakeUpFromMotion(anyLong(), anyInt(), anyBoolean()); 206 } 207 208 @Test testTheaterModeChecksNotAppliedWhenScreenIsOn()209 public void testTheaterModeChecksNotAppliedWhenScreenIsOn() { 210 mSetFlagsRule.enableFlags(FLAG_SUPPORT_INPUT_WAKEUP_DELEGATE); 211 setDefaultDisplayState(Display.STATE_ON); 212 setTheaterModeEnabled(true); 213 setBooleanRes(config_allowTheaterModeWakeFromMotion, false); 214 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 215 216 mPolicy.wakeUpFromMotion(200L, SOURCE_TOUCHSCREEN, true); 217 218 verify(mPowerManager).wakeUp(200L, WAKE_REASON_WAKE_MOTION, "android.policy:MOTION"); 219 } 220 221 @Test testWakeUpFromMotion()222 public void testWakeUpFromMotion() { 223 runPowerManagerUpChecks( 224 () -> mPolicy.wakeUpFromMotion(mClock.uptimeMillis(), SOURCE_TOUCHSCREEN, true), 225 config_allowTheaterModeWakeFromMotion, 226 WAKE_REASON_WAKE_MOTION, 227 "android.policy:MOTION"); 228 } 229 230 @Test testWakeUpFromKey_nonPowerKey()231 public void testWakeUpFromKey_nonPowerKey() { 232 runPowerManagerUpChecks( 233 () -> mPolicy.wakeUpFromKey(mClock.uptimeMillis(), KEYCODE_HOME, true), 234 config_allowTheaterModeWakeFromKey, 235 WAKE_REASON_WAKE_KEY, 236 "android.policy:KEY"); 237 } 238 239 @Test testWakeUpFromKey_powerKey()240 public void testWakeUpFromKey_powerKey() { 241 // Disable the resource affecting all wake keys because it affects power key as well. 242 // That way, power key wake during theater mode will solely be controlled by 243 // `config_allowTheaterModeWakeFromPowerKey` in the checks. 244 setBooleanRes(config_allowTheaterModeWakeFromKey, false); 245 246 // Test with power key 247 runPowerManagerUpChecks( 248 () -> mPolicy.wakeUpFromKey(mClock.uptimeMillis(), KEYCODE_POWER, true), 249 config_allowTheaterModeWakeFromPowerKey, 250 WAKE_REASON_POWER_BUTTON, 251 "android.policy:POWER"); 252 253 // Test that power key wake ups happen during theater mode as long as wake-keys are allowed 254 // even if the power-key specific theater mode config is disabled. 255 setBooleanRes(config_allowTheaterModeWakeFromPowerKey, false); 256 runPowerManagerUpChecks( 257 () -> mPolicy.wakeUpFromKey(mClock.uptimeMillis(), KEYCODE_POWER, false), 258 config_allowTheaterModeWakeFromKey, 259 WAKE_REASON_POWER_BUTTON, 260 "android.policy:POWER"); 261 } 262 263 @Test testWakeUpFromLid()264 public void testWakeUpFromLid() { 265 runPowerManagerUpChecks( 266 () -> mPolicy.wakeUpFromLid(), 267 config_allowTheaterModeWakeFromLidSwitch, 268 WAKE_REASON_LID, 269 "android.policy:LID"); 270 } 271 272 @Test testWakeUpFromWakeGesture()273 public void testWakeUpFromWakeGesture() { 274 runPowerManagerUpChecks( 275 () -> mPolicy.wakeUpFromWakeGesture(), 276 config_allowTheaterModeWakeFromGesture, 277 WAKE_REASON_GESTURE, 278 "android.policy:GESTURE"); 279 } 280 281 @Test testwakeUpFromCameraCover()282 public void testwakeUpFromCameraCover() { 283 runPowerManagerUpChecks( 284 () -> mPolicy.wakeUpFromCameraCover(mClock.uptimeMillis()), 285 config_allowTheaterModeWakeFromCameraLens, 286 WAKE_REASON_CAMERA_LAUNCH, 287 "android.policy:CAMERA_COVER"); 288 } 289 290 @Test testWakeUpFromPowerKeyCameraGesture()291 public void testWakeUpFromPowerKeyCameraGesture() { 292 // Disable the resource affecting all wake keys because it affects power key as well. 293 // That way, power key wake during theater mode will solely be controlled by 294 // `config_allowTheaterModeWakeFromPowerKey` in the checks. 295 setBooleanRes(config_allowTheaterModeWakeFromKey, false); 296 297 runPowerManagerUpChecks( 298 () -> mPolicy.wakeUpFromPowerKeyCameraGesture(), 299 config_allowTheaterModeWakeFromPowerKey, 300 WAKE_REASON_CAMERA_LAUNCH, 301 "android.policy:CAMERA_GESTURE_PREVENT_LOCK"); 302 } 303 runPowerManagerUpChecks( BooleanSupplier wakeUpCall, int theatherModeWakeResId, int expectedWakeReason, String expectedWakeDetails)304 private void runPowerManagerUpChecks( 305 BooleanSupplier wakeUpCall, 306 int theatherModeWakeResId, 307 int expectedWakeReason, 308 String expectedWakeDetails) { 309 // Test under theater mode enabled. 310 setTheaterModeEnabled(true); 311 312 Mockito.reset(mPowerManager); 313 setBooleanRes(theatherModeWakeResId, true); 314 LocalServices.removeServiceForTest(WindowWakeUpPolicyInternal.class); 315 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 316 setUptimeMillis(200); 317 assertWithMessage("Wake should happen in theater mode when config allows it.") 318 .that(wakeUpCall.getAsBoolean()).isTrue(); 319 verify(mPowerManager).wakeUp(200L, expectedWakeReason, expectedWakeDetails); 320 321 Mockito.reset(mPowerManager); 322 setBooleanRes(theatherModeWakeResId, false); 323 LocalServices.removeServiceForTest(WindowWakeUpPolicyInternal.class); 324 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 325 setUptimeMillis(250); 326 assertWithMessage("Wake should not happen in theater mode when config disallows it.") 327 .that(wakeUpCall.getAsBoolean()).isFalse(); 328 verifyNoPowerManagerWakeUp(); 329 330 // Cases when theater mode is disabled. 331 setTheaterModeEnabled(false); 332 333 Mockito.reset(mPowerManager); 334 setBooleanRes(theatherModeWakeResId, true); 335 LocalServices.removeServiceForTest(WindowWakeUpPolicyInternal.class); 336 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 337 setUptimeMillis(300); 338 assertWithMessage("Wake should happen when not in theater mode.") 339 .that(wakeUpCall.getAsBoolean()).isTrue(); 340 verify(mPowerManager).wakeUp(300L, expectedWakeReason, expectedWakeDetails); 341 342 Mockito.reset(mPowerManager); 343 setBooleanRes(theatherModeWakeResId, false); 344 LocalServices.removeServiceForTest(WindowWakeUpPolicyInternal.class); 345 mPolicy = new WindowWakeUpPolicy(mContextSpy, mClock); 346 setUptimeMillis(350); 347 assertWithMessage("Wake should happen when not in theater mode.") 348 .that(wakeUpCall.getAsBoolean()).isTrue(); 349 verify(mPowerManager).wakeUp(350L, expectedWakeReason, expectedWakeDetails); 350 } 351 verifyNoPowerManagerWakeUp()352 private void verifyNoPowerManagerWakeUp() { 353 verify(mPowerManager, never()).wakeUp(anyLong(), anyInt(), anyString()); 354 } 355 setBooleanRes(int resId, boolean val)356 private void setBooleanRes(int resId, boolean val) { 357 when(mResourcesSpy.getBoolean(resId)).thenReturn(val); 358 } 359 setUptimeMillis(long uptimeMillis)360 private void setUptimeMillis(long uptimeMillis) { 361 when(mClock.uptimeMillis()).thenReturn(uptimeMillis); 362 } 363 setTheaterModeEnabled(boolean enabled)364 private void setTheaterModeEnabled(boolean enabled) { 365 Settings.Global.putInt( 366 mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, enabled ? 1 : 0); 367 } 368 setDelegatedMotionWakeUpResult(boolean result)369 private void setDelegatedMotionWakeUpResult(boolean result) { 370 when(mInputWakeUpDelegate.wakeUpFromMotion(anyLong(), anyInt(), anyBoolean())) 371 .thenReturn(result); 372 } 373 setDelegatedKeyWakeUpResult(boolean result)374 private void setDelegatedKeyWakeUpResult(boolean result) { 375 when(mInputWakeUpDelegate.wakeUpFromKey(anyLong(), anyInt(), anyBoolean())) 376 .thenReturn(result); 377 } 378 setDefaultDisplayState(int displayState)379 private void setDefaultDisplayState(int displayState) { 380 when(mDefaultDisplay.getState()).thenReturn(displayState); 381 } 382 } 383