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