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