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