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.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