1 /* 2 * Copyright (C) 2020 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.server.vibrator; 18 19 import static android.os.VibrationAttributes.USAGE_ACCESSIBILITY; 20 import static android.os.VibrationAttributes.USAGE_ALARM; 21 import static android.os.VibrationAttributes.USAGE_COMMUNICATION_REQUEST; 22 import static android.os.VibrationAttributes.USAGE_HARDWARE_FEEDBACK; 23 import static android.os.VibrationAttributes.USAGE_IME_FEEDBACK; 24 import static android.os.VibrationAttributes.USAGE_MEDIA; 25 import static android.os.VibrationAttributes.USAGE_NOTIFICATION; 26 import static android.os.VibrationAttributes.USAGE_PHYSICAL_EMULATION; 27 import static android.os.VibrationAttributes.USAGE_RINGTONE; 28 import static android.os.VibrationAttributes.USAGE_TOUCH; 29 import static android.os.VibrationAttributes.USAGE_UNKNOWN; 30 31 import android.annotation.NonNull; 32 import android.annotation.Nullable; 33 import android.app.ActivityManager; 34 import android.app.IActivityManager; 35 import android.app.SynchronousUserSwitchObserver; 36 import android.app.UidObserver; 37 import android.content.BroadcastReceiver; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.content.IntentFilter; 41 import android.content.pm.PackageManagerInternal; 42 import android.content.res.Resources; 43 import android.database.ContentObserver; 44 import android.media.AudioManager; 45 import android.net.Uri; 46 import android.os.BatteryManager; 47 import android.os.Handler; 48 import android.os.PowerManager; 49 import android.os.PowerManagerInternal; 50 import android.os.PowerSaveState; 51 import android.os.Process; 52 import android.os.RemoteException; 53 import android.os.UserHandle; 54 import android.os.VibrationAttributes; 55 import android.os.VibrationEffect; 56 import android.os.Vibrator; 57 import android.os.Vibrator.VibrationIntensity; 58 import android.os.vibrator.VibrationConfig; 59 import android.provider.Settings; 60 import android.util.IndentingPrintWriter; 61 import android.util.Slog; 62 import android.util.SparseArray; 63 import android.util.SparseIntArray; 64 import android.util.proto.ProtoOutputStream; 65 66 import com.android.internal.annotations.GuardedBy; 67 import com.android.internal.annotations.VisibleForTesting; 68 import com.android.server.LocalServices; 69 import com.android.server.companion.virtual.VirtualDeviceManagerInternal; 70 import com.android.server.vibrator.VibrationSession.CallerInfo; 71 import com.android.server.vibrator.VibrationSession.Status; 72 73 import java.io.PrintWriter; 74 import java.util.ArrayList; 75 import java.util.Arrays; 76 import java.util.HashSet; 77 import java.util.List; 78 import java.util.Objects; 79 import java.util.Set; 80 81 /** Controls all the system settings related to vibration. */ 82 final class VibrationSettings { 83 private static final String TAG = "VibrationSettings"; 84 85 /** 86 * Set of usages allowed for vibrations from background processes. 87 * 88 * <p>Some examples are notification, ringtone or alarm vibrations, that are allowed to vibrate 89 * unexpectedly as they are meant to grab the user's attention. Hardware feedback and physical 90 * emulation are also supported, as the trigger process might still be in the background when 91 * the user interaction wakes the device. 92 */ 93 private static final Set<Integer> BACKGROUND_PROCESS_USAGE_ALLOWLIST = new HashSet<>( 94 Arrays.asList( 95 USAGE_RINGTONE, 96 USAGE_ALARM, 97 USAGE_NOTIFICATION, 98 USAGE_COMMUNICATION_REQUEST, 99 USAGE_HARDWARE_FEEDBACK, 100 USAGE_PHYSICAL_EMULATION)); 101 102 /** 103 * Set of usages allowed for vibrations in battery saver mode (low power). 104 * 105 * <p>Some examples are ringtone or alarm vibrations, that have high priority and should vibrate 106 * even when the device is saving battery. 107 */ 108 private static final Set<Integer> BATTERY_SAVER_USAGE_ALLOWLIST = new HashSet<>( 109 Arrays.asList( 110 USAGE_RINGTONE, 111 USAGE_ALARM, 112 USAGE_COMMUNICATION_REQUEST, 113 USAGE_PHYSICAL_EMULATION, 114 USAGE_HARDWARE_FEEDBACK)); 115 116 /** 117 * Usage allowed for vibrations when {@link Settings.System#VIBRATE_ON} is disabled. 118 * 119 * <p>The only allowed usage is accessibility, which is applied when the user enables talkback. 120 * Other usages that must ignore this setting should use 121 * {@link VibrationAttributes#FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF}. 122 */ 123 private static final int VIBRATE_ON_DISABLED_USAGE_ALLOWED = USAGE_ACCESSIBILITY; 124 125 /** 126 * Set of usages allowed for vibrations from system packages when the screen goes off. 127 * 128 * <p>Some examples are touch and hardware feedback, and physical emulation. When the system is 129 * playing one of these usages during the screen off event then the vibration will not be 130 * cancelled by the service. 131 */ 132 private static final Set<Integer> SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST = new HashSet<>( 133 Arrays.asList( 134 USAGE_TOUCH, 135 USAGE_ACCESSIBILITY, 136 USAGE_PHYSICAL_EMULATION, 137 USAGE_HARDWARE_FEEDBACK)); 138 139 /** 140 * Set of reasons for {@link PowerManager} going to sleep events that allows vibrations to 141 * continue running. 142 * 143 * <p>Some examples are timeout and inattentive, which indicates automatic screen off events. 144 * When a vibration is playing during one of these screen off events then it will not be 145 * cancelled by the service. 146 */ 147 private static final Set<Integer> POWER_MANAGER_SLEEP_REASON_ALLOWLIST = new HashSet<>( 148 Arrays.asList( 149 PowerManager.GO_TO_SLEEP_REASON_INATTENTIVE, 150 PowerManager.GO_TO_SLEEP_REASON_TIMEOUT)); 151 152 /** Listener for changes on vibration settings. */ 153 interface OnVibratorSettingsChanged { 154 /** Callback triggered when any of the vibrator settings change. */ onChange()155 void onChange(); 156 } 157 158 private final Object mLock = new Object(); 159 private final Context mContext; 160 @VisibleForTesting 161 final SettingsContentObserver mSettingObserver; 162 @VisibleForTesting 163 final RingerModeBroadcastReceiver mRingerModeBroadcastReceiver; 164 @VisibleForTesting 165 final BatteryBroadcastReceiver mBatteryBroadcastReceiver; 166 @VisibleForTesting 167 final VibrationUidObserver mUidObserver; 168 @VisibleForTesting 169 final VibrationUserSwitchObserver mUserSwitchObserver; 170 @VisibleForTesting 171 final VibrationLowPowerModeListener mLowPowerModeListener; 172 173 @GuardedBy("mLock") 174 private final List<OnVibratorSettingsChanged> mListeners = new ArrayList<>(); 175 private final SparseArray<VibrationEffect> mFallbackEffects; 176 177 private final VibrationConfig mVibrationConfig; 178 179 @GuardedBy("mLock") 180 @Nullable 181 private AudioManager mAudioManager; 182 @GuardedBy("mLock") 183 @Nullable 184 private PowerManagerInternal mPowerManagerInternal; 185 @GuardedBy("mLock") 186 @Nullable 187 private VirtualDeviceManagerInternal mVirtualDeviceManagerInternal; 188 189 @GuardedBy("mLock") 190 private String mSystemUiPackage; 191 @GuardedBy("mLock") 192 private boolean mVibrateInputDevices; 193 @GuardedBy("mLock") 194 private SparseIntArray mCurrentVibrationIntensities = new SparseIntArray(); 195 @GuardedBy("mLock") 196 private boolean mBatterySaverMode; 197 @GuardedBy("mLock") 198 private boolean mVibrateOn; 199 @GuardedBy("mLock") 200 private int mRingerMode; 201 @GuardedBy("mLock") 202 private boolean mOnWirelessCharger; 203 VibrationSettings(Context context, Handler handler)204 VibrationSettings(Context context, Handler handler) { 205 this(context, handler, new VibrationConfig(context.getResources())); 206 } 207 208 @VisibleForTesting VibrationSettings(Context context, Handler handler, VibrationConfig config)209 VibrationSettings(Context context, Handler handler, VibrationConfig config) { 210 mContext = context; 211 mVibrationConfig = config; 212 mSettingObserver = new SettingsContentObserver(handler); 213 mRingerModeBroadcastReceiver = new RingerModeBroadcastReceiver(); 214 mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(); 215 mUidObserver = new VibrationUidObserver(); 216 mUserSwitchObserver = new VibrationUserSwitchObserver(); 217 mLowPowerModeListener = new VibrationLowPowerModeListener(); 218 219 VibrationEffect clickEffect = createEffectFromResource( 220 com.android.internal.R.array.config_virtualKeyVibePattern); 221 VibrationEffect doubleClickEffect = createEffectFromResource( 222 com.android.internal.R.array.config_doubleClickVibePattern); 223 VibrationEffect heavyClickEffect = createEffectFromResource( 224 com.android.internal.R.array.config_longPressVibePattern); 225 VibrationEffect tickEffect = createEffectFromResource( 226 com.android.internal.R.array.config_clockTickVibePattern); 227 228 mFallbackEffects = new SparseArray<>(); 229 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect); 230 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect); 231 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect); 232 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect); 233 mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK, 234 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)); 235 236 // Update with current values from settings. 237 update(); 238 } 239 onSystemReady()240 public void onSystemReady() { 241 onSystemReady(LocalServices.getService(PackageManagerInternal.class), 242 LocalServices.getService(PowerManagerInternal.class), 243 ActivityManager.getService(), 244 LocalServices.getService(VirtualDeviceManagerInternal.class), 245 mContext.getSystemService(AudioManager.class)); 246 } 247 248 @VisibleForTesting onSystemReady(PackageManagerInternal packageManagerInternal, PowerManagerInternal powerManagerInternal, IActivityManager activityManagerInternal, @Nullable VirtualDeviceManagerInternal virtualDeviceManagerInternal, @Nullable AudioManager audioManager)249 void onSystemReady(PackageManagerInternal packageManagerInternal, 250 PowerManagerInternal powerManagerInternal, 251 IActivityManager activityManagerInternal, 252 @Nullable VirtualDeviceManagerInternal virtualDeviceManagerInternal, 253 @Nullable AudioManager audioManager) { 254 int ringerMode = (audioManager == null) 255 ? AudioManager.RINGER_MODE_NORMAL 256 : audioManager.getRingerModeInternal(); 257 String sysUiPackage = packageManagerInternal.getSystemUiServiceComponent().getPackageName(); 258 259 synchronized (mLock) { 260 mPowerManagerInternal = powerManagerInternal; 261 mVirtualDeviceManagerInternal = virtualDeviceManagerInternal; 262 mAudioManager = audioManager; 263 mRingerMode = ringerMode; 264 mSystemUiPackage = sysUiPackage; 265 } 266 267 try { 268 activityManagerInternal.registerUidObserver(mUidObserver, 269 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, 270 ActivityManager.PROCESS_STATE_UNKNOWN, /* callingPackage= */ null); 271 } catch (RemoteException e) { 272 // ignored; both services live in system_server 273 } 274 275 try { 276 activityManagerInternal.registerUserSwitchObserver(mUserSwitchObserver, TAG); 277 } catch (RemoteException e) { 278 // ignored; both services live in system_server 279 } 280 281 powerManagerInternal.registerLowPowerModeObserver(mLowPowerModeListener); 282 283 mContext.registerReceiver(mRingerModeBroadcastReceiver, 284 new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION), 285 Context.RECEIVER_EXPORTED_UNAUDITED); 286 287 // Listen to all settings that might affect the result of Vibrator.getVibrationIntensity. 288 registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES)); 289 registerSettingsObserver(Settings.System.getUriFor(Settings.System.VIBRATE_ON)); 290 registerSettingsObserver(Settings.System.getUriFor( 291 Settings.System.HAPTIC_FEEDBACK_ENABLED)); 292 registerSettingsObserver( 293 Settings.System.getUriFor(Settings.System.ALARM_VIBRATION_INTENSITY)); 294 registerSettingsObserver( 295 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY)); 296 registerSettingsObserver( 297 Settings.System.getUriFor(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY)); 298 registerSettingsObserver( 299 Settings.System.getUriFor(Settings.System.MEDIA_VIBRATION_INTENSITY)); 300 registerSettingsObserver( 301 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY)); 302 registerSettingsObserver( 303 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY)); 304 registerSettingsObserver( 305 Settings.System.getUriFor(Settings.System.KEYBOARD_VIBRATION_ENABLED)); 306 307 if (mVibrationConfig.ignoreVibrationsOnWirelessCharger()) { 308 Intent batteryStatus = mContext.registerReceiver( 309 mBatteryBroadcastReceiver, 310 new IntentFilter(Intent.ACTION_BATTERY_CHANGED), 311 Context.RECEIVER_NOT_EXPORTED); 312 // After registering the receiver for battery status, process the sticky broadcast that 313 // may have been returned upon registration of the receiver. This helps to capture the 314 // current charging state, and subsequent charging states can be listened to via the 315 // receiver registered. 316 if (batteryStatus != null) { 317 updateBatteryInfo(batteryStatus); 318 } 319 } 320 321 // Update with newly loaded services. 322 update(); 323 } 324 325 /** 326 * Add listener to vibrator settings changes. This will trigger the listener with current state 327 * immediately and every time one of the settings change. 328 */ addListener(OnVibratorSettingsChanged listener)329 public void addListener(OnVibratorSettingsChanged listener) { 330 synchronized (mLock) { 331 if (!mListeners.contains(listener)) { 332 mListeners.add(listener); 333 } 334 } 335 } 336 337 /** Remove listener to vibrator settings. */ removeListener(OnVibratorSettingsChanged listener)338 public void removeListener(OnVibratorSettingsChanged listener) { 339 synchronized (mLock) { 340 mListeners.remove(listener); 341 } 342 } 343 344 /** 345 * The duration, in milliseconds, that should be applied to convert vibration effect's 346 * {@link android.os.vibrator.RampSegment} to a {@link android.os.vibrator.StepSegment} on 347 * devices without PWLE support. 348 */ getRampStepDuration()349 public int getRampStepDuration() { 350 return mVibrationConfig.getRampStepDurationMs(); 351 } 352 353 /** 354 * The duration, in milliseconds, that should be applied to the ramp to turn off the vibrator 355 * when a vibration is cancelled or finished at non-zero amplitude. 356 */ getRampDownDuration()357 public int getRampDownDuration() { 358 return mVibrationConfig.getRampDownDurationMs(); 359 } 360 361 /** 362 * Return default vibration intensity for given usage. 363 * 364 * @param usageHint one of VibrationAttributes.USAGE_* 365 * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_* 366 */ getDefaultIntensity(@ibrationAttributes.Usage int usageHint)367 public int getDefaultIntensity(@VibrationAttributes.Usage int usageHint) { 368 return mVibrationConfig.getDefaultVibrationIntensity(usageHint); 369 } 370 371 /** 372 * Return the current vibration intensity set for given usage at the user settings. 373 * 374 * @param usageHint one of VibrationAttributes.USAGE_* 375 * @return The vibration intensity, one of Vibrator.VIBRATION_INTENSITY_* 376 */ getCurrentIntensity(@ibrationAttributes.Usage int usageHint)377 public int getCurrentIntensity(@VibrationAttributes.Usage int usageHint) { 378 int defaultIntensity = getDefaultIntensity(usageHint); 379 synchronized (mLock) { 380 return mCurrentVibrationIntensities.get(usageHint, defaultIntensity); 381 } 382 } 383 384 /** 385 * Returns the duration, in milliseconds, that the vibrator control service will wait for new 386 * vibration params. 387 * @return The request vibration params timeout in milliseconds. 388 */ getRequestVibrationParamsTimeoutMs()389 public int getRequestVibrationParamsTimeoutMs() { 390 return mVibrationConfig.getRequestVibrationParamsTimeoutMs(); 391 } 392 393 /** 394 * The list of usages that should request vibration params before they are played. These 395 * usages don't have strong latency requirements, e.g. ringtone and notification, and can be 396 * slightly delayed. 397 */ getRequestVibrationParamsForUsages()398 public int[] getRequestVibrationParamsForUsages() { 399 return mVibrationConfig.getRequestVibrationParamsForUsages(); 400 } 401 402 /** 403 * Return a {@link VibrationEffect} that should be played if the device do not support given 404 * {@code effectId}. 405 * 406 * @param effectId one of VibrationEffect.EFFECT_* 407 * @return The effect to be played as a fallback 408 */ getFallbackEffect(int effectId)409 public VibrationEffect getFallbackEffect(int effectId) { 410 return mFallbackEffects.get(effectId); 411 } 412 413 /** Return {@code true} if input devices should vibrate instead of this device. */ shouldVibrateInputDevices()414 public boolean shouldVibrateInputDevices() { 415 return mVibrateInputDevices; 416 } 417 418 /** 419 * Check if given vibration should be ignored by the service. 420 * 421 * @return One of VibrationSession.Status.IGNORED_* values if the vibration should be ignored, 422 * null otherwise. 423 */ 424 @Nullable shouldIgnoreVibration(@onNull CallerInfo callerInfo)425 public Status shouldIgnoreVibration(@NonNull CallerInfo callerInfo) { 426 final int usage = callerInfo.attrs.getUsage(); 427 synchronized (mLock) { 428 if (!mUidObserver.isUidForeground(callerInfo.uid) 429 && !BACKGROUND_PROCESS_USAGE_ALLOWLIST.contains(usage)) { 430 return Status.IGNORED_BACKGROUND; 431 } 432 433 if (callerInfo.deviceId != Context.DEVICE_ID_DEFAULT 434 && callerInfo.deviceId != Context.DEVICE_ID_INVALID) { 435 return Status.IGNORED_FROM_VIRTUAL_DEVICE; 436 } 437 438 if (callerInfo.deviceId == Context.DEVICE_ID_INVALID 439 && isAppRunningOnAnyVirtualDevice(callerInfo.uid)) { 440 return Status.IGNORED_FROM_VIRTUAL_DEVICE; 441 } 442 443 if (mBatterySaverMode && !BATTERY_SAVER_USAGE_ALLOWLIST.contains(usage)) { 444 return Status.IGNORED_FOR_POWER; 445 } 446 447 if (!callerInfo.attrs.isFlagSet( 448 VibrationAttributes.FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF) 449 && !shouldVibrateForUserSetting(callerInfo)) { 450 return Status.IGNORED_FOR_SETTINGS; 451 } 452 453 if (!callerInfo.attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY)) { 454 if (!shouldVibrateForRingerModeLocked(usage)) { 455 return Status.IGNORED_FOR_RINGER_MODE; 456 } 457 } 458 459 if (mVibrationConfig.ignoreVibrationsOnWirelessCharger() && mOnWirelessCharger) { 460 return Status.IGNORED_ON_WIRELESS_CHARGER; 461 } 462 } 463 return null; 464 } 465 466 /** 467 * Check if given vibration should be cancelled by the service when the screen goes off. 468 * 469 * <p>When the system is entering a non-interactive state, we want to cancel vibrations in case 470 * a misbehaving app has abandoned them. However, it may happen that the system is currently 471 * playing haptic feedback as part of the transition. So we don't cancel system vibrations of 472 * usages like touch and hardware feedback, and physical emulation. 473 * 474 * @return true if the vibration should be cancelled when the screen goes off, false otherwise. 475 */ shouldCancelVibrationOnScreenOff(@onNull CallerInfo callerInfo, long vibrationStartUptimeMillis)476 public boolean shouldCancelVibrationOnScreenOff(@NonNull CallerInfo callerInfo, 477 long vibrationStartUptimeMillis) { 478 PowerManagerInternal pm; 479 String sysUiPackageName; 480 synchronized (mLock) { 481 pm = mPowerManagerInternal; 482 sysUiPackageName = mSystemUiPackage; 483 } 484 if (pm != null) { 485 // The SleepData from PowerManager may refer to a more recent sleep than the broadcast 486 // that triggered this method call. That's ok because only automatic sleeps would be 487 // ignored here and not cancel a vibration, and those are usually triggered by timeout 488 // or inactivity, so it's unlikely that it will override a more active goToSleep reason. 489 PowerManager.SleepData sleepData = pm.getLastGoToSleep(); 490 if (sleepData != null && (sleepData.goToSleepUptimeMillis < vibrationStartUptimeMillis 491 || POWER_MANAGER_SLEEP_REASON_ALLOWLIST.contains(sleepData.goToSleepReason))) { 492 // Ignore screen off events triggered before the vibration started, and all 493 // automatic "go to sleep" events from allowlist. 494 Slog.d(TAG, "Ignoring screen off event triggered at uptime " 495 + sleepData.goToSleepUptimeMillis + " for reason " 496 + PowerManager.sleepReasonToString(sleepData.goToSleepReason)); 497 return false; 498 } 499 } 500 if (!SYSTEM_VIBRATION_SCREEN_OFF_USAGE_ALLOWLIST.contains(callerInfo.attrs.getUsage())) { 501 // Usages not allowed even for system vibrations should always be cancelled. 502 return true; 503 } 504 // Only allow vibrations from System packages to continue vibrating when the screen goes off 505 return callerInfo.uid != Process.SYSTEM_UID && callerInfo.uid != 0 506 && !Objects.equals(sysUiPackageName, callerInfo.opPkg); 507 } 508 509 /** 510 * Return {@code true} if the device should vibrate for current ringer mode. 511 * 512 * <p>This checks the current {@link AudioManager#getRingerModeInternal()} against user settings 513 * for ringtone and notification usages. All other usages are allowed by this method. 514 */ 515 @GuardedBy("mLock") shouldVibrateForRingerModeLocked(@ibrationAttributes.Usage int usageHint)516 private boolean shouldVibrateForRingerModeLocked(@VibrationAttributes.Usage int usageHint) { 517 if ((usageHint != USAGE_RINGTONE) && (usageHint != USAGE_NOTIFICATION)) { 518 // Only ringtone and notification vibrations are disabled when phone is on silent mode. 519 return true; 520 } 521 return mRingerMode != AudioManager.RINGER_MODE_SILENT; 522 } 523 524 /** 525 * Return {@code true} if the device should vibrate for user setting, and 526 * {@code false} to ignore the vibration. 527 */ 528 @GuardedBy("mLock") shouldVibrateForUserSetting(CallerInfo callerInfo)529 private boolean shouldVibrateForUserSetting(CallerInfo callerInfo) { 530 final int usage = callerInfo.attrs.getUsage(); 531 if (!mVibrateOn && (VIBRATE_ON_DISABLED_USAGE_ALLOWED != usage)) { 532 // Main setting disabled. 533 return false; 534 } 535 536 // Apply individual user setting based on usage. 537 return getCurrentIntensity(usage) != Vibrator.VIBRATION_INTENSITY_OFF; 538 } 539 540 /** Update all cached settings and triggers registered listeners. */ update()541 void update() { 542 updateSettings(UserHandle.USER_CURRENT); 543 updateRingerMode(); 544 notifyListeners(); 545 } 546 updateSettings(int userHandle)547 private void updateSettings(int userHandle) { 548 synchronized (mLock) { 549 mVibrateInputDevices = 550 loadSystemSetting(Settings.System.VIBRATE_INPUT_DEVICES, 0, userHandle) > 0; 551 mVibrateOn = loadSystemSetting(Settings.System.VIBRATE_ON, 1, userHandle) > 0; 552 553 boolean isKeyboardVibrationOn = loadSystemSetting( 554 Settings.System.KEYBOARD_VIBRATION_ENABLED, 1, userHandle) > 0; 555 int keyboardIntensity = toIntensity(isKeyboardVibrationOn, 556 getDefaultIntensity(USAGE_IME_FEEDBACK)); 557 int alarmIntensity = toIntensity( 558 loadSystemSetting(Settings.System.ALARM_VIBRATION_INTENSITY, -1, userHandle), 559 getDefaultIntensity(USAGE_ALARM)); 560 int defaultHapticFeedbackIntensity = getDefaultIntensity(USAGE_TOUCH); 561 int hapticFeedbackIntensity = toIntensity( 562 loadSystemSetting(Settings.System.HAPTIC_FEEDBACK_INTENSITY, -1, userHandle), 563 defaultHapticFeedbackIntensity); 564 int positiveHapticFeedbackIntensity = toPositiveIntensity( 565 hapticFeedbackIntensity, defaultHapticFeedbackIntensity); 566 int hardwareFeedbackIntensity = toIntensity( 567 loadSystemSetting(Settings.System.HARDWARE_HAPTIC_FEEDBACK_INTENSITY, -1, 568 userHandle), 569 positiveHapticFeedbackIntensity); 570 int mediaIntensity = toIntensity( 571 loadSystemSetting(Settings.System.MEDIA_VIBRATION_INTENSITY, -1, userHandle), 572 getDefaultIntensity(USAGE_MEDIA)); 573 int defaultNotificationIntensity = getDefaultIntensity(USAGE_NOTIFICATION); 574 int notificationIntensity = toIntensity( 575 loadSystemSetting(Settings.System.NOTIFICATION_VIBRATION_INTENSITY, -1, 576 userHandle), 577 defaultNotificationIntensity); 578 int positiveNotificationIntensity = toPositiveIntensity( 579 notificationIntensity, defaultNotificationIntensity); 580 int ringIntensity = toIntensity( 581 loadSystemSetting(Settings.System.RING_VIBRATION_INTENSITY, -1, userHandle), 582 getDefaultIntensity(USAGE_RINGTONE)); 583 584 mCurrentVibrationIntensities.clear(); 585 mCurrentVibrationIntensities.put(USAGE_ALARM, alarmIntensity); 586 mCurrentVibrationIntensities.put(USAGE_NOTIFICATION, notificationIntensity); 587 mCurrentVibrationIntensities.put(USAGE_MEDIA, mediaIntensity); 588 mCurrentVibrationIntensities.put(USAGE_UNKNOWN, mediaIntensity); 589 mCurrentVibrationIntensities.put(USAGE_RINGTONE, ringIntensity); 590 591 // Communication request is not disabled by the notification setting. 592 mCurrentVibrationIntensities.put(USAGE_COMMUNICATION_REQUEST, 593 positiveNotificationIntensity); 594 595 // This should adapt the behavior preceding the introduction of this new setting 596 // key, which is to apply HAPTIC_FEEDBACK_INTENSITY, unless it's disabled. 597 mCurrentVibrationIntensities.put(USAGE_HARDWARE_FEEDBACK, hardwareFeedbackIntensity); 598 mCurrentVibrationIntensities.put(USAGE_PHYSICAL_EMULATION, hardwareFeedbackIntensity); 599 600 if (!loadBooleanSetting(Settings.System.HAPTIC_FEEDBACK_ENABLED, userHandle)) { 601 // Make sure deprecated boolean setting still disables touch vibrations. 602 mCurrentVibrationIntensities.put(USAGE_TOUCH, Vibrator.VIBRATION_INTENSITY_OFF); 603 } else { 604 mCurrentVibrationIntensities.put(USAGE_TOUCH, hapticFeedbackIntensity); 605 } 606 607 if (mVibrationConfig.isKeyboardVibrationSettingsSupported()) { 608 mCurrentVibrationIntensities.put(USAGE_IME_FEEDBACK, keyboardIntensity); 609 } else { 610 mCurrentVibrationIntensities.put(USAGE_IME_FEEDBACK, hapticFeedbackIntensity); 611 } 612 613 // A11y is not disabled by any haptic feedback setting. 614 mCurrentVibrationIntensities.put(USAGE_ACCESSIBILITY, positiveHapticFeedbackIntensity); 615 } 616 } 617 updateRingerMode()618 private void updateRingerMode() { 619 synchronized (mLock) { 620 if (mAudioManager == null) { 621 // Service not ready yet or audio service not available, skip this update request. 622 return; 623 } 624 mRingerMode = mAudioManager.getRingerModeInternal(); 625 } 626 } 627 updateBatteryInfo(Intent intent)628 private void updateBatteryInfo(Intent intent) { 629 int pluggedInfo = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); 630 synchronized (mLock) { 631 mOnWirelessCharger = pluggedInfo == BatteryManager.BATTERY_PLUGGED_WIRELESS; 632 } 633 } 634 635 @Override toString()636 public String toString() { 637 synchronized (mLock) { 638 StringBuilder vibrationIntensitiesString = new StringBuilder("{"); 639 for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) { 640 int usage = mCurrentVibrationIntensities.keyAt(i); 641 int intensity = mCurrentVibrationIntensities.valueAt(i); 642 vibrationIntensitiesString.append(VibrationAttributes.usageToString(usage)) 643 .append("=(").append(intensityToString(intensity)) 644 .append(",default:").append(intensityToString(getDefaultIntensity(usage))) 645 .append("), "); 646 } 647 vibrationIntensitiesString.append('}'); 648 return "VibrationSettings{" 649 + "mVibratorConfig=" + mVibrationConfig 650 + ", mVibrateOn=" + mVibrateOn 651 + ", mVibrateInputDevices=" + mVibrateInputDevices 652 + ", mBatterySaverMode=" + mBatterySaverMode 653 + ", mRingerMode=" + ringerModeToString(mRingerMode) 654 + ", mOnWirelessCharger=" + mOnWirelessCharger 655 + ", mVibrationIntensities=" + vibrationIntensitiesString 656 + ", mProcStatesCache=" + mUidObserver.mProcStatesCache 657 + '}'; 658 } 659 } 660 661 /** Write current settings into given {@link PrintWriter}. */ dump(IndentingPrintWriter pw)662 void dump(IndentingPrintWriter pw) { 663 synchronized (mLock) { 664 pw.println("VibrationSettings:"); 665 pw.increaseIndent(); 666 pw.println("vibrateOn = " + mVibrateOn); 667 pw.println("vibrateInputDevices = " + mVibrateInputDevices); 668 pw.println("batterySaverMode = " + mBatterySaverMode); 669 pw.println("ringerMode = " + ringerModeToString(mRingerMode)); 670 pw.println("onWirelessCharger = " + mOnWirelessCharger); 671 pw.println("processStateCache size = " + mUidObserver.mProcStatesCache.size()); 672 673 pw.println("VibrationIntensities:"); 674 pw.increaseIndent(); 675 for (int i = 0; i < mCurrentVibrationIntensities.size(); i++) { 676 int usage = mCurrentVibrationIntensities.keyAt(i); 677 int intensity = mCurrentVibrationIntensities.valueAt(i); 678 pw.println(VibrationAttributes.usageToString(usage) + " = " 679 + intensityToString(intensity) 680 + ", default: " + intensityToString(getDefaultIntensity(usage))); 681 } 682 pw.decreaseIndent(); 683 684 mVibrationConfig.dumpWithoutDefaultSettings(pw); 685 pw.decreaseIndent(); 686 } 687 } 688 689 /** Write current settings into given {@link ProtoOutputStream}. */ dump(ProtoOutputStream proto)690 void dump(ProtoOutputStream proto) { 691 synchronized (mLock) { 692 proto.write(VibratorManagerServiceDumpProto.VIBRATE_ON, mVibrateOn); 693 proto.write(VibratorManagerServiceDumpProto.LOW_POWER_MODE, mBatterySaverMode); 694 proto.write(VibratorManagerServiceDumpProto.ALARM_INTENSITY, 695 getCurrentIntensity(USAGE_ALARM)); 696 proto.write(VibratorManagerServiceDumpProto.ALARM_DEFAULT_INTENSITY, 697 getDefaultIntensity(USAGE_ALARM)); 698 proto.write(VibratorManagerServiceDumpProto.HARDWARE_FEEDBACK_INTENSITY, 699 getCurrentIntensity(USAGE_HARDWARE_FEEDBACK)); 700 proto.write(VibratorManagerServiceDumpProto.HARDWARE_FEEDBACK_DEFAULT_INTENSITY, 701 getDefaultIntensity(USAGE_HARDWARE_FEEDBACK)); 702 proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_INTENSITY, 703 getCurrentIntensity(USAGE_TOUCH)); 704 proto.write(VibratorManagerServiceDumpProto.HAPTIC_FEEDBACK_DEFAULT_INTENSITY, 705 getDefaultIntensity(USAGE_TOUCH)); 706 proto.write(VibratorManagerServiceDumpProto.MEDIA_INTENSITY, 707 getCurrentIntensity(USAGE_MEDIA)); 708 proto.write(VibratorManagerServiceDumpProto.MEDIA_DEFAULT_INTENSITY, 709 getDefaultIntensity(USAGE_MEDIA)); 710 proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_INTENSITY, 711 getCurrentIntensity(USAGE_NOTIFICATION)); 712 proto.write(VibratorManagerServiceDumpProto.NOTIFICATION_DEFAULT_INTENSITY, 713 getDefaultIntensity(USAGE_NOTIFICATION)); 714 proto.write(VibratorManagerServiceDumpProto.RING_INTENSITY, 715 getCurrentIntensity(USAGE_RINGTONE)); 716 proto.write(VibratorManagerServiceDumpProto.RING_DEFAULT_INTENSITY, 717 getDefaultIntensity(USAGE_RINGTONE)); 718 } 719 } 720 notifyListeners()721 private void notifyListeners() { 722 List<OnVibratorSettingsChanged> currentListeners; 723 synchronized (mLock) { 724 currentListeners = new ArrayList<>(mListeners); 725 } 726 for (OnVibratorSettingsChanged listener : currentListeners) { 727 listener.onChange(); 728 } 729 } 730 intensityToString(int intensity)731 private static String intensityToString(int intensity) { 732 return switch (intensity) { 733 case Vibrator.VIBRATION_INTENSITY_OFF -> "OFF"; 734 case Vibrator.VIBRATION_INTENSITY_LOW -> "LOW"; 735 case Vibrator.VIBRATION_INTENSITY_MEDIUM -> "MEDIUM"; 736 case Vibrator.VIBRATION_INTENSITY_HIGH -> "HIGH"; 737 default -> "UNKNOWN INTENSITY " + intensity; 738 }; 739 } 740 ringerModeToString(int ringerMode)741 private static String ringerModeToString(int ringerMode) { 742 return switch (ringerMode) { 743 case AudioManager.RINGER_MODE_SILENT -> "silent"; 744 case AudioManager.RINGER_MODE_VIBRATE -> "vibrate"; 745 case AudioManager.RINGER_MODE_NORMAL -> "normal"; 746 default -> String.valueOf(ringerMode); 747 }; 748 } 749 750 @VibrationIntensity 751 private int toPositiveIntensity(int value, @VibrationIntensity int defaultValue) { 752 if (value == Vibrator.VIBRATION_INTENSITY_OFF) { 753 return defaultValue; 754 } 755 return toIntensity(value, defaultValue); 756 } 757 758 @VibrationIntensity 759 private int toIntensity(int value, @VibrationIntensity int defaultValue) { 760 if ((value < Vibrator.VIBRATION_INTENSITY_OFF) 761 || (value > Vibrator.VIBRATION_INTENSITY_HIGH)) { 762 return defaultValue; 763 } 764 return value; 765 } 766 767 @VibrationIntensity 768 private int toIntensity(boolean enabled, @VibrationIntensity int defaultValue) { 769 return enabled ? defaultValue : Vibrator.VIBRATION_INTENSITY_OFF; 770 } 771 772 private boolean loadBooleanSetting(String settingKey, int userHandle) { 773 return loadSystemSetting(settingKey, 0, userHandle) != 0; 774 } 775 776 private int loadSystemSetting(String settingName, int defaultValue, int userHandle) { 777 return Settings.System.getIntForUser(mContext.getContentResolver(), 778 settingName, defaultValue, userHandle); 779 } 780 781 private void registerSettingsObserver(Uri settingUri) { 782 mContext.getContentResolver().registerContentObserver( 783 settingUri, /* notifyForDescendants= */ true, mSettingObserver, 784 UserHandle.USER_ALL); 785 } 786 787 @Nullable 788 private VibrationEffect createEffectFromResource(int resId) { 789 return createEffectFromResource(mContext.getResources(), resId); 790 } 791 792 /** 793 * Provides a {@link VibrationEffect} from a timings-array provided as an int-array resource.. 794 * 795 * <p>If the timings array is {@code null} or empty, it returns {@code null}. 796 * 797 * <p>If the timings array has a size of one, it returns a one-shot vibration with duration that 798 * is equal to the single value in the array. 799 * 800 * <p>If the timings array has more than one values, it returns a non-repeating wave-form 801 * vibration with off-on timings as per the provided timings array. 802 */ 803 @Nullable 804 static VibrationEffect createEffectFromResource(Resources res, int resId) { 805 long[] timings = getLongIntArray(res, resId); 806 return createEffectFromTimings(timings); 807 } 808 809 @Nullable 810 private static VibrationEffect createEffectFromTimings(@Nullable long[] timings) { 811 if (timings == null || timings.length == 0) { 812 return null; 813 } else if (timings.length == 1) { 814 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE); 815 } else { 816 return VibrationEffect.createWaveform(timings, -1); 817 } 818 } 819 820 private static long[] getLongIntArray(Resources r, int resid) { 821 int[] ar = r.getIntArray(resid); 822 if (ar == null) { 823 return null; 824 } 825 long[] out = new long[ar.length]; 826 for (int i = 0; i < ar.length; i++) { 827 out[i] = ar[i]; 828 } 829 return out; 830 } 831 832 private boolean isAppRunningOnAnyVirtualDevice(int uid) { 833 VirtualDeviceManagerInternal vdm; 834 synchronized (mLock) { 835 vdm = mVirtualDeviceManagerInternal; 836 } 837 return vdm != null && vdm.isAppRunningOnAnyVirtualDevice(uid); 838 } 839 840 /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */ 841 @VisibleForTesting 842 final class SettingsContentObserver extends ContentObserver { 843 SettingsContentObserver(Handler handler) { 844 super(handler); 845 } 846 847 @Override 848 public void onChange(boolean selfChange) { 849 updateSettings(UserHandle.USER_CURRENT); 850 notifyListeners(); 851 } 852 } 853 854 /** Implementation of {@link BroadcastReceiver} to update on ringer mode change. */ 855 @VisibleForTesting 856 final class RingerModeBroadcastReceiver extends BroadcastReceiver { 857 @Override 858 public void onReceive(Context context, Intent intent) { 859 String action = intent.getAction(); 860 if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) { 861 updateRingerMode(); 862 notifyListeners(); 863 } 864 } 865 } 866 867 /** Implementation of {@link BroadcastReceiver} to update on battery mode change. */ 868 @VisibleForTesting 869 final class BatteryBroadcastReceiver extends BroadcastReceiver { 870 @Override 871 public void onReceive(Context context, Intent intent) { 872 String action = intent.getAction(); 873 if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { 874 updateBatteryInfo(intent); 875 } 876 } 877 } 878 879 /** Implementation of {@link ContentObserver} to be registered to a setting {@link Uri}. */ 880 @VisibleForTesting 881 final class VibrationUidObserver extends UidObserver { 882 private final SparseArray<Integer> mProcStatesCache = new SparseArray<>(); 883 884 public boolean isUidForeground(int uid) { 885 synchronized (this) { 886 return mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) 887 <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; 888 } 889 } 890 891 @Override 892 public void onUidGone(int uid, boolean disabled) { 893 synchronized (this) { 894 mProcStatesCache.delete(uid); 895 } 896 } 897 898 @Override 899 public void onUidStateChanged(int uid, int procState, long procStateSeq, int capability) { 900 synchronized (this) { 901 mProcStatesCache.put(uid, procState); 902 } 903 } 904 } 905 906 /** Implementation of {@link SynchronousUserSwitchObserver} to update on user switch. */ 907 @VisibleForTesting 908 final class VibrationUserSwitchObserver extends SynchronousUserSwitchObserver { 909 910 @Override 911 public void onUserSwitching(int newUserId) { 912 // Reload settings early based on new user id. 913 updateSettings(newUserId); 914 notifyListeners(); 915 } 916 917 @Override 918 public void onUserSwitchComplete(int newUserId) { 919 // Reload all settings including ones from AudioManager, 920 // as they are based on UserHandle.USER_CURRENT. 921 update(); 922 } 923 } 924 925 /** Implementation of {@link PowerManagerInternal.LowPowerModeListener} for low battery. */ 926 @VisibleForTesting 927 final class VibrationLowPowerModeListener implements PowerManagerInternal.LowPowerModeListener { 928 @Override 929 public int getServiceType() { 930 return PowerManager.ServiceType.VIBRATION; 931 } 932 933 @Override 934 public void onLowPowerModeChanged(PowerSaveState result) { 935 boolean shouldNotifyListeners; 936 synchronized (mLock) { 937 shouldNotifyListeners = result.batterySaverEnabled != mBatterySaverMode; 938 mBatterySaverMode = result.batterySaverEnabled; 939 } 940 if (shouldNotifyListeners) { 941 notifyListeners(); 942 } 943 } 944 } 945 } 946