Home | History | Annotate | Download | only in phone
      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