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