• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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