VibratorService.java revision f7b4725375dfb5f6b65433f1679c44501c2478e3
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
17package com.android.server;
18
19import android.app.AppOpsManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
25import android.content.res.Resources;
26import android.database.ContentObserver;
27import android.hardware.input.InputManager;
28import android.hardware.vibrator.V1_0.EffectStrength;
29import android.icu.text.DateFormat;
30import android.media.AudioManager;
31import android.os.PowerManager.ServiceType;
32import android.os.PowerSaveState;
33import android.os.BatteryStats;
34import android.os.Handler;
35import android.os.IVibratorService;
36import android.os.PowerManager;
37import android.os.PowerManagerInternal;
38import android.os.Process;
39import android.os.RemoteException;
40import android.os.ResultReceiver;
41import android.os.IBinder;
42import android.os.Binder;
43import android.os.ServiceManager;
44import android.os.ShellCallback;
45import android.os.ShellCommand;
46import android.os.SystemClock;
47import android.os.Trace;
48import android.os.UserHandle;
49import android.os.Vibrator;
50import android.os.VibrationEffect;
51import android.os.WorkSource;
52import android.provider.Settings;
53import android.provider.Settings.SettingNotFoundException;
54import android.util.DebugUtils;
55import android.util.Slog;
56import android.view.InputDevice;
57import android.media.AudioAttributes;
58
59import com.android.internal.annotations.GuardedBy;
60import com.android.internal.app.IAppOpsService;
61import com.android.internal.app.IBatteryStats;
62import com.android.internal.util.DumpUtils;
63
64import java.io.FileDescriptor;
65import java.io.PrintWriter;
66import java.util.ArrayList;
67import java.util.LinkedList;
68import java.util.Date;
69
70public class VibratorService extends IVibratorService.Stub
71        implements InputManager.InputDeviceListener {
72    private static final String TAG = "VibratorService";
73    private static final boolean DEBUG = false;
74    private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
75
76    private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
77
78    private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f;
79    private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f;
80    private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f;
81    private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f;
82
83    private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255
84    private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255
85
86    // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
87    private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
88
89    private final LinkedList<VibrationInfo> mPreviousVibrations;
90    private final int mPreviousVibrationsLimit;
91    private final boolean mAllowPriorityVibrationsInLowPowerMode;
92    private final boolean mSupportsAmplitudeControl;
93    private final int mDefaultVibrationAmplitude;
94    private final VibrationEffect[] mFallbackEffects;
95    private final WorkSource mTmpWorkSource = new WorkSource();
96    private final Handler mH = new Handler();
97    private final Object mLock = new Object();
98
99    private final Context mContext;
100    private final PowerManager.WakeLock mWakeLock;
101    private final AppOpsManager mAppOps;
102    private final IBatteryStats mBatteryStatsService;
103    private PowerManagerInternal mPowerManagerInternal;
104    private InputManager mIm;
105    private Vibrator mVibrator;
106    private SettingsObserver mSettingObserver;
107
108    private volatile VibrateThread mThread;
109
110    // mInputDeviceVibrators lock should be acquired after mLock, if both are
111    // to be acquired
112    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
113    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
114    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
115
116    @GuardedBy("mLock")
117    private Vibration mCurrentVibration;
118    private int mCurVibUid = -1;
119    private boolean mLowPowerMode;
120    private int mHapticFeedbackIntensity;
121    private int mNotificationIntensity;
122
123    native static boolean vibratorExists();
124    native static void vibratorInit();
125    native static void vibratorOn(long milliseconds);
126    native static void vibratorOff();
127    native static boolean vibratorSupportsAmplitudeControl();
128    native static void vibratorSetAmplitude(int amplitude);
129    native static long vibratorPerformEffect(long effect, long strength);
130
131    private class Vibration implements IBinder.DeathRecipient {
132        public final IBinder token;
133        // Start time in CLOCK_BOOTTIME base.
134        public final long startTime;
135        // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
136        // with other system events, any duration calculations should be done use startTime so as
137        // not to be affected by discontinuities created by RTC adjustments.
138        public final long startTimeDebug;
139        public final int usageHint;
140        public final int uid;
141        public final String opPkg;
142
143        // The actual effect to be played.
144        public VibrationEffect effect;
145        // The original effect that was requested. This is non-null only when the original effect
146        // differs from the effect that's being played. Typically these two things differ because
147        // the effect was scaled based on the users vibration intensity settings.
148        public VibrationEffect originalEffect;
149
150        private Vibration(IBinder token, VibrationEffect effect,
151                int usageHint, int uid, String opPkg) {
152            this.token = token;
153            this.effect = effect;
154            this.startTime = SystemClock.elapsedRealtime();
155            this.startTimeDebug = System.currentTimeMillis();
156            this.usageHint = usageHint;
157            this.uid = uid;
158            this.opPkg = opPkg;
159        }
160
161        public void binderDied() {
162            synchronized (mLock) {
163                if (this == mCurrentVibration) {
164                    doCancelVibrateLocked();
165                }
166            }
167        }
168
169        public boolean hasTimeoutLongerThan(long millis) {
170            final long duration = effect.getDuration();
171            return duration >= 0 && duration > millis;
172        }
173
174        public boolean isHapticFeedback() {
175            if (effect instanceof VibrationEffect.Prebaked) {
176                VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
177                switch (prebaked.getId()) {
178                    case VibrationEffect.EFFECT_CLICK:
179                    case VibrationEffect.EFFECT_DOUBLE_CLICK:
180                    case VibrationEffect.EFFECT_TICK:
181                        return true;
182                    default:
183                        Slog.w(TAG, "Unknown prebaked vibration effect, "
184                                + "assuming it isn't haptic feedback.");
185                        return false;
186                }
187            }
188            final long duration = effect.getDuration();
189            return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
190        }
191
192        public boolean isNotification() {
193            switch (usageHint) {
194                case AudioAttributes.USAGE_NOTIFICATION:
195                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
196                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
197                case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
198                    return true;
199                default:
200                    return false;
201            }
202        }
203
204        public boolean isRingtone() {
205            return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
206        }
207
208        public boolean isFromSystem() {
209            return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
210        }
211
212        public VibrationInfo toInfo() {
213            return new VibrationInfo(
214                    startTimeDebug, effect, originalEffect, usageHint, uid, opPkg);
215        }
216    }
217
218    private static class VibrationInfo {
219        private final long mStartTimeDebug;
220        private final VibrationEffect mEffect;
221        private final VibrationEffect mOriginalEffect;
222        private final int mUsageHint;
223        private final int mUid;
224        private final String mOpPkg;
225
226        public VibrationInfo(long startTimeDebug, VibrationEffect effect,
227                VibrationEffect originalEffect, int usageHint, int uid, String opPkg) {
228            mStartTimeDebug = startTimeDebug;
229            mEffect = effect;
230            mOriginalEffect = originalEffect;
231            mUsageHint = usageHint;
232            mUid = uid;
233            mOpPkg = opPkg;
234        }
235
236        @Override
237        public String toString() {
238            return new StringBuilder()
239                    .append("startTime: ")
240                    .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
241                    .append(", effect: ")
242                    .append(mEffect)
243                    .append(", originalEffect: ")
244                    .append(mOriginalEffect)
245                    .append(", usageHint: ")
246                    .append(mUsageHint)
247                    .append(", uid: ")
248                    .append(mUid)
249                    .append(", opPkg: ")
250                    .append(mOpPkg)
251                    .toString();
252        }
253    }
254
255    VibratorService(Context context) {
256        vibratorInit();
257        // Reset the hardware to a default state, in case this is a runtime
258        // restart instead of a fresh boot.
259        vibratorOff();
260
261        mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
262
263        mContext = context;
264        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
265        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
266        mWakeLock.setReferenceCounted(true);
267
268        mAppOps = mContext.getSystemService(AppOpsManager.class);
269        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
270                BatteryStats.SERVICE_NAME));
271
272        mPreviousVibrationsLimit = mContext.getResources().getInteger(
273                com.android.internal.R.integer.config_previousVibrationsDumpLimit);
274
275        mDefaultVibrationAmplitude = mContext.getResources().getInteger(
276                com.android.internal.R.integer.config_defaultVibrationAmplitude);
277
278        mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
279                com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
280
281        mPreviousVibrations = new LinkedList<>();
282
283        IntentFilter filter = new IntentFilter();
284        filter.addAction(Intent.ACTION_SCREEN_OFF);
285        context.registerReceiver(mIntentReceiver, filter);
286
287        long[] clickEffectTimings = getLongIntArray(context.getResources(),
288                com.android.internal.R.array.config_virtualKeyVibePattern);
289        VibrationEffect clickEffect = createEffect(clickEffectTimings);
290        VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
291                DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
292        long[] tickEffectTimings = getLongIntArray(context.getResources(),
293                com.android.internal.R.array.config_clockTickVibePattern);
294        VibrationEffect tickEffect = createEffect(tickEffectTimings);
295
296        mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
297    }
298
299    private static VibrationEffect createEffect(long[] timings) {
300        if (timings == null || timings.length == 0) {
301            return null;
302        } else if (timings.length == 1) {
303            return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
304        } else {
305            return VibrationEffect.createWaveform(timings, -1);
306        }
307    }
308
309    public void systemReady() {
310        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
311        try {
312            mIm = mContext.getSystemService(InputManager.class);
313            mVibrator = mContext.getSystemService(Vibrator.class);
314            mSettingObserver = new SettingsObserver(mH);
315
316            mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
317            mPowerManagerInternal.registerLowPowerModeObserver(
318                    new PowerManagerInternal.LowPowerModeListener() {
319                        @Override
320                        public int getServiceType() {
321                            return ServiceType.VIBRATION;
322                        }
323
324                        @Override
325                        public void onLowPowerModeChanged(PowerSaveState result) {
326                            updateVibrators();
327                        }
328            });
329
330            mContext.getContentResolver().registerContentObserver(
331                    Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
332                    true, mSettingObserver, UserHandle.USER_ALL);
333
334            mContext.getContentResolver().registerContentObserver(
335                    Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
336                    true, mSettingObserver, UserHandle.USER_ALL);
337
338            mContext.getContentResolver().registerContentObserver(
339                    Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
340                    true, mSettingObserver, UserHandle.USER_ALL);
341
342            mContext.registerReceiver(new BroadcastReceiver() {
343                @Override
344                public void onReceive(Context context, Intent intent) {
345                    updateVibrators();
346                }
347            }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
348
349            updateVibrators();
350        } finally {
351            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
352        }
353    }
354
355    private final class SettingsObserver extends ContentObserver {
356        public SettingsObserver(Handler handler) {
357            super(handler);
358        }
359
360        @Override
361        public void onChange(boolean SelfChange) {
362            updateVibrators();
363        }
364    }
365
366    @Override // Binder call
367    public boolean hasVibrator() {
368        return doVibratorExists();
369    }
370
371    @Override // Binder call
372    public boolean hasAmplitudeControl() {
373        synchronized (mInputDeviceVibrators) {
374            // Input device vibrators don't support amplitude controls yet, but are still used over
375            // the system vibrator when connected.
376            return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
377        }
378    }
379
380    private void verifyIncomingUid(int uid) {
381        if (uid == Binder.getCallingUid()) {
382            return;
383        }
384        if (Binder.getCallingPid() == Process.myPid()) {
385            return;
386        }
387        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
388                Binder.getCallingPid(), Binder.getCallingUid(), null);
389    }
390
391    /**
392     * Validate the incoming VibrationEffect.
393     *
394     * We can't throw exceptions here since we might be called from some system_server component,
395     * which would bring the whole system down.
396     *
397     * @return whether the VibrationEffect is valid
398     */
399    private static boolean verifyVibrationEffect(VibrationEffect effect) {
400        if (effect == null) {
401            // Effect must not be null.
402            Slog.wtf(TAG, "effect must not be null");
403            return false;
404        }
405        try {
406            effect.validate();
407        } catch (Exception e) {
408            Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
409            return false;
410        }
411        return true;
412    }
413
414    private static long[] getLongIntArray(Resources r, int resid) {
415        int[] ar = r.getIntArray(resid);
416        if (ar == null) {
417            return null;
418        }
419        long[] out = new long[ar.length];
420        for (int i = 0; i < ar.length; i++) {
421            out[i] = ar[i];
422        }
423        return out;
424    }
425
426    @Override // Binder call
427    public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
428            IBinder token) {
429        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate");
430        try {
431            if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
432                    != PackageManager.PERMISSION_GRANTED) {
433                throw new SecurityException("Requires VIBRATE permission");
434            }
435            if (token == null) {
436                Slog.e(TAG, "token must not be null");
437                return;
438            }
439            verifyIncomingUid(uid);
440            if (!verifyVibrationEffect(effect)) {
441                return;
442            }
443
444            // If our current vibration is longer than the new vibration and is the same amplitude,
445            // then just let the current one finish.
446            synchronized (mLock) {
447                if (effect instanceof VibrationEffect.OneShot
448                        && mCurrentVibration != null
449                        && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
450                    VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
451                    VibrationEffect.OneShot currentOneShot =
452                            (VibrationEffect.OneShot) mCurrentVibration.effect;
453                    if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
454                            && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
455                        if (DEBUG) {
456                            Slog.d(TAG,
457                                    "Ignoring incoming vibration in favor of current vibration");
458                        }
459                        return;
460                    }
461                }
462
463                // If the current vibration is repeating and the incoming one is non-repeating,
464                // then ignore the non-repeating vibration. This is so that we don't cancel
465                // vibrations that are meant to grab the attention of the user, like ringtones and
466                // alarms, in favor of one-shot vibrations that are likely quite short.
467                if (!isRepeatingVibration(effect)
468                        && mCurrentVibration != null
469                        && isRepeatingVibration(mCurrentVibration.effect)) {
470                    if (DEBUG) {
471                        Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
472                    }
473                    return;
474                }
475
476                Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
477                linkVibration(vib);
478                long ident = Binder.clearCallingIdentity();
479                try {
480                    doCancelVibrateLocked();
481                    startVibrationLocked(vib);
482                    addToPreviousVibrationsLocked(vib);
483                } finally {
484                    Binder.restoreCallingIdentity(ident);
485                }
486            }
487        } finally {
488            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
489        }
490    }
491
492    private static boolean isRepeatingVibration(VibrationEffect effect) {
493        return effect.getDuration() == Long.MAX_VALUE;
494    }
495
496    private void addToPreviousVibrationsLocked(Vibration vib) {
497        if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
498            mPreviousVibrations.removeFirst();
499        }
500        mPreviousVibrations.addLast(vib.toInfo());
501    }
502
503    @Override // Binder call
504    public void cancelVibrate(IBinder token) {
505        mContext.enforceCallingOrSelfPermission(
506                android.Manifest.permission.VIBRATE,
507                "cancelVibrate");
508
509        synchronized (mLock) {
510            if (mCurrentVibration != null && mCurrentVibration.token == token) {
511                if (DEBUG) {
512                    Slog.d(TAG, "Canceling vibration.");
513                }
514                long ident = Binder.clearCallingIdentity();
515                try {
516                    doCancelVibrateLocked();
517                } finally {
518                    Binder.restoreCallingIdentity(ident);
519                }
520            }
521        }
522    }
523
524    private final Runnable mVibrationEndRunnable = new Runnable() {
525        @Override
526        public void run() {
527            onVibrationFinished();
528        }
529    };
530
531    @GuardedBy("mLock")
532    private void doCancelVibrateLocked() {
533        Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
534        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
535        try {
536            mH.removeCallbacks(mVibrationEndRunnable);
537            if (mThread != null) {
538                mThread.cancel();
539                mThread = null;
540            }
541            doVibratorOff();
542            reportFinishVibrationLocked();
543        } finally {
544            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
545        }
546    }
547
548    // Callback for whenever the current vibration has finished played out
549    public void onVibrationFinished() {
550        if (DEBUG) {
551            Slog.e(TAG, "Vibration finished, cleaning up");
552        }
553        synchronized (mLock) {
554            // Make sure the vibration is really done. This also reports that the vibration is
555            // finished.
556            doCancelVibrateLocked();
557        }
558    }
559
560    @GuardedBy("mLock")
561    private void startVibrationLocked(final Vibration vib) {
562        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
563        try {
564            if (!isAllowedToVibrateLocked(vib)) {
565                return;
566            }
567
568            final int intensity = getCurrentIntensityLocked(vib);
569            if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
570                return;
571            }
572
573            if (vib.isRingtone() && !shouldVibrateForRingtone()) {
574                if (DEBUG) {
575                    Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
576                }
577                return;
578            }
579
580            final int mode = getAppOpMode(vib);
581            if (mode != AppOpsManager.MODE_ALLOWED) {
582                if (mode == AppOpsManager.MODE_ERRORED) {
583                    // We might be getting calls from within system_server, so we don't actually
584                    // want to throw a SecurityException here.
585                    Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
586                }
587                return;
588            }
589            applyVibrationIntensityScalingLocked(vib, intensity);
590            startVibrationInnerLocked(vib);
591        } finally {
592            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
593        }
594    }
595
596    @GuardedBy("mLock")
597    private void startVibrationInnerLocked(Vibration vib) {
598        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
599        try {
600            mCurrentVibration = vib;
601            if (vib.effect instanceof VibrationEffect.OneShot) {
602                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
603                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
604                doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
605                mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
606            } else if (vib.effect instanceof VibrationEffect.Waveform) {
607                // mThread better be null here. doCancelVibrate should always be
608                // called before startNextVibrationLocked or startVibrationLocked.
609                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
610                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
611                mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
612                mThread.start();
613            } else if (vib.effect instanceof VibrationEffect.Prebaked) {
614                Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
615                long timeout = doVibratorPrebakedEffectLocked(vib);
616                if (timeout > 0) {
617                    mH.postDelayed(mVibrationEndRunnable, timeout);
618                }
619            } else {
620                Slog.e(TAG, "Unknown vibration type, ignoring");
621            }
622        } finally {
623            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
624        }
625    }
626
627    private boolean isAllowedToVibrateLocked(Vibration vib) {
628        if (!mLowPowerMode) {
629            return true;
630        }
631
632        if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
633            return true;
634        }
635
636        if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
637                vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
638                vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
639            return true;
640        }
641
642        return false;
643    }
644
645    private int getCurrentIntensityLocked(Vibration vib) {
646        if (vib.isNotification() || vib.isRingtone()){
647            return mNotificationIntensity;
648        } else if (vib.isHapticFeedback()) {
649            return mHapticFeedbackIntensity;
650        } else {
651            return Vibrator.VIBRATION_INTENSITY_MEDIUM;
652        }
653    }
654
655    /**
656     * Scale the vibration effect by the intensity as appropriate based its intent.
657     */
658    private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
659        if (vib.effect instanceof VibrationEffect.Prebaked) {
660            // Prebaked effects are always just a direct translation from intensity to
661            // EffectStrength.
662            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
663            prebaked.setEffectStrength(intensityToEffectStrength(intensity));
664            return;
665        }
666
667        final float gamma;
668        final int maxAmplitude;
669        if (vib.isNotification() || vib.isRingtone()) {
670            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
671                gamma = GAMMA_SCALE_FACTOR_MINIMUM;
672                maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY;
673            } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) {
674                gamma = GAMMA_SCALE_FACTOR_LOW;
675                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
676            } else {
677                gamma = GAMMA_SCALE_FACTOR_NONE;
678                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
679            }
680        } else {
681            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
682                gamma = GAMMA_SCALE_FACTOR_LOW;
683                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
684            } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) {
685                gamma = GAMMA_SCALE_FACTOR_HIGH;
686                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
687            } else {
688                gamma = GAMMA_SCALE_FACTOR_NONE;
689                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
690            }
691        }
692
693        VibrationEffect scaledEffect = null;
694        if (vib.effect instanceof VibrationEffect.OneShot) {
695            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
696            scaledEffect = oneShot.scale(gamma, maxAmplitude);
697        } else if (vib.effect instanceof VibrationEffect.Waveform) {
698            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
699            scaledEffect = waveform.scale(gamma, maxAmplitude);
700        } else {
701            Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
702        }
703
704        if (scaledEffect != null) {
705            vib.originalEffect = vib.effect;
706            vib.effect = scaledEffect;
707        }
708    }
709
710    private boolean shouldVibrateForRingtone() {
711        AudioManager audioManager = mContext.getSystemService(AudioManager.class);
712        int ringerMode = audioManager.getRingerModeInternal();
713        // "Also vibrate for calls" Setting in Sound
714        if (Settings.System.getInt(
715                mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
716            return ringerMode != AudioManager.RINGER_MODE_SILENT;
717        } else {
718            return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
719        }
720    }
721
722    private int getAppOpMode(Vibration vib) {
723        int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
724                vib.usageHint, vib.uid, vib.opPkg);
725        if (mode == AppOpsManager.MODE_ALLOWED) {
726            mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
727        }
728        return mode;
729    }
730
731    @GuardedBy("mLock")
732    private void reportFinishVibrationLocked() {
733        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
734        try {
735            if (mCurrentVibration != null) {
736                mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
737                        mCurrentVibration.opPkg);
738                unlinkVibration(mCurrentVibration);
739                mCurrentVibration = null;
740            }
741        } finally {
742            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
743        }
744    }
745
746    private void linkVibration(Vibration vib) {
747        // Only link against waveforms since they potentially don't have a finish if
748        // they're repeating. Let other effects just play out until they're done.
749        if (vib.effect instanceof VibrationEffect.Waveform) {
750            try {
751                vib.token.linkToDeath(vib, 0);
752            } catch (RemoteException e) {
753                return;
754            }
755        }
756    }
757
758    private void unlinkVibration(Vibration vib) {
759        if (vib.effect instanceof VibrationEffect.Waveform) {
760            vib.token.unlinkToDeath(vib, 0);
761        }
762    }
763
764    private void updateVibrators() {
765        synchronized (mLock) {
766            boolean devicesUpdated = updateInputDeviceVibratorsLocked();
767            boolean lowPowerModeUpdated = updateLowPowerModeLocked();
768            updateVibrationIntensityLocked();
769
770            if (devicesUpdated || lowPowerModeUpdated) {
771                // If the state changes out from under us then just reset.
772                doCancelVibrateLocked();
773            }
774        }
775    }
776
777    private boolean updateInputDeviceVibratorsLocked() {
778        boolean changed = false;
779        boolean vibrateInputDevices = false;
780        try {
781            vibrateInputDevices = Settings.System.getIntForUser(
782                    mContext.getContentResolver(),
783                    Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
784        } catch (SettingNotFoundException snfe) {
785        }
786        if (vibrateInputDevices != mVibrateInputDevicesSetting) {
787            changed = true;
788            mVibrateInputDevicesSetting = vibrateInputDevices;
789        }
790
791        if (mVibrateInputDevicesSetting) {
792            if (!mInputDeviceListenerRegistered) {
793                mInputDeviceListenerRegistered = true;
794                mIm.registerInputDeviceListener(this, mH);
795            }
796        } else {
797            if (mInputDeviceListenerRegistered) {
798                mInputDeviceListenerRegistered = false;
799                mIm.unregisterInputDeviceListener(this);
800            }
801        }
802
803        mInputDeviceVibrators.clear();
804        if (mVibrateInputDevicesSetting) {
805            int[] ids = mIm.getInputDeviceIds();
806            for (int i = 0; i < ids.length; i++) {
807                InputDevice device = mIm.getInputDevice(ids[i]);
808                Vibrator vibrator = device.getVibrator();
809                if (vibrator.hasVibrator()) {
810                    mInputDeviceVibrators.add(vibrator);
811                }
812            }
813            return true;
814        }
815        return changed;
816    }
817
818    private boolean updateLowPowerModeLocked() {
819        boolean lowPowerMode = mPowerManagerInternal
820                .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
821        if (lowPowerMode != mLowPowerMode) {
822            mLowPowerMode = lowPowerMode;
823            return true;
824        }
825        return false;
826    }
827
828    private void updateVibrationIntensityLocked() {
829        mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
830                Settings.System.HAPTIC_FEEDBACK_INTENSITY,
831                mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
832        mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
833                Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
834                mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
835    }
836
837    @Override
838    public void onInputDeviceAdded(int deviceId) {
839        updateVibrators();
840    }
841
842    @Override
843    public void onInputDeviceChanged(int deviceId) {
844        updateVibrators();
845    }
846
847    @Override
848    public void onInputDeviceRemoved(int deviceId) {
849        updateVibrators();
850    }
851
852    private boolean doVibratorExists() {
853        // For now, we choose to ignore the presence of input devices that have vibrators
854        // when reporting whether the device has a vibrator.  Applications often use this
855        // information to decide whether to enable certain features so they expect the
856        // result of hasVibrator() to be constant.  For now, just report whether
857        // the device has a built-in vibrator.
858        //synchronized (mInputDeviceVibrators) {
859        //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
860        //}
861        return vibratorExists();
862    }
863
864    private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
865        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
866        try {
867            synchronized (mInputDeviceVibrators) {
868                if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
869                    amplitude = mDefaultVibrationAmplitude;
870                }
871                if (DEBUG) {
872                    Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
873                            " with amplitude " + amplitude + ".");
874                }
875                noteVibratorOnLocked(uid, millis);
876                final int vibratorCount = mInputDeviceVibrators.size();
877                if (vibratorCount != 0) {
878                    final AudioAttributes attributes =
879                            new AudioAttributes.Builder().setUsage(usageHint).build();
880                    for (int i = 0; i < vibratorCount; i++) {
881                        mInputDeviceVibrators.get(i).vibrate(millis, attributes);
882                    }
883                } else {
884                    // Note: ordering is important here! Many haptic drivers will reset their
885                    // amplitude when enabled, so we always have to enable frst, then set the
886                    // amplitude.
887                    vibratorOn(millis);
888                    doVibratorSetAmplitude(amplitude);
889                }
890            }
891        } finally {
892            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
893        }
894    }
895
896    private void doVibratorSetAmplitude(int amplitude) {
897        if (mSupportsAmplitudeControl) {
898            vibratorSetAmplitude(amplitude);
899        }
900    }
901
902    private void doVibratorOff() {
903        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
904        try {
905            synchronized (mInputDeviceVibrators) {
906                if (DEBUG) {
907                    Slog.d(TAG, "Turning vibrator off.");
908                }
909                noteVibratorOffLocked();
910                final int vibratorCount = mInputDeviceVibrators.size();
911                if (vibratorCount != 0) {
912                    for (int i = 0; i < vibratorCount; i++) {
913                        mInputDeviceVibrators.get(i).cancel();
914                    }
915                } else {
916                    vibratorOff();
917                }
918            }
919        } finally {
920            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
921        }
922    }
923
924    @GuardedBy("mLock")
925    private long doVibratorPrebakedEffectLocked(Vibration vib) {
926        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
927        try {
928            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
929            final boolean usingInputDeviceVibrators;
930            synchronized (mInputDeviceVibrators) {
931                usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
932            }
933            // Input devices don't support prebaked effect, so skip trying it with them.
934            if (!usingInputDeviceVibrators) {
935                long timeout = vibratorPerformEffect(prebaked.getId(),
936                        prebaked.getEffectStrength());
937                if (timeout > 0) {
938                    noteVibratorOnLocked(vib.uid, timeout);
939                    return timeout;
940                }
941            }
942            if (!prebaked.shouldFallback()) {
943                return 0;
944            }
945            VibrationEffect effect = getFallbackEffect(prebaked.getId());
946            if (effect == null) {
947                Slog.w(TAG, "Failed to play prebaked effect, no fallback");
948                return 0;
949            }
950            Vibration fallbackVib =
951                    new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
952            final int intensity = getCurrentIntensityLocked(fallbackVib);
953            linkVibration(fallbackVib);
954            applyVibrationIntensityScalingLocked(fallbackVib, intensity);
955            startVibrationInnerLocked(fallbackVib);
956            return 0;
957        } finally {
958            Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
959        }
960    }
961
962    private VibrationEffect getFallbackEffect(int effectId) {
963        if (effectId < 0 || effectId >= mFallbackEffects.length) {
964            return null;
965        }
966        return mFallbackEffects[effectId];
967    }
968
969    /**
970     * Return the current desired effect strength.
971     *
972     * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
973     */
974    private static int intensityToEffectStrength(int intensity) {
975        switch (intensity) {
976            case Vibrator.VIBRATION_INTENSITY_LOW:
977                return EffectStrength.LIGHT;
978            case Vibrator.VIBRATION_INTENSITY_MEDIUM:
979                return EffectStrength.MEDIUM;
980            case Vibrator.VIBRATION_INTENSITY_HIGH:
981                return EffectStrength.STRONG;
982            default:
983                Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
984                return EffectStrength.STRONG;
985        }
986    }
987
988    private void noteVibratorOnLocked(int uid, long millis) {
989        try {
990            mBatteryStatsService.noteVibratorOn(uid, millis);
991            mCurVibUid = uid;
992        } catch (RemoteException e) {
993        }
994    }
995
996    private void noteVibratorOffLocked() {
997        if (mCurVibUid >= 0) {
998            try {
999                mBatteryStatsService.noteVibratorOff(mCurVibUid);
1000            } catch (RemoteException e) { }
1001            mCurVibUid = -1;
1002        }
1003    }
1004
1005    private class VibrateThread extends Thread {
1006        private final VibrationEffect.Waveform mWaveform;
1007        private final int mUid;
1008        private final int mUsageHint;
1009
1010        private boolean mForceStop;
1011
1012        VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1013            mWaveform = waveform;
1014            mUid = uid;
1015            mUsageHint = usageHint;
1016            mTmpWorkSource.set(uid);
1017            mWakeLock.setWorkSource(mTmpWorkSource);
1018        }
1019
1020        private long delayLocked(long duration) {
1021            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1022            try {
1023                long durationRemaining = duration;
1024                if (duration > 0) {
1025                    final long bedtime = duration + SystemClock.uptimeMillis();
1026                    do {
1027                        try {
1028                            this.wait(durationRemaining);
1029                        }
1030                        catch (InterruptedException e) { }
1031                        if (mForceStop) {
1032                            break;
1033                        }
1034                        durationRemaining = bedtime - SystemClock.uptimeMillis();
1035                    } while (durationRemaining > 0);
1036                    return duration - durationRemaining;
1037                }
1038                return 0;
1039            } finally {
1040                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1041            }
1042        }
1043
1044        public void run() {
1045            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
1046            mWakeLock.acquire();
1047            try {
1048                boolean finished = playWaveform();
1049                if (finished) {
1050                    onVibrationFinished();
1051                }
1052            } finally {
1053                mWakeLock.release();
1054            }
1055        }
1056
1057        /**
1058         * Play the waveform.
1059         *
1060         * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1061         */
1062        public boolean playWaveform() {
1063            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1064            try {
1065                synchronized (this) {
1066                    final long[] timings = mWaveform.getTimings();
1067                    final int[] amplitudes = mWaveform.getAmplitudes();
1068                    final int len = timings.length;
1069                    final int repeat = mWaveform.getRepeatIndex();
1070
1071                    int index = 0;
1072                    long onDuration = 0;
1073                    while (!mForceStop) {
1074                        if (index < len) {
1075                            final int amplitude = amplitudes[index];
1076                            final long duration = timings[index++];
1077                            if (duration <= 0) {
1078                                continue;
1079                            }
1080                            if (amplitude != 0) {
1081                                if (onDuration <= 0) {
1082                                    // Telling the vibrator to start multiple times usually causes
1083                                    // effects to feel "choppy" because the motor resets at every on
1084                                    // command.  Instead we figure out how long our next "on" period
1085                                    // is going to be, tell the motor to stay on for the full
1086                                    // duration, and then wake up to change the amplitude at the
1087                                    // appropriate intervals.
1088                                    onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1089                                            repeat);
1090                                    doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1091                                } else {
1092                                    doVibratorSetAmplitude(amplitude);
1093                                }
1094                            }
1095
1096                            long waitTime = delayLocked(duration);
1097                            if (amplitude != 0) {
1098                                onDuration -= waitTime;
1099                            }
1100                        } else if (repeat < 0) {
1101                            break;
1102                        } else {
1103                            index = repeat;
1104                        }
1105                    }
1106                    return !mForceStop;
1107                }
1108            } finally {
1109                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1110            }
1111        }
1112
1113        public void cancel() {
1114            synchronized (this) {
1115                mThread.mForceStop = true;
1116                mThread.notify();
1117            }
1118        }
1119
1120        /**
1121         * Get the duration the vibrator will be on starting at startIndex until the next time it's
1122         * off.
1123         */
1124        private long getTotalOnDuration(
1125                long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1126            int i = startIndex;
1127            long timing = 0;
1128            while(amplitudes[i] != 0) {
1129                timing += timings[i++];
1130                if (i >= timings.length) {
1131                    if (repeatIndex >= 0) {
1132                        i = repeatIndex;
1133                    } else {
1134                        break;
1135                    }
1136                }
1137                if (i == startIndex) {
1138                    return 1000;
1139                }
1140            }
1141            return timing;
1142        }
1143    }
1144
1145    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
1146        @Override
1147        public void onReceive(Context context, Intent intent) {
1148            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
1149                synchronized (mLock) {
1150                    // When the system is entering a non-interactive state, we want
1151                    // to cancel vibrations in case a misbehaving app has abandoned
1152                    // them.  However it may happen that the system is currently playing
1153                    // haptic feedback as part of the transition.  So we don't cancel
1154                    // system vibrations.
1155                    if (mCurrentVibration != null
1156                            && !(mCurrentVibration.isHapticFeedback()
1157                                && mCurrentVibration.isFromSystem())) {
1158                        doCancelVibrateLocked();
1159                    }
1160                }
1161            }
1162        }
1163    };
1164
1165    @Override
1166    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1167        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
1168
1169        pw.println("Vibrator Service:");
1170        synchronized (mLock) {
1171            pw.print("  mCurrentVibration=");
1172            if (mCurrentVibration != null) {
1173                pw.println(mCurrentVibration.toInfo().toString());
1174            } else {
1175                pw.println("null");
1176            }
1177            pw.println("  mLowPowerMode=" + mLowPowerMode);
1178            pw.println("  mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1179            pw.println("  mNotificationIntensity=" + mNotificationIntensity);
1180            pw.println("");
1181            pw.println("  Previous vibrations:");
1182            for (VibrationInfo info : mPreviousVibrations) {
1183                pw.print("    ");
1184                pw.println(info.toString());
1185            }
1186        }
1187    }
1188
1189    @Override
1190    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1191            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1192            throws RemoteException {
1193        new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1194    }
1195
1196    private final class VibratorShellCommand extends ShellCommand {
1197
1198        private static final long MAX_VIBRATION_MS = 200;
1199
1200        private final IBinder mToken;
1201
1202        private VibratorShellCommand(IBinder token) {
1203            mToken = token;
1204        }
1205
1206        @Override
1207        public int onCommand(String cmd) {
1208            if ("vibrate".equals(cmd)) {
1209                return runVibrate();
1210            }
1211            return handleDefaultCommands(cmd);
1212        }
1213
1214        private int runVibrate() {
1215            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
1216            try {
1217                try {
1218                    final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1219                            Settings.Global.ZEN_MODE);
1220                    if (zenMode != Settings.Global.ZEN_MODE_OFF) {
1221                        try (PrintWriter pw = getOutPrintWriter();) {
1222                            pw.print("Ignoring because device is on DND mode ");
1223                            pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1224                                    zenMode));
1225                            return 0;
1226                        }
1227                    }
1228                } catch (SettingNotFoundException e) {
1229                    // ignore
1230                }
1231
1232                final long duration = Long.parseLong(getNextArgRequired());
1233                if (duration > MAX_VIBRATION_MS) {
1234                    throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
1235                }
1236                String description = getNextArg();
1237                if (description == null) {
1238                    description = "Shell command";
1239                }
1240
1241                VibrationEffect effect =
1242                        VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1243                vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1244                        mToken);
1245                return 0;
1246            } finally {
1247                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1248            }
1249        }
1250
1251        @Override
1252        public void onHelp() {
1253            try (PrintWriter pw = getOutPrintWriter();) {
1254                pw.println("Vibrator commands:");
1255                pw.println("  help");
1256                pw.println("    Prints this help text.");
1257                pw.println("");
1258                pw.println("  vibrate duration [description]");
1259                pw.println("    Vibrates for duration milliseconds; ignored when device is on DND ");
1260                pw.println("    (Do Not Disturb) mode.");
1261                pw.println("");
1262            }
1263        }
1264    }
1265
1266}
1267