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