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