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