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