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