• 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.Context;
20 import android.hardware.display.AmbientDisplayConfiguration;
21 import android.os.PowerManager;
22 import android.os.SystemProperties;
23 import android.os.UserHandle;
24 import android.provider.Settings;
25 import android.text.TextUtils;
26 import android.util.MathUtils;
27 import android.util.SparseBooleanArray;
28 
29 import com.android.internal.annotations.VisibleForTesting;
30 import com.android.systemui.Dependency;
31 import com.android.systemui.R;
32 import com.android.systemui.doze.AlwaysOnDisplayPolicy;
33 import com.android.systemui.doze.DozeScreenState;
34 import com.android.systemui.tuner.TunerService;
35 
36 import java.io.PrintWriter;
37 
38 public class DozeParameters implements TunerService.Tunable {
39     private static final int MAX_DURATION = 60 * 1000;
40     public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
41     public static final boolean FORCE_NO_BLANKING =
42             SystemProperties.getBoolean("debug.force_no_blanking", false);
43     public static final boolean FORCE_BLANKING =
44             SystemProperties.getBoolean("debug.force_blanking", false);
45 
46     private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
47     private static DozeParameters sInstance;
48 
49     private final Context mContext;
50     private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
51     private final PowerManager mPowerManager;
52 
53     private final AlwaysOnDisplayPolicy mAlwaysOnPolicy;
54 
55     private boolean mDozeAlwaysOn;
56     private boolean mControlScreenOffAnimation;
57 
getInstance(Context context)58     public static DozeParameters getInstance(Context context) {
59         if (sInstance == null) {
60             sInstance = new DozeParameters(context);
61         }
62         return sInstance;
63     }
64 
65     @VisibleForTesting
DozeParameters(Context context)66     protected DozeParameters(Context context) {
67         mContext = context.getApplicationContext();
68         mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
69         mAlwaysOnPolicy = new AlwaysOnDisplayPolicy(mContext);
70 
71         mControlScreenOffAnimation = !getDisplayNeedsBlanking();
72         mPowerManager = mContext.getSystemService(PowerManager.class);
73         mPowerManager.setDozeAfterScreenOff(!mControlScreenOffAnimation);
74 
75         Dependency.get(TunerService.class).addTunable(this, Settings.Secure.DOZE_ALWAYS_ON,
76                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
77     }
78 
dump(PrintWriter pw)79     public void dump(PrintWriter pw) {
80         pw.println("  DozeParameters:");
81         pw.print("    getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
82         pw.print("    getPulseDuration(): "); pw.println(getPulseDuration());
83         pw.print("    getPulseInDuration(): "); pw.println(getPulseInDuration());
84         pw.print("    getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
85         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
86         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
87         pw.print("    getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
88         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
89         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
90         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
91         pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
92                 dumpPickupSubtypePerformsProxCheck());
93     }
94 
dumpPickupSubtypePerformsProxCheck()95     private String dumpPickupSubtypePerformsProxCheck() {
96         // Refresh sPickupSubtypePerformsProxMatcher
97         getPickupSubtypePerformsProxCheck(0);
98 
99         if (sPickupSubtypePerformsProxMatcher == null) {
100             return "fallback: " + mContext.getResources().getBoolean(
101                     R.bool.doze_pickup_performs_proximity_check);
102         } else {
103             return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
104         }
105     }
106 
getDisplayStateSupported()107     public boolean getDisplayStateSupported() {
108         return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
109     }
110 
getDozeSuspendDisplayStateSupported()111     public boolean getDozeSuspendDisplayStateSupported() {
112         return mContext.getResources().getBoolean(R.bool.doze_suspend_display_state_supported);
113     }
114 
getPulseDuration()115     public int getPulseDuration() {
116         return getPulseInDuration() + getPulseVisibleDuration() + getPulseOutDuration();
117     }
118 
getScreenBrightnessDoze()119     public float getScreenBrightnessDoze() {
120         return mContext.getResources().getInteger(
121                 com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
122     }
123 
getPulseInDuration()124     public int getPulseInDuration() {
125         return getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
126     }
127 
getPulseVisibleDuration()128     public int getPulseVisibleDuration() {
129         return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
130     }
131 
getPulseOutDuration()132     public int getPulseOutDuration() {
133         return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out);
134     }
135 
getPulseOnSigMotion()136     public boolean getPulseOnSigMotion() {
137         return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion);
138     }
139 
getVibrateOnSigMotion()140     public boolean getVibrateOnSigMotion() {
141         return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
142     }
143 
getVibrateOnPickup()144     public boolean getVibrateOnPickup() {
145         return SystemProperties.getBoolean("doze.vibrate.pickup", false);
146     }
147 
getProxCheckBeforePulse()148     public boolean getProxCheckBeforePulse() {
149         return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
150     }
151 
getPickupVibrationThreshold()152     public int getPickupVibrationThreshold() {
153         return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
154     }
155 
156     /**
157      * For how long a wallpaper can be visible in AoD before it fades aways.
158      * @return duration in millis.
159      */
getWallpaperAodDuration()160     public long getWallpaperAodDuration() {
161         if (shouldControlScreenOff()) {
162             return DozeScreenState.ENTER_DOZE_HIDE_WALLPAPER_DELAY;
163         }
164         return mAlwaysOnPolicy.wallpaperVisibilityDuration;
165     }
166 
167     /**
168      * How long it takes for the wallpaper fade away (Animation duration.)
169      * @return duration in millis.
170      */
getWallpaperFadeOutDuration()171     public long getWallpaperFadeOutDuration() {
172         return mAlwaysOnPolicy.wallpaperFadeOutDuration;
173     }
174 
175     /**
176      * Checks if always on is available and enabled for the current user.
177      * @return {@code true} if enabled and available.
178      */
getAlwaysOn()179     public boolean getAlwaysOn() {
180         return mDozeAlwaysOn;
181     }
182 
183     /**
184      * Some screens need to be completely black before changing the display power mode,
185      * unexpected behavior might happen if this parameter isn't respected.
186      *
187      * @return {@code true} if screen needs to be completely black before a power transition.
188      */
getDisplayNeedsBlanking()189     public boolean getDisplayNeedsBlanking() {
190         return FORCE_BLANKING || !FORCE_NO_BLANKING && mContext.getResources().getBoolean(
191                 com.android.internal.R.bool.config_displayBlanksAfterDoze);
192     }
193 
shouldControlScreenOff()194     public boolean shouldControlScreenOff() {
195         return mControlScreenOffAnimation;
196     }
197 
setControlScreenOffAnimation(boolean controlScreenOffAnimation)198     public void setControlScreenOffAnimation(boolean controlScreenOffAnimation) {
199         if (mControlScreenOffAnimation == controlScreenOffAnimation) {
200             return;
201         }
202         mControlScreenOffAnimation = controlScreenOffAnimation;
203         getPowerManager().setDozeAfterScreenOff(!controlScreenOffAnimation);
204     }
205 
206     @VisibleForTesting
getPowerManager()207     protected PowerManager getPowerManager() {
208         return mPowerManager;
209     }
210 
getBoolean(String propName, int resId)211     private boolean getBoolean(String propName, int resId) {
212         return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
213     }
214 
getInt(String propName, int resId)215     private int getInt(String propName, int resId) {
216         int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
217         return MathUtils.constrain(value, 0, MAX_DURATION);
218     }
219 
getString(String propName, int resId)220     private String getString(String propName, int resId) {
221         return SystemProperties.get(propName, mContext.getString(resId));
222     }
223 
getPickupSubtypePerformsProxCheck(int subType)224     public boolean getPickupSubtypePerformsProxCheck(int subType) {
225         String spec = getString("doze.pickup.proxcheck",
226                 R.string.doze_pickup_subtype_performs_proximity_check);
227 
228         if (TextUtils.isEmpty(spec)) {
229             // Fall back to non-subtype based property.
230             return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
231         }
232 
233         if (sPickupSubtypePerformsProxMatcher == null
234                 || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
235             sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
236         }
237 
238         return sPickupSubtypePerformsProxMatcher.isIn(subType);
239     }
240 
getPulseVisibleDurationExtended()241     public int getPulseVisibleDurationExtended() {
242         return 2 * getPulseVisibleDuration();
243     }
244 
doubleTapReportsTouchCoordinates()245     public boolean doubleTapReportsTouchCoordinates() {
246         return mContext.getResources().getBoolean(R.bool.doze_double_tap_reports_touch_coordinates);
247     }
248 
249     @Override
onTuningChanged(String key, String newValue)250     public void onTuningChanged(String key, String newValue) {
251         mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
252     }
253 
getPolicy()254     public AlwaysOnDisplayPolicy getPolicy() {
255         return mAlwaysOnPolicy;
256     }
257 
258     /**
259      * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
260      * listed, will not match numbers that are listed with a ! prefix, and will match / not match
261      * unlisted numbers depending on whether * or !* is present.
262      *
263      * *  -> match any numbers that are not explicitly listed
264      * !* -> don't match any numbers that are not explicitly listed
265      * 2  -> match 2
266      * !3 -> don't match 3
267      *
268      * It is illegal to specify:
269      * - an empty spec
270      * - a spec containing that are empty, or a lone !
271      * - a spec for anything other than numbers or *
272      * - multiple terms for the same number / multiple *s
273      */
274     public static class IntInOutMatcher {
275         private static final String WILDCARD = "*";
276         private static final char OUT_PREFIX = '!';
277 
278         private final SparseBooleanArray mIsIn;
279         private final boolean mDefaultIsIn;
280         final String mSpec;
281 
IntInOutMatcher(String spec)282         public IntInOutMatcher(String spec) {
283             if (TextUtils.isEmpty(spec)) {
284                 throw new IllegalArgumentException("Spec must not be empty");
285             }
286 
287             boolean defaultIsIn = false;
288             boolean foundWildcard = false;
289 
290             mSpec = spec;
291             mIsIn = new SparseBooleanArray();
292 
293             for (String itemPrefixed : spec.split(",", -1)) {
294                 if (itemPrefixed.length() == 0) {
295                     throw new IllegalArgumentException(
296                             "Illegal spec, must not have zero-length items: `" + spec + "`");
297                 }
298                 boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
299                 String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
300 
301                 if (itemPrefixed.length() == 0) {
302                     throw new IllegalArgumentException(
303                             "Illegal spec, must not have zero-length items: `" + spec + "`");
304                 }
305 
306                 if (WILDCARD.equals(item)) {
307                     if (foundWildcard) {
308                         throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
309                                 "` must not appear multiple times in `" + spec + "`");
310                     }
311                     defaultIsIn = isIn;
312                     foundWildcard = true;
313                 } else {
314                     int key = Integer.parseInt(item);
315                     if (mIsIn.indexOfKey(key) >= 0) {
316                         throw new IllegalArgumentException("Illegal spec, `" + key +
317                                 "` must not appear multiple times in `" + spec + "`");
318                     }
319                     mIsIn.put(key, isIn);
320                 }
321             }
322 
323             if (!foundWildcard) {
324                 throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
325             }
326 
327             mDefaultIsIn = defaultIsIn;
328         }
329 
isIn(int value)330         public boolean isIn(int value) {
331             return (mIsIn.get(value, mDefaultIsIn));
332         }
333     }
334 }
335