• 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.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