blob: c4676d12c8bdf50402a7d426521f503ef31869c8 [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;
jackqdyulei455e90a2017-02-09 15:29:16 -080057import com.android.server.power.BatterySaverPolicy.ServiceType;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080058
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070059import java.io.FileDescriptor;
60import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070061import java.util.ArrayList;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070062import java.util.Arrays;
Jeff Brown969579b2014-05-20 19:29:29 -070063import java.util.Iterator;
Patrick Scott18dd5f02009-07-02 11:31:12 -040064import java.util.LinkedList;
65import java.util.ListIterator;
66
Jeff Brown7f6c2312012-04-13 20:38:38 -070067public class VibratorService extends IVibratorService.Stub
68 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050069 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070070 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070071 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050072
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070073 private final LinkedList<VibrationInfo> mPreviousVibrations;
74 private final int mPreviousVibrationsLimit;
Michael Wright71216972017-01-31 18:33:54 +000075 private final boolean mSupportsAmplitudeControl;
76 private final int mDefaultVibrationAmplitude;
77 private final VibrationEffect[] mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070078 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070079 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +000080 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -070081
82 private final Context mContext;
83 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080084 private final IAppOpsService mAppOpsService;
85 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070086 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070087 private InputManager mIm;
88
Michael Wright71216972017-01-31 18:33:54 +000089 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -070090
Michael Wright71216972017-01-31 18:33:54 +000091 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -070092 // to be acquired
93 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
94 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
95 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
96
Michael Wright71216972017-01-31 18:33:54 +000097 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080098 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -070099 private boolean mLowPowerMode;
100 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800101
Jeff Brown7f6c2312012-04-13 20:38:38 -0700102 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200103 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700104 native static void vibratorOn(long milliseconds);
105 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000106 native static boolean vibratorSupportsAmplitudeControl();
107 native static void vibratorSetAmplitude(int amplitude);
108 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400109
Patrick Scott18dd5f02009-07-02 11:31:12 -0400110 private class Vibration implements IBinder.DeathRecipient {
111 private final IBinder mToken;
Michael Wright71216972017-01-31 18:33:54 +0000112 private final VibrationEffect mEffect;
113 private final long mStartTime;
114 private final int mUsageHint;
115 private final int mUid;
116 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400117
Michael Wright71216972017-01-31 18:33:54 +0000118 private Vibration(IBinder token, VibrationEffect effect,
119 int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400120 mToken = token;
Michael Wright71216972017-01-31 18:33:54 +0000121 mEffect = effect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400122 mStartTime = SystemClock.uptimeMillis();
John Spurlock7b414672014-07-18 13:02:39 -0400123 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700124 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400125 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400126 }
127
128 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000129 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400130 if (this == mCurrentVibration) {
131 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400132 }
133 }
134 }
135
136 public boolean hasLongerTimeout(long millis) {
Michael Wright71216972017-01-31 18:33:54 +0000137 // If the current effect is a one shot vibration that will end after the given timeout
138 // for the new one shot vibration, then just let the current vibration finish. All
139 // other effect types will get pre-empted.
140 if (mEffect instanceof VibrationEffect.OneShot) {
141 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
142 return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400143 }
Michael Wright71216972017-01-31 18:33:54 +0000144 return false;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400145 }
Jeff Brown969579b2014-05-20 19:29:29 -0700146
147 public boolean isSystemHapticFeedback() {
Michael Wright71216972017-01-31 18:33:54 +0000148 boolean repeating = false;
149 if (mEffect instanceof VibrationEffect.Waveform) {
150 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
151 repeating = (waveform.getRepeatIndex() < 0);
152 }
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700153 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
Michael Wright71216972017-01-31 18:33:54 +0000154 && !repeating;
Jeff Brown969579b2014-05-20 19:29:29 -0700155 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400156 }
157
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700158 private static class VibrationInfo {
Michael Wright71216972017-01-31 18:33:54 +0000159 private final long mStartTime;
160 private final VibrationEffect mEffect;
161 private final int mUsageHint;
162 private final int mUid;
163 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700164
Michael Wright71216972017-01-31 18:33:54 +0000165 public VibrationInfo(long startTime, VibrationEffect effect,
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700166 int usageHint, int uid, String opPkg) {
Michael Wright71216972017-01-31 18:33:54 +0000167 mStartTime = startTime;
168 mEffect = effect;
169 mUsageHint = usageHint;
170 mUid = uid;
171 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700172 }
173
174 @Override
175 public String toString() {
176 return new StringBuilder()
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700177 .append(", startTime: ")
Michael Wright71216972017-01-31 18:33:54 +0000178 .append(mStartTime)
179 .append(", effect: ")
180 .append(mEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700181 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000182 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700183 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000184 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700185 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000186 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700187 .toString();
188 }
189 }
190
Mike Lockwood3a322132009-11-24 00:30:52 -0500191 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200192 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 // Reset the hardware to a default state, in case this is a runtime
194 // restart instead of a fresh boot.
195 vibratorOff();
196
Michael Wright71216972017-01-31 18:33:54 +0000197 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
198
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000200 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700201 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 mWakeLock.setReferenceCounted(true);
203
Michael Wright71216972017-01-31 18:33:54 +0000204 mAppOpsService =
205 IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700206 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
207 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800208
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700209 mPreviousVibrationsLimit = mContext.getResources().getInteger(
210 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
211
Michael Wright71216972017-01-31 18:33:54 +0000212 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
213 com.android.internal.R.integer.config_defaultVibrationAmplitude);
214
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700215 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 IntentFilter filter = new IntentFilter();
218 filter.addAction(Intent.ACTION_SCREEN_OFF);
219 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000220
221 long[] clickEffectTimings = getLongIntArray(context.getResources(),
222 com.android.internal.R.array.config_virtualKeyVibePattern);
223 VibrationEffect clickEffect = VibrationEffect.createWaveform(clickEffectTimings, -1);
224 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
225 new long[] {0, 30, 100, 30} /*timings*/, -1);
226
227 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };
228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 }
230
Jeff Brown7f6c2312012-04-13 20:38:38 -0700231 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800232 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700233 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700234
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700235 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
236 mPowerManagerInternal.registerLowPowerModeObserver(
237 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800238 @Override
239 public int getServiceType() {
240 return ServiceType.VIBRATION;
241 }
242
243 @Override
244 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000245 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800246 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700247 });
248
Jeff Brown7f6c2312012-04-13 20:38:38 -0700249 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700250 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
251 true, mSettingObserver, UserHandle.USER_ALL);
252
Jeff Brownd4935962012-09-25 13:27:20 -0700253 mContext.registerReceiver(new BroadcastReceiver() {
254 @Override
255 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000256 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700257 }
258 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
259
Michael Wright71216972017-01-31 18:33:54 +0000260 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700261 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700262
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700263 private final class SettingsObserver extends ContentObserver {
264 public SettingsObserver(Handler handler) {
265 super(handler);
266 }
267
268 @Override
269 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000270 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700271 }
272 }
273
Jeff Brown82379ba2014-07-25 19:03:28 -0700274 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700275 public boolean hasVibrator() {
276 return doVibratorExists();
277 }
278
Michael Wright71216972017-01-31 18:33:54 +0000279 @Override // Binder call
280 public boolean hasAmplitudeControl() {
281 synchronized (mInputDeviceVibrators) {
282 // Input device vibrators don't support amplitude controls yet, but are still used over
283 // the system vibrator when connected.
284 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
285 }
286 }
287
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800288 private void verifyIncomingUid(int uid) {
289 if (uid == Binder.getCallingUid()) {
290 return;
291 }
292 if (Binder.getCallingPid() == Process.myPid()) {
293 return;
294 }
295 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
296 Binder.getCallingPid(), Binder.getCallingUid(), null);
297 }
298
Michael Wright71216972017-01-31 18:33:54 +0000299 /**
300 * Validate the incoming VibrationEffect.
301 *
302 * We can't throw exceptions here since we might be called from some system_server component,
303 * which would bring the whole system down.
304 *
305 * @return whether the VibrationEffect is valid
306 */
307 private static boolean verifyVibrationEffect(VibrationEffect effect) {
308 if (effect == null) {
309 // Effect must not be null.
310 Slog.wtf(TAG, "effect must not be null");
311 return false;
312 }
313 try {
314 effect.validate();
315 } catch (Exception e) {
316 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
317 return false;
318 }
319 return true;
320 }
321
322 private static long[] getLongIntArray(Resources r, int resid) {
323 int[] ar = r.getIntArray(resid);
324 if (ar == null) {
325 return null;
326 }
327 long[] out = new long[ar.length];
328 for (int i = 0; i < ar.length; i++) {
329 out[i] = ar[i];
330 }
331 return out;
332 }
333
Jeff Brown82379ba2014-07-25 19:03:28 -0700334 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000335 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400336 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700337 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
338 != PackageManager.PERMISSION_GRANTED) {
339 throw new SecurityException("Requires VIBRATE permission");
340 }
Michael Wright71216972017-01-31 18:33:54 +0000341 if (token == null) {
342 Slog.e(TAG, "token must not be null");
343 return;
344 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800345 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000346 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400347 return;
348 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700349
Michael Wright71216972017-01-31 18:33:54 +0000350 // If our current vibration is longer than the new vibration and is the same amplitude,
351 // then just let the current one finish.
352 if (effect instanceof VibrationEffect.OneShot
353 && mCurrentVibration != null
354 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
355 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
356 VibrationEffect.OneShot currentOneShot =
357 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
358 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
359 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
360 if (DEBUG) {
361 Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 return;
364 }
Michael Wright71216972017-01-31 18:33:54 +0000365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366
Michael Wright71216972017-01-31 18:33:54 +0000367 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
368
369 // Only link against waveforms since they potentially don't have a finish if
370 // they're repeating. Let other effects just play out until they're done.
371 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400372 try {
373 token.linkToDeath(vib, 0);
374 } catch (RemoteException e) {
375 return;
376 }
Michael Wright71216972017-01-31 18:33:54 +0000377 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400378
Michael Wright71216972017-01-31 18:33:54 +0000379
380 long ident = Binder.clearCallingIdentity();
381 try {
382 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400383 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000384 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700385 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 }
Michael Wright71216972017-01-31 18:33:54 +0000387 } finally {
388 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390 }
391
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700392 private void addToPreviousVibrationsLocked(Vibration vib) {
393 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
394 mPreviousVibrations.removeFirst();
395 }
Michael Wright71216972017-01-31 18:33:54 +0000396 mPreviousVibrations.addLast(new VibrationInfo(
397 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700398 }
399
Jeff Brown82379ba2014-07-25 19:03:28 -0700400 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400401 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 mContext.enforceCallingOrSelfPermission(
403 android.Manifest.permission.VIBRATE,
404 "cancelVibrate");
405
Michael Wright71216972017-01-31 18:33:54 +0000406 synchronized (mLock) {
407 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
408 if (DEBUG) {
409 Slog.d(TAG, "Canceling vibration.");
410 }
411 long ident = Binder.clearCallingIdentity();
412 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400413 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000414 } finally {
415 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400416 }
417 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700420
Michael Wright71216972017-01-31 18:33:54 +0000421 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700422 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400423 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000424 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400425 }
426 };
427
Patrick Scott18dd5f02009-07-02 11:31:12 -0400428 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000429 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400430 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000431 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400432 mThread = null;
433 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700434 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800435 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400436 }
437
Michael Wright71216972017-01-31 18:33:54 +0000438 // Callback for whenever the current vibration has finished played out
439 public void onVibrationFinished() {
440 if (DEBUG) {
441 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400442 }
Michael Wright71216972017-01-31 18:33:54 +0000443 synchronized (mLock) {
444 // Make sure the vibration is really done. This also reports that the vibration is
445 // finished.
446 doCancelVibrateLocked();
447 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400448 }
449
Patrick Scott18dd5f02009-07-02 11:31:12 -0400450 private void startVibrationLocked(final Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000451 if (mLowPowerMode && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
452 if (DEBUG) {
453 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700454 }
Michael Wright71216972017-01-31 18:33:54 +0000455 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800456 }
Michael Wright71216972017-01-31 18:33:54 +0000457
458 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
459 !shouldVibrateForRingtone()) {
460 if (DEBUG) {
461 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
462 }
463 return;
464 }
465
466 final int mode = getAppOpMode(vib);
467 if (mode != AppOpsManager.MODE_ALLOWED) {
468 if (mode == AppOpsManager.MODE_ERRORED) {
469 // We might be getting calls from within system_server, so we don't actually want
470 // to throw a SecurityException here.
471 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
472 }
473 return;
474 }
475 startVibrationInnerLocked(vib);
476 }
477
478 private void startVibrationInnerLocked(Vibration vib) {
479 mCurrentVibration = vib;
480 if (vib.mEffect instanceof VibrationEffect.OneShot) {
481 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
482 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
483 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
484 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400485 // mThread better be null here. doCancelVibrate should always be
486 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000487 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
488 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400489 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000490 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
491 long timeout = doVibratorPrebakedEffectLocked(vib);
492 if (timeout > 0) {
493 mH.postDelayed(mVibrationEndRunnable, timeout);
494 }
495 } else {
496 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 }
498 }
499
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700500 private boolean shouldVibrateForRingtone() {
501 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700502 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700503 // "Also vibrate for calls" Setting in Sound
504 if (Settings.System.getInt(
505 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
506 return ringerMode != AudioManager.RINGER_MODE_SILENT;
507 } else {
508 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
509 }
510 }
511
Michael Wright71216972017-01-31 18:33:54 +0000512 private int getAppOpMode(Vibration vib) {
513 int mode;
514 try {
515 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
516 vib.mUsageHint, vib.mUid, vib.mOpPkg);
517 if (mode == AppOpsManager.MODE_ALLOWED) {
518 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
519 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
520 }
521 } catch (RemoteException e) {
522 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
523 mode = AppOpsManager.MODE_IGNORED;
524 }
525 return mode;
526 }
527
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800528 private void reportFinishVibrationLocked() {
529 if (mCurrentVibration != null) {
530 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700531 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
532 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400533 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000534 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800535 mCurrentVibration = null;
536 }
537 }
538
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200539 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000540 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200541 vib.mToken.unlinkToDeath(vib, 0);
542 }
543 }
544
Michael Wright71216972017-01-31 18:33:54 +0000545 private void updateVibrators() {
546 synchronized (mLock) {
547 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
548 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700549
Michael Wright71216972017-01-31 18:33:54 +0000550 if (devicesUpdated || lowPowerModeUpdated) {
551 // If the state changes out from under us then just reset.
552 doCancelVibrateLocked();
553 }
554 }
555 }
Jeff Brown82065252012-04-16 13:19:05 -0700556
Michael Wright71216972017-01-31 18:33:54 +0000557 private boolean updateInputDeviceVibratorsLocked() {
558 boolean changed = false;
559 boolean vibrateInputDevices = false;
560 try {
561 vibrateInputDevices = Settings.System.getIntForUser(
562 mContext.getContentResolver(),
563 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
564 } catch (SettingNotFoundException snfe) {
565 }
566 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
567 changed = true;
568 mVibrateInputDevicesSetting = vibrateInputDevices;
569 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700570
Michael Wright71216972017-01-31 18:33:54 +0000571 if (mVibrateInputDevicesSetting) {
572 if (!mInputDeviceListenerRegistered) {
573 mInputDeviceListenerRegistered = true;
574 mIm.registerInputDeviceListener(this, mH);
575 }
576 } else {
577 if (mInputDeviceListenerRegistered) {
578 mInputDeviceListenerRegistered = false;
579 mIm.unregisterInputDeviceListener(this);
580 }
581 }
Jeff Brown82065252012-04-16 13:19:05 -0700582
Michael Wright71216972017-01-31 18:33:54 +0000583 mInputDeviceVibrators.clear();
584 if (mVibrateInputDevicesSetting) {
585 int[] ids = mIm.getInputDeviceIds();
586 for (int i = 0; i < ids.length; i++) {
587 InputDevice device = mIm.getInputDevice(ids[i]);
588 Vibrator vibrator = device.getVibrator();
589 if (vibrator.hasVibrator()) {
590 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700591 }
592 }
Michael Wright71216972017-01-31 18:33:54 +0000593 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700594 }
Michael Wright71216972017-01-31 18:33:54 +0000595 return changed;
596 }
597
598 private boolean updateLowPowerModeLocked() {
599 boolean lowPowerMode = mPowerManagerInternal
600 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
601 if (lowPowerMode != mLowPowerMode) {
602 mLowPowerMode = lowPowerMode;
603 return true;
604 }
605 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700606 }
607
608 @Override
609 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000610 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700611 }
612
613 @Override
614 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000615 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700616 }
617
618 @Override
619 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000620 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700621 }
622
623 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700624 // For now, we choose to ignore the presence of input devices that have vibrators
625 // when reporting whether the device has a vibrator. Applications often use this
626 // information to decide whether to enable certain features so they expect the
627 // result of hasVibrator() to be constant. For now, just report whether
628 // the device has a built-in vibrator.
629 //synchronized (mInputDeviceVibrators) {
630 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
631 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800632 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700633 }
634
Michael Wright71216972017-01-31 18:33:54 +0000635 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700636 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000637 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
638 amplitude = mDefaultVibrationAmplitude;
639 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700640 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000641 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
642 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700643 }
Michael Wright71216972017-01-31 18:33:54 +0000644 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700645 final int vibratorCount = mInputDeviceVibrators.size();
646 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000647 final AudioAttributes attributes =
648 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700649 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400650 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700651 }
652 } else {
Michael Wright71216972017-01-31 18:33:54 +0000653 // Note: ordering is important here! Many haptic drivers will reset their amplitude
654 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700655 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000656 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700657 }
658 }
659 }
660
Michael Wright71216972017-01-31 18:33:54 +0000661 private void doVibratorSetAmplitude(int amplitude) {
662 if (mSupportsAmplitudeControl) {
663 vibratorSetAmplitude(amplitude);
664 }
665 }
666
Jeff Brown7f6c2312012-04-13 20:38:38 -0700667 private void doVibratorOff() {
668 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700669 if (DEBUG) {
670 Slog.d(TAG, "Turning vibrator off.");
671 }
Michael Wright71216972017-01-31 18:33:54 +0000672 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700673 final int vibratorCount = mInputDeviceVibrators.size();
674 if (vibratorCount != 0) {
675 for (int i = 0; i < vibratorCount; i++) {
676 mInputDeviceVibrators.get(i).cancel();
677 }
678 } else {
679 vibratorOff();
680 }
681 }
682 }
683
Michael Wright71216972017-01-31 18:33:54 +0000684 private long doVibratorPrebakedEffectLocked(Vibration vib) {
685 synchronized (mInputDeviceVibrators) {
686 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
687 // Input devices don't support prebaked effect, so skip trying it with them.
688 final int vibratorCount = mInputDeviceVibrators.size();
689 if (vibratorCount == 0) {
690 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
691 if (timeout > 0) {
692 noteVibratorOnLocked(vib.mUid, timeout);
693 return timeout;
694 }
695 }
696 final int id = prebaked.getId();
697 if (id < 0 || id >= mFallbackEffects.length) {
698 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
699 return 0;
700 }
701 VibrationEffect effect = mFallbackEffects[id];
702 Vibration fallbackVib =
703 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
704 startVibrationInnerLocked(fallbackVib);
705 }
706 return 0;
707 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700708
Michael Wright71216972017-01-31 18:33:54 +0000709 private void noteVibratorOnLocked(int uid, long millis) {
710 try {
711 mBatteryStatsService.noteVibratorOn(uid, millis);
712 mCurVibUid = uid;
713 } catch (RemoteException e) {
714 }
715 }
716
717 private void noteVibratorOffLocked() {
718 if (mCurVibUid >= 0) {
719 try {
720 mBatteryStatsService.noteVibratorOff(mCurVibUid);
721 } catch (RemoteException e) { }
722 mCurVibUid = -1;
723 }
724 }
725
726 private class VibrateThread extends Thread {
727 private final VibrationEffect.Waveform mWaveform;
728 private final int mUid;
729 private final int mUsageHint;
730
731 private boolean mForceStop;
732
733 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
734 mWaveform = waveform;
735 mUid = uid;
736 mUsageHint = usageHint;
737 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700738 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 }
740
Michael Wright71216972017-01-31 18:33:54 +0000741 private long delayLocked(long duration) {
742 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000744 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 do {
746 try {
Michael Wright71216972017-01-31 18:33:54 +0000747 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800748 }
Michael Wright71216972017-01-31 18:33:54 +0000749 catch (InterruptedException e) { }
750 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 break;
752 }
Michael Wright71216972017-01-31 18:33:54 +0000753 durationRemaining = bedtime - SystemClock.uptimeMillis();
754 } while (durationRemaining > 0);
755 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 }
Michael Wright71216972017-01-31 18:33:54 +0000757 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
759
760 public void run() {
761 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000762 mWakeLock.acquire();
763 try {
764 boolean finished = playWaveform();
765 if (finished) {
766 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 }
Michael Wright71216972017-01-31 18:33:54 +0000768 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 mWakeLock.release();
770 }
Michael Wright71216972017-01-31 18:33:54 +0000771 }
772
773 /**
774 * Play the waveform.
775 *
776 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
777 */
778 public boolean playWaveform() {
779 synchronized (this) {
780 final long[] timings = mWaveform.getTimings();
781 final int[] amplitudes = mWaveform.getAmplitudes();
782 final int len = timings.length;
783 final int repeat = mWaveform.getRepeatIndex();
784
785 int index = 0;
786 long onDuration = 0;
787 while (!mForceStop) {
788 if (index < len) {
789 final int amplitude = amplitudes[index];
790 final long duration = timings[index++];
791 if (duration <= 0) {
792 continue;
793 }
794 if (amplitude != 0) {
795 if (onDuration <= 0) {
796 // Telling the vibrator to start multiple times usually causes
797 // effects to feel "choppy" because the motor resets at every on
798 // command. Instead we figure out how long our next "on" period is
799 // going to be, tell the motor to stay on for the full duration,
800 // and then wake up to change the amplitude at the appropriate
801 // intervals.
802 onDuration =
803 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
804 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
805 } else {
806 doVibratorSetAmplitude(amplitude);
807 }
808 }
809
810 long waitTime = delayLocked(duration);
811 if (amplitude != 0) {
812 onDuration -= waitTime;
813 }
814 } else if (repeat < 0) {
815 break;
816 } else {
817 index = repeat;
818 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 }
Michael Wright71216972017-01-31 18:33:54 +0000820 return !mForceStop;
821 }
822 }
823
824 public void cancel() {
825 synchronized (this) {
826 mThread.mForceStop = true;
827 mThread.notify();
828 }
829 }
830
831 /**
832 * Get the duration the vibrator will be on starting at startIndex until the next time it's
833 * off.
834 */
835 private long getTotalOnDuration(
836 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
837 int i = startIndex;
838 long timing = 0;
839 while(amplitudes[i] != 0) {
840 timing += timings[i++];
841 if (i >= timings.length) {
842 if (repeatIndex >= 0) {
843 i = repeatIndex;
844 } else {
845 break;
846 }
847 }
848 if (i == startIndex) {
849 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
Michael Wright71216972017-01-31 18:33:54 +0000852 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
Jeff Brown969579b2014-05-20 19:29:29 -0700854 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700857 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 public void onReceive(Context context, Intent intent) {
859 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000860 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700861 // When the system is entering a non-interactive state, we want
862 // to cancel vibrations in case a misbehaving app has abandoned
863 // them. However it may happen that the system is currently playing
864 // haptic feedback as part of the transition. So we don't cancel
865 // system vibrations.
866 if (mCurrentVibration != null
867 && !mCurrentVibration.isSystemHapticFeedback()) {
868 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700869 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 }
872 }
873 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700874
875 @Override
876 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
877 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
878 != PackageManager.PERMISSION_GRANTED) {
879
880 pw.println("Permission Denial: can't dump vibrator service from from pid="
881 + Binder.getCallingPid()
882 + ", uid=" + Binder.getCallingUid());
883 return;
884 }
885 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000886 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700887 for (VibrationInfo info : mPreviousVibrations) {
888 pw.print(" ");
889 pw.println(info.toString());
890 }
891 }
892 }
Felipe Lemea5281002017-02-10 15:13:48 -0800893
894 @Override
895 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
896 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
897 throws RemoteException {
898 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
899 }
900
901 private final class VibratorShellCommand extends ShellCommand {
902
903 private static final long MAX_VIBRATION_MS = 200;
904
905 private final IBinder mToken;
906
907 private VibratorShellCommand(IBinder token) {
908 mToken = token;
909 }
910
911 @Override
912 public int onCommand(String cmd) {
913 if ("vibrate".equals(cmd)) {
914 return runVibrate();
915 }
916 return handleDefaultCommands(cmd);
917 }
918
919 private int runVibrate() {
920 final long duration = Long.parseLong(getNextArgRequired());
921 if (duration > MAX_VIBRATION_MS) {
922 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
923 }
924 String description = getNextArg();
925 if (description == null) {
926 description = "Shell command";
927 }
Michael Wright71216972017-01-31 18:33:54 +0000928
929 VibrationEffect effect =
930 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
931 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800932 mToken);
933 return 0;
934 }
935
936 @Override
937 public void onHelp() {
938 try (PrintWriter pw = getOutPrintWriter();) {
939 pw.println("Vibrator commands:");
940 pw.println(" help");
941 pw.println(" Prints this help text.");
942 pw.println("");
943 pw.println(" vibrate duration [description]");
944 pw.println(" Vibrates for duration milliseconds.");
945 pw.println("");
946 }
947 }
948 }
949
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950}