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