DozeParameters.java revision 4540811b4d2e749161afa4f0e64019b836431c3b
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
17package com.android.systemui.statusbar.phone;
18
19import android.content.Context;
20import android.os.SystemProperties;
21import android.os.UserHandle;
22import android.provider.Settings;
23import android.text.TextUtils;
24import android.util.MathUtils;
25import android.util.SparseBooleanArray;
26
27import com.android.internal.hardware.AmbientDisplayConfiguration;
28import com.android.systemui.R;
29
30import java.io.PrintWriter;
31
32public class DozeParameters {
33    private static final int MAX_DURATION = 60 * 1000;
34    public static final String DOZE_SENSORS_WAKE_UP_FULLY = "doze_sensors_wake_up_fully";
35
36    private final Context mContext;
37    private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
38
39    private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
40
41    public DozeParameters(Context context) {
42        mContext = context;
43        mAmbientDisplayConfiguration = new AmbientDisplayConfiguration(mContext);
44    }
45
46    public void dump(PrintWriter pw) {
47        pw.println("  DozeParameters:");
48        pw.print("    getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
49        pw.print("    getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false));
50        pw.print("    getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
51        pw.print("    getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
52        pw.print("    getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
53        pw.print("    getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
54        pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
55        pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
56        pw.print("    getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
57        pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
58        pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
59        pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
60        pw.print("    getPickupSubtypePerformsProxCheck(): ");pw.println(
61                dumpPickupSubtypePerformsProxCheck());
62        if (mAmbientDisplayConfiguration.alwaysOnAvailable()) {
63            pw.print("    getSensorsWakeUpFully(): "); pw.println(getSensorsWakeUpFully());
64        }
65    }
66
67    private String dumpPickupSubtypePerformsProxCheck() {
68        // Refresh sPickupSubtypePerformsProxMatcher
69        getPickupSubtypePerformsProxCheck(0);
70
71        if (sPickupSubtypePerformsProxMatcher == null) {
72            return "fallback: " + mContext.getResources().getBoolean(
73                    R.bool.doze_pickup_performs_proximity_check);
74        } else {
75            return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
76        }
77    }
78
79    public boolean getDisplayStateSupported() {
80        return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
81    }
82
83    public int getPulseDuration(boolean pickup) {
84        return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
85    }
86
87    public int getPulseInDuration(boolean pickupOrDoubleTap) {
88        return pickupOrDoubleTap
89                ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
90                : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
91    }
92
93    public int getPulseVisibleDuration() {
94        return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
95    }
96
97    public int getPulseOutDuration() {
98        return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out);
99    }
100
101    public boolean getPulseOnSigMotion() {
102        return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion);
103    }
104
105    public boolean getVibrateOnSigMotion() {
106        return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
107    }
108
109    public boolean getVibrateOnPickup() {
110        return SystemProperties.getBoolean("doze.vibrate.pickup", false);
111    }
112
113    public boolean getProxCheckBeforePulse() {
114        return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
115    }
116
117    public int getPickupVibrationThreshold() {
118        return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
119    }
120
121    public boolean getAlwaysOn() {
122        return mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
123    }
124
125    public boolean getSensorsWakeUpFully() {
126        return mAmbientDisplayConfiguration.alwaysOnAvailable()
127                && Settings.Secure.getIntForUser(mContext.getContentResolver(),
128                DOZE_SENSORS_WAKE_UP_FULLY, 1, UserHandle.USER_CURRENT) != 0;
129    }
130
131    private boolean getBoolean(String propName, int resId) {
132        return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
133    }
134
135    private int getInt(String propName, int resId) {
136        int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
137        return MathUtils.constrain(value, 0, MAX_DURATION);
138    }
139
140    private String getString(String propName, int resId) {
141        return SystemProperties.get(propName, mContext.getString(resId));
142    }
143
144    public boolean getPickupSubtypePerformsProxCheck(int subType) {
145        String spec = getString("doze.pickup.proxcheck",
146                R.string.doze_pickup_subtype_performs_proximity_check);
147
148        if (TextUtils.isEmpty(spec)) {
149            // Fall back to non-subtype based property.
150            return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
151        }
152
153        if (sPickupSubtypePerformsProxMatcher == null
154                || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
155            sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
156        }
157
158        return sPickupSubtypePerformsProxMatcher.isIn(subType);
159    }
160
161
162    /**
163     * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
164     * listed, will not match numbers that are listed with a ! prefix, and will match / not match
165     * unlisted numbers depending on whether * or !* is present.
166     *
167     * *  -> match any numbers that are not explicitly listed
168     * !* -> don't match any numbers that are not explicitly listed
169     * 2  -> match 2
170     * !3 -> don't match 3
171     *
172     * It is illegal to specify:
173     * - an empty spec
174     * - a spec containing that are empty, or a lone !
175     * - a spec for anything other than numbers or *
176     * - multiple terms for the same number / multiple *s
177     */
178    public static class IntInOutMatcher {
179        private static final String WILDCARD = "*";
180        private static final char OUT_PREFIX = '!';
181
182        private final SparseBooleanArray mIsIn;
183        private final boolean mDefaultIsIn;
184        final String mSpec;
185
186        public IntInOutMatcher(String spec) {
187            if (TextUtils.isEmpty(spec)) {
188                throw new IllegalArgumentException("Spec must not be empty");
189            }
190
191            boolean defaultIsIn = false;
192            boolean foundWildcard = false;
193
194            mSpec = spec;
195            mIsIn = new SparseBooleanArray();
196
197            for (String itemPrefixed : spec.split(",", -1)) {
198                if (itemPrefixed.length() == 0) {
199                    throw new IllegalArgumentException(
200                            "Illegal spec, must not have zero-length items: `" + spec + "`");
201                }
202                boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
203                String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
204
205                if (itemPrefixed.length() == 0) {
206                    throw new IllegalArgumentException(
207                            "Illegal spec, must not have zero-length items: `" + spec + "`");
208                }
209
210                if (WILDCARD.equals(item)) {
211                    if (foundWildcard) {
212                        throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
213                                "` must not appear multiple times in `" + spec + "`");
214                    }
215                    defaultIsIn = isIn;
216                    foundWildcard = true;
217                } else {
218                    int key = Integer.parseInt(item);
219                    if (mIsIn.indexOfKey(key) >= 0) {
220                        throw new IllegalArgumentException("Illegal spec, `" + key +
221                                "` must not appear multiple times in `" + spec + "`");
222                    }
223                    mIsIn.put(key, isIn);
224                }
225            }
226
227            if (!foundWildcard) {
228                throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
229            }
230
231            mDefaultIsIn = defaultIsIn;
232        }
233
234        public boolean isIn(int value) {
235            return (mIsIn.get(value, mDefaultIsIn));
236        }
237    }
238}
239