• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server;
18 
19 import android.app.AppOpsManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.content.pm.PackageManager;
25 import android.content.res.Resources;
26 import android.database.ContentObserver;
27 import android.hardware.input.InputManager;
28 import android.hardware.vibrator.V1_0.Constants.EffectStrength;
29 import android.media.AudioManager;
30 import android.os.PowerSaveState;
31 import android.os.BatteryStats;
32 import android.os.Handler;
33 import android.os.IVibratorService;
34 import android.os.PowerManager;
35 import android.os.PowerManagerInternal;
36 import android.os.Process;
37 import android.os.RemoteException;
38 import android.os.ResultReceiver;
39 import android.os.IBinder;
40 import android.os.Binder;
41 import android.os.ServiceManager;
42 import android.os.ShellCallback;
43 import android.os.ShellCommand;
44 import android.os.SystemClock;
45 import android.os.UserHandle;
46 import android.os.Vibrator;
47 import android.os.VibrationEffect;
48 import android.os.WorkSource;
49 import android.provider.Settings;
50 import android.provider.Settings.SettingNotFoundException;
51 import android.util.Slog;
52 import android.view.InputDevice;
53 import android.media.AudioAttributes;
54 
55 import com.android.internal.app.IAppOpsService;
56 import com.android.internal.app.IBatteryStats;
57 import com.android.internal.util.DumpUtils;
58 import com.android.server.power.BatterySaverPolicy.ServiceType;
59 
60 import java.io.FileDescriptor;
61 import java.io.PrintWriter;
62 import java.util.ArrayList;
63 import java.util.Arrays;
64 import java.util.Iterator;
65 import java.util.LinkedList;
66 import java.util.ListIterator;
67 
68 public 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 
vibratorExists()104     native static boolean vibratorExists();
vibratorInit()105     native static void vibratorInit();
vibratorOn(long milliseconds)106     native static void vibratorOn(long milliseconds);
vibratorOff()107     native static void vibratorOff();
vibratorSupportsAmplitudeControl()108     native static boolean vibratorSupportsAmplitudeControl();
vibratorSetAmplitude(int amplitude)109     native static void vibratorSetAmplitude(int amplitude);
vibratorPerformEffect(long effect, long strength)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 
Vibration(IBinder token, VibrationEffect effect, int usageHint, int uid, String opPkg)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 
binderDied()130         public void binderDied() {
131             synchronized (mLock) {
132                 if (this == mCurrentVibration) {
133                     doCancelVibrateLocked();
134                 }
135             }
136         }
137 
hasLongerTimeout(long millis)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 
isSystemHapticFeedback()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 
VibrationInfo(long startTime, VibrationEffect effect, int usageHint, int uid, String opPkg)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
toString()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 
VibratorService(Context context)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 
systemReady()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 {
SettingsObserver(Handler handler)276         public SettingsObserver(Handler handler) {
277             super(handler);
278         }
279 
280         @Override
onChange(boolean SelfChange)281         public void onChange(boolean SelfChange) {
282             updateVibrators();
283         }
284     }
285 
286     @Override // Binder call
hasVibrator()287     public boolean hasVibrator() {
288         return doVibratorExists();
289     }
290 
291     @Override // Binder call
hasAmplitudeControl()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 
verifyIncomingUid(int uid)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      */
verifyVibrationEffect(VibrationEffect effect)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 
getLongIntArray(Resources r, int resid)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
vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, IBinder token)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 
addToPreviousVibrationsLocked(Vibration vib)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
cancelVibrate(IBinder token)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 
doCancelVibrateLocked()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
onVibrationFinished()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 
startVibrationLocked(final Vibration vib)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 
startVibrationInnerLocked(Vibration vib)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 
isAllowedToVibrate(Vibration vib)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 
shouldVibrateForRingtone()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 
getAppOpMode(Vibration vib)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 
reportFinishVibrationLocked()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 
unlinkVibration(Vibration vib)571     private void unlinkVibration(Vibration vib) {
572         if (vib.mEffect instanceof VibrationEffect.Waveform) {
573             vib.mToken.unlinkToDeath(vib, 0);
574         }
575     }
576 
updateVibrators()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 
updateInputDeviceVibratorsLocked()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 
updateLowPowerModeLocked()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
onInputDeviceAdded(int deviceId)641     public void onInputDeviceAdded(int deviceId) {
642         updateVibrators();
643     }
644 
645     @Override
onInputDeviceChanged(int deviceId)646     public void onInputDeviceChanged(int deviceId) {
647         updateVibrators();
648     }
649 
650     @Override
onInputDeviceRemoved(int deviceId)651     public void onInputDeviceRemoved(int deviceId) {
652         updateVibrators();
653     }
654 
doVibratorExists()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 
doVibratorOn(long millis, int amplitude, int uid, int usageHint)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 
doVibratorSetAmplitude(int amplitude)693     private void doVibratorSetAmplitude(int amplitude) {
694         if (mSupportsAmplitudeControl) {
695             vibratorSetAmplitude(amplitude);
696         }
697     }
698 
doVibratorOff()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 
doVibratorPrebakedEffectLocked(Vibration vib)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 
noteVibratorOnLocked(int uid, long millis)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 
noteVibratorOffLocked()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 
VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint)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 
delayLocked(long duration)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 
run()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          */
playWaveform()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 
cancel()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          */
getTotalOnDuration( long[] timings, int[] amplitudes, int startIndex, int repeatIndex)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
dump(FileDescriptor fd, PrintWriter pw, String[] args)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
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)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 
VibratorShellCommand(IBinder token)933         private VibratorShellCommand(IBinder token) {
934             mToken = token;
935         }
936 
937         @Override
onCommand(String cmd)938         public int onCommand(String cmd) {
939             if ("vibrate".equals(cmd)) {
940                 return runVibrate();
941             }
942             return handleDefaultCommands(cmd);
943         }
944 
runVibrate()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
onHelp()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