1 /* 2 * Copyright (C) 2016 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 android.hardware.display; 18 19 import static android.provider.Settings.Secure.SCREEN_OFF_UNLOCK_UDFPS_ENABLED; 20 21 import android.annotation.TestApi; 22 import android.content.Context; 23 import android.hardware.biometrics.Flags; 24 import android.os.Build; 25 import android.os.SystemProperties; 26 import android.provider.Settings; 27 import android.text.TextUtils; 28 import android.util.ArrayMap; 29 import android.util.SparseArray; 30 31 import com.android.internal.R; 32 import com.android.internal.util.ArrayUtils; 33 34 import java.util.Map; 35 36 /** 37 * AmbientDisplayConfiguration encapsulates reading access to the configuration of ambient display. 38 * 39 * @hide 40 */ 41 @TestApi 42 public class AmbientDisplayConfiguration { 43 private static final String TAG = "AmbientDisplayConfig"; 44 private final Context mContext; 45 private final boolean mAlwaysOnByDefault; 46 private final boolean mPickupGestureEnabledByDefault; 47 private final boolean mScreenOffUdfpsAvailable; 48 49 /** Copied from android.provider.Settings.Secure since these keys are hidden. */ 50 private static final String[] DOZE_SETTINGS = { 51 Settings.Secure.DOZE_ENABLED, 52 Settings.Secure.DOZE_ALWAYS_ON, 53 Settings.Secure.DOZE_PICK_UP_GESTURE, 54 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, 55 Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, 56 Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, 57 Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, 58 Settings.Secure.DOZE_TAP_SCREEN_GESTURE 59 }; 60 61 /** Non-user configurable doze settings */ 62 private static final String[] NON_USER_CONFIGURABLE_DOZE_SETTINGS = { 63 Settings.Secure.DOZE_QUICK_PICKUP_GESTURE 64 }; 65 66 final SparseArray<Map<String, String>> mUsersInitialValues = new SparseArray<>(); 67 68 /** @hide */ 69 @TestApi AmbientDisplayConfiguration(Context context)70 public AmbientDisplayConfiguration(Context context) { 71 mContext = context; 72 mAlwaysOnByDefault = mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnEnabled); 73 mPickupGestureEnabledByDefault = 74 mContext.getResources().getBoolean(R.bool.config_dozePickupGestureEnabled); 75 mScreenOffUdfpsAvailable = 76 mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_enabled); 77 } 78 79 /** @hide */ enabled(int user)80 public boolean enabled(int user) { 81 return pulseOnNotificationEnabled(user) 82 || pulseOnLongPressEnabled(user) 83 || alwaysOnEnabled(user) 84 || wakeLockScreenGestureEnabled(user) 85 || wakeDisplayGestureEnabled(user) 86 || pickupGestureEnabled(user) 87 || tapGestureEnabled(user) 88 || doubleTapGestureEnabled(user) 89 || quickPickupSensorEnabled(user) 90 || screenOffUdfpsEnabled(user); 91 } 92 93 /** @hide */ pulseOnNotificationEnabled(int user)94 public boolean pulseOnNotificationEnabled(int user) { 95 return boolSettingDefaultOn(Settings.Secure.DOZE_ENABLED, user) 96 && pulseOnNotificationAvailable(); 97 } 98 99 /** @hide */ pulseOnNotificationAvailable()100 public boolean pulseOnNotificationAvailable() { 101 return mContext.getResources().getBoolean(R.bool.config_pulseOnNotificationsAvailable) 102 && ambientDisplayAvailable(); 103 } 104 105 /** @hide */ pickupGestureEnabled(int user)106 public boolean pickupGestureEnabled(int user) { 107 return boolSetting(Settings.Secure.DOZE_PICK_UP_GESTURE, user, 108 mPickupGestureEnabledByDefault ? 1 : 0) 109 && dozePickupSensorAvailable(); 110 } 111 112 /** @hide */ dozePickupSensorAvailable()113 public boolean dozePickupSensorAvailable() { 114 return mContext.getResources().getBoolean(R.bool.config_dozePulsePickup); 115 } 116 117 /** @hide */ tapGestureEnabled(int user)118 public boolean tapGestureEnabled(int user) { 119 return boolSettingDefaultOn(Settings.Secure.DOZE_TAP_SCREEN_GESTURE, user) 120 && tapSensorAvailable(); 121 } 122 123 /** @hide */ tapSensorAvailable()124 public boolean tapSensorAvailable() { 125 for (String tapType : tapSensorTypeMapping()) { 126 if (!TextUtils.isEmpty(tapType)) { 127 return true; 128 } 129 } 130 return false; 131 } 132 133 /** @hide */ doubleTapGestureEnabled(int user)134 public boolean doubleTapGestureEnabled(int user) { 135 return boolSettingDefaultOn(Settings.Secure.DOZE_DOUBLE_TAP_GESTURE, user) 136 && doubleTapSensorAvailable(); 137 } 138 139 /** @hide */ doubleTapSensorAvailable()140 public boolean doubleTapSensorAvailable() { 141 return !TextUtils.isEmpty(doubleTapSensorType()); 142 } 143 144 /** @hide */ quickPickupSensorEnabled(int user)145 public boolean quickPickupSensorEnabled(int user) { 146 return boolSettingDefaultOn(Settings.Secure.DOZE_QUICK_PICKUP_GESTURE, user) 147 && !TextUtils.isEmpty(quickPickupSensorType()) 148 && pickupGestureEnabled(user) 149 && !alwaysOnEnabled(user); 150 } 151 152 /** @hide */ screenOffUdfpsEnabled(int user)153 public boolean screenOffUdfpsEnabled(int user) { 154 return !TextUtils.isEmpty(udfpsLongPressSensorType()) 155 && ((mScreenOffUdfpsAvailable && Flags.screenOffUnlockUdfps()) 156 && mContext.getResources().getBoolean(R.bool.config_screen_off_udfps_default_on) 157 ? boolSettingDefaultOn(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user) 158 : boolSettingDefaultOff(SCREEN_OFF_UNLOCK_UDFPS_ENABLED, user)); 159 } 160 161 /** @hide */ wakeScreenGestureAvailable()162 public boolean wakeScreenGestureAvailable() { 163 return mContext.getResources() 164 .getBoolean(R.bool.config_dozeWakeLockScreenSensorAvailable); 165 } 166 167 /** @hide */ wakeLockScreenGestureEnabled(int user)168 public boolean wakeLockScreenGestureEnabled(int user) { 169 return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE, user) 170 && wakeScreenGestureAvailable(); 171 } 172 173 /** @hide */ wakeDisplayGestureEnabled(int user)174 public boolean wakeDisplayGestureEnabled(int user) { 175 return boolSettingDefaultOn(Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE, user) 176 && wakeScreenGestureAvailable(); 177 } 178 179 /** @hide */ getWakeLockScreenDebounce()180 public long getWakeLockScreenDebounce() { 181 return mContext.getResources().getInteger(R.integer.config_dozeWakeLockScreenDebounce); 182 } 183 184 /** @hide */ doubleTapSensorType()185 public String doubleTapSensorType() { 186 return mContext.getResources().getString(R.string.config_dozeDoubleTapSensorType); 187 } 188 189 /** @hide 190 * May support multiple postures. 191 */ tapSensorTypeMapping()192 public String[] tapSensorTypeMapping() { 193 String[] postureMapping = 194 mContext.getResources().getStringArray(R.array.config_dozeTapSensorPostureMapping); 195 if (ArrayUtils.isEmpty(postureMapping)) { 196 return new String[] { 197 mContext.getResources().getString(R.string.config_dozeTapSensorType) 198 }; 199 } 200 return postureMapping; 201 } 202 203 /** @hide */ longPressSensorType()204 public String longPressSensorType() { 205 return mContext.getResources().getString(R.string.config_dozeLongPressSensorType); 206 } 207 208 /** @hide */ udfpsLongPressSensorType()209 public String udfpsLongPressSensorType() { 210 return mContext.getResources().getString(R.string.config_dozeUdfpsLongPressSensorType); 211 } 212 213 /** @hide */ quickPickupSensorType()214 public String quickPickupSensorType() { 215 return mContext.getResources().getString(R.string.config_quickPickupSensorType); 216 } 217 218 /** @hide */ pulseOnLongPressEnabled(int user)219 public boolean pulseOnLongPressEnabled(int user) { 220 return pulseOnLongPressAvailable() && boolSettingDefaultOff( 221 Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, user); 222 } 223 pulseOnLongPressAvailable()224 private boolean pulseOnLongPressAvailable() { 225 return !TextUtils.isEmpty(longPressSensorType()); 226 } 227 228 /** 229 * Returns if Always-on-Display functionality is enabled on the display for a specified user. 230 * 231 * @hide 232 */ 233 @TestApi alwaysOnEnabled(int user)234 public boolean alwaysOnEnabled(int user) { 235 return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0) 236 && alwaysOnAvailable() && !accessibilityInversionEnabled(user); 237 } 238 239 /** 240 * Returns if Always-on-Display functionality is available on the display. 241 * 242 * @hide 243 */ 244 @TestApi alwaysOnAvailable()245 public boolean alwaysOnAvailable() { 246 return (alwaysOnDisplayDebuggingEnabled() || alwaysOnDisplayAvailable()) 247 && ambientDisplayAvailable(); 248 } 249 250 /** 251 * Returns if Always-on-Display functionality is available on the display for a specified user. 252 * 253 * @hide 254 */ 255 @TestApi alwaysOnAvailableForUser(int user)256 public boolean alwaysOnAvailableForUser(int user) { 257 return alwaysOnAvailable() && !accessibilityInversionEnabled(user); 258 } 259 260 /** @hide */ ambientDisplayComponent()261 public String ambientDisplayComponent() { 262 return mContext.getResources().getString(R.string.config_dozeComponent); 263 } 264 265 /** @hide */ accessibilityInversionEnabled(int user)266 public boolean accessibilityInversionEnabled(int user) { 267 return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user); 268 } 269 270 /** @hide */ ambientDisplayAvailable()271 public boolean ambientDisplayAvailable() { 272 return !TextUtils.isEmpty(ambientDisplayComponent()); 273 } 274 275 /** @hide */ dozeSuppressed(int user)276 public boolean dozeSuppressed(int user) { 277 return boolSettingDefaultOff(Settings.Secure.SUPPRESS_DOZE, user); 278 } 279 alwaysOnDisplayAvailable()280 private boolean alwaysOnDisplayAvailable() { 281 return mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnDisplayAvailable); 282 } 283 alwaysOnDisplayDebuggingEnabled()284 private boolean alwaysOnDisplayDebuggingEnabled() { 285 return SystemProperties.getBoolean("debug.doze.aod", false) && Build.IS_DEBUGGABLE; 286 } 287 boolSettingDefaultOn(String name, int user)288 private boolean boolSettingDefaultOn(String name, int user) { 289 return boolSetting(name, user, 1); 290 } 291 boolSettingDefaultOff(String name, int user)292 private boolean boolSettingDefaultOff(String name, int user) { 293 return boolSetting(name, user, 0); 294 } 295 boolSetting(String name, int user, int def)296 private boolean boolSetting(String name, int user, int def) { 297 return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0; 298 } 299 300 /** @hide */ 301 @TestApi disableDozeSettings(int userId)302 public void disableDozeSettings(int userId) { 303 disableDozeSettings(false /* shouldDisableNonUserConfigurable */, userId); 304 } 305 306 /** @hide */ 307 @TestApi disableDozeSettings(boolean shouldDisableNonUserConfigurable, int userId)308 public void disableDozeSettings(boolean shouldDisableNonUserConfigurable, int userId) { 309 Map<String, String> initialValues = mUsersInitialValues.get(userId); 310 if (initialValues != null && !initialValues.isEmpty()) { 311 throw new IllegalStateException("Don't call #disableDozeSettings more than once," 312 + "without first calling #restoreDozeSettings"); 313 } 314 initialValues = new ArrayMap<>(); 315 for (String name : DOZE_SETTINGS) { 316 initialValues.put(name, getDozeSetting(name, userId)); 317 putDozeSetting(name, "0", userId); 318 } 319 if (shouldDisableNonUserConfigurable) { 320 for (String name : NON_USER_CONFIGURABLE_DOZE_SETTINGS) { 321 initialValues.put(name, getDozeSetting(name, userId)); 322 putDozeSetting(name, "0", userId); 323 } 324 } 325 mUsersInitialValues.put(userId, initialValues); 326 } 327 328 /** @hide */ 329 @TestApi restoreDozeSettings(int userId)330 public void restoreDozeSettings(int userId) { 331 final Map<String, String> initialValues = mUsersInitialValues.get(userId); 332 if (initialValues != null && !initialValues.isEmpty()) { 333 for (String name : DOZE_SETTINGS) { 334 putDozeSetting(name, initialValues.get(name), userId); 335 } 336 mUsersInitialValues.remove(userId); 337 } 338 } 339 getDozeSetting(String name, int userId)340 private String getDozeSetting(String name, int userId) { 341 return Settings.Secure.getStringForUser(mContext.getContentResolver(), name, userId); 342 } 343 putDozeSetting(String name, String value, int userId)344 private void putDozeSetting(String name, String value, int userId) { 345 Settings.Secure.putStringForUser(mContext.getContentResolver(), name, value, userId); 346 } 347 } 348