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.os.SystemProperties;
21 import android.text.TextUtils;
22 import android.util.Log;
23 import android.util.MathUtils;
24 
25 import com.android.systemui.R;
26 
27 import java.io.PrintWriter;
28 import java.util.Arrays;
29 import java.util.regex.Matcher;
30 import java.util.regex.Pattern;
31 
32 public class DozeParameters {
33     private static final String TAG = "DozeParameters";
34     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
35 
36     private static final int MAX_DURATION = 10 * 1000;
37 
38     private final Context mContext;
39 
40     private static PulseSchedule sPulseSchedule;
41 
DozeParameters(Context context)42     public DozeParameters(Context context) {
43         mContext = context;
44     }
45 
dump(PrintWriter pw)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("    getPulseInDelay(pickup=false): "); pw.println(getPulseInDelay(false));
54         pw.print("    getPulseInDelay(pickup=true): "); pw.println(getPulseInDelay(true));
55         pw.print("    getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
56         pw.print("    getPulseOutDuration(): "); pw.println(getPulseOutDuration());
57         pw.print("    getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
58         pw.print("    getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion());
59         pw.print("    getPulseOnPickup(): "); pw.println(getPulseOnPickup());
60         pw.print("    getVibrateOnPickup(): "); pw.println(getVibrateOnPickup());
61         pw.print("    getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse());
62         pw.print("    getPulseOnNotifications(): "); pw.println(getPulseOnNotifications());
63         pw.print("    getPulseSchedule(): "); pw.println(getPulseSchedule());
64         pw.print("    getPulseScheduleResets(): "); pw.println(getPulseScheduleResets());
65         pw.print("    getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold());
66         pw.print("    getPickupPerformsProxCheck(): "); pw.println(getPickupPerformsProxCheck());
67     }
68 
getDisplayStateSupported()69     public boolean getDisplayStateSupported() {
70         return getBoolean("doze.display.supported", R.bool.doze_display_state_supported);
71     }
72 
getPulseDuration(boolean pickup)73     public int getPulseDuration(boolean pickup) {
74         return getPulseInDuration(pickup) + getPulseVisibleDuration() + getPulseOutDuration();
75     }
76 
getPulseInDuration(boolean pickup)77     public int getPulseInDuration(boolean pickup) {
78         return pickup
79                 ? getInt("doze.pulse.duration.in.pickup", R.integer.doze_pulse_duration_in_pickup)
80                 : getInt("doze.pulse.duration.in", R.integer.doze_pulse_duration_in);
81     }
82 
getPulseInDelay(boolean pickup)83     public int getPulseInDelay(boolean pickup) {
84         return pickup
85                 ? getInt("doze.pulse.delay.in.pickup", R.integer.doze_pulse_delay_in_pickup)
86                 : getInt("doze.pulse.delay.in", R.integer.doze_pulse_delay_in);
87     }
88 
getPulseVisibleDuration()89     public int getPulseVisibleDuration() {
90         return getInt("doze.pulse.duration.visible", R.integer.doze_pulse_duration_visible);
91     }
92 
getPulseOutDuration()93     public int getPulseOutDuration() {
94         return getInt("doze.pulse.duration.out", R.integer.doze_pulse_duration_out);
95     }
96 
getPulseOnSigMotion()97     public boolean getPulseOnSigMotion() {
98         return getBoolean("doze.pulse.sigmotion", R.bool.doze_pulse_on_significant_motion);
99     }
100 
getVibrateOnSigMotion()101     public boolean getVibrateOnSigMotion() {
102         return SystemProperties.getBoolean("doze.vibrate.sigmotion", false);
103     }
104 
getPulseOnPickup()105     public boolean getPulseOnPickup() {
106         return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up);
107     }
108 
getVibrateOnPickup()109     public boolean getVibrateOnPickup() {
110         return SystemProperties.getBoolean("doze.vibrate.pickup", false);
111     }
112 
getProxCheckBeforePulse()113     public boolean getProxCheckBeforePulse() {
114         return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse);
115     }
116 
getPickupPerformsProxCheck()117     public boolean getPickupPerformsProxCheck() {
118         return getBoolean("doze.pickup.proxcheck", R.bool.doze_pickup_performs_proximity_check);
119     }
120 
getPulseOnNotifications()121     public boolean getPulseOnNotifications() {
122         return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications);
123     }
124 
getPulseSchedule()125     public PulseSchedule getPulseSchedule() {
126         final String spec = getString("doze.pulse.schedule", R.string.doze_pulse_schedule);
127         if (sPulseSchedule == null || !sPulseSchedule.mSpec.equals(spec)) {
128             sPulseSchedule = PulseSchedule.parse(spec);
129         }
130         return sPulseSchedule;
131     }
132 
getPulseScheduleResets()133     public int getPulseScheduleResets() {
134         return getInt("doze.pulse.schedule.resets", R.integer.doze_pulse_schedule_resets);
135     }
136 
getPickupVibrationThreshold()137     public int getPickupVibrationThreshold() {
138         return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold);
139     }
140 
getBoolean(String propName, int resId)141     private boolean getBoolean(String propName, int resId) {
142         return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId));
143     }
144 
getInt(String propName, int resId)145     private int getInt(String propName, int resId) {
146         int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId));
147         return MathUtils.constrain(value, 0, MAX_DURATION);
148     }
149 
getString(String propName, int resId)150     private String getString(String propName, int resId) {
151         return SystemProperties.get(propName, mContext.getString(resId));
152     }
153 
154     public static class PulseSchedule {
155         private static final Pattern PATTERN = Pattern.compile("(\\d+?)s", 0);
156 
157         private String mSpec;
158         private int[] mSchedule;
159 
parse(String spec)160         public static PulseSchedule parse(String spec) {
161             if (TextUtils.isEmpty(spec)) return null;
162             try {
163                 final PulseSchedule rt = new PulseSchedule();
164                 rt.mSpec = spec;
165                 final String[] tokens = spec.split(",");
166                 rt.mSchedule = new int[tokens.length];
167                 for (int i = 0; i < tokens.length; i++) {
168                     final Matcher m = PATTERN.matcher(tokens[i]);
169                     if (!m.matches()) throw new IllegalArgumentException("Bad token: " + tokens[i]);
170                     rt.mSchedule[i] = Integer.parseInt(m.group(1));
171                 }
172                 if (DEBUG) Log.d(TAG, "Parsed spec [" + spec + "] as: " + rt);
173                 return rt;
174             } catch (RuntimeException e) {
175                 Log.w(TAG, "Error parsing spec: " + spec, e);
176                 return null;
177             }
178         }
179 
180         @Override
toString()181         public String toString() {
182             return Arrays.toString(mSchedule);
183         }
184 
getNextTime(long now, long notificationTime)185         public long getNextTime(long now, long notificationTime) {
186             for (int i = 0; i < mSchedule.length; i++) {
187                 final long time = notificationTime + mSchedule[i] * 1000;
188                 if (time > now) return time;
189             }
190             return 0;
191         }
192     }
193 }
194