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 import android.util.SparseBooleanArray; 25 26 import com.android.systemui.R; 27 28 import java.io.PrintWriter; 29 import java.util.Arrays; 30 import java.util.regex.Matcher; 31 import java.util.regex.Pattern; 32 33 public class DozeParameters { 34 private static final String TAG = "DozeParameters"; 35 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 36 37 private static final int MAX_DURATION = 60 * 1000; 38 39 private final Context mContext; 40 41 private static IntInOutMatcher sPickupSubtypePerformsProxMatcher; 42 43 public DozeParameters(Context context) { 44 mContext = context; 45 } 46 47 public void dump(PrintWriter pw) { 48 pw.println(" DozeParameters:"); 49 pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported()); 50 pw.print(" getPulseDuration(pickup=false): "); pw.println(getPulseDuration(false)); 51 pw.print(" getPulseDuration(pickup=true): "); pw.println(getPulseDuration(true)); 52 pw.print(" getPulseInDuration(pickup=false): "); pw.println(getPulseInDuration(false)); 53 pw.print(" getPulseInDuration(pickup=true): "); pw.println(getPulseInDuration(true)); 54 pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration()); 55 pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration()); 56 pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion()); 57 pw.print(" getVibrateOnSigMotion(): "); pw.println(getVibrateOnSigMotion()); 58 pw.print(" getPulseOnPickup(): "); pw.println(getPulseOnPickup()); 59 pw.print(" getVibrateOnPickup(): "); pw.println(getVibrateOnPickup()); 60 pw.print(" getProxCheckBeforePulse(): "); pw.println(getProxCheckBeforePulse()); 61 pw.print(" getPulseOnNotifications(): "); pw.println(getPulseOnNotifications()); 62 pw.print(" getPickupVibrationThreshold(): "); pw.println(getPickupVibrationThreshold()); 63 pw.print(" getPickupSubtypePerformsProxCheck(): ");pw.println( 64 dumpPickupSubtypePerformsProxCheck()); 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 pickup) { 88 return pickup 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 getPulseOnPickup() { 110 return getBoolean("doze.pulse.pickup", R.bool.doze_pulse_on_pick_up); 111 } 112 113 public boolean getVibrateOnPickup() { 114 return SystemProperties.getBoolean("doze.vibrate.pickup", false); 115 } 116 117 public boolean getProxCheckBeforePulse() { 118 return getBoolean("doze.pulse.proxcheck", R.bool.doze_proximity_check_before_pulse); 119 } 120 121 public boolean getPulseOnNotifications() { 122 return getBoolean("doze.pulse.notifications", R.bool.doze_pulse_on_notifications); 123 } 124 125 public int getPickupVibrationThreshold() { 126 return getInt("doze.pickup.vibration.threshold", R.integer.doze_pickup_vibration_threshold); 127 } 128 129 private boolean getBoolean(String propName, int resId) { 130 return SystemProperties.getBoolean(propName, mContext.getResources().getBoolean(resId)); 131 } 132 133 private int getInt(String propName, int resId) { 134 int value = SystemProperties.getInt(propName, mContext.getResources().getInteger(resId)); 135 return MathUtils.constrain(value, 0, MAX_DURATION); 136 } 137 138 private String getString(String propName, int resId) { 139 return SystemProperties.get(propName, mContext.getString(resId)); 140 } 141 142 public boolean getPickupSubtypePerformsProxCheck(int subType) { 143 String spec = getString("doze.pickup.proxcheck", 144 R.string.doze_pickup_subtype_performs_proximity_check); 145 146 if (TextUtils.isEmpty(spec)) { 147 // Fall back to non-subtype based property. 148 return mContext.getResources().getBoolean(R.bool.doze_pickup_performs_proximity_check); 149 } 150 151 if (sPickupSubtypePerformsProxMatcher == null 152 || !TextUtils.equals(spec, sPickupSubtypePerformsProxMatcher.mSpec)) { 153 sPickupSubtypePerformsProxMatcher = new IntInOutMatcher(spec); 154 } 155 156 return sPickupSubtypePerformsProxMatcher.isIn(subType); 157 } 158 159 160 /** 161 * Parses a spec of the form `1,2,3,!5,*`. The resulting object will match numbers that are 162 * listed, will not match numbers that are listed with a ! prefix, and will match / not match 163 * unlisted numbers depending on whether * or !* is present. 164 * 165 * * -> match any numbers that are not explicitly listed 166 * !* -> don't match any numbers that are not explicitly listed 167 * 2 -> match 2 168 * !3 -> don't match 3 169 * 170 * It is illegal to specify: 171 * - an empty spec 172 * - a spec containing that are empty, or a lone ! 173 * - a spec for anything other than numbers or * 174 * - multiple terms for the same number / multiple *s 175 */ 176 public static class IntInOutMatcher { 177 private static final String WILDCARD = "*"; 178 private static final char OUT_PREFIX = '!'; 179 180 private final SparseBooleanArray mIsIn; 181 private final boolean mDefaultIsIn; 182 final String mSpec; 183 184 public IntInOutMatcher(String spec) { 185 if (TextUtils.isEmpty(spec)) { 186 throw new IllegalArgumentException("Spec must not be empty"); 187 } 188 189 boolean defaultIsIn = false; 190 boolean foundWildcard = false; 191 192 mSpec = spec; 193 mIsIn = new SparseBooleanArray(); 194 195 for (String itemPrefixed : spec.split(",", -1)) { 196 if (itemPrefixed.length() == 0) { 197 throw new IllegalArgumentException( 198 "Illegal spec, must not have zero-length items: `" + spec + "`"); 199 } 200 boolean isIn = itemPrefixed.charAt(0) != OUT_PREFIX; 201 String item = isIn ? itemPrefixed : itemPrefixed.substring(1); 202 203 if (itemPrefixed.length() == 0) { 204 throw new IllegalArgumentException( 205 "Illegal spec, must not have zero-length items: `" + spec + "`"); 206 } 207 208 if (WILDCARD.equals(item)) { 209 if (foundWildcard) { 210 throw new IllegalArgumentException("Illegal spec, `" + WILDCARD + 211 "` must not appear multiple times in `" + spec + "`"); 212 } 213 defaultIsIn = isIn; 214 foundWildcard = true; 215 } else { 216 int key = Integer.parseInt(item); 217 if (mIsIn.indexOfKey(key) >= 0) { 218 throw new IllegalArgumentException("Illegal spec, `" + key + 219 "` must not appear multiple times in `" + spec + "`"); 220 } 221 mIsIn.put(key, isIn); 222 } 223 } 224 225 if (!foundWildcard) { 226 throw new IllegalArgumentException("Illegal spec, must specify either * or !*"); 227 } 228 229 mDefaultIsIn = defaultIsIn; 230 } 231 232 public boolean isIn(int value) { 233 return (mIsIn.get(value, mDefaultIsIn)); 234 } 235 } 236 } 237