blob: 678ae38514a37e789d273de1d024aad277a3c425 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
Michael Wright71216972017-01-31 18:33:54 +000025import android.content.res.Resources;
Jeff Brown7f6c2312012-04-13 20:38:38 -070026import android.database.ContentObserver;
27import android.hardware.input.InputManager;
Michael Wright71216972017-01-31 18:33:54 +000028import android.hardware.vibrator.V1_0.Constants.EffectStrength;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070029import android.media.AudioManager;
jackqdyulei455e90a2017-02-09 15:29:16 -080030import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070031import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070032import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050033import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070035import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.Process;
37import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080038import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.os.IBinder;
40import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080041import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080042import android.os.ShellCallback;
43import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070045import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070046import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000047import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070048import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070049import android.provider.Settings;
50import android.provider.Settings.SettingNotFoundException;
Joe Onorato8a9b2202010-02-26 18:56:32 -080051import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070052import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040053import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
Dianne Hackborna06de0f2012-12-11 16:34:47 -080055import com.android.internal.app.IAppOpsService;
56import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060057import com.android.internal.util.DumpUtils;
jackqdyulei455e90a2017-02-09 15:29:16 -080058import com.android.server.power.BatterySaverPolicy.ServiceType;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080059
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070060import java.io.FileDescriptor;
61import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070062import java.util.ArrayList;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070063import java.util.Arrays;
Jeff Brown969579b2014-05-20 19:29:29 -070064import java.util.Iterator;
Patrick Scott18dd5f02009-07-02 11:31:12 -040065import java.util.LinkedList;
66import java.util.ListIterator;
67
Jeff Brown7f6c2312012-04-13 20:38:38 -070068public class VibratorService extends IVibratorService.Stub
69 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050070 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070071 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070072 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050073
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070074 private final LinkedList<VibrationInfo> mPreviousVibrations;
75 private final int mPreviousVibrationsLimit;
Michael Wright71216972017-01-31 18:33:54 +000076 private final boolean mSupportsAmplitudeControl;
77 private final int mDefaultVibrationAmplitude;
78 private final VibrationEffect[] mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070079 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070080 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +000081 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -070082
83 private final Context mContext;
84 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080085 private final IAppOpsService mAppOpsService;
86 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070087 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070088 private InputManager mIm;
89
Michael Wright71216972017-01-31 18:33:54 +000090 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -070091
Michael Wright71216972017-01-31 18:33:54 +000092 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -070093 // to be acquired
94 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
95 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
96 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
97
Michael Wright71216972017-01-31 18:33:54 +000098 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080099 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700100 private boolean mLowPowerMode;
101 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800102
Jeff Brown7f6c2312012-04-13 20:38:38 -0700103 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200104 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700105 native static void vibratorOn(long milliseconds);
106 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000107 native static boolean vibratorSupportsAmplitudeControl();
108 native static void vibratorSetAmplitude(int amplitude);
109 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400110
Patrick Scott18dd5f02009-07-02 11:31:12 -0400111 private class Vibration implements IBinder.DeathRecipient {
112 private final IBinder mToken;
Michael Wright71216972017-01-31 18:33:54 +0000113 private final VibrationEffect mEffect;
114 private final long mStartTime;
115 private final int mUsageHint;
116 private final int mUid;
117 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400118
Michael Wright71216972017-01-31 18:33:54 +0000119 private Vibration(IBinder token, VibrationEffect effect,
120 int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400121 mToken = token;
Michael Wright71216972017-01-31 18:33:54 +0000122 mEffect = effect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400123 mStartTime = SystemClock.uptimeMillis();
John Spurlock7b414672014-07-18 13:02:39 -0400124 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700125 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400126 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400127 }
128
129 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000130 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400131 if (this == mCurrentVibration) {
132 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400133 }
134 }
135 }
136
137 public boolean hasLongerTimeout(long millis) {
Michael Wright71216972017-01-31 18:33:54 +0000138 // If the current effect is a one shot vibration that will end after the given timeout
139 // for the new one shot vibration, then just let the current vibration finish. All
140 // other effect types will get pre-empted.
141 if (mEffect instanceof VibrationEffect.OneShot) {
142 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
143 return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400144 }
Michael Wright71216972017-01-31 18:33:54 +0000145 return false;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400146 }
Jeff Brown969579b2014-05-20 19:29:29 -0700147
148 public boolean isSystemHapticFeedback() {
Michael Wright71216972017-01-31 18:33:54 +0000149 boolean repeating = false;
150 if (mEffect instanceof VibrationEffect.Waveform) {
151 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
152 repeating = (waveform.getRepeatIndex() < 0);
153 }
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700154 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
Michael Wright71216972017-01-31 18:33:54 +0000155 && !repeating;
Jeff Brown969579b2014-05-20 19:29:29 -0700156 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400157 }
158
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700159 private static class VibrationInfo {
Michael Wright71216972017-01-31 18:33:54 +0000160 private final long mStartTime;
161 private final VibrationEffect mEffect;
162 private final int mUsageHint;
163 private final int mUid;
164 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700165
Michael Wright71216972017-01-31 18:33:54 +0000166 public VibrationInfo(long startTime, VibrationEffect effect,
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700167 int usageHint, int uid, String opPkg) {
Michael Wright71216972017-01-31 18:33:54 +0000168 mStartTime = startTime;
169 mEffect = effect;
170 mUsageHint = usageHint;
171 mUid = uid;
172 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700173 }
174
175 @Override
176 public String toString() {
177 return new StringBuilder()
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700178 .append(", startTime: ")
Michael Wright71216972017-01-31 18:33:54 +0000179 .append(mStartTime)
180 .append(", effect: ")
181 .append(mEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700182 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000183 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700184 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000185 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700186 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000187 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700188 .toString();
189 }
190 }
191
Mike Lockwood3a322132009-11-24 00:30:52 -0500192 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200193 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 // Reset the hardware to a default state, in case this is a runtime
195 // restart instead of a fresh boot.
196 vibratorOff();
197
Michael Wright71216972017-01-31 18:33:54 +0000198 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000201 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700202 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 mWakeLock.setReferenceCounted(true);
204
Michael Wright71216972017-01-31 18:33:54 +0000205 mAppOpsService =
206 IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700207 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
208 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800209
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700210 mPreviousVibrationsLimit = mContext.getResources().getInteger(
211 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
212
Michael Wright71216972017-01-31 18:33:54 +0000213 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
214 com.android.internal.R.integer.config_defaultVibrationAmplitude);
215
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700216 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800218 IntentFilter filter = new IntentFilter();
219 filter.addAction(Intent.ACTION_SCREEN_OFF);
220 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000221
222 long[] clickEffectTimings = getLongIntArray(context.getResources(),
223 com.android.internal.R.array.config_virtualKeyVibePattern);
224 VibrationEffect clickEffect = VibrationEffect.createWaveform(clickEffectTimings, -1);
225 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
226 new long[] {0, 30, 100, 30} /*timings*/, -1);
227
228 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };
229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 }
231
Jeff Brown7f6c2312012-04-13 20:38:38 -0700232 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800233 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700234 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700235
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700236 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
237 mPowerManagerInternal.registerLowPowerModeObserver(
238 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800239 @Override
240 public int getServiceType() {
241 return ServiceType.VIBRATION;
242 }
243
244 @Override
245 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000246 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800247 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700248 });
249
Jeff Brown7f6c2312012-04-13 20:38:38 -0700250 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700251 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
252 true, mSettingObserver, UserHandle.USER_ALL);
253
Jeff Brownd4935962012-09-25 13:27:20 -0700254 mContext.registerReceiver(new BroadcastReceiver() {
255 @Override
256 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000257 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700258 }
259 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
260
Michael Wright71216972017-01-31 18:33:54 +0000261 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700262 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700263
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700264 private final class SettingsObserver extends ContentObserver {
265 public SettingsObserver(Handler handler) {
266 super(handler);
267 }
268
269 @Override
270 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000271 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700272 }
273 }
274
Jeff Brown82379ba2014-07-25 19:03:28 -0700275 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700276 public boolean hasVibrator() {
277 return doVibratorExists();
278 }
279
Michael Wright71216972017-01-31 18:33:54 +0000280 @Override // Binder call
281 public boolean hasAmplitudeControl() {
282 synchronized (mInputDeviceVibrators) {
283 // Input device vibrators don't support amplitude controls yet, but are still used over
284 // the system vibrator when connected.
285 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
286 }
287 }
288
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800289 private void verifyIncomingUid(int uid) {
290 if (uid == Binder.getCallingUid()) {
291 return;
292 }
293 if (Binder.getCallingPid() == Process.myPid()) {
294 return;
295 }
296 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
297 Binder.getCallingPid(), Binder.getCallingUid(), null);
298 }
299
Michael Wright71216972017-01-31 18:33:54 +0000300 /**
301 * Validate the incoming VibrationEffect.
302 *
303 * We can't throw exceptions here since we might be called from some system_server component,
304 * which would bring the whole system down.
305 *
306 * @return whether the VibrationEffect is valid
307 */
308 private static boolean verifyVibrationEffect(VibrationEffect effect) {
309 if (effect == null) {
310 // Effect must not be null.
311 Slog.wtf(TAG, "effect must not be null");
312 return false;
313 }
314 try {
315 effect.validate();
316 } catch (Exception e) {
317 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
318 return false;
319 }
320 return true;
321 }
322
323 private static long[] getLongIntArray(Resources r, int resid) {
324 int[] ar = r.getIntArray(resid);
325 if (ar == null) {
326 return null;
327 }
328 long[] out = new long[ar.length];
329 for (int i = 0; i < ar.length; i++) {
330 out[i] = ar[i];
331 }
332 return out;
333 }
334
Jeff Brown82379ba2014-07-25 19:03:28 -0700335 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000336 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400337 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700338 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
339 != PackageManager.PERMISSION_GRANTED) {
340 throw new SecurityException("Requires VIBRATE permission");
341 }
Michael Wright71216972017-01-31 18:33:54 +0000342 if (token == null) {
343 Slog.e(TAG, "token must not be null");
344 return;
345 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800346 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000347 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400348 return;
349 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700350
Michael Wright71216972017-01-31 18:33:54 +0000351 // If our current vibration is longer than the new vibration and is the same amplitude,
352 // then just let the current one finish.
353 if (effect instanceof VibrationEffect.OneShot
354 && mCurrentVibration != null
355 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
356 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
357 VibrationEffect.OneShot currentOneShot =
358 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
359 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
360 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
361 if (DEBUG) {
362 Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 return;
365 }
Michael Wright71216972017-01-31 18:33:54 +0000366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367
Michael Wright71216972017-01-31 18:33:54 +0000368 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
369
370 // Only link against waveforms since they potentially don't have a finish if
371 // they're repeating. Let other effects just play out until they're done.
372 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400373 try {
374 token.linkToDeath(vib, 0);
375 } catch (RemoteException e) {
376 return;
377 }
Michael Wright71216972017-01-31 18:33:54 +0000378 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400379
Michael Wright71216972017-01-31 18:33:54 +0000380
381 long ident = Binder.clearCallingIdentity();
382 try {
383 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400384 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000385 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700386 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
Michael Wright71216972017-01-31 18:33:54 +0000388 } finally {
389 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 }
391 }
392
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700393 private void addToPreviousVibrationsLocked(Vibration vib) {
394 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
395 mPreviousVibrations.removeFirst();
396 }
Michael Wright71216972017-01-31 18:33:54 +0000397 mPreviousVibrations.addLast(new VibrationInfo(
398 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700399 }
400
Jeff Brown82379ba2014-07-25 19:03:28 -0700401 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400402 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 mContext.enforceCallingOrSelfPermission(
404 android.Manifest.permission.VIBRATE,
405 "cancelVibrate");
406
Michael Wright71216972017-01-31 18:33:54 +0000407 synchronized (mLock) {
408 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
409 if (DEBUG) {
410 Slog.d(TAG, "Canceling vibration.");
411 }
412 long ident = Binder.clearCallingIdentity();
413 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400414 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000415 } finally {
416 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400417 }
418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700421
Michael Wright71216972017-01-31 18:33:54 +0000422 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700423 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400424 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000425 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400426 }
427 };
428
Patrick Scott18dd5f02009-07-02 11:31:12 -0400429 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000430 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400431 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000432 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400433 mThread = null;
434 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700435 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800436 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400437 }
438
Michael Wright71216972017-01-31 18:33:54 +0000439 // Callback for whenever the current vibration has finished played out
440 public void onVibrationFinished() {
441 if (DEBUG) {
442 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400443 }
Michael Wright71216972017-01-31 18:33:54 +0000444 synchronized (mLock) {
445 // Make sure the vibration is really done. This also reports that the vibration is
446 // finished.
447 doCancelVibrateLocked();
448 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400449 }
450
Patrick Scott18dd5f02009-07-02 11:31:12 -0400451 private void startVibrationLocked(final Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000452 if (mLowPowerMode && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
453 if (DEBUG) {
454 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700455 }
Michael Wright71216972017-01-31 18:33:54 +0000456 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800457 }
Michael Wright71216972017-01-31 18:33:54 +0000458
459 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
460 !shouldVibrateForRingtone()) {
461 if (DEBUG) {
462 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
463 }
464 return;
465 }
466
467 final int mode = getAppOpMode(vib);
468 if (mode != AppOpsManager.MODE_ALLOWED) {
469 if (mode == AppOpsManager.MODE_ERRORED) {
470 // We might be getting calls from within system_server, so we don't actually want
471 // to throw a SecurityException here.
472 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
473 }
474 return;
475 }
476 startVibrationInnerLocked(vib);
477 }
478
479 private void startVibrationInnerLocked(Vibration vib) {
480 mCurrentVibration = vib;
481 if (vib.mEffect instanceof VibrationEffect.OneShot) {
482 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
483 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
484 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
485 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400486 // mThread better be null here. doCancelVibrate should always be
487 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000488 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
489 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400490 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000491 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
492 long timeout = doVibratorPrebakedEffectLocked(vib);
493 if (timeout > 0) {
494 mH.postDelayed(mVibrationEndRunnable, timeout);
495 }
496 } else {
497 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 }
499 }
500
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700501 private boolean shouldVibrateForRingtone() {
502 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700503 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700504 // "Also vibrate for calls" Setting in Sound
505 if (Settings.System.getInt(
506 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
507 return ringerMode != AudioManager.RINGER_MODE_SILENT;
508 } else {
509 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
510 }
511 }
512
Michael Wright71216972017-01-31 18:33:54 +0000513 private int getAppOpMode(Vibration vib) {
514 int mode;
515 try {
516 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
517 vib.mUsageHint, vib.mUid, vib.mOpPkg);
518 if (mode == AppOpsManager.MODE_ALLOWED) {
519 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
520 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
521 }
522 } catch (RemoteException e) {
523 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
524 mode = AppOpsManager.MODE_IGNORED;
525 }
526 return mode;
527 }
528
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800529 private void reportFinishVibrationLocked() {
530 if (mCurrentVibration != null) {
531 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700532 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
533 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400534 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000535 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800536 mCurrentVibration = null;
537 }
538 }
539
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200540 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000541 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200542 vib.mToken.unlinkToDeath(vib, 0);
543 }
544 }
545
Michael Wright71216972017-01-31 18:33:54 +0000546 private void updateVibrators() {
547 synchronized (mLock) {
548 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
549 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700550
Michael Wright71216972017-01-31 18:33:54 +0000551 if (devicesUpdated || lowPowerModeUpdated) {
552 // If the state changes out from under us then just reset.
553 doCancelVibrateLocked();
554 }
555 }
556 }
Jeff Brown82065252012-04-16 13:19:05 -0700557
Michael Wright71216972017-01-31 18:33:54 +0000558 private boolean updateInputDeviceVibratorsLocked() {
559 boolean changed = false;
560 boolean vibrateInputDevices = false;
561 try {
562 vibrateInputDevices = Settings.System.getIntForUser(
563 mContext.getContentResolver(),
564 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
565 } catch (SettingNotFoundException snfe) {
566 }
567 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
568 changed = true;
569 mVibrateInputDevicesSetting = vibrateInputDevices;
570 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700571
Michael Wright71216972017-01-31 18:33:54 +0000572 if (mVibrateInputDevicesSetting) {
573 if (!mInputDeviceListenerRegistered) {
574 mInputDeviceListenerRegistered = true;
575 mIm.registerInputDeviceListener(this, mH);
576 }
577 } else {
578 if (mInputDeviceListenerRegistered) {
579 mInputDeviceListenerRegistered = false;
580 mIm.unregisterInputDeviceListener(this);
581 }
582 }
Jeff Brown82065252012-04-16 13:19:05 -0700583
Michael Wright71216972017-01-31 18:33:54 +0000584 mInputDeviceVibrators.clear();
585 if (mVibrateInputDevicesSetting) {
586 int[] ids = mIm.getInputDeviceIds();
587 for (int i = 0; i < ids.length; i++) {
588 InputDevice device = mIm.getInputDevice(ids[i]);
589 Vibrator vibrator = device.getVibrator();
590 if (vibrator.hasVibrator()) {
591 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700592 }
593 }
Michael Wright71216972017-01-31 18:33:54 +0000594 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700595 }
Michael Wright71216972017-01-31 18:33:54 +0000596 return changed;
597 }
598
599 private boolean updateLowPowerModeLocked() {
600 boolean lowPowerMode = mPowerManagerInternal
601 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
602 if (lowPowerMode != mLowPowerMode) {
603 mLowPowerMode = lowPowerMode;
604 return true;
605 }
606 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700607 }
608
609 @Override
610 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000611 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700612 }
613
614 @Override
615 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000616 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700617 }
618
619 @Override
620 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000621 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700622 }
623
624 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700625 // For now, we choose to ignore the presence of input devices that have vibrators
626 // when reporting whether the device has a vibrator. Applications often use this
627 // information to decide whether to enable certain features so they expect the
628 // result of hasVibrator() to be constant. For now, just report whether
629 // the device has a built-in vibrator.
630 //synchronized (mInputDeviceVibrators) {
631 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
632 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800633 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700634 }
635
Michael Wright71216972017-01-31 18:33:54 +0000636 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700637 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000638 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
639 amplitude = mDefaultVibrationAmplitude;
640 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700641 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000642 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
643 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700644 }
Michael Wright71216972017-01-31 18:33:54 +0000645 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700646 final int vibratorCount = mInputDeviceVibrators.size();
647 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000648 final AudioAttributes attributes =
649 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700650 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400651 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700652 }
653 } else {
Michael Wright71216972017-01-31 18:33:54 +0000654 // Note: ordering is important here! Many haptic drivers will reset their amplitude
655 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700656 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000657 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700658 }
659 }
660 }
661
Michael Wright71216972017-01-31 18:33:54 +0000662 private void doVibratorSetAmplitude(int amplitude) {
663 if (mSupportsAmplitudeControl) {
664 vibratorSetAmplitude(amplitude);
665 }
666 }
667
Jeff Brown7f6c2312012-04-13 20:38:38 -0700668 private void doVibratorOff() {
669 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700670 if (DEBUG) {
671 Slog.d(TAG, "Turning vibrator off.");
672 }
Michael Wright71216972017-01-31 18:33:54 +0000673 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700674 final int vibratorCount = mInputDeviceVibrators.size();
675 if (vibratorCount != 0) {
676 for (int i = 0; i < vibratorCount; i++) {
677 mInputDeviceVibrators.get(i).cancel();
678 }
679 } else {
680 vibratorOff();
681 }
682 }
683 }
684
Michael Wright71216972017-01-31 18:33:54 +0000685 private long doVibratorPrebakedEffectLocked(Vibration vib) {
686 synchronized (mInputDeviceVibrators) {
687 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
688 // Input devices don't support prebaked effect, so skip trying it with them.
689 final int vibratorCount = mInputDeviceVibrators.size();
690 if (vibratorCount == 0) {
691 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
692 if (timeout > 0) {
693 noteVibratorOnLocked(vib.mUid, timeout);
694 return timeout;
695 }
696 }
697 final int id = prebaked.getId();
698 if (id < 0 || id >= mFallbackEffects.length) {
699 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
700 return 0;
701 }
702 VibrationEffect effect = mFallbackEffects[id];
703 Vibration fallbackVib =
704 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
705 startVibrationInnerLocked(fallbackVib);
706 }
707 return 0;
708 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700709
Michael Wright71216972017-01-31 18:33:54 +0000710 private void noteVibratorOnLocked(int uid, long millis) {
711 try {
712 mBatteryStatsService.noteVibratorOn(uid, millis);
713 mCurVibUid = uid;
714 } catch (RemoteException e) {
715 }
716 }
717
718 private void noteVibratorOffLocked() {
719 if (mCurVibUid >= 0) {
720 try {
721 mBatteryStatsService.noteVibratorOff(mCurVibUid);
722 } catch (RemoteException e) { }
723 mCurVibUid = -1;
724 }
725 }
726
727 private class VibrateThread extends Thread {
728 private final VibrationEffect.Waveform mWaveform;
729 private final int mUid;
730 private final int mUsageHint;
731
732 private boolean mForceStop;
733
734 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
735 mWaveform = waveform;
736 mUid = uid;
737 mUsageHint = usageHint;
738 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700739 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 }
741
Michael Wright71216972017-01-31 18:33:54 +0000742 private long delayLocked(long duration) {
743 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000745 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 do {
747 try {
Michael Wright71216972017-01-31 18:33:54 +0000748 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 }
Michael Wright71216972017-01-31 18:33:54 +0000750 catch (InterruptedException e) { }
751 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800752 break;
753 }
Michael Wright71216972017-01-31 18:33:54 +0000754 durationRemaining = bedtime - SystemClock.uptimeMillis();
755 } while (durationRemaining > 0);
756 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 }
Michael Wright71216972017-01-31 18:33:54 +0000758 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
760
761 public void run() {
762 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000763 mWakeLock.acquire();
764 try {
765 boolean finished = playWaveform();
766 if (finished) {
767 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 }
Michael Wright71216972017-01-31 18:33:54 +0000769 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 mWakeLock.release();
771 }
Michael Wright71216972017-01-31 18:33:54 +0000772 }
773
774 /**
775 * Play the waveform.
776 *
777 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
778 */
779 public boolean playWaveform() {
780 synchronized (this) {
781 final long[] timings = mWaveform.getTimings();
782 final int[] amplitudes = mWaveform.getAmplitudes();
783 final int len = timings.length;
784 final int repeat = mWaveform.getRepeatIndex();
785
786 int index = 0;
787 long onDuration = 0;
788 while (!mForceStop) {
789 if (index < len) {
790 final int amplitude = amplitudes[index];
791 final long duration = timings[index++];
792 if (duration <= 0) {
793 continue;
794 }
795 if (amplitude != 0) {
796 if (onDuration <= 0) {
797 // Telling the vibrator to start multiple times usually causes
798 // effects to feel "choppy" because the motor resets at every on
799 // command. Instead we figure out how long our next "on" period is
800 // going to be, tell the motor to stay on for the full duration,
801 // and then wake up to change the amplitude at the appropriate
802 // intervals.
803 onDuration =
804 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
805 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
806 } else {
807 doVibratorSetAmplitude(amplitude);
808 }
809 }
810
811 long waitTime = delayLocked(duration);
812 if (amplitude != 0) {
813 onDuration -= waitTime;
814 }
815 } else if (repeat < 0) {
816 break;
817 } else {
818 index = repeat;
819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
Michael Wright71216972017-01-31 18:33:54 +0000821 return !mForceStop;
822 }
823 }
824
825 public void cancel() {
826 synchronized (this) {
827 mThread.mForceStop = true;
828 mThread.notify();
829 }
830 }
831
832 /**
833 * Get the duration the vibrator will be on starting at startIndex until the next time it's
834 * off.
835 */
836 private long getTotalOnDuration(
837 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
838 int i = startIndex;
839 long timing = 0;
840 while(amplitudes[i] != 0) {
841 timing += timings[i++];
842 if (i >= timings.length) {
843 if (repeatIndex >= 0) {
844 i = repeatIndex;
845 } else {
846 break;
847 }
848 }
849 if (i == startIndex) {
850 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400851 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 }
Michael Wright71216972017-01-31 18:33:54 +0000853 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
Jeff Brown969579b2014-05-20 19:29:29 -0700855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700858 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 public void onReceive(Context context, Intent intent) {
860 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000861 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700862 // When the system is entering a non-interactive state, we want
863 // to cancel vibrations in case a misbehaving app has abandoned
864 // them. However it may happen that the system is currently playing
865 // haptic feedback as part of the transition. So we don't cancel
866 // system vibrations.
867 if (mCurrentVibration != null
868 && !mCurrentVibration.isSystemHapticFeedback()) {
869 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700870 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400871 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 }
873 }
874 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700875
876 @Override
877 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600878 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700879
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700880 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000881 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700882 for (VibrationInfo info : mPreviousVibrations) {
883 pw.print(" ");
884 pw.println(info.toString());
885 }
886 }
887 }
Felipe Lemea5281002017-02-10 15:13:48 -0800888
889 @Override
890 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
891 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
892 throws RemoteException {
893 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
894 }
895
896 private final class VibratorShellCommand extends ShellCommand {
897
898 private static final long MAX_VIBRATION_MS = 200;
899
900 private final IBinder mToken;
901
902 private VibratorShellCommand(IBinder token) {
903 mToken = token;
904 }
905
906 @Override
907 public int onCommand(String cmd) {
908 if ("vibrate".equals(cmd)) {
909 return runVibrate();
910 }
911 return handleDefaultCommands(cmd);
912 }
913
914 private int runVibrate() {
915 final long duration = Long.parseLong(getNextArgRequired());
916 if (duration > MAX_VIBRATION_MS) {
917 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
918 }
919 String description = getNextArg();
920 if (description == null) {
921 description = "Shell command";
922 }
Michael Wright71216972017-01-31 18:33:54 +0000923
924 VibrationEffect effect =
925 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
926 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800927 mToken);
928 return 0;
929 }
930
931 @Override
932 public void onHelp() {
933 try (PrintWriter pw = getOutPrintWriter();) {
934 pw.println("Vibrator commands:");
935 pw.println(" help");
936 pw.println(" Prints this help text.");
937 pw.println("");
938 pw.println(" vibrate duration [description]");
939 pw.println(" Vibrates for duration milliseconds.");
940 pw.println("");
941 }
942 }
943 }
944
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945}