1 /*
2  * Copyright (C) 2008 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;
18 
19 import android.annotation.Nullable;
20 import android.app.ActivityManager;
21 import android.app.AppOpsManager;
22 import android.app.IUidObserver;
23 import android.content.BroadcastReceiver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.pm.PackageManager;
28 import android.content.res.Resources;
29 import android.database.ContentObserver;
30 import android.hardware.input.InputManager;
31 import android.hardware.vibrator.IVibrator;
32 import android.hardware.vibrator.V1_0.EffectStrength;
33 import android.icu.text.DateFormat;
34 import android.media.AudioAttributes;
35 import android.media.AudioManager;
36 import android.os.BatteryStats;
37 import android.os.Binder;
38 import android.os.ExternalVibration;
39 import android.os.Handler;
40 import android.os.IBinder;
41 import android.os.IExternalVibratorService;
42 import android.os.IVibratorService;
43 import android.os.PowerManager;
44 import android.os.PowerManager.ServiceType;
45 import android.os.PowerManagerInternal;
46 import android.os.PowerSaveState;
47 import android.os.Process;
48 import android.os.RemoteException;
49 import android.os.ResultReceiver;
50 import android.os.ServiceManager;
51 import android.os.ShellCallback;
52 import android.os.ShellCommand;
53 import android.os.SystemClock;
54 import android.os.Trace;
55 import android.os.UserHandle;
56 import android.os.VibrationEffect;
57 import android.os.Vibrator;
58 import android.os.WorkSource;
59 import android.provider.DeviceConfig;
60 import android.provider.Settings;
61 import android.provider.Settings.SettingNotFoundException;
62 import android.util.DebugUtils;
63 import android.util.Slog;
64 import android.util.SparseArray;
65 import android.util.StatsLog;
66 import android.view.InputDevice;
67 
68 import com.android.internal.annotations.GuardedBy;
69 import com.android.internal.app.IBatteryStats;
70 import com.android.internal.util.DumpUtils;
71 
72 import java.io.FileDescriptor;
73 import java.io.PrintWriter;
74 import java.util.ArrayList;
75 import java.util.Date;
76 import java.util.LinkedList;
77 
78 public class VibratorService extends IVibratorService.Stub
79         implements InputManager.InputDeviceListener {
80     private static final String TAG = "VibratorService";
81     private static final boolean DEBUG = false;
82     private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
83     private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
84     private static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
85 
86     private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
87 
88     // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
89     // and the default intensity for that type of vibration (i.e. current - default).
90     private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
91     private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
92     private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
93     private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
94     private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
95     private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
96 
97     // Gamma adjustments for scale levels.
98     private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
99     private static final float SCALE_LOW_GAMMA = 1.5f;
100     private static final float SCALE_NONE_GAMMA = 1.0f;
101     private static final float SCALE_HIGH_GAMMA = 0.5f;
102     private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
103 
104     // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
105     // max amplitude.
106     private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
107     private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
108 
109     // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
110     private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
111 
112     // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration.
113     private static final long ASYNC_TIMEOUT_MULTIPLIER = 2;
114 
115 
116     // A mapping from the intensity adjustment to the scaling to apply, where the intensity
117     // adjustment is defined as the delta between the default intensity level and the user selected
118     // intensity level. It's important that we apply the scaling on the delta between the two so
119     // that the default intensity level applies no scaling to application provided effects.
120     private final SparseArray<ScaleLevel> mScaleLevels;
121     private final LinkedList<VibrationInfo> mPreviousRingVibrations;
122     private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
123     private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
124     private final LinkedList<ExternalVibration> mPreviousExternalVibrations;
125     private final LinkedList<VibrationInfo> mPreviousVibrations;
126     private final int mPreviousVibrationsLimit;
127     private final boolean mAllowPriorityVibrationsInLowPowerMode;
128     private final boolean mSupportsAmplitudeControl;
129     private final boolean mSupportsExternalControl;
130     private final long mCapabilities;
131     private final int mDefaultVibrationAmplitude;
132     private final SparseArray<VibrationEffect> mFallbackEffects;
133     private final SparseArray<Integer> mProcStatesCache = new SparseArray();
134     private final WorkSource mTmpWorkSource = new WorkSource();
135     private final Handler mH = new Handler();
136     private final Object mLock = new Object();
137 
138     private final Context mContext;
139     private final PowerManager.WakeLock mWakeLock;
140     private final AppOpsManager mAppOps;
141     private final IBatteryStats mBatteryStatsService;
142     private PowerManagerInternal mPowerManagerInternal;
143     private InputManager mIm;
144     private Vibrator mVibrator;
145     private SettingsObserver mSettingObserver;
146 
147     private volatile VibrateThread mThread;
148 
149     // mInputDeviceVibrators lock should be acquired after mLock, if both are
150     // to be acquired
151     private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
152     private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
153     private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
154 
155     @GuardedBy("mLock")
156     private Vibration mCurrentVibration;
157     private int mCurVibUid = -1;
158     private ExternalVibration mCurrentExternalVibration;
159     private boolean mVibratorUnderExternalControl;
160     private boolean mLowPowerMode;
161     private int mHapticFeedbackIntensity;
162     private int mNotificationIntensity;
163     private int mRingIntensity;
164     private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
165 
vibratorExists()166     static native boolean vibratorExists();
vibratorInit()167     static native void vibratorInit();
vibratorOn(long milliseconds)168     static native void vibratorOn(long milliseconds);
vibratorOff()169     static native void vibratorOff();
vibratorSupportsAmplitudeControl()170     static native boolean vibratorSupportsAmplitudeControl();
vibratorSetAmplitude(int amplitude)171     static native void vibratorSetAmplitude(int amplitude);
vibratorPerformEffect(long effect, long strength, Vibration vibration)172     static native long vibratorPerformEffect(long effect, long strength, Vibration vibration);
vibratorSupportsExternalControl()173     static native boolean vibratorSupportsExternalControl();
vibratorSetExternalControl(boolean enabled)174     static native void vibratorSetExternalControl(boolean enabled);
vibratorGetCapabilities()175     static native long vibratorGetCapabilities();
vibratorAlwaysOnEnable(long id, long effect, long strength)176     static native void vibratorAlwaysOnEnable(long id, long effect, long strength);
vibratorAlwaysOnDisable(long id)177     static native void vibratorAlwaysOnDisable(long id);
178 
179     private final IUidObserver mUidObserver = new IUidObserver.Stub() {
180         @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
181             mProcStatesCache.put(uid, procState);
182         }
183 
184         @Override public void onUidGone(int uid, boolean disabled) {
185             mProcStatesCache.delete(uid);
186         }
187 
188         @Override public void onUidActive(int uid) {
189         }
190 
191         @Override public void onUidIdle(int uid, boolean disabled) {
192         }
193 
194         @Override public void onUidCachedChanged(int uid, boolean cached) {
195         }
196     };
197 
198     private class Vibration implements IBinder.DeathRecipient {
199         public final IBinder token;
200         // Start time in CLOCK_BOOTTIME base.
201         public final long startTime;
202         // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
203         // with other system events, any duration calculations should be done use startTime so as
204         // not to be affected by discontinuities created by RTC adjustments.
205         public final long startTimeDebug;
206         public final AudioAttributes attrs;
207         public final int uid;
208         public final String opPkg;
209         public final String reason;
210 
211         // The actual effect to be played.
212         public VibrationEffect effect;
213         // The original effect that was requested. This is non-null only when the original effect
214         // differs from the effect that's being played. Typically these two things differ because
215         // the effect was scaled based on the users vibration intensity settings.
216         public VibrationEffect originalEffect;
217 
Vibration(IBinder token, VibrationEffect effect, AudioAttributes attrs, int uid, String opPkg, String reason)218         private Vibration(IBinder token, VibrationEffect effect,
219                 AudioAttributes attrs, int uid, String opPkg, String reason) {
220             this.token = token;
221             this.effect = effect;
222             this.startTime = SystemClock.elapsedRealtime();
223             this.startTimeDebug = System.currentTimeMillis();
224             this.attrs = attrs;
225             this.uid = uid;
226             this.opPkg = opPkg;
227             this.reason = reason;
228         }
229 
binderDied()230         public void binderDied() {
231             synchronized (mLock) {
232                 if (this == mCurrentVibration) {
233                     doCancelVibrateLocked();
234                 }
235             }
236         }
237 
onComplete()238         private void onComplete() {
239             synchronized (mLock) {
240                 if (this == mCurrentVibration) {
241                     doCancelVibrateLocked();
242                 }
243             }
244         }
245 
hasTimeoutLongerThan(long millis)246         public boolean hasTimeoutLongerThan(long millis) {
247             final long duration = effect.getDuration();
248             return duration >= 0 && duration > millis;
249         }
250 
isHapticFeedback()251         public boolean isHapticFeedback() {
252             if (VibratorService.this.isHapticFeedback(attrs.getUsage())) {
253                 return true;
254             }
255             if (effect instanceof VibrationEffect.Prebaked) {
256                 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
257                 switch (prebaked.getId()) {
258                     case VibrationEffect.EFFECT_CLICK:
259                     case VibrationEffect.EFFECT_DOUBLE_CLICK:
260                     case VibrationEffect.EFFECT_HEAVY_CLICK:
261                     case VibrationEffect.EFFECT_TEXTURE_TICK:
262                     case VibrationEffect.EFFECT_TICK:
263                     case VibrationEffect.EFFECT_POP:
264                     case VibrationEffect.EFFECT_THUD:
265                         return true;
266                     default:
267                         Slog.w(TAG, "Unknown prebaked vibration effect, "
268                                 + "assuming it isn't haptic feedback.");
269                         return false;
270                 }
271             }
272             final long duration = effect.getDuration();
273             return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
274         }
275 
isNotification()276         public boolean isNotification() {
277             return VibratorService.this.isNotification(attrs.getUsage());
278         }
279 
isRingtone()280         public boolean isRingtone() {
281             return VibratorService.this.isRingtone(attrs.getUsage());
282         }
283 
isAlarm()284         public boolean isAlarm() {
285             return VibratorService.this.isAlarm(attrs.getUsage());
286         }
287 
isFromSystem()288         public boolean isFromSystem() {
289             return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
290         }
291 
toInfo()292         public VibrationInfo toInfo() {
293             return new VibrationInfo(
294                     startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason);
295         }
296     }
297 
298     private static class VibrationInfo {
299         private final long mStartTimeDebug;
300         private final VibrationEffect mEffect;
301         private final VibrationEffect mOriginalEffect;
302         private final AudioAttributes mAttrs;
303         private final int mUid;
304         private final String mOpPkg;
305         private final String mReason;
306 
VibrationInfo(long startTimeDebug, VibrationEffect effect, VibrationEffect originalEffect, AudioAttributes attrs, int uid, String opPkg, String reason)307         public VibrationInfo(long startTimeDebug, VibrationEffect effect,
308                 VibrationEffect originalEffect, AudioAttributes attrs, int uid,
309                 String opPkg, String reason) {
310             mStartTimeDebug = startTimeDebug;
311             mEffect = effect;
312             mOriginalEffect = originalEffect;
313             mAttrs = attrs;
314             mUid = uid;
315             mOpPkg = opPkg;
316             mReason = reason;
317         }
318 
319         @Override
toString()320         public String toString() {
321             return new StringBuilder()
322                     .append("startTime: ")
323                     .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
324                     .append(", effect: ")
325                     .append(mEffect)
326                     .append(", originalEffect: ")
327                     .append(mOriginalEffect)
328                     .append(", attrs: ")
329                     .append(mAttrs)
330                     .append(", uid: ")
331                     .append(mUid)
332                     .append(", opPkg: ")
333                     .append(mOpPkg)
334                     .append(", reason: ")
335                     .append(mReason)
336                     .toString();
337         }
338     }
339 
340     private static final class ScaleLevel {
341         public final float gamma;
342         public final int maxAmplitude;
343 
ScaleLevel(float gamma)344         public ScaleLevel(float gamma) {
345             this(gamma, VibrationEffect.MAX_AMPLITUDE);
346         }
347 
ScaleLevel(float gamma, int maxAmplitude)348         public ScaleLevel(float gamma, int maxAmplitude) {
349             this.gamma = gamma;
350             this.maxAmplitude = maxAmplitude;
351         }
352 
353         @Override
toString()354         public String toString() {
355             return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
356         }
357     }
358 
VibratorService(Context context)359     VibratorService(Context context) {
360         vibratorInit();
361         // Reset the hardware to a default state, in case this is a runtime
362         // restart instead of a fresh boot.
363         vibratorOff();
364 
365         mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
366         mSupportsExternalControl = vibratorSupportsExternalControl();
367         mCapabilities = vibratorGetCapabilities();
368 
369         mContext = context;
370         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
371         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
372         mWakeLock.setReferenceCounted(true);
373 
374         mAppOps = mContext.getSystemService(AppOpsManager.class);
375         mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
376                 BatteryStats.SERVICE_NAME));
377 
378         mPreviousVibrationsLimit = mContext.getResources().getInteger(
379                 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
380 
381         mDefaultVibrationAmplitude = mContext.getResources().getInteger(
382                 com.android.internal.R.integer.config_defaultVibrationAmplitude);
383 
384         mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
385                 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
386 
387         mPreviousRingVibrations = new LinkedList<>();
388         mPreviousNotificationVibrations = new LinkedList<>();
389         mPreviousAlarmVibrations = new LinkedList<>();
390         mPreviousVibrations = new LinkedList<>();
391         mPreviousExternalVibrations = new LinkedList<>();
392 
393         IntentFilter filter = new IntentFilter();
394         filter.addAction(Intent.ACTION_SCREEN_OFF);
395         context.registerReceiver(mIntentReceiver, filter);
396 
397         VibrationEffect clickEffect = createEffectFromResource(
398                 com.android.internal.R.array.config_virtualKeyVibePattern);
399         VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
400                 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
401         VibrationEffect heavyClickEffect = createEffectFromResource(
402                 com.android.internal.R.array.config_longPressVibePattern);
403         VibrationEffect tickEffect = createEffectFromResource(
404                 com.android.internal.R.array.config_clockTickVibePattern);
405 
406         mFallbackEffects = new SparseArray<>();
407         mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
408         mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
409         mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
410         mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
411 
412         mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
413                 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
414 
415         mScaleLevels = new SparseArray<>();
416         mScaleLevels.put(SCALE_VERY_LOW,
417                 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
418         mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
419         mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
420         mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
421         mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
422 
423         ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
424     }
425 
createEffectFromResource(int resId)426     private VibrationEffect createEffectFromResource(int resId) {
427         long[] timings = getLongIntArray(mContext.getResources(), resId);
428         return createEffectFromTimings(timings);
429     }
430 
createEffectFromTimings(long[] timings)431     private static VibrationEffect createEffectFromTimings(long[] timings) {
432         if (timings == null || timings.length == 0) {
433             return null;
434         } else if (timings.length == 1) {
435             return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
436         } else {
437             return VibrationEffect.createWaveform(timings, -1);
438         }
439     }
440 
systemReady()441     public void systemReady() {
442         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
443         try {
444             mIm = mContext.getSystemService(InputManager.class);
445             mVibrator = mContext.getSystemService(Vibrator.class);
446             mSettingObserver = new SettingsObserver(mH);
447 
448             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
449             mPowerManagerInternal.registerLowPowerModeObserver(
450                     new PowerManagerInternal.LowPowerModeListener() {
451                         @Override
452                         public int getServiceType() {
453                             return ServiceType.VIBRATION;
454                         }
455 
456                         @Override
457                         public void onLowPowerModeChanged(PowerSaveState result) {
458                             updateVibrators();
459                         }
460             });
461 
462             mContext.getContentResolver().registerContentObserver(
463                     Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
464                     true, mSettingObserver, UserHandle.USER_ALL);
465 
466             mContext.getContentResolver().registerContentObserver(
467                     Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
468                     true, mSettingObserver, UserHandle.USER_ALL);
469 
470             mContext.getContentResolver().registerContentObserver(
471                     Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
472                     true, mSettingObserver, UserHandle.USER_ALL);
473 
474             mContext.getContentResolver().registerContentObserver(
475                     Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
476                     true, mSettingObserver, UserHandle.USER_ALL);
477 
478             mContext.getContentResolver().registerContentObserver(
479                     Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
480                     true, mSettingObserver, UserHandle.USER_ALL);
481 
482             mContext.registerReceiver(new BroadcastReceiver() {
483                 @Override
484                 public void onReceive(Context context, Intent intent) {
485                     updateVibrators();
486                 }
487             }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
488 
489             try {
490                 ActivityManager.getService().registerUidObserver(mUidObserver,
491                         ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
492                         ActivityManager.PROCESS_STATE_UNKNOWN, null);
493             } catch (RemoteException e) {
494                 // ignored; both services live in system_server
495             }
496 
497             updateVibrators();
498         } finally {
499             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
500         }
501     }
502 
503     private final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)504         public SettingsObserver(Handler handler) {
505             super(handler);
506         }
507 
508         @Override
onChange(boolean SelfChange)509         public void onChange(boolean SelfChange) {
510             updateVibrators();
511         }
512     }
513 
514     @Override // Binder call
hasVibrator()515     public boolean hasVibrator() {
516         return doVibratorExists();
517     }
518 
519     @Override // Binder call
hasAmplitudeControl()520     public boolean hasAmplitudeControl() {
521         synchronized (mInputDeviceVibrators) {
522             // Input device vibrators don't support amplitude controls yet, but are still used over
523             // the system vibrator when connected.
524             return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
525         }
526     }
527 
528     @Override // Binder call
setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, AudioAttributes attrs)529     public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
530             AudioAttributes attrs) {
531         if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
532             throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
533         }
534         if ((mCapabilities & IVibrator.CAP_ALWAYS_ON_CONTROL) == 0) {
535             Slog.e(TAG, "Always-on effects not supported.");
536             return false;
537         }
538         if (effect == null) {
539             synchronized (mLock) {
540                 mAlwaysOnEffects.delete(alwaysOnId);
541                 vibratorAlwaysOnDisable(alwaysOnId);
542             }
543         } else {
544             if (!verifyVibrationEffect(effect)) {
545                 return false;
546             }
547             if (!(effect instanceof VibrationEffect.Prebaked)) {
548                 Slog.e(TAG, "Only prebaked effects supported for always-on.");
549                 return false;
550             }
551             attrs = fixupVibrationAttributes(attrs);
552             synchronized (mLock) {
553                 Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
554                 mAlwaysOnEffects.put(alwaysOnId, vib);
555                 updateAlwaysOnLocked(alwaysOnId, vib);
556             }
557         }
558         return true;
559     }
560 
verifyIncomingUid(int uid)561     private void verifyIncomingUid(int uid) {
562         if (uid == Binder.getCallingUid()) {
563             return;
564         }
565         if (Binder.getCallingPid() == Process.myPid()) {
566             return;
567         }
568         mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
569                 Binder.getCallingPid(), Binder.getCallingUid(), null);
570     }
571 
572     /**
573      * Validate the incoming VibrationEffect.
574      *
575      * We can't throw exceptions here since we might be called from some system_server component,
576      * which would bring the whole system down.
577      *
578      * @return whether the VibrationEffect is valid
579      */
verifyVibrationEffect(VibrationEffect effect)580     private static boolean verifyVibrationEffect(VibrationEffect effect) {
581         if (effect == null) {
582             // Effect must not be null.
583             Slog.wtf(TAG, "effect must not be null");
584             return false;
585         }
586         try {
587             effect.validate();
588         } catch (Exception e) {
589             Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
590             return false;
591         }
592         return true;
593     }
594 
fixupVibrationAttributes(AudioAttributes attrs)595     private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) {
596         if (attrs == null) {
597             attrs = new AudioAttributes.Builder()
598                     .setUsage(AudioAttributes.USAGE_UNKNOWN)
599                     .build();
600         }
601         if (shouldBypassDnd(attrs)) {
602             if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
603                     || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
604                     || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
605                 final int flags = attrs.getAllFlags()
606                         & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY;
607                 attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build();
608             }
609         }
610 
611         return attrs;
612     }
613 
getLongIntArray(Resources r, int resid)614     private static long[] getLongIntArray(Resources r, int resid) {
615         int[] ar = r.getIntArray(resid);
616         if (ar == null) {
617             return null;
618         }
619         long[] out = new long[ar.length];
620         for (int i = 0; i < ar.length; i++) {
621             out[i] = ar[i];
622         }
623         return out;
624     }
625 
626     @Override // Binder call
vibrate(int uid, String opPkg, VibrationEffect effect, @Nullable AudioAttributes attrs, String reason, IBinder token)627     public void vibrate(int uid, String opPkg, VibrationEffect effect,
628             @Nullable AudioAttributes attrs, String reason, IBinder token) {
629         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
630         try {
631             if (!hasPermission(android.Manifest.permission.VIBRATE)) {
632                 throw new SecurityException("Requires VIBRATE permission");
633             }
634             if (token == null) {
635                 Slog.e(TAG, "token must not be null");
636                 return;
637             }
638             verifyIncomingUid(uid);
639             if (!verifyVibrationEffect(effect)) {
640                 return;
641             }
642 
643             attrs = fixupVibrationAttributes(attrs);
644 
645             // If our current vibration is longer than the new vibration and is the same amplitude,
646             // then just let the current one finish.
647             synchronized (mLock) {
648                 if (effect instanceof VibrationEffect.OneShot
649                         && mCurrentVibration != null
650                         && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
651                     VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
652                     VibrationEffect.OneShot currentOneShot =
653                             (VibrationEffect.OneShot) mCurrentVibration.effect;
654                     if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
655                             && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
656                         if (DEBUG) {
657                             Slog.d(TAG,
658                                     "Ignoring incoming vibration in favor of current vibration");
659                         }
660                         return;
661                     }
662                 }
663 
664 
665                 // If something has external control of the vibrator, assume that it's more
666                 // important for now.
667                 if (mCurrentExternalVibration != null) {
668                     if (DEBUG) {
669                         Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
670                     }
671                     return;
672                 }
673 
674                 // If the current vibration is repeating and the incoming one is non-repeating,
675                 // then ignore the non-repeating vibration. This is so that we don't cancel
676                 // vibrations that are meant to grab the attention of the user, like ringtones and
677                 // alarms, in favor of one-shot vibrations that are likely quite short.
678                 if (!isRepeatingVibration(effect)
679                         && mCurrentVibration != null
680                         && isRepeatingVibration(mCurrentVibration.effect)) {
681                     if (DEBUG) {
682                         Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
683                     }
684                     return;
685                 }
686 
687                 Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason);
688                 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
689                         > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
690                         && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
691                     Slog.e(TAG, "Ignoring incoming vibration as process with"
692                             + " uid= " + uid + " is background,"
693                             + " attrs= " + vib.attrs);
694                     return;
695                 }
696                 linkVibration(vib);
697                 long ident = Binder.clearCallingIdentity();
698                 try {
699                     doCancelVibrateLocked();
700                     startVibrationLocked(vib);
701                     addToPreviousVibrationsLocked(vib);
702                 } finally {
703                     Binder.restoreCallingIdentity(ident);
704                 }
705             }
706         } finally {
707             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
708         }
709     }
710 
hasPermission(String permission)711     private boolean hasPermission(String permission) {
712         return mContext.checkCallingOrSelfPermission(permission)
713                 == PackageManager.PERMISSION_GRANTED;
714     }
715 
isRepeatingVibration(VibrationEffect effect)716     private static boolean isRepeatingVibration(VibrationEffect effect) {
717         return effect.getDuration() == Long.MAX_VALUE;
718     }
719 
addToPreviousVibrationsLocked(Vibration vib)720     private void addToPreviousVibrationsLocked(Vibration vib) {
721         final LinkedList<VibrationInfo> previousVibrations;
722         if (vib.isRingtone()) {
723             previousVibrations = mPreviousRingVibrations;
724         } else if (vib.isNotification()) {
725             previousVibrations = mPreviousNotificationVibrations;
726         } else if (vib.isAlarm()) {
727             previousVibrations = mPreviousAlarmVibrations;
728         } else {
729             previousVibrations = mPreviousVibrations;
730         }
731 
732         if (previousVibrations.size() > mPreviousVibrationsLimit) {
733             previousVibrations.removeFirst();
734         }
735         previousVibrations.addLast(vib.toInfo());
736     }
737 
738     @Override // Binder call
cancelVibrate(IBinder token)739     public void cancelVibrate(IBinder token) {
740         mContext.enforceCallingOrSelfPermission(
741                 android.Manifest.permission.VIBRATE,
742                 "cancelVibrate");
743 
744         synchronized (mLock) {
745             if (mCurrentVibration != null && mCurrentVibration.token == token) {
746                 if (DEBUG) {
747                     Slog.d(TAG, "Canceling vibration.");
748                 }
749                 long ident = Binder.clearCallingIdentity();
750                 try {
751                     doCancelVibrateLocked();
752                 } finally {
753                     Binder.restoreCallingIdentity(ident);
754                 }
755             }
756         }
757     }
758 
759     private final Runnable mVibrationEndRunnable = new Runnable() {
760         @Override
761         public void run() {
762             onVibrationFinished();
763         }
764     };
765 
766     @GuardedBy("mLock")
doCancelVibrateLocked()767     private void doCancelVibrateLocked() {
768         Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
769         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
770         try {
771             mH.removeCallbacks(mVibrationEndRunnable);
772             if (mThread != null) {
773                 mThread.cancel();
774                 mThread = null;
775             }
776             if (mCurrentExternalVibration != null) {
777                 mCurrentExternalVibration.mute();
778                 mCurrentExternalVibration = null;
779                 setVibratorUnderExternalControl(false);
780             }
781             doVibratorOff();
782             reportFinishVibrationLocked();
783         } finally {
784             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
785         }
786     }
787 
788     // Callback for whenever the current vibration has finished played out
onVibrationFinished()789     public void onVibrationFinished() {
790         if (DEBUG) {
791             Slog.e(TAG, "Vibration finished, cleaning up");
792         }
793         synchronized (mLock) {
794             // Make sure the vibration is really done. This also reports that the vibration is
795             // finished.
796             doCancelVibrateLocked();
797         }
798     }
799 
800     @GuardedBy("mLock")
startVibrationLocked(final Vibration vib)801     private void startVibrationLocked(final Vibration vib) {
802         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
803         try {
804             final int intensity = getCurrentIntensityLocked(vib);
805             if (!shouldVibrate(vib, intensity)) {
806                 return;
807             }
808             applyVibrationIntensityScalingLocked(vib, intensity);
809             startVibrationInnerLocked(vib);
810         } finally {
811             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
812         }
813     }
814 
815     @GuardedBy("mLock")
startVibrationInnerLocked(Vibration vib)816     private void startVibrationInnerLocked(Vibration vib) {
817         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
818         try {
819             mCurrentVibration = vib;
820             if (vib.effect instanceof VibrationEffect.OneShot) {
821                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
822                 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
823                 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs);
824                 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
825             } else if (vib.effect instanceof VibrationEffect.Waveform) {
826                 // mThread better be null here. doCancelVibrate should always be
827                 // called before startNextVibrationLocked or startVibrationLocked.
828                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
829                 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
830                 mThread = new VibrateThread(waveform, vib.uid, vib.attrs);
831                 mThread.start();
832             } else if (vib.effect instanceof VibrationEffect.Prebaked) {
833                 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
834                 long timeout = doVibratorPrebakedEffectLocked(vib);
835                 if (timeout > 0) {
836                     mH.postDelayed(mVibrationEndRunnable, timeout);
837                 }
838             } else {
839                 Slog.e(TAG, "Unknown vibration type, ignoring");
840             }
841         } finally {
842             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
843         }
844     }
845 
isAllowedToVibrateLocked(Vibration vib)846     private boolean isAllowedToVibrateLocked(Vibration vib) {
847         if (!mLowPowerMode) {
848             return true;
849         }
850 
851         if (vib.attrs.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
852             return true;
853         }
854 
855         if (vib.attrs.getUsage() == AudioAttributes.USAGE_ALARM
856                 || vib.attrs.getUsage() == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY
857                 || vib.attrs.getUsage()
858                     == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
859             return true;
860         }
861 
862         return false;
863     }
864 
getCurrentIntensityLocked(Vibration vib)865     private int getCurrentIntensityLocked(Vibration vib) {
866         if (vib.isRingtone()) {
867             return mRingIntensity;
868         } else if (vib.isNotification()) {
869             return mNotificationIntensity;
870         } else if (vib.isHapticFeedback()) {
871             return mHapticFeedbackIntensity;
872         } else if (vib.isAlarm()) {
873             return Vibrator.VIBRATION_INTENSITY_HIGH;
874         } else {
875             return Vibrator.VIBRATION_INTENSITY_MEDIUM;
876         }
877     }
878 
879     /**
880      * Scale the vibration effect by the intensity as appropriate based its intent.
881      */
applyVibrationIntensityScalingLocked(Vibration vib, int intensity)882     private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
883         if (vib.effect instanceof VibrationEffect.Prebaked) {
884             // Prebaked effects are always just a direct translation from intensity to
885             // EffectStrength.
886             VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
887             prebaked.setEffectStrength(intensityToEffectStrength(intensity));
888             return;
889         }
890 
891         final int defaultIntensity;
892         if (vib.isRingtone()) {
893             defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
894         } else if (vib.isNotification()) {
895             defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
896         } else if (vib.isHapticFeedback()) {
897             defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
898         } else if (vib.isAlarm()) {
899             defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
900         } else {
901             // If we don't know what kind of vibration we're playing then just skip scaling for
902             // now.
903             return;
904         }
905 
906         final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
907         if (scale == null) {
908             // We should have scaling levels for all cases, so not being able to scale because of a
909             // missing level is unexpected.
910             Slog.e(TAG, "No configured scaling level!"
911                     + " (current=" + intensity + ", default= " + defaultIntensity + ")");
912             return;
913         }
914 
915         VibrationEffect scaledEffect = null;
916         if (vib.effect instanceof VibrationEffect.OneShot) {
917             VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
918             oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
919             scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
920         } else if (vib.effect instanceof VibrationEffect.Waveform) {
921             VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
922             waveform = waveform.resolve(mDefaultVibrationAmplitude);
923             scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
924         } else {
925             Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
926         }
927 
928         if (scaledEffect != null) {
929             vib.originalEffect = vib.effect;
930             vib.effect = scaledEffect;
931         }
932     }
933 
shouldVibrateForRingtone()934     private boolean shouldVibrateForRingtone() {
935         AudioManager audioManager = mContext.getSystemService(AudioManager.class);
936         int ringerMode = audioManager.getRingerModeInternal();
937         // "Also vibrate for calls" Setting in Sound
938         if (Settings.System.getInt(
939                 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
940             return ringerMode != AudioManager.RINGER_MODE_SILENT;
941         } else if (Settings.Global.getInt(
942                     mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0
943                 && DeviceConfig.getBoolean(
944                     DeviceConfig.NAMESPACE_TELEPHONY, RAMPING_RINGER_ENABLED, false)) {
945             return ringerMode != AudioManager.RINGER_MODE_SILENT;
946         } else {
947             return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
948         }
949     }
950 
shouldBypassDnd(AudioAttributes attrs)951     private static boolean shouldBypassDnd(AudioAttributes attrs) {
952         return (attrs.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
953     }
954 
getAppOpMode(Vibration vib)955     private int getAppOpMode(Vibration vib) {
956         int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
957                 vib.attrs.getUsage(), vib.uid, vib.opPkg);
958         if (mode == AppOpsManager.MODE_ALLOWED) {
959             mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
960         }
961 
962         if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(vib.attrs)) {
963             // If we're just ignoring the vibration op then this is set by DND and we should ignore
964             // if we're asked to bypass. AppOps won't be able to record this operation, so make
965             // sure we at least note it in the logs for debugging.
966             Slog.d(TAG, "Bypassing DND for vibration: " + vib);
967             mode = AppOpsManager.MODE_ALLOWED;
968         }
969         return mode;
970     }
971 
shouldVibrate(Vibration vib, int intensity)972     private boolean shouldVibrate(Vibration vib, int intensity) {
973         if (!isAllowedToVibrateLocked(vib)) {
974             return false;
975         }
976 
977         if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
978             return false;
979         }
980 
981         if (vib.isRingtone() && !shouldVibrateForRingtone()) {
982             if (DEBUG) {
983                 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
984             }
985             return false;
986         }
987 
988         final int mode = getAppOpMode(vib);
989         if (mode != AppOpsManager.MODE_ALLOWED) {
990             if (mode == AppOpsManager.MODE_ERRORED) {
991                 // We might be getting calls from within system_server, so we don't actually
992                 // want to throw a SecurityException here.
993                 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
994             }
995             return false;
996         }
997 
998         return true;
999     }
1000 
1001     @GuardedBy("mLock")
reportFinishVibrationLocked()1002     private void reportFinishVibrationLocked() {
1003         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
1004         try {
1005             if (mCurrentVibration != null) {
1006                 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
1007                         mCurrentVibration.opPkg);
1008                 unlinkVibration(mCurrentVibration);
1009                 mCurrentVibration = null;
1010             }
1011         } finally {
1012             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1013         }
1014     }
1015 
linkVibration(Vibration vib)1016     private void linkVibration(Vibration vib) {
1017         // Only link against waveforms since they potentially don't have a finish if
1018         // they're repeating. Let other effects just play out until they're done.
1019         if (vib.effect instanceof VibrationEffect.Waveform) {
1020             try {
1021                 vib.token.linkToDeath(vib, 0);
1022             } catch (RemoteException e) {
1023                 return;
1024             }
1025         }
1026     }
1027 
unlinkVibration(Vibration vib)1028     private void unlinkVibration(Vibration vib) {
1029         if (vib.effect instanceof VibrationEffect.Waveform) {
1030             vib.token.unlinkToDeath(vib, 0);
1031         }
1032     }
1033 
updateVibrators()1034     private void updateVibrators() {
1035         synchronized (mLock) {
1036             boolean devicesUpdated = updateInputDeviceVibratorsLocked();
1037             boolean lowPowerModeUpdated = updateLowPowerModeLocked();
1038             updateVibrationIntensityLocked();
1039 
1040             if (devicesUpdated || lowPowerModeUpdated) {
1041                 // If the state changes out from under us then just reset.
1042                 doCancelVibrateLocked();
1043             }
1044 
1045             updateAlwaysOnLocked();
1046         }
1047     }
1048 
updateInputDeviceVibratorsLocked()1049     private boolean updateInputDeviceVibratorsLocked() {
1050         boolean changed = false;
1051         boolean vibrateInputDevices = false;
1052         try {
1053             vibrateInputDevices = Settings.System.getIntForUser(
1054                     mContext.getContentResolver(),
1055                     Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
1056         } catch (SettingNotFoundException snfe) {
1057         }
1058         if (vibrateInputDevices != mVibrateInputDevicesSetting) {
1059             changed = true;
1060             mVibrateInputDevicesSetting = vibrateInputDevices;
1061         }
1062 
1063         if (mVibrateInputDevicesSetting) {
1064             if (!mInputDeviceListenerRegistered) {
1065                 mInputDeviceListenerRegistered = true;
1066                 mIm.registerInputDeviceListener(this, mH);
1067             }
1068         } else {
1069             if (mInputDeviceListenerRegistered) {
1070                 mInputDeviceListenerRegistered = false;
1071                 mIm.unregisterInputDeviceListener(this);
1072             }
1073         }
1074 
1075         mInputDeviceVibrators.clear();
1076         if (mVibrateInputDevicesSetting) {
1077             int[] ids = mIm.getInputDeviceIds();
1078             for (int i = 0; i < ids.length; i++) {
1079                 InputDevice device = mIm.getInputDevice(ids[i]);
1080                 Vibrator vibrator = device.getVibrator();
1081                 if (vibrator.hasVibrator()) {
1082                     mInputDeviceVibrators.add(vibrator);
1083                 }
1084             }
1085             return true;
1086         }
1087         return changed;
1088     }
1089 
updateLowPowerModeLocked()1090     private boolean updateLowPowerModeLocked() {
1091         boolean lowPowerMode = mPowerManagerInternal
1092                 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
1093         if (lowPowerMode != mLowPowerMode) {
1094             mLowPowerMode = lowPowerMode;
1095             return true;
1096         }
1097         return false;
1098     }
1099 
updateVibrationIntensityLocked()1100     private void updateVibrationIntensityLocked() {
1101         mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1102                 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
1103                 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
1104         mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1105                 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
1106                 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
1107         mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1108                 Settings.System.RING_VIBRATION_INTENSITY,
1109                 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
1110     }
1111 
updateAlwaysOnLocked(int id, Vibration vib)1112     private void updateAlwaysOnLocked(int id, Vibration vib) {
1113         final int intensity = getCurrentIntensityLocked(vib);
1114         if (!shouldVibrate(vib, intensity)) {
1115             vibratorAlwaysOnDisable(id);
1116         } else {
1117             final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1118             final int strength = intensityToEffectStrength(intensity);
1119             vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
1120         }
1121     }
1122 
updateAlwaysOnLocked()1123     private void updateAlwaysOnLocked() {
1124         for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
1125             int id = mAlwaysOnEffects.keyAt(i);
1126             Vibration vib = mAlwaysOnEffects.valueAt(i);
1127             updateAlwaysOnLocked(id, vib);
1128         }
1129     }
1130 
1131     @Override
onInputDeviceAdded(int deviceId)1132     public void onInputDeviceAdded(int deviceId) {
1133         updateVibrators();
1134     }
1135 
1136     @Override
onInputDeviceChanged(int deviceId)1137     public void onInputDeviceChanged(int deviceId) {
1138         updateVibrators();
1139     }
1140 
1141     @Override
onInputDeviceRemoved(int deviceId)1142     public void onInputDeviceRemoved(int deviceId) {
1143         updateVibrators();
1144     }
1145 
doVibratorExists()1146     private boolean doVibratorExists() {
1147         // For now, we choose to ignore the presence of input devices that have vibrators
1148         // when reporting whether the device has a vibrator.  Applications often use this
1149         // information to decide whether to enable certain features so they expect the
1150         // result of hasVibrator() to be constant.  For now, just report whether
1151         // the device has a built-in vibrator.
1152         //synchronized (mInputDeviceVibrators) {
1153         //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
1154         //}
1155         return vibratorExists();
1156     }
1157 
doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs)1158     private void doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs) {
1159         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
1160         try {
1161             synchronized (mInputDeviceVibrators) {
1162                 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
1163                     amplitude = mDefaultVibrationAmplitude;
1164                 }
1165                 if (DEBUG) {
1166                     Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
1167                             " with amplitude " + amplitude + ".");
1168                 }
1169                 noteVibratorOnLocked(uid, millis);
1170                 final int vibratorCount = mInputDeviceVibrators.size();
1171                 if (vibratorCount != 0) {
1172                     for (int i = 0; i < vibratorCount; i++) {
1173                         mInputDeviceVibrators.get(i).vibrate(millis, attrs);
1174                     }
1175                 } else {
1176                     // Note: ordering is important here! Many haptic drivers will reset their
1177                     // amplitude when enabled, so we always have to enable frst, then set the
1178                     // amplitude.
1179                     vibratorOn(millis);
1180                     doVibratorSetAmplitude(amplitude);
1181                 }
1182             }
1183         } finally {
1184             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1185         }
1186     }
1187 
doVibratorSetAmplitude(int amplitude)1188     private void doVibratorSetAmplitude(int amplitude) {
1189         if (mSupportsAmplitudeControl) {
1190             vibratorSetAmplitude(amplitude);
1191         }
1192     }
1193 
doVibratorOff()1194     private void doVibratorOff() {
1195         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
1196         try {
1197             synchronized (mInputDeviceVibrators) {
1198                 if (DEBUG) {
1199                     Slog.d(TAG, "Turning vibrator off.");
1200                 }
1201                 noteVibratorOffLocked();
1202                 final int vibratorCount = mInputDeviceVibrators.size();
1203                 if (vibratorCount != 0) {
1204                     for (int i = 0; i < vibratorCount; i++) {
1205                         mInputDeviceVibrators.get(i).cancel();
1206                     }
1207                 } else {
1208                     vibratorOff();
1209                 }
1210             }
1211         } finally {
1212             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1213         }
1214     }
1215 
1216     @GuardedBy("mLock")
doVibratorPrebakedEffectLocked(Vibration vib)1217     private long doVibratorPrebakedEffectLocked(Vibration vib) {
1218         Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
1219         try {
1220             final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1221             final boolean usingInputDeviceVibrators;
1222             synchronized (mInputDeviceVibrators) {
1223                 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
1224             }
1225             // Input devices don't support prebaked effect, so skip trying it with them.
1226             if (!usingInputDeviceVibrators) {
1227                 long duration = vibratorPerformEffect(prebaked.getId(),
1228                         prebaked.getEffectStrength(), vib);
1229                 long timeout = duration;
1230                 if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) {
1231                     timeout *= ASYNC_TIMEOUT_MULTIPLIER;
1232                 }
1233                 if (timeout > 0) {
1234                     noteVibratorOnLocked(vib.uid, duration);
1235                     return timeout;
1236                 }
1237             }
1238             if (!prebaked.shouldFallback()) {
1239                 return 0;
1240             }
1241             VibrationEffect effect = getFallbackEffect(prebaked.getId());
1242             if (effect == null) {
1243                 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1244                 return 0;
1245             }
1246             Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid,
1247                     vib.opPkg, vib.reason + " (fallback)");
1248             final int intensity = getCurrentIntensityLocked(fallbackVib);
1249             linkVibration(fallbackVib);
1250             applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1251             startVibrationInnerLocked(fallbackVib);
1252             return 0;
1253         } finally {
1254             Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1255         }
1256     }
1257 
getFallbackEffect(int effectId)1258     private VibrationEffect getFallbackEffect(int effectId) {
1259         return mFallbackEffects.get(effectId);
1260     }
1261 
1262     /**
1263      * Return the current desired effect strength.
1264      *
1265      * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1266      */
intensityToEffectStrength(int intensity)1267     private static int intensityToEffectStrength(int intensity) {
1268         switch (intensity) {
1269             case Vibrator.VIBRATION_INTENSITY_LOW:
1270                 return EffectStrength.LIGHT;
1271             case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1272                 return EffectStrength.MEDIUM;
1273             case Vibrator.VIBRATION_INTENSITY_HIGH:
1274                 return EffectStrength.STRONG;
1275             default:
1276                 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1277                 return EffectStrength.STRONG;
1278         }
1279     }
1280 
isNotification(int usageHint)1281     private static boolean isNotification(int usageHint) {
1282         switch (usageHint) {
1283             case AudioAttributes.USAGE_NOTIFICATION:
1284             case AudioAttributes.USAGE_NOTIFICATION_EVENT:
1285             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
1286             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
1287             case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
1288                 return true;
1289             default:
1290                 return false;
1291         }
1292     }
1293 
isRingtone(int usageHint)1294     private static boolean isRingtone(int usageHint) {
1295         return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
1296     }
1297 
isHapticFeedback(int usageHint)1298     private static boolean isHapticFeedback(int usageHint) {
1299         return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
1300     }
1301 
isAlarm(int usageHint)1302     private static boolean isAlarm(int usageHint) {
1303         return usageHint == AudioAttributes.USAGE_ALARM;
1304     }
1305 
noteVibratorOnLocked(int uid, long millis)1306     private void noteVibratorOnLocked(int uid, long millis) {
1307         try {
1308             mBatteryStatsService.noteVibratorOn(uid, millis);
1309             StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null,
1310                     StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
1311             mCurVibUid = uid;
1312         } catch (RemoteException e) {
1313         }
1314     }
1315 
noteVibratorOffLocked()1316     private void noteVibratorOffLocked() {
1317         if (mCurVibUid >= 0) {
1318             try {
1319                 mBatteryStatsService.noteVibratorOff(mCurVibUid);
1320                 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null,
1321                         StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
1322             } catch (RemoteException e) { }
1323             mCurVibUid = -1;
1324         }
1325     }
1326 
setVibratorUnderExternalControl(boolean externalControl)1327     private void setVibratorUnderExternalControl(boolean externalControl) {
1328         if (DEBUG) {
1329             if (externalControl) {
1330                 Slog.d(TAG, "Vibrator going under external control.");
1331             } else {
1332                 Slog.d(TAG, "Taking back control of vibrator.");
1333             }
1334         }
1335         mVibratorUnderExternalControl = externalControl;
1336         vibratorSetExternalControl(externalControl);
1337     }
1338 
1339     private class VibrateThread extends Thread {
1340         private final VibrationEffect.Waveform mWaveform;
1341         private final int mUid;
1342         private final AudioAttributes mAttrs;
1343 
1344         private boolean mForceStop;
1345 
VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs)1346         VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs) {
1347             mWaveform = waveform;
1348             mUid = uid;
1349             mAttrs = attrs;
1350             mTmpWorkSource.set(uid);
1351             mWakeLock.setWorkSource(mTmpWorkSource);
1352         }
1353 
delayLocked(long duration)1354         private long delayLocked(long duration) {
1355             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1356             try {
1357                 long durationRemaining = duration;
1358                 if (duration > 0) {
1359                     final long bedtime = duration + SystemClock.uptimeMillis();
1360                     do {
1361                         try {
1362                             this.wait(durationRemaining);
1363                         }
1364                         catch (InterruptedException e) { }
1365                         if (mForceStop) {
1366                             break;
1367                         }
1368                         durationRemaining = bedtime - SystemClock.uptimeMillis();
1369                     } while (durationRemaining > 0);
1370                     return duration - durationRemaining;
1371                 }
1372                 return 0;
1373             } finally {
1374                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1375             }
1376         }
1377 
run()1378         public void run() {
1379             Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
1380             mWakeLock.acquire();
1381             try {
1382                 boolean finished = playWaveform();
1383                 if (finished) {
1384                     onVibrationFinished();
1385                 }
1386             } finally {
1387                 mWakeLock.release();
1388             }
1389         }
1390 
1391         /**
1392          * Play the waveform.
1393          *
1394          * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1395          */
playWaveform()1396         public boolean playWaveform() {
1397             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1398             try {
1399                 synchronized (this) {
1400                     final long[] timings = mWaveform.getTimings();
1401                     final int[] amplitudes = mWaveform.getAmplitudes();
1402                     final int len = timings.length;
1403                     final int repeat = mWaveform.getRepeatIndex();
1404 
1405                     int index = 0;
1406                     long onDuration = 0;
1407                     while (!mForceStop) {
1408                         if (index < len) {
1409                             final int amplitude = amplitudes[index];
1410                             final long duration = timings[index++];
1411                             if (duration <= 0) {
1412                                 continue;
1413                             }
1414                             if (amplitude != 0) {
1415                                 if (onDuration <= 0) {
1416                                     // Telling the vibrator to start multiple times usually causes
1417                                     // effects to feel "choppy" because the motor resets at every on
1418                                     // command.  Instead we figure out how long our next "on" period
1419                                     // is going to be, tell the motor to stay on for the full
1420                                     // duration, and then wake up to change the amplitude at the
1421                                     // appropriate intervals.
1422                                     onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1423                                             repeat);
1424                                     doVibratorOn(onDuration, amplitude, mUid, mAttrs);
1425                                 } else {
1426                                     doVibratorSetAmplitude(amplitude);
1427                                 }
1428                             }
1429 
1430                             long waitTime = delayLocked(duration);
1431                             if (amplitude != 0) {
1432                                 onDuration -= waitTime;
1433                             }
1434                         } else if (repeat < 0) {
1435                             break;
1436                         } else {
1437                             index = repeat;
1438                         }
1439                     }
1440                     return !mForceStop;
1441                 }
1442             } finally {
1443                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1444             }
1445         }
1446 
cancel()1447         public void cancel() {
1448             synchronized (this) {
1449                 mThread.mForceStop = true;
1450                 mThread.notify();
1451             }
1452         }
1453 
1454         /**
1455          * Get the duration the vibrator will be on starting at startIndex until the next time it's
1456          * off.
1457          */
getTotalOnDuration( long[] timings, int[] amplitudes, int startIndex, int repeatIndex)1458         private long getTotalOnDuration(
1459                 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1460             int i = startIndex;
1461             long timing = 0;
1462             while(amplitudes[i] != 0) {
1463                 timing += timings[i++];
1464                 if (i >= timings.length) {
1465                     if (repeatIndex >= 0) {
1466                         i = repeatIndex;
1467                         // prevent infinite loop
1468                         repeatIndex = -1;
1469                     } else {
1470                         break;
1471                     }
1472                 }
1473                 if (i == startIndex) {
1474                     return 1000;
1475                 }
1476             }
1477             return timing;
1478         }
1479     }
1480 
1481     BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1482         @Override
1483         public void onReceive(Context context, Intent intent) {
1484             if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
1485                 synchronized (mLock) {
1486                     // When the system is entering a non-interactive state, we want
1487                     // to cancel vibrations in case a misbehaving app has abandoned
1488                     // them.  However it may happen that the system is currently playing
1489                     // haptic feedback as part of the transition.  So we don't cancel
1490                     // system vibrations.
1491                     if (mCurrentVibration != null
1492                             && !(mCurrentVibration.isHapticFeedback()
1493                                 && mCurrentVibration.isFromSystem())) {
1494                         doCancelVibrateLocked();
1495                     }
1496                 }
1497             }
1498         }
1499     };
1500 
1501     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1502     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1503         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1504 
1505         pw.println("Vibrator Service:");
1506         synchronized (mLock) {
1507             pw.print("  mCurrentVibration=");
1508             if (mCurrentVibration != null) {
1509                 pw.println(mCurrentVibration.toInfo().toString());
1510             } else {
1511                 pw.println("null");
1512             }
1513             pw.print("  mCurrentExternalVibration=");
1514             if (mCurrentExternalVibration != null) {
1515                 pw.println(mCurrentExternalVibration.toString());
1516             } else {
1517                 pw.println("null");
1518             }
1519             pw.println("  mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
1520             pw.println("  mLowPowerMode=" + mLowPowerMode);
1521             pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1522             pw.println("  mNotificationIntensity=" + mNotificationIntensity);
1523             pw.println("  mRingIntensity=" + mRingIntensity);
1524             pw.println("");
1525             pw.println("  Previous ring vibrations:");
1526             for (VibrationInfo info : mPreviousRingVibrations) {
1527                 pw.print("    ");
1528                 pw.println(info.toString());
1529             }
1530 
1531             pw.println("  Previous notification vibrations:");
1532             for (VibrationInfo info : mPreviousNotificationVibrations) {
1533                 pw.print("    ");
1534                 pw.println(info.toString());
1535             }
1536 
1537             pw.println("  Previous alarm vibrations:");
1538             for (VibrationInfo info : mPreviousAlarmVibrations) {
1539                 pw.print("    ");
1540                 pw.println(info.toString());
1541             }
1542 
1543             pw.println("  Previous vibrations:");
1544             for (VibrationInfo info : mPreviousVibrations) {
1545                 pw.print("    ");
1546                 pw.println(info.toString());
1547             }
1548 
1549             pw.println("  Previous external vibrations:");
1550             for (ExternalVibration vib : mPreviousExternalVibrations) {
1551                 pw.print("    ");
1552                 pw.println(vib.toString());
1553             }
1554         }
1555     }
1556 
1557     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1558     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1559             String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1560             throws RemoteException {
1561         new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1562     }
1563 
1564     final class ExternalVibratorService extends IExternalVibratorService.Stub {
1565         ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient;
1566 
1567         @Override
onExternalVibrationStart(ExternalVibration vib)1568         public int onExternalVibrationStart(ExternalVibration vib) {
1569             if (!mSupportsExternalControl) {
1570                 return SCALE_MUTE;
1571             }
1572             if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
1573                         vib.getUid(), -1 /*owningUid*/, true /*exported*/)
1574                     != PackageManager.PERMISSION_GRANTED) {
1575                 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
1576                         + " tried to play externally controlled vibration"
1577                         + " without VIBRATE permission, ignoring.");
1578                 return SCALE_MUTE;
1579             }
1580 
1581             final int scaleLevel;
1582             synchronized (mLock) {
1583                 if (!vib.equals(mCurrentExternalVibration)) {
1584                     if (mCurrentExternalVibration == null) {
1585                         // If we're not under external control right now, then cancel any normal
1586                         // vibration that may be playing and ready the vibrator for external
1587                         // control.
1588                         doCancelVibrateLocked();
1589                         setVibratorUnderExternalControl(true);
1590                     }
1591                     // At this point we either have an externally controlled vibration playing, or
1592                     // no vibration playing. Since the interface defines that only one externally
1593                     // controlled vibration can play at a time, by returning something other than
1594                     // SCALE_MUTE from this function we can be assured that if we are currently
1595                     // playing vibration, it will be muted in favor of the new vibration.
1596                     //
1597                     // Note that this doesn't support multiple concurrent external controls, as we
1598                     // would need to mute the old one still if it came from a different controller.
1599                     mCurrentExternalVibration = vib;
1600                     mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
1601                     mCurrentExternalVibration.linkToDeath(mCurrentExternalDeathRecipient);
1602                     if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
1603                         mPreviousExternalVibrations.removeFirst();
1604                     }
1605                     mPreviousExternalVibrations.addLast(vib);
1606                     if (DEBUG) {
1607                         Slog.e(TAG, "Playing external vibration: " + vib);
1608                     }
1609                 }
1610                 final int usage = vib.getAudioAttributes().getUsage();
1611                 final int defaultIntensity;
1612                 final int currentIntensity;
1613                 if (isRingtone(usage)) {
1614                     defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
1615                     currentIntensity = mRingIntensity;
1616                 } else if (isNotification(usage)) {
1617                     defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
1618                     currentIntensity = mNotificationIntensity;
1619                 } else if (isHapticFeedback(usage)) {
1620                     defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
1621                     currentIntensity = mHapticFeedbackIntensity;
1622                 } else if (isAlarm(usage)) {
1623                     defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1624                     currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1625                 } else {
1626                     defaultIntensity = 0;
1627                     currentIntensity = 0;
1628                 }
1629                 scaleLevel = currentIntensity - defaultIntensity;
1630             }
1631             if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
1632                 return scaleLevel;
1633             } else {
1634                 // Presumably we want to play this but something about our scaling has gone
1635                 // wrong, so just play with no scaling.
1636                 Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
1637                         + scaleLevel + " for vibration " + vib);
1638                 return SCALE_NONE;
1639             }
1640         }
1641 
1642         @Override
onExternalVibrationStop(ExternalVibration vib)1643         public void onExternalVibrationStop(ExternalVibration vib) {
1644             synchronized (mLock) {
1645                 if (vib.equals(mCurrentExternalVibration)) {
1646                     mCurrentExternalVibration.unlinkToDeath(mCurrentExternalDeathRecipient);
1647                     mCurrentExternalDeathRecipient = null;
1648                     mCurrentExternalVibration = null;
1649                     setVibratorUnderExternalControl(false);
1650                     if (DEBUG) {
1651                         Slog.e(TAG, "Stopping external vibration" + vib);
1652                     }
1653                 }
1654             }
1655         }
1656 
1657         private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
binderDied()1658             public void binderDied() {
1659                 synchronized (mLock) {
1660                     onExternalVibrationStop(mCurrentExternalVibration);
1661                 }
1662             }
1663         }
1664     }
1665 
1666     private final class VibratorShellCommand extends ShellCommand {
1667 
1668         private final IBinder mToken;
1669 
1670         private final class CommonOptions {
1671             public boolean force = false;
check(String opt)1672             public void check(String opt) {
1673                 switch (opt) {
1674                     case "-f":
1675                         force = true;
1676                         break;
1677                 }
1678             }
1679         }
1680 
VibratorShellCommand(IBinder token)1681         private VibratorShellCommand(IBinder token) {
1682             mToken = token;
1683         }
1684 
1685         @Override
onCommand(String cmd)1686         public int onCommand(String cmd) {
1687             if ("vibrate".equals(cmd)) {
1688                 return runVibrate();
1689             } else if ("waveform".equals(cmd)) {
1690                 return runWaveform();
1691             } else if ("prebaked".equals(cmd)) {
1692                 return runPrebaked();
1693             } else if ("cancel".equals(cmd)) {
1694                 cancelVibrate(mToken);
1695                 return 0;
1696             }
1697             return handleDefaultCommands(cmd);
1698         }
1699 
checkDoNotDisturb(CommonOptions opts)1700         private boolean checkDoNotDisturb(CommonOptions opts) {
1701             try {
1702                 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1703                         Settings.Global.ZEN_MODE);
1704                 if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
1705                     try (PrintWriter pw = getOutPrintWriter();) {
1706                         pw.print("Ignoring because device is on DND mode ");
1707                         pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1708                                 zenMode));
1709                         return true;
1710                     }
1711                 }
1712             } catch (SettingNotFoundException e) {
1713                 // ignore
1714             }
1715 
1716             return false;
1717         }
1718 
runVibrate()1719         private int runVibrate() {
1720             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
1721             try {
1722                 CommonOptions commonOptions = new CommonOptions();
1723 
1724                 String opt;
1725                 while ((opt = getNextOption()) != null) {
1726                     commonOptions.check(opt);
1727                 }
1728 
1729                 if (checkDoNotDisturb(commonOptions)) {
1730                     return 0;
1731                 }
1732 
1733                 final long duration = Long.parseLong(getNextArgRequired());
1734                 String description = getNextArg();
1735                 if (description == null) {
1736                     description = "Shell command";
1737                 }
1738 
1739                 VibrationEffect effect =
1740                         VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1741                 AudioAttributes attrs = createAudioAttributes(commonOptions);
1742                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
1743                         mToken);
1744                 return 0;
1745             } finally {
1746                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1747             }
1748         }
1749 
runWaveform()1750         private int runWaveform() {
1751             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
1752             try {
1753                 String description = "Shell command";
1754                 int repeat = -1;
1755                 ArrayList<Integer> amplitudesList = null;
1756                 CommonOptions commonOptions = new CommonOptions();
1757 
1758                 String opt;
1759                 while ((opt = getNextOption()) != null) {
1760                     switch (opt) {
1761                         case "-d":
1762                             description = getNextArgRequired();
1763                             break;
1764                         case "-r":
1765                             repeat = Integer.parseInt(getNextArgRequired());
1766                             break;
1767                         case "-a":
1768                             if (amplitudesList == null) {
1769                                 amplitudesList = new ArrayList<Integer>();
1770                             }
1771                             break;
1772                         default:
1773                             commonOptions.check(opt);
1774                             break;
1775                     }
1776                 }
1777 
1778                 if (checkDoNotDisturb(commonOptions)) {
1779                     return 0;
1780                 }
1781 
1782                 ArrayList<Long> timingsList = new ArrayList<Long>();
1783 
1784                 String arg;
1785                 while ((arg = getNextArg()) != null) {
1786                     if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
1787                         amplitudesList.add(Integer.parseInt(arg));
1788                     } else {
1789                         timingsList.add(Long.parseLong(arg));
1790                     }
1791                 }
1792 
1793                 VibrationEffect effect;
1794                 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
1795                 if (amplitudesList == null) {
1796                     effect = VibrationEffect.createWaveform(timings, repeat);
1797                 } else {
1798                     int[] amplitudes =
1799                             amplitudesList.stream().mapToInt(Integer::intValue).toArray();
1800                     effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
1801                 }
1802                 AudioAttributes attrs = createAudioAttributes(commonOptions);
1803                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
1804                         mToken);
1805                 return 0;
1806             } finally {
1807                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1808             }
1809         }
1810 
runPrebaked()1811         private int runPrebaked() {
1812             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
1813             try {
1814                 CommonOptions commonOptions = new CommonOptions();
1815 
1816                 String opt;
1817                 while ((opt = getNextOption()) != null) {
1818                     commonOptions.check(opt);
1819                 }
1820 
1821                 if (checkDoNotDisturb(commonOptions)) {
1822                     return 0;
1823                 }
1824 
1825                 final int id = Integer.parseInt(getNextArgRequired());
1826 
1827                 String description = getNextArg();
1828                 if (description == null) {
1829                     description = "Shell command";
1830                 }
1831 
1832                 VibrationEffect effect =
1833                         VibrationEffect.get(id, false);
1834                 AudioAttributes attrs = createAudioAttributes(commonOptions);
1835                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
1836                         mToken);
1837                 return 0;
1838             } finally {
1839                 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1840             }
1841         }
1842 
createAudioAttributes(CommonOptions commonOptions)1843         private AudioAttributes createAudioAttributes(CommonOptions commonOptions) {
1844             final int flags = commonOptions.force
1845                     ? AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
1846                     : 0;
1847             return new AudioAttributes.Builder()
1848                     .setUsage(AudioAttributes.USAGE_UNKNOWN)
1849                     .setFlags(flags)
1850                     .build();
1851         }
1852 
1853         @Override
onHelp()1854         public void onHelp() {
1855             try (PrintWriter pw = getOutPrintWriter();) {
1856                 pw.println("Vibrator commands:");
1857                 pw.println("  help");
1858                 pw.println("    Prints this help text.");
1859                 pw.println("");
1860                 pw.println("  vibrate duration [description]");
1861                 pw.println("    Vibrates for duration milliseconds; ignored when device is on DND ");
1862                 pw.println("    (Do Not Disturb) mode.");
1863                 pw.println("  waveform [-d description] [-r index] [-a] duration [amplitude] ...");
1864                 pw.println("    Vibrates for durations and amplitudes in list;");
1865                 pw.println("    ignored when device is on DND (Do Not Disturb) mode.");
1866                 pw.println("    If -r is provided, the waveform loops back to the specified");
1867                 pw.println("    index (e.g. 0 loops from the beginning)");
1868                 pw.println("    If -a is provided, the command accepts duration-amplitude pairs;");
1869                 pw.println("    otherwise, it accepts durations only and alternates off/on");
1870                 pw.println("    Duration is in milliseconds; amplitude is a scale of 1-255.");
1871                 pw.println("  prebaked effect-id [description]");
1872                 pw.println("    Vibrates with prebaked effect; ignored when device is on DND ");
1873                 pw.println("    (Do Not Disturb) mode.");
1874                 pw.println("  cancel");
1875                 pw.println("    Cancels any active vibration");
1876                 pw.println("Common Options:");
1877                 pw.println("  -f - Force. Ignore Do Not Disturb setting.");
1878                 pw.println("");
1879             }
1880         }
1881     }
1882 
1883 }
1884