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