VibratorService.java revision 5e2e632085f44e289dfcf3d6c32e952244e894fc
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.Constants.EffectStrength;
29import android.media.AudioManager;
30import android.os.PowerSaveState;
31import android.os.BatteryStats;
32import android.os.Handler;
33import android.os.IVibratorService;
34import android.os.PowerManager;
35import android.os.PowerManagerInternal;
36import android.os.Process;
37import android.os.RemoteException;
38import android.os.ResultReceiver;
39import android.os.IBinder;
40import android.os.Binder;
41import android.os.ServiceManager;
42import android.os.ShellCallback;
43import android.os.ShellCommand;
44import android.os.SystemClock;
45import android.os.UserHandle;
46import android.os.Vibrator;
47import android.os.VibrationEffect;
48import android.os.WorkSource;
49import android.provider.Settings;
50import android.provider.Settings.SettingNotFoundException;
51import android.util.DebugUtils;
52import android.util.Slog;
53import android.view.InputDevice;
54import android.media.AudioAttributes;
55
56import com.android.internal.app.IAppOpsService;
57import com.android.internal.app.IBatteryStats;
58import com.android.internal.util.DumpUtils;
59import com.android.server.power.BatterySaverPolicy.ServiceType;
60
61import java.io.FileDescriptor;
62import java.io.PrintWriter;
63import java.util.ArrayList;
64import java.util.LinkedList;
65
66public class VibratorService extends IVibratorService.Stub
67        implements InputManager.InputDeviceListener {
68    private static final String TAG = "VibratorService";
69    private static final boolean DEBUG = false;
70    private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
71
72    private final LinkedList<VibrationInfo> mPreviousVibrations;
73    private final int mPreviousVibrationsLimit;
74    private final boolean mAllowPriorityVibrationsInLowPowerMode;
75    private final boolean mSupportsAmplitudeControl;
76    private final int mDefaultVibrationAmplitude;
77    private final VibrationEffect[] mFallbackEffects;
78    private final WorkSource mTmpWorkSource = new WorkSource();
79    private final Handler mH = new Handler();
80    private final Object mLock = new Object();
81
82    private final Context mContext;
83    private final PowerManager.WakeLock mWakeLock;
84    private final IAppOpsService mAppOpsService;
85    private final IBatteryStats mBatteryStatsService;
86    private PowerManagerInternal mPowerManagerInternal;
87    private InputManager mIm;
88
89    private volatile VibrateThread mThread;
90
91    // mInputDeviceVibrators lock should be acquired after mLock, if both are
92    // to be acquired
93    private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
94    private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
95    private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
96
97    private Vibration mCurrentVibration;
98    private int mCurVibUid = -1;
99    private boolean mLowPowerMode;
100    private SettingsObserver mSettingObserver;
101
102    native static boolean vibratorExists();
103    native static void vibratorInit();
104    native static void vibratorOn(long milliseconds);
105    native static void vibratorOff();
106    native static boolean vibratorSupportsAmplitudeControl();
107    native static void vibratorSetAmplitude(int amplitude);
108    native static long vibratorPerformEffect(long effect, long strength);
109
110    private class Vibration implements IBinder.DeathRecipient {
111        private final IBinder mToken;
112        private final VibrationEffect mEffect;
113        private final long mStartTime;
114        private final int mUsageHint;
115        private final int mUid;
116        private final String mOpPkg;
117
118        private Vibration(IBinder token, VibrationEffect effect,
119                int usageHint, int uid, String opPkg) {
120            mToken = token;
121            mEffect = effect;
122            mStartTime = SystemClock.uptimeMillis();
123            mUsageHint = usageHint;
124            mUid = uid;
125            mOpPkg = opPkg;
126        }
127
128        public void binderDied() {
129            synchronized (mLock) {
130                if (this == mCurrentVibration) {
131                    doCancelVibrateLocked();
132                }
133            }
134        }
135
136        public boolean hasLongerTimeout(long millis) {
137            // If the current effect is a one shot vibration that will end after the given timeout
138            // for the new one shot vibration, then just let the current vibration finish. All
139            // other effect types will get pre-empted.
140            if (mEffect instanceof VibrationEffect.OneShot) {
141                VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
142                return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
143            }
144            return false;
145        }
146
147        public boolean isSystemHapticFeedback() {
148            boolean repeating = false;
149            if (mEffect instanceof VibrationEffect.Waveform) {
150                VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
151                repeating = (waveform.getRepeatIndex() < 0);
152            }
153            return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
154                    && !repeating;
155        }
156    }
157
158    private static class VibrationInfo {
159        private final long mStartTime;
160        private final VibrationEffect mEffect;
161        private final int mUsageHint;
162        private final int mUid;
163        private final String mOpPkg;
164
165        public VibrationInfo(long startTime, VibrationEffect effect,
166                int usageHint, int uid, String opPkg) {
167            mStartTime = startTime;
168            mEffect = effect;
169            mUsageHint = usageHint;
170            mUid = uid;
171            mOpPkg = opPkg;
172        }
173
174        @Override
175        public String toString() {
176            return new StringBuilder()
177                    .append(", startTime: ")
178                    .append(mStartTime)
179                    .append(", effect: ")
180                    .append(mEffect)
181                    .append(", usageHint: ")
182                    .append(mUsageHint)
183                    .append(", uid: ")
184                    .append(mUid)
185                    .append(", opPkg: ")
186                    .append(mOpPkg)
187                    .toString();
188        }
189    }
190
191    VibratorService(Context context) {
192        vibratorInit();
193        // Reset the hardware to a default state, in case this is a runtime
194        // restart instead of a fresh boot.
195        vibratorOff();
196
197        mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
198
199        mContext = context;
200        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
201        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
202        mWakeLock.setReferenceCounted(true);
203
204        mAppOpsService =
205            IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
206        mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
207                BatteryStats.SERVICE_NAME));
208
209        mPreviousVibrationsLimit = mContext.getResources().getInteger(
210                com.android.internal.R.integer.config_previousVibrationsDumpLimit);
211
212        mDefaultVibrationAmplitude = mContext.getResources().getInteger(
213                com.android.internal.R.integer.config_defaultVibrationAmplitude);
214
215        mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
216                com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
217
218        mPreviousVibrations = new LinkedList<>();
219
220        IntentFilter filter = new IntentFilter();
221        filter.addAction(Intent.ACTION_SCREEN_OFF);
222        context.registerReceiver(mIntentReceiver, filter);
223
224        long[] clickEffectTimings = getLongIntArray(context.getResources(),
225                com.android.internal.R.array.config_virtualKeyVibePattern);
226        VibrationEffect clickEffect = createEffect(clickEffectTimings);
227        VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
228                new long[] {0, 30, 100, 30} /*timings*/, -1);
229        long[] tickEffectTimings = getLongIntArray(context.getResources(),
230                com.android.internal.R.array.config_clockTickVibePattern);
231        VibrationEffect tickEffect = createEffect(tickEffectTimings);
232
233        mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
234    }
235
236    private static VibrationEffect createEffect(long[] timings) {
237        if (timings == null || timings.length == 0) {
238            return null;
239        } else if (timings.length == 1) {
240            return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
241        } else {
242            return VibrationEffect.createWaveform(timings, -1);
243        }
244    }
245
246    public void systemReady() {
247        mIm = mContext.getSystemService(InputManager.class);
248        mSettingObserver = new SettingsObserver(mH);
249
250        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
251        mPowerManagerInternal.registerLowPowerModeObserver(
252                new PowerManagerInternal.LowPowerModeListener() {
253                    @Override
254                    public int getServiceType() {
255                        return ServiceType.VIBRATION;
256                    }
257
258                    @Override
259                    public void onLowPowerModeChanged(PowerSaveState result) {
260                        updateVibrators();
261                    }
262        });
263
264        mContext.getContentResolver().registerContentObserver(
265                Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
266                true, mSettingObserver, UserHandle.USER_ALL);
267
268        mContext.registerReceiver(new BroadcastReceiver() {
269            @Override
270            public void onReceive(Context context, Intent intent) {
271                updateVibrators();
272            }
273        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
274
275        updateVibrators();
276    }
277
278    private final class SettingsObserver extends ContentObserver {
279        public SettingsObserver(Handler handler) {
280            super(handler);
281        }
282
283        @Override
284        public void onChange(boolean SelfChange) {
285            updateVibrators();
286        }
287    }
288
289    @Override // Binder call
290    public boolean hasVibrator() {
291        return doVibratorExists();
292    }
293
294    @Override // Binder call
295    public boolean hasAmplitudeControl() {
296        synchronized (mInputDeviceVibrators) {
297            // Input device vibrators don't support amplitude controls yet, but are still used over
298            // the system vibrator when connected.
299            return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
300        }
301    }
302
303    private void verifyIncomingUid(int uid) {
304        if (uid == Binder.getCallingUid()) {
305            return;
306        }
307        if (Binder.getCallingPid() == Process.myPid()) {
308            return;
309        }
310        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
311                Binder.getCallingPid(), Binder.getCallingUid(), null);
312    }
313
314    /**
315     * Validate the incoming VibrationEffect.
316     *
317     * We can't throw exceptions here since we might be called from some system_server component,
318     * which would bring the whole system down.
319     *
320     * @return whether the VibrationEffect is valid
321     */
322    private static boolean verifyVibrationEffect(VibrationEffect effect) {
323        if (effect == null) {
324            // Effect must not be null.
325            Slog.wtf(TAG, "effect must not be null");
326            return false;
327        }
328        try {
329            effect.validate();
330        } catch (Exception e) {
331            Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
332            return false;
333        }
334        return true;
335    }
336
337    private static long[] getLongIntArray(Resources r, int resid) {
338        int[] ar = r.getIntArray(resid);
339        if (ar == null) {
340            return null;
341        }
342        long[] out = new long[ar.length];
343        for (int i = 0; i < ar.length; i++) {
344            out[i] = ar[i];
345        }
346        return out;
347    }
348
349    @Override // Binder call
350    public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
351            IBinder token) {
352        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
353                != PackageManager.PERMISSION_GRANTED) {
354            throw new SecurityException("Requires VIBRATE permission");
355        }
356        if (token == null) {
357            Slog.e(TAG, "token must not be null");
358            return;
359        }
360        verifyIncomingUid(uid);
361        if (!verifyVibrationEffect(effect)) {
362            return;
363        }
364
365        // If our current vibration is longer than the new vibration and is the same amplitude,
366        // then just let the current one finish.
367        if (effect instanceof VibrationEffect.OneShot
368                && mCurrentVibration != null
369                && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
370            VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
371            VibrationEffect.OneShot currentOneShot =
372                    (VibrationEffect.OneShot) mCurrentVibration.mEffect;
373            if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
374                    && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
375                if (DEBUG) {
376                    Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
377                }
378                return;
379            }
380        }
381
382        Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
383
384        // Only link against waveforms since they potentially don't have a finish if
385        // they're repeating. Let other effects just play out until they're done.
386        if (effect instanceof VibrationEffect.Waveform) {
387            try {
388                token.linkToDeath(vib, 0);
389            } catch (RemoteException e) {
390                return;
391            }
392        }
393
394
395        long ident = Binder.clearCallingIdentity();
396        try {
397            synchronized (mLock) {
398                doCancelVibrateLocked();
399                startVibrationLocked(vib);
400                addToPreviousVibrationsLocked(vib);
401            }
402        } finally {
403            Binder.restoreCallingIdentity(ident);
404        }
405    }
406
407    private void addToPreviousVibrationsLocked(Vibration vib) {
408        if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
409            mPreviousVibrations.removeFirst();
410        }
411        mPreviousVibrations.addLast(new VibrationInfo(
412                    vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
413    }
414
415    @Override // Binder call
416    public void cancelVibrate(IBinder token) {
417        mContext.enforceCallingOrSelfPermission(
418                android.Manifest.permission.VIBRATE,
419                "cancelVibrate");
420
421        synchronized (mLock) {
422            if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
423                if (DEBUG) {
424                    Slog.d(TAG, "Canceling vibration.");
425                }
426                long ident = Binder.clearCallingIdentity();
427                try {
428                    doCancelVibrateLocked();
429                } finally {
430                    Binder.restoreCallingIdentity(ident);
431                }
432            }
433        }
434    }
435
436    private final Runnable mVibrationEndRunnable = new Runnable() {
437        @Override
438        public void run() {
439            onVibrationFinished();
440        }
441    };
442
443    private void doCancelVibrateLocked() {
444        mH.removeCallbacks(mVibrationEndRunnable);
445        if (mThread != null) {
446            mThread.cancel();
447            mThread = null;
448        }
449        doVibratorOff();
450        reportFinishVibrationLocked();
451    }
452
453    // Callback for whenever the current vibration has finished played out
454    public void onVibrationFinished() {
455        if (DEBUG) {
456            Slog.e(TAG, "Vibration finished, cleaning up");
457        }
458        synchronized (mLock) {
459            // Make sure the vibration is really done. This also reports that the vibration is
460            // finished.
461            doCancelVibrateLocked();
462        }
463    }
464
465    private void startVibrationLocked(final Vibration vib) {
466        if (!isAllowedToVibrate(vib)) {
467            if (DEBUG) {
468                Slog.e(TAG, "Vibrate ignored, low power mode");
469            }
470            return;
471        }
472
473        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
474                !shouldVibrateForRingtone()) {
475            if (DEBUG) {
476                Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
477            }
478            return;
479        }
480
481        final int mode = getAppOpMode(vib);
482        if (mode != AppOpsManager.MODE_ALLOWED) {
483            if (mode == AppOpsManager.MODE_ERRORED) {
484                // We might be getting calls from within system_server, so we don't actually want
485                // to throw a SecurityException here.
486                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
487            }
488            return;
489        }
490        startVibrationInnerLocked(vib);
491    }
492
493    private void startVibrationInnerLocked(Vibration vib) {
494        mCurrentVibration = vib;
495        if (vib.mEffect instanceof VibrationEffect.OneShot) {
496            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
497            doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
498            mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
499        } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
500            // mThread better be null here. doCancelVibrate should always be
501            // called before startNextVibrationLocked or startVibrationLocked.
502            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
503            mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
504            mThread.start();
505        } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
506            long timeout = doVibratorPrebakedEffectLocked(vib);
507            if (timeout > 0) {
508                mH.postDelayed(mVibrationEndRunnable, timeout);
509            }
510        } else {
511            Slog.e(TAG, "Unknown vibration type, ignoring");
512        }
513    }
514
515    private boolean isAllowedToVibrate(Vibration vib) {
516        if (!mLowPowerMode) {
517            return true;
518        }
519        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
520            return true;
521        }
522        if (!mAllowPriorityVibrationsInLowPowerMode) {
523            return false;
524        }
525        if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
526            vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
527            vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
528
529            return true;
530        }
531
532        return false;
533    }
534
535    private boolean shouldVibrateForRingtone() {
536        AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
537        int ringerMode = audioManager.getRingerModeInternal();
538        // "Also vibrate for calls" Setting in Sound
539        if (Settings.System.getInt(
540                mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
541            return ringerMode != AudioManager.RINGER_MODE_SILENT;
542        } else {
543            return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
544        }
545    }
546
547    private int getAppOpMode(Vibration vib) {
548        int mode;
549        try {
550            mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
551                    vib.mUsageHint, vib.mUid, vib.mOpPkg);
552            if (mode == AppOpsManager.MODE_ALLOWED) {
553                mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
554                    AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
555            }
556        } catch (RemoteException e) {
557            Slog.e(TAG, "Failed to get appop mode for vibration!", e);
558            mode = AppOpsManager.MODE_IGNORED;
559        }
560        return mode;
561    }
562
563    private void reportFinishVibrationLocked() {
564        if (mCurrentVibration != null) {
565            try {
566                mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
567                        AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
568                        mCurrentVibration.mOpPkg);
569            } catch (RemoteException e) { }
570            mCurrentVibration = null;
571        }
572    }
573
574    private void unlinkVibration(Vibration vib) {
575        if (vib.mEffect instanceof VibrationEffect.Waveform) {
576            vib.mToken.unlinkToDeath(vib, 0);
577        }
578    }
579
580    private void updateVibrators() {
581        synchronized (mLock) {
582            boolean devicesUpdated = updateInputDeviceVibratorsLocked();
583            boolean lowPowerModeUpdated = updateLowPowerModeLocked();
584
585            if (devicesUpdated || lowPowerModeUpdated) {
586                // If the state changes out from under us then just reset.
587                doCancelVibrateLocked();
588            }
589        }
590    }
591
592    private boolean updateInputDeviceVibratorsLocked() {
593        boolean changed = false;
594        boolean vibrateInputDevices = false;
595        try {
596            vibrateInputDevices = Settings.System.getIntForUser(
597                    mContext.getContentResolver(),
598                    Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
599        } catch (SettingNotFoundException snfe) {
600        }
601        if (vibrateInputDevices != mVibrateInputDevicesSetting) {
602            changed = true;
603            mVibrateInputDevicesSetting = vibrateInputDevices;
604        }
605
606        if (mVibrateInputDevicesSetting) {
607            if (!mInputDeviceListenerRegistered) {
608                mInputDeviceListenerRegistered = true;
609                mIm.registerInputDeviceListener(this, mH);
610            }
611        } else {
612            if (mInputDeviceListenerRegistered) {
613                mInputDeviceListenerRegistered = false;
614                mIm.unregisterInputDeviceListener(this);
615            }
616        }
617
618        mInputDeviceVibrators.clear();
619        if (mVibrateInputDevicesSetting) {
620            int[] ids = mIm.getInputDeviceIds();
621            for (int i = 0; i < ids.length; i++) {
622                InputDevice device = mIm.getInputDevice(ids[i]);
623                Vibrator vibrator = device.getVibrator();
624                if (vibrator.hasVibrator()) {
625                    mInputDeviceVibrators.add(vibrator);
626                }
627            }
628            return true;
629        }
630        return changed;
631    }
632
633    private boolean updateLowPowerModeLocked() {
634        boolean lowPowerMode = mPowerManagerInternal
635                .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
636        if (lowPowerMode != mLowPowerMode) {
637            mLowPowerMode = lowPowerMode;
638            return true;
639        }
640        return false;
641    }
642
643    @Override
644    public void onInputDeviceAdded(int deviceId) {
645        updateVibrators();
646    }
647
648    @Override
649    public void onInputDeviceChanged(int deviceId) {
650        updateVibrators();
651    }
652
653    @Override
654    public void onInputDeviceRemoved(int deviceId) {
655        updateVibrators();
656    }
657
658    private boolean doVibratorExists() {
659        // For now, we choose to ignore the presence of input devices that have vibrators
660        // when reporting whether the device has a vibrator.  Applications often use this
661        // information to decide whether to enable certain features so they expect the
662        // result of hasVibrator() to be constant.  For now, just report whether
663        // the device has a built-in vibrator.
664        //synchronized (mInputDeviceVibrators) {
665        //    return !mInputDeviceVibrators.isEmpty() || vibratorExists();
666        //}
667        return vibratorExists();
668    }
669
670    private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
671        synchronized (mInputDeviceVibrators) {
672            if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
673                amplitude = mDefaultVibrationAmplitude;
674            }
675            if (DEBUG) {
676                Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
677                        " with amplitude " + amplitude + ".");
678            }
679            noteVibratorOnLocked(uid, millis);
680            final int vibratorCount = mInputDeviceVibrators.size();
681            if (vibratorCount != 0) {
682                final AudioAttributes attributes =
683                        new AudioAttributes.Builder().setUsage(usageHint).build();
684                for (int i = 0; i < vibratorCount; i++) {
685                    mInputDeviceVibrators.get(i).vibrate(millis, attributes);
686                }
687            } else {
688                // Note: ordering is important here! Many haptic drivers will reset their amplitude
689                // when enabled, so we always have to enable frst, then set the amplitude.
690                vibratorOn(millis);
691                doVibratorSetAmplitude(amplitude);
692            }
693        }
694    }
695
696    private void doVibratorSetAmplitude(int amplitude) {
697        if (mSupportsAmplitudeControl) {
698            vibratorSetAmplitude(amplitude);
699        }
700    }
701
702    private void doVibratorOff() {
703        synchronized (mInputDeviceVibrators) {
704            if (DEBUG) {
705                Slog.d(TAG, "Turning vibrator off.");
706            }
707            noteVibratorOffLocked();
708            final int vibratorCount = mInputDeviceVibrators.size();
709            if (vibratorCount != 0) {
710                for (int i = 0; i < vibratorCount; i++) {
711                    mInputDeviceVibrators.get(i).cancel();
712                }
713            } else {
714                vibratorOff();
715            }
716        }
717    }
718
719    private long doVibratorPrebakedEffectLocked(Vibration vib) {
720        synchronized (mInputDeviceVibrators) {
721            VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
722            // Input devices don't support prebaked effect, so skip trying it with them.
723            final int vibratorCount = mInputDeviceVibrators.size();
724            if (vibratorCount == 0) {
725                long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
726                if (timeout > 0) {
727                    noteVibratorOnLocked(vib.mUid, timeout);
728                    return timeout;
729                }
730            }
731            final int id = prebaked.getId();
732            if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
733                Slog.w(TAG, "Failed to play prebaked effect, no fallback");
734                return 0;
735            }
736            VibrationEffect effect = mFallbackEffects[id];
737            Vibration fallbackVib =
738                    new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
739            startVibrationInnerLocked(fallbackVib);
740        }
741        return 0;
742    }
743
744    private void noteVibratorOnLocked(int uid, long millis) {
745        try {
746            mBatteryStatsService.noteVibratorOn(uid, millis);
747            mCurVibUid = uid;
748        } catch (RemoteException e) {
749        }
750    }
751
752    private void noteVibratorOffLocked() {
753        if (mCurVibUid >= 0) {
754            try {
755                mBatteryStatsService.noteVibratorOff(mCurVibUid);
756            } catch (RemoteException e) { }
757            mCurVibUid = -1;
758        }
759    }
760
761    private class VibrateThread extends Thread {
762        private final VibrationEffect.Waveform mWaveform;
763        private final int mUid;
764        private final int mUsageHint;
765
766        private boolean mForceStop;
767
768        VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
769            mWaveform = waveform;
770            mUid = uid;
771            mUsageHint = usageHint;
772            mTmpWorkSource.set(uid);
773            mWakeLock.setWorkSource(mTmpWorkSource);
774        }
775
776        private long delayLocked(long duration) {
777            long durationRemaining = duration;
778            if (duration > 0) {
779                final long bedtime = duration + SystemClock.uptimeMillis();
780                do {
781                    try {
782                        this.wait(durationRemaining);
783                    }
784                    catch (InterruptedException e) { }
785                    if (mForceStop) {
786                        break;
787                    }
788                    durationRemaining = bedtime - SystemClock.uptimeMillis();
789                } while (durationRemaining > 0);
790                return duration - durationRemaining;
791            }
792            return 0;
793        }
794
795        public void run() {
796            Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
797            mWakeLock.acquire();
798            try {
799                boolean finished = playWaveform();
800                if (finished) {
801                    onVibrationFinished();
802                }
803            } finally {
804                mWakeLock.release();
805            }
806        }
807
808        /**
809         * Play the waveform.
810         *
811         * @return true if it finished naturally, false otherwise (e.g. it was canceled).
812         */
813        public boolean playWaveform() {
814            synchronized (this) {
815                final long[] timings = mWaveform.getTimings();
816                final int[] amplitudes = mWaveform.getAmplitudes();
817                final int len = timings.length;
818                final int repeat = mWaveform.getRepeatIndex();
819
820                int index = 0;
821                long onDuration = 0;
822                while (!mForceStop) {
823                    if (index < len) {
824                        final int amplitude = amplitudes[index];
825                        final long duration = timings[index++];
826                        if (duration <= 0) {
827                            continue;
828                        }
829                        if (amplitude != 0) {
830                            if (onDuration <= 0) {
831                                // Telling the vibrator to start multiple times usually causes
832                                // effects to feel "choppy" because the motor resets at every on
833                                // command.  Instead we figure out how long our next "on" period is
834                                // going to be, tell the motor to stay on for the full duration,
835                                // and then wake up to change the amplitude at the appropriate
836                                // intervals.
837                                onDuration =
838                                        getTotalOnDuration(timings, amplitudes, index - 1, repeat);
839                                doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
840                            } else {
841                                doVibratorSetAmplitude(amplitude);
842                            }
843                        }
844
845                        long waitTime = delayLocked(duration);
846                        if (amplitude != 0) {
847                            onDuration -= waitTime;
848                        }
849                    } else if (repeat < 0) {
850                        break;
851                    } else {
852                        index = repeat;
853                    }
854                }
855                return !mForceStop;
856            }
857        }
858
859        public void cancel() {
860            synchronized (this) {
861                mThread.mForceStop = true;
862                mThread.notify();
863            }
864        }
865
866        /**
867         * Get the duration the vibrator will be on starting at startIndex until the next time it's
868         * off.
869         */
870        private long getTotalOnDuration(
871                long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
872            int i = startIndex;
873            long timing = 0;
874            while(amplitudes[i] != 0) {
875                timing += timings[i++];
876                if (i >= timings.length) {
877                    if (repeatIndex >= 0) {
878                        i = repeatIndex;
879                    } else {
880                        break;
881                    }
882                }
883                if (i == startIndex) {
884                    return 1000;
885                }
886            }
887            return timing;
888        }
889    }
890
891    BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
892        @Override
893        public void onReceive(Context context, Intent intent) {
894            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
895                synchronized (mLock) {
896                    // When the system is entering a non-interactive state, we want
897                    // to cancel vibrations in case a misbehaving app has abandoned
898                    // them.  However it may happen that the system is currently playing
899                    // haptic feedback as part of the transition.  So we don't cancel
900                    // system vibrations.
901                    if (mCurrentVibration != null
902                            && !mCurrentVibration.isSystemHapticFeedback()) {
903                        doCancelVibrateLocked();
904                    }
905                }
906            }
907        }
908    };
909
910    @Override
911    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
912        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
913
914        pw.println("Previous vibrations:");
915        synchronized (mLock) {
916            for (VibrationInfo info : mPreviousVibrations) {
917                pw.print("  ");
918                pw.println(info.toString());
919            }
920        }
921    }
922
923    @Override
924    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
925            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
926            throws RemoteException {
927        new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
928    }
929
930    private final class VibratorShellCommand extends ShellCommand {
931
932        private static final long MAX_VIBRATION_MS = 200;
933
934        private final IBinder mToken;
935
936        private VibratorShellCommand(IBinder token) {
937            mToken = token;
938        }
939
940        @Override
941        public int onCommand(String cmd) {
942            if ("vibrate".equals(cmd)) {
943                return runVibrate();
944            }
945            return handleDefaultCommands(cmd);
946        }
947
948        private int runVibrate() {
949            try {
950                final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
951                        Settings.Global.ZEN_MODE);
952                if (zenMode != Settings.Global.ZEN_MODE_OFF) {
953                    try (PrintWriter pw = getOutPrintWriter();) {
954                        pw.print("Ignoring because device is on DND mode ");
955                        pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
956                                zenMode));
957                        return 0;
958                    }
959                }
960            } catch (SettingNotFoundException e) {
961                // ignore
962            }
963
964            final long duration = Long.parseLong(getNextArgRequired());
965            if (duration > MAX_VIBRATION_MS) {
966                throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
967            }
968            String description = getNextArg();
969            if (description == null) {
970                description = "Shell command";
971            }
972
973            VibrationEffect effect =
974                    VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
975            vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
976                    mToken);
977            return 0;
978        }
979
980        @Override
981        public void onHelp() {
982            try (PrintWriter pw = getOutPrintWriter();) {
983                pw.println("Vibrator commands:");
984                pw.println("  help");
985                pw.println("    Prints this help text.");
986                pw.println("");
987                pw.println("  vibrate duration [description]");
988                pw.println("    Vibrates for duration milliseconds; ignored when device is on DND ");
989                pw.println("    (Do Not Disturb) mode.");
990                pw.println("");
991            }
992        }
993    }
994
995}
996