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