1 /* 2 * Copyright (C) 2014 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.systemui.statusbar.phone; 18 19 import android.content.ContentResolver; 20 import android.content.Context; 21 import android.content.res.Configuration; 22 import android.content.res.Resources; 23 import android.database.ContentObserver; 24 import android.hardware.display.AmbientDisplayConfiguration; 25 import android.net.Uri; 26 import android.os.Handler; 27 import android.os.PowerManager; 28 import android.os.SystemProperties; 29 import android.os.UserHandle; 30 import android.provider.Settings; 31 import android.util.Log; 32 import android.util.MathUtils; 33 34 import androidx.annotation.NonNull; 35 import androidx.annotation.VisibleForTesting; 36 37 import com.android.keyguard.KeyguardUpdateMonitor; 38 import com.android.keyguard.KeyguardUpdateMonitorCallback; 39 import com.android.systemui.Dumpable; 40 import com.android.systemui.Flags; 41 import com.android.systemui.dagger.SysUISingleton; 42 import com.android.systemui.dagger.qualifiers.Background; 43 import com.android.systemui.dagger.qualifiers.Main; 44 import com.android.systemui.doze.AlwaysOnDisplayPolicy; 45 import com.android.systemui.doze.DozeScreenState; 46 import com.android.systemui.dump.DumpManager; 47 import com.android.systemui.keyguard.domain.interactor.DozeInteractor; 48 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor; 49 import com.android.systemui.keyguard.shared.model.KeyguardState; 50 import com.android.systemui.plugins.statusbar.StatusBarStateController; 51 import com.android.systemui.res.R; 52 import com.android.systemui.settings.UserTracker; 53 import com.android.systemui.statusbar.policy.BatteryController; 54 import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; 55 import com.android.systemui.statusbar.policy.ConfigurationController; 56 import com.android.systemui.statusbar.policy.DevicePostureController; 57 import com.android.systemui.tuner.TunerService; 58 import com.android.systemui.unfold.FoldAodAnimationController; 59 import com.android.systemui.unfold.SysUIUnfoldComponent; 60 import com.android.systemui.util.settings.SecureSettings; 61 62 import java.io.PrintWriter; 63 import java.util.Optional; 64 65 import javax.inject.Inject; 66 67 /** 68 * Retrieve doze information 69 */ 70 @SysUISingleton 71 public class DozeParameters implements 72 TunerService.Tunable, 73 com.android.systemui.plugins.statusbar.DozeParameters, 74 Dumpable, ConfigurationController.ConfigurationListener, 75 StatusBarStateController.StateListener, FoldAodAnimationController.FoldAodAnimationStatus { 76 private static final int MAX_DURATION = 60 * 1000; 77 public static final boolean FORCE_NO_BLANKING = 78 SystemProperties.getBoolean("debug.force_no_blanking", false); 79 public static final boolean FORCE_BLANKING = 80 SystemProperties.getBoolean("debug.force_blanking", false); 81 82 private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; 83 private final PowerManager mPowerManager; 84 85 private final AlwaysOnDisplayPolicy mAlwaysOnPolicy; 86 private final Resources mResources; 87 private final BatteryController mBatteryController; 88 private final ScreenOffAnimationController mScreenOffAnimationController; 89 private final DozeInteractor mDozeInteractor; 90 private final KeyguardTransitionInteractor mTransitionInteractor; 91 private final FoldAodAnimationController mFoldAodAnimationController; 92 private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; 93 private final UserTracker mUserTracker; 94 private final SecureSettings mSecureSettings; 95 96 private boolean mDozeAlwaysOn; 97 private boolean mControlScreenOffAnimation; 98 private boolean mIsQuickPickupEnabled; 99 100 private boolean mKeyguardVisible; 101 @VisibleForTesting 102 final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback = 103 new KeyguardUpdateMonitorCallback() { 104 @Override 105 public void onKeyguardVisibilityChanged(boolean visible) { 106 mKeyguardVisible = visible; 107 updateControlScreenOff(); 108 } 109 110 @Override 111 public void onShadeExpandedChanged(boolean expanded) { 112 updateControlScreenOff(); 113 } 114 115 @Override 116 public void onUserSwitchComplete(int newUserId) { 117 updateQuickPickupEnabled(); 118 } 119 }; 120 121 @Inject DozeParameters( Context context, @Background Handler handler, @Main Resources resources, AmbientDisplayConfiguration ambientDisplayConfiguration, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, PowerManager powerManager, BatteryController batteryController, TunerService tunerService, DumpManager dumpManager, ScreenOffAnimationController screenOffAnimationController, Optional<SysUIUnfoldComponent> sysUiUnfoldComponent, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, KeyguardUpdateMonitor keyguardUpdateMonitor, ConfigurationController configurationController, StatusBarStateController statusBarStateController, UserTracker userTracker, DozeInteractor dozeInteractor, KeyguardTransitionInteractor transitionInteractor, SecureSettings secureSettings)122 protected DozeParameters( 123 Context context, 124 @Background Handler handler, 125 @Main Resources resources, 126 AmbientDisplayConfiguration ambientDisplayConfiguration, 127 AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, 128 PowerManager powerManager, 129 BatteryController batteryController, 130 TunerService tunerService, 131 DumpManager dumpManager, 132 ScreenOffAnimationController screenOffAnimationController, 133 Optional<SysUIUnfoldComponent> sysUiUnfoldComponent, 134 UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, 135 KeyguardUpdateMonitor keyguardUpdateMonitor, 136 ConfigurationController configurationController, 137 StatusBarStateController statusBarStateController, 138 UserTracker userTracker, 139 DozeInteractor dozeInteractor, 140 KeyguardTransitionInteractor transitionInteractor, 141 SecureSettings secureSettings) { 142 mResources = resources; 143 mAmbientDisplayConfiguration = ambientDisplayConfiguration; 144 mAlwaysOnPolicy = alwaysOnDisplayPolicy; 145 mBatteryController = batteryController; 146 dumpManager.registerDumpable("DozeParameters", this); 147 148 mControlScreenOffAnimation = !getDisplayNeedsBlanking(); 149 mPowerManager = powerManager; 150 mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation); 151 mScreenOffAnimationController = screenOffAnimationController; 152 mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; 153 mUserTracker = userTracker; 154 mDozeInteractor = dozeInteractor; 155 mTransitionInteractor = transitionInteractor; 156 mSecureSettings = secureSettings; 157 158 keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); 159 tunerService.addTunable( 160 this, 161 Settings.Secure.DOZE_ALWAYS_ON, 162 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); 163 configurationController.addCallback(this); 164 statusBarStateController.addCallback(this); 165 166 mFoldAodAnimationController = sysUiUnfoldComponent 167 .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null); 168 169 if (mFoldAodAnimationController != null) { 170 mFoldAodAnimationController.addCallback(this); 171 } 172 173 SettingsObserver quickPickupSettingsObserver = 174 new SettingsObserver(context, handler, mSecureSettings); 175 quickPickupSettingsObserver.observe(); 176 177 batteryController.addCallback(new BatteryStateChangeCallback() { 178 @Override 179 public void onPowerSaveChanged(boolean isPowerSave) { 180 dispatchAlwaysOnEvent(); 181 } 182 }); 183 } 184 updateQuickPickupEnabled()185 private void updateQuickPickupEnabled() { 186 mIsQuickPickupEnabled = 187 mAmbientDisplayConfiguration.quickPickupSensorEnabled(mUserTracker.getUserId()); 188 } 189 getDisplayStateSupported()190 public boolean getDisplayStateSupported() { 191 return getBoolean("doze.display.supported", R.bool.doze_display_state_supported); 192 } 193 getDozeSuspendDisplayStateSupported()194 public boolean getDozeSuspendDisplayStateSupported() { 195 return mResources.getBoolean(R.bool.doze_suspend_display_state_supported); 196 } 197 getPulseDuration()198 public int getPulseDuration() { 199 return getPulseInDuration() + getPulseVisibleDuration() + getPulseOutDuration(); 200 } 201 getScreenBrightnessDoze()202 public float getScreenBrightnessDoze() { 203 return mResources.getInteger( 204 com.android.internal.R.integer.config_screenBrightnessDoze) / 255f; 205 } 206 getPulseInDuration()207 public int getPulseInDuration() { 208 return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in); 209 } 210 getPulseVisibleDuration()211 public int getPulseVisibleDuration() { 212 return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible); 213 } 214 getPulseOutDuration()215 public int getPulseOutDuration() { 216 return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out); 217 } 218 getPulseOnSigMotion()219 public boolean getPulseOnSigMotion() { 220 return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion); 221 } 222 getVibrateOnSigMotion()223 public boolean getVibrateOnSigMotion() { 224 return SystemProperties.getBoolean("doze.vibrate.sigmotion", false); 225 } 226 getVibrateOnPickup()227 public boolean getVibrateOnPickup() { 228 return SystemProperties.getBoolean("doze.vibrate.pickup", false); 229 } 230 getProxCheckBeforePulse()231 public boolean getProxCheckBeforePulse() { 232 return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse); 233 } 234 235 /** 236 * @return true if we should only register for sensors that use the proximity sensor when the 237 * display state is {@link android.view.Display.STATE_OFF}, 238 * {@link android.view.Display.STATE_DOZE} or {@link android.view.Display.STATE_DOZE_SUSPEND} 239 */ getSelectivelyRegisterSensorsUsingProx()240 public boolean getSelectivelyRegisterSensorsUsingProx() { 241 return getBoolean("doze.prox.selectively_register", 242 R.bool.doze_selectively_register_prox); 243 } 244 getPickupVibrationThreshold()245 public int getPickupVibrationThreshold() { 246 return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold); 247 } 248 getQuickPickupAodDuration()249 public int getQuickPickupAodDuration() { 250 return getInt("doze.gesture.quickpickup.duration", 251 R.integer.doze_quick_pickup_aod_duration); 252 } 253 254 /** 255 * For how long a wallpaper can be visible in AoD before it fades aways. 256 * @return duration in millis. 257 */ getWallpaperAodDuration()258 public long getWallpaperAodDuration() { 259 if (shouldControlScreenOff()) { 260 return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY; 261 } 262 return mAlwaysOnPolicy.wallpaperVisibilityDuration; 263 } 264 265 /** 266 * How long it takes for the wallpaper fade away (Animation duration.) 267 * @return duration in millis. 268 */ getWallpaperFadeOutDuration()269 public long getWallpaperFadeOutDuration() { 270 return mAlwaysOnPolicy.wallpaperFadeOutDuration; 271 } 272 273 /** 274 * Checks if always on is available and enabled for the current user. 275 * @return {@code true} if enabled and available. 276 */ getAlwaysOn()277 public boolean getAlwaysOn() { 278 return mDozeAlwaysOn && !mBatteryController.isAodPowerSave(); 279 } 280 281 /** 282 * Whether the quick pickup gesture is supported and enabled for the device. 283 */ isQuickPickupEnabled()284 public boolean isQuickPickupEnabled() { 285 return mIsQuickPickupEnabled; 286 } 287 288 /** 289 * Some screens need to be completely black before changing the display power mode, 290 * unexpected behavior might happen if this parameter isn't respected. 291 * 292 * @return {@code true} if screen needs to be completely black before a power transition. 293 */ getDisplayNeedsBlanking()294 public boolean getDisplayNeedsBlanking() { 295 return FORCE_BLANKING || !FORCE_NO_BLANKING && mResources.getBoolean( 296 com.android.internal.R.bool.config_displayBlanksAfterDoze); 297 } 298 shouldControlScreenOff()299 public boolean shouldControlScreenOff() { 300 return mControlScreenOffAnimation; 301 } 302 setControlScreenOffAnimation(boolean controlScreenOffAnimation)303 public void setControlScreenOffAnimation(boolean controlScreenOffAnimation) { 304 if (mControlScreenOffAnimation == controlScreenOffAnimation) { 305 return; 306 } 307 mControlScreenOffAnimation = controlScreenOffAnimation; 308 mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation); 309 } 310 updateControlScreenOff()311 public void updateControlScreenOff() { 312 if (!getDisplayNeedsBlanking()) { 313 final boolean controlScreenOff = 314 getAlwaysOn() && (mKeyguardVisible || shouldControlUnlockedScreenOff()); 315 setControlScreenOffAnimation(controlScreenOff); 316 } 317 } 318 319 /** 320 * Whether we're capable of controlling the screen off animation if we want to. This isn't 321 * possible if AOD isn't even enabled or if the display needs blanking. 322 */ canControlUnlockedScreenOff()323 public boolean canControlUnlockedScreenOff() { 324 return getAlwaysOn() && !getDisplayNeedsBlanking(); 325 } 326 327 /** 328 * Whether we want to control the screen off animation when the device is unlocked. If we do, 329 * we'll animate in AOD before turning off the screen, rather than simply fading to black and 330 * then abruptly showing AOD. 331 * 332 * There are currently several reasons we might not want to control the screen off even if we 333 * are able to, such as the shade being expanded, being in landscape, or having animations 334 * disabled for a11y. 335 */ shouldControlUnlockedScreenOff()336 public boolean shouldControlUnlockedScreenOff() { 337 return mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation(); 338 } 339 shouldDelayKeyguardShow()340 public boolean shouldDelayKeyguardShow() { 341 return mScreenOffAnimationController.shouldDelayKeyguardShow(); 342 } 343 shouldClampToDimBrightness()344 public boolean shouldClampToDimBrightness() { 345 return mScreenOffAnimationController.shouldClampDozeScreenBrightness(); 346 } 347 shouldShowLightRevealScrim()348 public boolean shouldShowLightRevealScrim() { 349 return mScreenOffAnimationController.shouldShowLightRevealScrim(); 350 } 351 shouldAnimateDozingChange()352 public boolean shouldAnimateDozingChange() { 353 return mScreenOffAnimationController.shouldAnimateDozingChange(); 354 } 355 356 /** 357 * When this method returns true then moving display state to power save mode will be 358 * delayed for a few seconds. This might be useful to play animations without reducing FPS. 359 */ shouldDelayDisplayDozeTransition()360 public boolean shouldDelayDisplayDozeTransition() { 361 if (mTransitionInteractor.getTransitionState().getValue().getTo() == KeyguardState.AOD) { 362 return true; 363 } 364 return willAnimateFromLockScreenToAod() 365 || mScreenOffAnimationController.shouldDelayDisplayDozeTransition(); 366 } 367 willAnimateFromLockScreenToAod()368 private boolean willAnimateFromLockScreenToAod() { 369 return shouldControlScreenOff() && mKeyguardVisible; 370 } 371 getBoolean(String propName, int resId)372 private boolean getBoolean(String propName, int resId) { 373 return SystemProperties.getBoolean(propName, mResources.getBoolean(resId)); 374 } 375 getInt(String propName, int resId)376 private int getInt(String propName, int resId) { 377 int value = SystemProperties.getInt(propName, mResources.getInteger(resId)); 378 return MathUtils.constrain(value, 0, MAX_DURATION); 379 } 380 getPulseVisibleDurationExtended()381 public int getPulseVisibleDurationExtended() { 382 return 2 * getPulseVisibleDuration(); 383 } 384 doubleTapReportsTouchCoordinates()385 public boolean doubleTapReportsTouchCoordinates() { 386 return mResources.getBoolean(R.bool.doze_double_tap_reports_touch_coordinates); 387 } 388 389 /** 390 * Whether the single tap sensor uses the proximity sensor for this device posture. 391 */ singleTapUsesProx(@evicePostureController.DevicePostureInt int devicePosture)392 public boolean singleTapUsesProx(@DevicePostureController.DevicePostureInt int devicePosture) { 393 return getPostureSpecificBool( 394 mResources.getIntArray(R.array.doze_single_tap_uses_prox_posture_mapping), 395 singleTapUsesProx(), 396 devicePosture 397 ); 398 } 399 400 /** 401 * Whether the single tap sensor uses the proximity sensor. 402 */ singleTapUsesProx()403 private boolean singleTapUsesProx() { 404 return mResources.getBoolean(R.bool.doze_single_tap_uses_prox); 405 } 406 407 /** 408 * Whether the long press sensor uses the proximity sensor. 409 */ longPressUsesProx()410 public boolean longPressUsesProx() { 411 return mResources.getBoolean(R.bool.doze_long_press_uses_prox); 412 } 413 414 /** 415 * Gets the brightness string array per posture. Brightness names along with 416 * doze_brightness_sensor_type is used to determine the brightness sensor to use for 417 * the current posture. 418 */ brightnessNames()419 public String[] brightnessNames() { 420 return mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping); 421 } 422 423 @Override onTuningChanged(String key, String newValue)424 public void onTuningChanged(String key, String newValue) { 425 mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(mUserTracker.getUserId()); 426 427 if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) { 428 updateControlScreenOff(); 429 } 430 431 dispatchAlwaysOnEvent(); 432 } 433 434 @Override onConfigChanged(Configuration newConfig)435 public void onConfigChanged(Configuration newConfig) { 436 updateControlScreenOff(); 437 } 438 439 @Override onStatePostChange()440 public void onStatePostChange() { 441 updateControlScreenOff(); 442 } 443 444 @Override onFoldToAodAnimationChanged()445 public void onFoldToAodAnimationChanged() { 446 updateControlScreenOff(); 447 } 448 449 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)450 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 451 pw.print("getAlwaysOn(): "); pw.println(getAlwaysOn()); 452 pw.print("getDisplayStateSupported(): "); pw.println(getDisplayStateSupported()); 453 pw.print("getPulseDuration(): "); pw.println(getPulseDuration()); 454 pw.print("getPulseInDuration(): "); pw.println(getPulseInDuration()); 455 pw.print("getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration()); 456 pw.print("getPulseOutDuration(): "); pw.println(getPulseOutDuration()); 457 pw.print("getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion()); 458 pw.print("getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion()); 459 pw.print("getVibrateOnPickup(): "); pw.println(getVibrateOnPickup()); 460 pw.print("getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse()); 461 pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); 462 pw.print("getSelectivelyRegisterSensorsUsingProx(): "); 463 pw.println(getSelectivelyRegisterSensorsUsingProx()); 464 pw.print("isQuickPickupEnabled(): "); pw.println(isQuickPickupEnabled()); 465 } 466 dispatchAlwaysOnEvent()467 private void dispatchAlwaysOnEvent() { 468 mScreenOffAnimationController.onAlwaysOnChanged(getAlwaysOn()); 469 mDozeInteractor.setAodAvailable(getAlwaysOn()); 470 471 } 472 getPostureSpecificBool( int[] postureMapping, boolean defaultSensorBool, int posture)473 private boolean getPostureSpecificBool( 474 int[] postureMapping, 475 boolean defaultSensorBool, 476 int posture) { 477 boolean bool = defaultSensorBool; 478 if (posture < postureMapping.length) { 479 bool = postureMapping[posture] != 0; 480 } else { 481 Log.e("DozeParameters", "Unsupported doze posture " + posture); 482 } 483 484 return bool; 485 } 486 487 private final class SettingsObserver extends ContentObserver { 488 private final Uri mQuickPickupGesture = 489 Settings.Secure.getUriFor(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE); 490 private final Uri mPickupGesture = 491 Settings.Secure.getUriFor(Settings.Secure.DOZE_PICK_UP_GESTURE); 492 private final Uri mAlwaysOnEnabled = 493 Settings.Secure.getUriFor(Settings.Secure.DOZE_ALWAYS_ON); 494 private final Context mContext; 495 496 private final Handler mHandler; 497 private final SecureSettings mSecureSettings; 498 SettingsObserver(Context context, Handler handler, SecureSettings secureSettings)499 SettingsObserver(Context context, Handler handler, SecureSettings secureSettings) { 500 super(handler); 501 mContext = context; 502 mHandler = handler; 503 mSecureSettings = secureSettings; 504 } 505 observe()506 void observe() { 507 if (Flags.registerContentObserversAsync()) { 508 mSecureSettings.registerContentObserverForUserAsync(mQuickPickupGesture, 509 this, UserHandle.USER_ALL); 510 mSecureSettings.registerContentObserverForUserAsync(mPickupGesture, 511 this, UserHandle.USER_ALL); 512 mSecureSettings.registerContentObserverForUserAsync(mAlwaysOnEnabled, 513 this, UserHandle.USER_ALL, 514 // The register calls are called in order, so this ensures that update() 515 // is called after them all and value retrieval isn't racy. 516 () -> mHandler.post(() -> update(null))); 517 } else { 518 ContentResolver resolver = mContext.getContentResolver(); 519 resolver.registerContentObserver(mQuickPickupGesture, false, this, 520 UserHandle.USER_ALL); 521 resolver.registerContentObserver(mPickupGesture, false, this, UserHandle.USER_ALL); 522 resolver.registerContentObserver(mAlwaysOnEnabled, false, this, 523 UserHandle.USER_ALL); 524 update(null); 525 } 526 } 527 528 @Override onChange(boolean selfChange, Uri uri)529 public void onChange(boolean selfChange, Uri uri) { 530 update(uri); 531 } 532 update(Uri uri)533 public void update(Uri uri) { 534 if (uri == null 535 || mQuickPickupGesture.equals(uri) 536 || mPickupGesture.equals(uri) 537 || mAlwaysOnEnabled.equals(uri)) { 538 // the quick pickup gesture is dependent on alwaysOn being disabled and 539 // the pickup gesture being enabled 540 updateQuickPickupEnabled(); 541 } 542 } 543 } 544 } 545