blob: 9b3ed33e315890a50fca9c67ab8ba889d7bb91c6 [file] [log] [blame]
John Spurlockd06aa572014-09-10 10:40:49 -04001/*
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.text.TextUtils;
22import android.util.Log;
23import android.util.MathUtils;
Adrian Roos5753f052016-07-13 10:30:37 -070024import android.util.SparseBooleanArray;
John Spurlockd06aa572014-09-10 10:40:49 -040025
26import com.android.systemui.R;
27
28import java.io.PrintWriter;
John Spurlock190d0262014-09-14 15:39:13 -040029import java.util.Arrays;
John Spurlockd06aa572014-09-10 10:40:49 -040030import java.util.regex.Matcher;
31import java.util.regex.Pattern;
32
33public class DozeParameters {
34 private static final String TAG = "DozeParameters";
John Spurlock190d0262014-09-14 15:39:13 -040035 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlockd06aa572014-09-10 10:40:49 -040036
Selim Cinekbb998c92015-09-22 10:05:29 +020037 private static final int MAX_DURATION = 60 * 1000;
John Spurlockd06aa572014-09-10 10:40:49 -040038
39 private final Context mContext;
40
John Spurlock190d0262014-09-14 15:39:13 -040041 private static PulseSchedule sPulseSchedule;
John Spurlockd06aa572014-09-10 10:40:49 -040042
Adrian Roos5753f052016-07-13 10:30:37 -070043 private static IntInOutMatcher sPickupSubtypePerformsProxMatcher;
44
John Spurlockd06aa572014-09-10 10:40:49 -040045 public DozeParameters(Context context) {
46 mContext = context;
47 }
48
49 public void dump(PrintWriter pw) {
50 pw.println(" DozeParameters:");
John Spurlock190d0262014-09-14 15:39:13 -040051 pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
John Spurlockf5d250d2014-12-02 10:41:25 -050052 pw.print(" getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false));
53 pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true));
54 pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false));
55 pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true));
John Spurlockd06aa572014-09-10 10:40:49 -040056 pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
57 pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
John Spurlock190d0262014-09-14 15:39:13 -040058 pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
59 pw.print(" getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
60 pw.print(" getPulseOnPickup(): "); pw.println(getPulseOnPickup());
61 pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
John Spurlock686e4d52014-11-20 21:48:09 -050062 pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
John Spurlock190d0262014-09-14 15:39:13 -040063 pw.print(" getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
64 pw.print(" getPulseSchedule(): "); pw.println(getPulseSchedule());
65 pw.print(" getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
John Spurlock50a8ea62014-09-16 09:12:03 -040066 pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
Adrian Roos5753f052016-07-13 10:30:37 -070067 pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println(
68 dumpPickupSubtypePerformsProxCheck());
69 }
70
71 private String dumpPickupSubtypePerformsProxCheck() {
72 // Refresh sPickupSubtypePerformsProxMatcher
73 getPickupSubtypePerformsProxCheck(0);
74
75 if (sPickupSubtypePerformsProxMatcher == null) {
76 return "fallback: " + mContext.getResources().getBoolean(
77 R.bool.doze_pickup_performs_proximity_check);
78 } else {
79 return "spec: " + sPickupSubtypePerformsProxMatcher.mSpec;
80 }
John Spurlock190d0262014-09-14 15:39:13 -040081 }
82
83 public boolean getDisplayStateSupported() {
84 return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
John Spurlockd06aa572014-09-10 10:40:49 -040085 }
86
John Spurlockf5d250d2014-12-02 10:41:25 -050087 public int getPulseDuration(boolean pickup) {
88 return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
John Spurlockd06aa572014-09-10 10:40:49 -040089 }
90
John Spurlockf5d250d2014-12-02 10:41:25 -050091 public int getPulseInDuration(boolean pickup) {
92 return pickup
93 ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
94 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
John Spurlockd06aa572014-09-10 10:40:49 -040095 }
96
97 public int getPulseVisibleDuration() {
98 return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
99 }
100
101 public int getPulseOutDuration() {
102 return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out);
103 }
104
John Spurlock190d0262014-09-14 15:39:13 -0400105 public boolean getPulseOnSigMotion() {
106 return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion);
John Spurlockd06aa572014-09-10 10:40:49 -0400107 }
108
John Spurlock190d0262014-09-14 15:39:13 -0400109 public boolean getVibrateOnSigMotion() {
110 return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
111 }
112
113 public boolean getPulseOnPickup() {
114 return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up);
115 }
116
117 public boolean getVibrateOnPickup() {
118 return SystemProperties.getBoolean("doze.vibrate.pickup", false);
119 }
120
John Spurlock686e4d52014-11-20 21:48:09 -0500121 public boolean getProxCheckBeforePulse() {
122 return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
123 }
124
John Spurlock190d0262014-09-14 15:39:13 -0400125 public boolean getPulseOnNotifications() {
126 return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
127 }
128
129 public PulseSchedule getPulseSchedule() {
130 final String spec = getString("doze.pulse.schedule", R.string.doze_pulse_schedule);
131 if (sPulseSchedule == null || !sPulseSchedule.mSpec.equals(spec)) {
132 sPulseSchedule = PulseSchedule.parse(spec);
John Spurlockd06aa572014-09-10 10:40:49 -0400133 }
John Spurlock190d0262014-09-14 15:39:13 -0400134 return sPulseSchedule;
John Spurlockd06aa572014-09-10 10:40:49 -0400135 }
136
John Spurlock190d0262014-09-14 15:39:13 -0400137 public int getPulseScheduleResets() {
138 return getInt("doze.pulse.schedule.resets", R.integer.doze_pulse_schedule_resets);
139 }
140
John Spurlock50a8ea62014-09-16 09:12:03 -0400141 public int getPickupVibrationThreshold() {
142 return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
143 }
144
John Spurlock190d0262014-09-14 15:39:13 -0400145 private boolean getBoolean(String propName, int resId) {
146 return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
John Spurlockd06aa572014-09-10 10:40:49 -0400147 }
148
149 private int getInt(String propName, int resId) {
150 int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
151 return MathUtils.constrain(value, 0, MAX_DURATION);
152 }
153
154 private String getString(String propName, int resId) {
155 return SystemProperties.get(propName, mContext.getString(resId));
156 }
157
Adrian Roos5753f052016-07-13 10:30:37 -0700158 public boolean getPickupSubtypePerformsProxCheck(int subType) {
159 String spec = getString("doze.pickup.proxcheck",
160 R.string.doze_pickup_subtype_performs_proximity_check);
161
162 if (TextUtils.isEmpty(spec)) {
163 // Fall back to non-subtype based property.
164 return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check);
165 }
166
167 if (sPickupSubtypePerformsProxMatcher == null
168 || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) {
169 sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec);
170 }
171
172 return sPickupSubtypePerformsProxMatcher.isIn(subType);
173 }
174
175
176 /**
177 * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are
178 * listed, will not match numbers that are listed with a ! prefix, and will match / not match
179 * unlisted numbers depending on whether * or !* is present.
180 *
181 * * -> match any numbers that are not explicitly listed
182 * !* -> don't match any numbers that are not explicitly listed
183 * 2 -> match 2
184 * !3 -> don't match 3
185 *
186 * It is illegal to specify:
187 * - an empty spec
188 * - a spec containing that are empty, or a lone !
189 * - a spec for anything other than numbers or *
190 * - multiple terms for the same number / multiple *s
191 */
192 public static class IntInOutMatcher {
193 private static final String WILDCARD = "*";
194 private static final char OUT_PREFIX = '!';
195
196 private final SparseBooleanArray mIsIn;
197 private final boolean mDefaultIsIn;
198 final String mSpec;
199
200 public IntInOutMatcher(String spec) {
201 if (TextUtils.isEmpty(spec)) {
202 throw new IllegalArgumentException("Spec must not be empty");
203 }
204
205 boolean defaultIsIn = false;
206 boolean foundWildcard = false;
207
208 mSpec = spec;
209 mIsIn = new SparseBooleanArray();
210
211 for (String itemPrefixed : spec.split(",", -1)) {
212 if (itemPrefixed.length() == 0) {
213 throw new IllegalArgumentException(
214 "Illegal spec, must not have zero-length items: `" + spec + "`");
215 }
216 boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX;
217 String item = isIn ? itemPrefixed : itemPrefixed.substring(1);
218
219 if (itemPrefixed.length() == 0) {
220 throw new IllegalArgumentException(
221 "Illegal spec, must not have zero-length items: `" + spec + "`");
222 }
223
224 if (WILDCARD.equals(item)) {
225 if (foundWildcard) {
226 throw new IllegalArgumentException("Illegal spec, `" + WILDCARD +
227 "` must not appear multiple times in `" + spec + "`");
228 }
229 defaultIsIn = isIn;
230 foundWildcard = true;
231 } else {
232 int key = Integer.parseInt(item);
233 if (mIsIn.indexOfKey(key) >= 0) {
234 throw new IllegalArgumentException("Illegal spec, `" + key +
235 "` must not appear multiple times in `" + spec + "`");
236 }
237 mIsIn.put(key, isIn);
238 }
239 }
240
241 if (!foundWildcard) {
242 throw new IllegalArgumentException("Illegal spec, must specify either * or !*");
243 }
244
245 mDefaultIsIn = defaultIsIn;
246 }
247
248 public boolean isIn(int value) {
249 return (mIsIn.get(value, mDefaultIsIn));
250 }
251 }
252
John Spurlock190d0262014-09-14 15:39:13 -0400253 public static class PulseSchedule {
254 private static final Pattern PATTERN = Pattern.compile("(\\d+?)s", 0);
John Spurlockd06aa572014-09-10 10:40:49 -0400255
256 private String mSpec;
John Spurlock190d0262014-09-14 15:39:13 -0400257 private int[] mSchedule;
John Spurlockd06aa572014-09-10 10:40:49 -0400258
John Spurlock190d0262014-09-14 15:39:13 -0400259 public static PulseSchedule parse(String spec) {
John Spurlockd06aa572014-09-10 10:40:49 -0400260 if (TextUtils.isEmpty(spec)) return null;
261 try {
John Spurlock190d0262014-09-14 15:39:13 -0400262 final PulseSchedule rt = new PulseSchedule();
John Spurlockd06aa572014-09-10 10:40:49 -0400263 rt.mSpec = spec;
264 final String[] tokens = spec.split(",");
John Spurlock190d0262014-09-14 15:39:13 -0400265 rt.mSchedule = new int[tokens.length];
266 for (int i = 0; i < tokens.length; i++) {
John Spurlockd06aa572014-09-10 10:40:49 -0400267 final Matcher m = PATTERN.matcher(tokens[i]);
268 if (!m.matches()) throw new IllegalArgumentException("Bad token: " + tokens[i]);
John Spurlock190d0262014-09-14 15:39:13 -0400269 rt.mSchedule[i] = Integer.parseInt(m.group(1));
John Spurlockd06aa572014-09-10 10:40:49 -0400270 }
John Spurlock190d0262014-09-14 15:39:13 -0400271 if (DEBUG) Log.d(TAG, "Parsed spec [" + spec + "] as: " + rt);
John Spurlockd06aa572014-09-10 10:40:49 -0400272 return rt;
273 } catch (RuntimeException e) {
274 Log.w(TAG, "Error parsing spec: " + spec, e);
275 return null;
276 }
277 }
278
John Spurlock190d0262014-09-14 15:39:13 -0400279 @Override
280 public String toString() {
281 return Arrays.toString(mSchedule);
282 }
283
284 public long getNextTime(long now, long notificationTime) {
285 for (int i = 0; i < mSchedule.length; i++) {
286 final long time = notificationTime + mSchedule[i] * 1000;
287 if (time > now) return time;
John Spurlockd06aa572014-09-10 10:40:49 -0400288 }
John Spurlock190d0262014-09-14 15:39:13 -0400289 return 0;
John Spurlockd06aa572014-09-10 10:40:49 -0400290 }
291 }
292}