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.res.Configuration; 20 import android.content.res.Resources; 21 import android.hardware.display.AmbientDisplayConfiguration; 22 import android.os.PowerManager; 23 import android.os.SystemProperties; 24 import android.os.UserHandle; 25 import android.provider.Settings; 26 import android.util.Log; 27 import android.util.MathUtils; 28 29 import androidx.annotation.NonNull; 30 import androidx.annotation.VisibleForTesting; 31 32 import com.android.keyguard.KeyguardUpdateMonitor; 33 import com.android.keyguard.KeyguardUpdateMonitorCallback; 34 import com.android.systemui.Dumpable; 35 import com.android.systemui.R; 36 import com.android.systemui.dagger.SysUISingleton; 37 import com.android.systemui.dagger.qualifiers.Main; 38 import com.android.systemui.doze.AlwaysOnDisplayPolicy; 39 import com.android.systemui.doze.DozeScreenState; 40 import com.android.systemui.dump.DumpManager; 41 import com.android.systemui.flags.FeatureFlags; 42 import com.android.systemui.plugins.statusbar.StatusBarStateController; 43 import com.android.systemui.statusbar.policy.BatteryController; 44 import com.android.systemui.statusbar.policy.ConfigurationController; 45 import com.android.systemui.statusbar.policy.DevicePostureController; 46 import com.android.systemui.tuner.TunerService; 47 48 import java.io.FileDescriptor; 49 import java.io.PrintWriter; 50 import java.util.HashSet; 51 import java.util.Set; 52 53 import javax.inject.Inject; 54 55 /** 56 * Retrieve doze information 57 */ 58 @SysUISingleton 59 public class DozeParameters implements 60 TunerService.Tunable, 61 com.android.systemui.plugins.statusbar.DozeParameters, 62 Dumpable, ConfigurationController.ConfigurationListener, 63 StatusBarStateController.StateListener { 64 private static final int MAX_DURATION = 60 * 1000; 65 public static final boolean FORCE_NO_BLANKING = 66 SystemProperties.getBoolean("debug.force_no_blanking", false); 67 public static final boolean FORCE_BLANKING = 68 SystemProperties.getBoolean("debug.force_blanking", false); 69 70 private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; 71 private final PowerManager mPowerManager; 72 73 private final AlwaysOnDisplayPolicy mAlwaysOnPolicy; 74 private final Resources mResources; 75 private final BatteryController mBatteryController; 76 private final FeatureFlags mFeatureFlags; 77 private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController; 78 79 private final Set<Callback> mCallbacks = new HashSet<>(); 80 81 private boolean mDozeAlwaysOn; 82 private boolean mControlScreenOffAnimation; 83 84 private boolean mKeyguardShowing; 85 @VisibleForTesting 86 final KeyguardUpdateMonitorCallback mKeyguardVisibilityCallback = 87 new KeyguardUpdateMonitorCallback() { 88 @Override 89 public void onKeyguardVisibilityChanged(boolean showing) { 90 mKeyguardShowing = showing; 91 updateControlScreenOff(); 92 } 93 94 @Override 95 public void onShadeExpandedChanged(boolean expanded) { 96 updateControlScreenOff(); 97 } 98 }; 99 100 @Inject DozeParameters( @ain Resources resources, AmbientDisplayConfiguration ambientDisplayConfiguration, AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, PowerManager powerManager, BatteryController batteryController, TunerService tunerService, DumpManager dumpManager, FeatureFlags featureFlags, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, KeyguardUpdateMonitor keyguardUpdateMonitor, ConfigurationController configurationController, StatusBarStateController statusBarStateController)101 protected DozeParameters( 102 @Main Resources resources, 103 AmbientDisplayConfiguration ambientDisplayConfiguration, 104 AlwaysOnDisplayPolicy alwaysOnDisplayPolicy, 105 PowerManager powerManager, 106 BatteryController batteryController, 107 TunerService tunerService, 108 DumpManager dumpManager, 109 FeatureFlags featureFlags, 110 UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, 111 KeyguardUpdateMonitor keyguardUpdateMonitor, 112 ConfigurationController configurationController, 113 StatusBarStateController statusBarStateController) { 114 mResources = resources; 115 mAmbientDisplayConfiguration = ambientDisplayConfiguration; 116 mAlwaysOnPolicy = alwaysOnDisplayPolicy; 117 mBatteryController = batteryController; 118 dumpManager.registerDumpable("DozeParameters", this); 119 120 mControlScreenOffAnimation = !getDisplayNeedsBlanking(); 121 mPowerManager = powerManager; 122 mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation); 123 mFeatureFlags = featureFlags; 124 mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController; 125 126 keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback); 127 tunerService.addTunable( 128 this, 129 Settings.Secure.DOZE_ALWAYS_ON, 130 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); 131 configurationController.addCallback(this); 132 statusBarStateController.addCallback(this); 133 } 134 getDisplayStateSupported()135 public boolean getDisplayStateSupported() { 136 return getBoolean("doze.display.supported", R.bool.doze_display_state_supported); 137 } 138 getDozeSuspendDisplayStateSupported()139 public boolean getDozeSuspendDisplayStateSupported() { 140 return mResources.getBoolean(R.bool.doze_suspend_display_state_supported); 141 } 142 getPulseDuration()143 public int getPulseDuration() { 144 return getPulseInDuration() + getPulseVisibleDuration() + getPulseOutDuration(); 145 } 146 getScreenBrightnessDoze()147 public float getScreenBrightnessDoze() { 148 return mResources.getInteger( 149 com.android.internal.R.integer.config_screenBrightnessDoze) / 255f; 150 } 151 getPulseInDuration()152 public int getPulseInDuration() { 153 return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in); 154 } 155 getPulseVisibleDuration()156 public int getPulseVisibleDuration() { 157 return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible); 158 } 159 getPulseOutDuration()160 public int getPulseOutDuration() { 161 return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out); 162 } 163 getPulseOnSigMotion()164 public boolean getPulseOnSigMotion() { 165 return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion); 166 } 167 getVibrateOnSigMotion()168 public boolean getVibrateOnSigMotion() { 169 return SystemProperties.getBoolean("doze.vibrate.sigmotion", false); 170 } 171 getVibrateOnPickup()172 public boolean getVibrateOnPickup() { 173 return SystemProperties.getBoolean("doze.vibrate.pickup", false); 174 } 175 getProxCheckBeforePulse()176 public boolean getProxCheckBeforePulse() { 177 return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse); 178 } 179 180 /** 181 * @return true if we should only register for sensors that use the proximity sensor when the 182 * display state is {@link android.view.Display.STATE_OFF}, 183 * {@link android.view.Display.STATE_DOZE} or {@link android.view.Display.STATE_DOZE_SUSPEND} 184 */ getSelectivelyRegisterSensorsUsingProx()185 public boolean getSelectivelyRegisterSensorsUsingProx() { 186 return getBoolean("doze.prox.selectively_register", 187 R.bool.doze_selectively_register_prox); 188 } 189 getPickupVibrationThreshold()190 public int getPickupVibrationThreshold() { 191 return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold); 192 } 193 getQuickPickupAodDuration()194 public int getQuickPickupAodDuration() { 195 return getInt("doze.gesture.quickpickup.duration", 196 R.integer.doze_quick_pickup_aod_duration); 197 } 198 199 /** 200 * For how long a wallpaper can be visible in AoD before it fades aways. 201 * @return duration in millis. 202 */ getWallpaperAodDuration()203 public long getWallpaperAodDuration() { 204 if (shouldControlScreenOff()) { 205 return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY; 206 } 207 return mAlwaysOnPolicy.wallpaperVisibilityDuration; 208 } 209 210 /** 211 * How long it takes for the wallpaper fade away (Animation duration.) 212 * @return duration in millis. 213 */ getWallpaperFadeOutDuration()214 public long getWallpaperFadeOutDuration() { 215 return mAlwaysOnPolicy.wallpaperFadeOutDuration; 216 } 217 218 /** 219 * Checks if always on is available and enabled for the current user. 220 * @return {@code true} if enabled and available. 221 */ getAlwaysOn()222 public boolean getAlwaysOn() { 223 return mDozeAlwaysOn && !mBatteryController.isAodPowerSave(); 224 } 225 isQuickPickupEnabled()226 public boolean isQuickPickupEnabled() { 227 return mAmbientDisplayConfiguration.quickPickupSensorEnabled(UserHandle.USER_CURRENT); 228 } 229 230 /** 231 * Some screens need to be completely black before changing the display power mode, 232 * unexpected behavior might happen if this parameter isn't respected. 233 * 234 * @return {@code true} if screen needs to be completely black before a power transition. 235 */ getDisplayNeedsBlanking()236 public boolean getDisplayNeedsBlanking() { 237 return FORCE_BLANKING || !FORCE_NO_BLANKING && mResources.getBoolean( 238 com.android.internal.R.bool.config_displayBlanksAfterDoze); 239 } 240 shouldControlScreenOff()241 public boolean shouldControlScreenOff() { 242 return mControlScreenOffAnimation; 243 } 244 setControlScreenOffAnimation(boolean controlScreenOffAnimation)245 public void setControlScreenOffAnimation(boolean controlScreenOffAnimation) { 246 if (mControlScreenOffAnimation == controlScreenOffAnimation) { 247 return; 248 } 249 mControlScreenOffAnimation = controlScreenOffAnimation; 250 mPowerManager.setDozeAfterScreenOff(!controlScreenOffAnimation); 251 } 252 253 /** 254 * 255 */ updateControlScreenOff()256 public void updateControlScreenOff() { 257 if (!getDisplayNeedsBlanking()) { 258 final boolean controlScreenOff = 259 getAlwaysOn() && (mKeyguardShowing || shouldControlUnlockedScreenOff()); 260 setControlScreenOffAnimation(controlScreenOff); 261 } 262 } 263 264 /** 265 * Whether we want to control the screen off animation when the device is unlocked. If we do, 266 * we'll animate in AOD before turning off the screen, rather than simply fading to black and 267 * then abruptly showing AOD. 268 * 269 * There are currently several reasons we might not want to control the screen off even if we 270 * are able to, such as the shade being expanded, being in landscape, or having animations 271 * disabled for a11y. 272 */ shouldControlUnlockedScreenOff()273 public boolean shouldControlUnlockedScreenOff() { 274 return canControlUnlockedScreenOff() 275 && mUnlockedScreenOffAnimationController.shouldPlayUnlockedScreenOffAnimation(); 276 } 277 278 /** 279 * Whether we're capable of controlling the screen off animation if we want to. This isn't 280 * possible if AOD isn't even enabled or if the flag is disabled. 281 */ canControlUnlockedScreenOff()282 public boolean canControlUnlockedScreenOff() { 283 return getAlwaysOn() 284 && mFeatureFlags.useNewLockscreenAnimations() 285 && !getDisplayNeedsBlanking(); 286 } 287 getBoolean(String propName, int resId)288 private boolean getBoolean(String propName, int resId) { 289 return SystemProperties.getBoolean(propName, mResources.getBoolean(resId)); 290 } 291 getInt(String propName, int resId)292 private int getInt(String propName, int resId) { 293 int value = SystemProperties.getInt(propName, mResources.getInteger(resId)); 294 return MathUtils.constrain(value, 0, MAX_DURATION); 295 } 296 getPulseVisibleDurationExtended()297 public int getPulseVisibleDurationExtended() { 298 return 2 * getPulseVisibleDuration(); 299 } 300 doubleTapReportsTouchCoordinates()301 public boolean doubleTapReportsTouchCoordinates() { 302 return mResources.getBoolean(R.bool.doze_double_tap_reports_touch_coordinates); 303 } 304 305 /** 306 * Whether the single tap sensor uses the proximity sensor for this device posture. 307 */ singleTapUsesProx(@evicePostureController.DevicePostureInt int devicePosture)308 public boolean singleTapUsesProx(@DevicePostureController.DevicePostureInt int devicePosture) { 309 return getPostureSpecificBool( 310 mResources.getIntArray(R.array.doze_single_tap_uses_prox_posture_mapping), 311 singleTapUsesProx(), 312 devicePosture 313 ); 314 } 315 316 /** 317 * Whether the single tap sensor uses the proximity sensor. 318 */ singleTapUsesProx()319 private boolean singleTapUsesProx() { 320 return mResources.getBoolean(R.bool.doze_single_tap_uses_prox); 321 } 322 323 /** 324 * Whether the long press sensor uses the proximity sensor. 325 */ longPressUsesProx()326 public boolean longPressUsesProx() { 327 return mResources.getBoolean(R.bool.doze_long_press_uses_prox); 328 } 329 330 /** 331 * Gets the brightness string array per posture. Brightness names along with 332 * doze_brightness_sensor_type is used to determine the brightness sensor to use for 333 * the current posture. 334 */ brightnessNames()335 public String[] brightnessNames() { 336 return mResources.getStringArray(R.array.doze_brightness_sensor_name_posture_mapping); 337 } 338 339 /** 340 * Callback to listen for DozeParameter changes. 341 */ addCallback(Callback callback)342 public void addCallback(Callback callback) { 343 mCallbacks.add(callback); 344 } 345 346 /** 347 * Remove callback that listens for DozeParameter changes. 348 */ removeCallback(Callback callback)349 public void removeCallback(Callback callback) { 350 mCallbacks.remove(callback); 351 } 352 353 @Override onTuningChanged(String key, String newValue)354 public void onTuningChanged(String key, String newValue) { 355 mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT); 356 357 if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) { 358 updateControlScreenOff(); 359 } 360 361 for (Callback callback : mCallbacks) { 362 callback.onAlwaysOnChange(); 363 } 364 } 365 366 @Override onConfigChanged(Configuration newConfig)367 public void onConfigChanged(Configuration newConfig) { 368 updateControlScreenOff(); 369 } 370 371 @Override onStatePostChange()372 public void onStatePostChange() { 373 updateControlScreenOff(); 374 } 375 376 @Override dump(@onNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args)377 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) { 378 pw.print("getAlwaysOn(): "); pw.println(getAlwaysOn()); 379 pw.print("getDisplayStateSupported(): "); pw.println(getDisplayStateSupported()); 380 pw.print("getPulseDuration(): "); pw.println(getPulseDuration()); 381 pw.print("getPulseInDuration(): "); pw.println(getPulseInDuration()); 382 pw.print("getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration()); 383 pw.print("getPulseOutDuration(): "); pw.println(getPulseOutDuration()); 384 pw.print("getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion()); 385 pw.print("getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion()); 386 pw.print("getVibrateOnPickup(): "); pw.println(getVibrateOnPickup()); 387 pw.print("getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse()); 388 pw.print("getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); 389 pw.print("getSelectivelyRegisterSensorsUsingProx(): "); 390 pw.println(getSelectivelyRegisterSensorsUsingProx()); 391 } 392 getPostureSpecificBool( int[] postureMapping, boolean defaultSensorBool, int posture)393 private boolean getPostureSpecificBool( 394 int[] postureMapping, 395 boolean defaultSensorBool, 396 int posture) { 397 boolean bool = defaultSensorBool; 398 if (posture < postureMapping.length) { 399 bool = postureMapping[posture] != 0; 400 } else { 401 Log.e("DozeParameters", "Unsupported doze posture " + posture); 402 } 403 404 return bool; 405 } 406 407 interface Callback { 408 /** 409 * Invoked when the value of getAlwaysOn may have changed. 410 */ onAlwaysOnChange()411 void onAlwaysOnChange(); 412 } 413 } 414