blob: 03e9dd2cc1ed1fb0a7ef56a819ba6e422279bae6 [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);
Erik Wolsheimerb97ae352017-05-22 16:58:18 -0700224 VibrationEffect clickEffect;
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700225 if (clickEffectTimings.length == 0) {
226 clickEffect = null;
227 } else if (clickEffectTimings.length == 1) {
Erik Wolsheimerb97ae352017-05-22 16:58:18 -0700228 clickEffect = VibrationEffect.createOneShot(
229 clickEffectTimings[0], VibrationEffect.DEFAULT_AMPLITUDE);
230 } else {
231 clickEffect = VibrationEffect.createWaveform(clickEffectTimings, -1);
232 }
Michael Wright71216972017-01-31 18:33:54 +0000233 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
234 new long[] {0, 30, 100, 30} /*timings*/, -1);
235
236 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 }
238
Jeff Brown7f6c2312012-04-13 20:38:38 -0700239 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800240 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700241 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700242
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700243 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
244 mPowerManagerInternal.registerLowPowerModeObserver(
245 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800246 @Override
247 public int getServiceType() {
248 return ServiceType.VIBRATION;
249 }
250
251 @Override
252 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000253 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800254 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700255 });
256
Jeff Brown7f6c2312012-04-13 20:38:38 -0700257 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700258 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
259 true, mSettingObserver, UserHandle.USER_ALL);
260
Jeff Brownd4935962012-09-25 13:27:20 -0700261 mContext.registerReceiver(new BroadcastReceiver() {
262 @Override
263 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000264 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700265 }
266 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
267
Michael Wright71216972017-01-31 18:33:54 +0000268 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700269 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700270
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700271 private final class SettingsObserver extends ContentObserver {
272 public SettingsObserver(Handler handler) {
273 super(handler);
274 }
275
276 @Override
277 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000278 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700279 }
280 }
281
Jeff Brown82379ba2014-07-25 19:03:28 -0700282 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700283 public boolean hasVibrator() {
284 return doVibratorExists();
285 }
286
Michael Wright71216972017-01-31 18:33:54 +0000287 @Override // Binder call
288 public boolean hasAmplitudeControl() {
289 synchronized (mInputDeviceVibrators) {
290 // Input device vibrators don't support amplitude controls yet, but are still used over
291 // the system vibrator when connected.
292 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
293 }
294 }
295
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800296 private void verifyIncomingUid(int uid) {
297 if (uid == Binder.getCallingUid()) {
298 return;
299 }
300 if (Binder.getCallingPid() == Process.myPid()) {
301 return;
302 }
303 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
304 Binder.getCallingPid(), Binder.getCallingUid(), null);
305 }
306
Michael Wright71216972017-01-31 18:33:54 +0000307 /**
308 * Validate the incoming VibrationEffect.
309 *
310 * We can't throw exceptions here since we might be called from some system_server component,
311 * which would bring the whole system down.
312 *
313 * @return whether the VibrationEffect is valid
314 */
315 private static boolean verifyVibrationEffect(VibrationEffect effect) {
316 if (effect == null) {
317 // Effect must not be null.
318 Slog.wtf(TAG, "effect must not be null");
319 return false;
320 }
321 try {
322 effect.validate();
323 } catch (Exception e) {
324 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
325 return false;
326 }
327 return true;
328 }
329
330 private static long[] getLongIntArray(Resources r, int resid) {
331 int[] ar = r.getIntArray(resid);
332 if (ar == null) {
333 return null;
334 }
335 long[] out = new long[ar.length];
336 for (int i = 0; i < ar.length; i++) {
337 out[i] = ar[i];
338 }
339 return out;
340 }
341
Jeff Brown82379ba2014-07-25 19:03:28 -0700342 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000343 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400344 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700345 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
346 != PackageManager.PERMISSION_GRANTED) {
347 throw new SecurityException("Requires VIBRATE permission");
348 }
Michael Wright71216972017-01-31 18:33:54 +0000349 if (token == null) {
350 Slog.e(TAG, "token must not be null");
351 return;
352 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800353 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000354 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400355 return;
356 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700357
Michael Wright71216972017-01-31 18:33:54 +0000358 // If our current vibration is longer than the new vibration and is the same amplitude,
359 // then just let the current one finish.
360 if (effect instanceof VibrationEffect.OneShot
361 && mCurrentVibration != null
362 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
363 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
364 VibrationEffect.OneShot currentOneShot =
365 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
366 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
367 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
368 if (DEBUG) {
369 Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 return;
372 }
Michael Wright71216972017-01-31 18:33:54 +0000373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374
Michael Wright71216972017-01-31 18:33:54 +0000375 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
376
377 // Only link against waveforms since they potentially don't have a finish if
378 // they're repeating. Let other effects just play out until they're done.
379 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400380 try {
381 token.linkToDeath(vib, 0);
382 } catch (RemoteException e) {
383 return;
384 }
Michael Wright71216972017-01-31 18:33:54 +0000385 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400386
Michael Wright71216972017-01-31 18:33:54 +0000387
388 long ident = Binder.clearCallingIdentity();
389 try {
390 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400391 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000392 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700393 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 }
Michael Wright71216972017-01-31 18:33:54 +0000395 } finally {
396 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
398 }
399
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700400 private void addToPreviousVibrationsLocked(Vibration vib) {
401 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
402 mPreviousVibrations.removeFirst();
403 }
Michael Wright71216972017-01-31 18:33:54 +0000404 mPreviousVibrations.addLast(new VibrationInfo(
405 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700406 }
407
Jeff Brown82379ba2014-07-25 19:03:28 -0700408 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400409 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 mContext.enforceCallingOrSelfPermission(
411 android.Manifest.permission.VIBRATE,
412 "cancelVibrate");
413
Michael Wright71216972017-01-31 18:33:54 +0000414 synchronized (mLock) {
415 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
416 if (DEBUG) {
417 Slog.d(TAG, "Canceling vibration.");
418 }
419 long ident = Binder.clearCallingIdentity();
420 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400421 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000422 } finally {
423 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400424 }
425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700428
Michael Wright71216972017-01-31 18:33:54 +0000429 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700430 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400431 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000432 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400433 }
434 };
435
Patrick Scott18dd5f02009-07-02 11:31:12 -0400436 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000437 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400438 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000439 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400440 mThread = null;
441 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700442 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800443 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400444 }
445
Michael Wright71216972017-01-31 18:33:54 +0000446 // Callback for whenever the current vibration has finished played out
447 public void onVibrationFinished() {
448 if (DEBUG) {
449 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400450 }
Michael Wright71216972017-01-31 18:33:54 +0000451 synchronized (mLock) {
452 // Make sure the vibration is really done. This also reports that the vibration is
453 // finished.
454 doCancelVibrateLocked();
455 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400456 }
457
Patrick Scott18dd5f02009-07-02 11:31:12 -0400458 private void startVibrationLocked(final Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000459 if (mLowPowerMode && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
460 if (DEBUG) {
461 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700462 }
Michael Wright71216972017-01-31 18:33:54 +0000463 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800464 }
Michael Wright71216972017-01-31 18:33:54 +0000465
466 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
467 !shouldVibrateForRingtone()) {
468 if (DEBUG) {
469 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
470 }
471 return;
472 }
473
474 final int mode = getAppOpMode(vib);
475 if (mode != AppOpsManager.MODE_ALLOWED) {
476 if (mode == AppOpsManager.MODE_ERRORED) {
477 // We might be getting calls from within system_server, so we don't actually want
478 // to throw a SecurityException here.
479 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
480 }
481 return;
482 }
483 startVibrationInnerLocked(vib);
484 }
485
486 private void startVibrationInnerLocked(Vibration vib) {
487 mCurrentVibration = vib;
488 if (vib.mEffect instanceof VibrationEffect.OneShot) {
489 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
490 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
491 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
492 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400493 // mThread better be null here. doCancelVibrate should always be
494 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000495 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
496 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400497 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000498 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
499 long timeout = doVibratorPrebakedEffectLocked(vib);
500 if (timeout > 0) {
501 mH.postDelayed(mVibrationEndRunnable, timeout);
502 }
503 } else {
504 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 }
506 }
507
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700508 private boolean shouldVibrateForRingtone() {
509 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700510 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700511 // "Also vibrate for calls" Setting in Sound
512 if (Settings.System.getInt(
513 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
514 return ringerMode != AudioManager.RINGER_MODE_SILENT;
515 } else {
516 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
517 }
518 }
519
Michael Wright71216972017-01-31 18:33:54 +0000520 private int getAppOpMode(Vibration vib) {
521 int mode;
522 try {
523 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
524 vib.mUsageHint, vib.mUid, vib.mOpPkg);
525 if (mode == AppOpsManager.MODE_ALLOWED) {
526 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
527 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
528 }
529 } catch (RemoteException e) {
530 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
531 mode = AppOpsManager.MODE_IGNORED;
532 }
533 return mode;
534 }
535
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800536 private void reportFinishVibrationLocked() {
537 if (mCurrentVibration != null) {
538 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700539 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
540 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400541 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000542 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800543 mCurrentVibration = null;
544 }
545 }
546
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200547 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000548 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200549 vib.mToken.unlinkToDeath(vib, 0);
550 }
551 }
552
Michael Wright71216972017-01-31 18:33:54 +0000553 private void updateVibrators() {
554 synchronized (mLock) {
555 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
556 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700557
Michael Wright71216972017-01-31 18:33:54 +0000558 if (devicesUpdated || lowPowerModeUpdated) {
559 // If the state changes out from under us then just reset.
560 doCancelVibrateLocked();
561 }
562 }
563 }
Jeff Brown82065252012-04-16 13:19:05 -0700564
Michael Wright71216972017-01-31 18:33:54 +0000565 private boolean updateInputDeviceVibratorsLocked() {
566 boolean changed = false;
567 boolean vibrateInputDevices = false;
568 try {
569 vibrateInputDevices = Settings.System.getIntForUser(
570 mContext.getContentResolver(),
571 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
572 } catch (SettingNotFoundException snfe) {
573 }
574 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
575 changed = true;
576 mVibrateInputDevicesSetting = vibrateInputDevices;
577 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700578
Michael Wright71216972017-01-31 18:33:54 +0000579 if (mVibrateInputDevicesSetting) {
580 if (!mInputDeviceListenerRegistered) {
581 mInputDeviceListenerRegistered = true;
582 mIm.registerInputDeviceListener(this, mH);
583 }
584 } else {
585 if (mInputDeviceListenerRegistered) {
586 mInputDeviceListenerRegistered = false;
587 mIm.unregisterInputDeviceListener(this);
588 }
589 }
Jeff Brown82065252012-04-16 13:19:05 -0700590
Michael Wright71216972017-01-31 18:33:54 +0000591 mInputDeviceVibrators.clear();
592 if (mVibrateInputDevicesSetting) {
593 int[] ids = mIm.getInputDeviceIds();
594 for (int i = 0; i < ids.length; i++) {
595 InputDevice device = mIm.getInputDevice(ids[i]);
596 Vibrator vibrator = device.getVibrator();
597 if (vibrator.hasVibrator()) {
598 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700599 }
600 }
Michael Wright71216972017-01-31 18:33:54 +0000601 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700602 }
Michael Wright71216972017-01-31 18:33:54 +0000603 return changed;
604 }
605
606 private boolean updateLowPowerModeLocked() {
607 boolean lowPowerMode = mPowerManagerInternal
608 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
609 if (lowPowerMode != mLowPowerMode) {
610 mLowPowerMode = lowPowerMode;
611 return true;
612 }
613 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700614 }
615
616 @Override
617 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000618 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700619 }
620
621 @Override
622 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000623 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700624 }
625
626 @Override
627 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000628 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700629 }
630
631 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700632 // For now, we choose to ignore the presence of input devices that have vibrators
633 // when reporting whether the device has a vibrator. Applications often use this
634 // information to decide whether to enable certain features so they expect the
635 // result of hasVibrator() to be constant. For now, just report whether
636 // the device has a built-in vibrator.
637 //synchronized (mInputDeviceVibrators) {
638 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
639 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800640 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700641 }
642
Michael Wright71216972017-01-31 18:33:54 +0000643 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700644 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000645 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
646 amplitude = mDefaultVibrationAmplitude;
647 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700648 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000649 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
650 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700651 }
Michael Wright71216972017-01-31 18:33:54 +0000652 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700653 final int vibratorCount = mInputDeviceVibrators.size();
654 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000655 final AudioAttributes attributes =
656 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700657 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400658 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700659 }
660 } else {
Michael Wright71216972017-01-31 18:33:54 +0000661 // Note: ordering is important here! Many haptic drivers will reset their amplitude
662 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700663 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000664 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700665 }
666 }
667 }
668
Michael Wright71216972017-01-31 18:33:54 +0000669 private void doVibratorSetAmplitude(int amplitude) {
670 if (mSupportsAmplitudeControl) {
671 vibratorSetAmplitude(amplitude);
672 }
673 }
674
Jeff Brown7f6c2312012-04-13 20:38:38 -0700675 private void doVibratorOff() {
676 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700677 if (DEBUG) {
678 Slog.d(TAG, "Turning vibrator off.");
679 }
Michael Wright71216972017-01-31 18:33:54 +0000680 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700681 final int vibratorCount = mInputDeviceVibrators.size();
682 if (vibratorCount != 0) {
683 for (int i = 0; i < vibratorCount; i++) {
684 mInputDeviceVibrators.get(i).cancel();
685 }
686 } else {
687 vibratorOff();
688 }
689 }
690 }
691
Michael Wright71216972017-01-31 18:33:54 +0000692 private long doVibratorPrebakedEffectLocked(Vibration vib) {
693 synchronized (mInputDeviceVibrators) {
694 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
695 // Input devices don't support prebaked effect, so skip trying it with them.
696 final int vibratorCount = mInputDeviceVibrators.size();
697 if (vibratorCount == 0) {
698 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
699 if (timeout > 0) {
700 noteVibratorOnLocked(vib.mUid, timeout);
701 return timeout;
702 }
703 }
704 final int id = prebaked.getId();
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700705 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Michael Wright71216972017-01-31 18:33:54 +0000706 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
707 return 0;
708 }
709 VibrationEffect effect = mFallbackEffects[id];
710 Vibration fallbackVib =
711 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
712 startVibrationInnerLocked(fallbackVib);
713 }
714 return 0;
715 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700716
Michael Wright71216972017-01-31 18:33:54 +0000717 private void noteVibratorOnLocked(int uid, long millis) {
718 try {
719 mBatteryStatsService.noteVibratorOn(uid, millis);
720 mCurVibUid = uid;
721 } catch (RemoteException e) {
722 }
723 }
724
725 private void noteVibratorOffLocked() {
726 if (mCurVibUid >= 0) {
727 try {
728 mBatteryStatsService.noteVibratorOff(mCurVibUid);
729 } catch (RemoteException e) { }
730 mCurVibUid = -1;
731 }
732 }
733
734 private class VibrateThread extends Thread {
735 private final VibrationEffect.Waveform mWaveform;
736 private final int mUid;
737 private final int mUsageHint;
738
739 private boolean mForceStop;
740
741 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
742 mWaveform = waveform;
743 mUid = uid;
744 mUsageHint = usageHint;
745 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700746 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748
Michael Wright71216972017-01-31 18:33:54 +0000749 private long delayLocked(long duration) {
750 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000752 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 do {
754 try {
Michael Wright71216972017-01-31 18:33:54 +0000755 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 }
Michael Wright71216972017-01-31 18:33:54 +0000757 catch (InterruptedException e) { }
758 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 break;
760 }
Michael Wright71216972017-01-31 18:33:54 +0000761 durationRemaining = bedtime - SystemClock.uptimeMillis();
762 } while (durationRemaining > 0);
763 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800764 }
Michael Wright71216972017-01-31 18:33:54 +0000765 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767
768 public void run() {
769 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000770 mWakeLock.acquire();
771 try {
772 boolean finished = playWaveform();
773 if (finished) {
774 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 }
Michael Wright71216972017-01-31 18:33:54 +0000776 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 mWakeLock.release();
778 }
Michael Wright71216972017-01-31 18:33:54 +0000779 }
780
781 /**
782 * Play the waveform.
783 *
784 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
785 */
786 public boolean playWaveform() {
787 synchronized (this) {
788 final long[] timings = mWaveform.getTimings();
789 final int[] amplitudes = mWaveform.getAmplitudes();
790 final int len = timings.length;
791 final int repeat = mWaveform.getRepeatIndex();
792
793 int index = 0;
794 long onDuration = 0;
795 while (!mForceStop) {
796 if (index < len) {
797 final int amplitude = amplitudes[index];
798 final long duration = timings[index++];
799 if (duration <= 0) {
800 continue;
801 }
802 if (amplitude != 0) {
803 if (onDuration <= 0) {
804 // Telling the vibrator to start multiple times usually causes
805 // effects to feel "choppy" because the motor resets at every on
806 // command. Instead we figure out how long our next "on" period is
807 // going to be, tell the motor to stay on for the full duration,
808 // and then wake up to change the amplitude at the appropriate
809 // intervals.
810 onDuration =
811 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
812 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
813 } else {
814 doVibratorSetAmplitude(amplitude);
815 }
816 }
817
818 long waitTime = delayLocked(duration);
819 if (amplitude != 0) {
820 onDuration -= waitTime;
821 }
822 } else if (repeat < 0) {
823 break;
824 } else {
825 index = repeat;
826 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
Michael Wright71216972017-01-31 18:33:54 +0000828 return !mForceStop;
829 }
830 }
831
832 public void cancel() {
833 synchronized (this) {
834 mThread.mForceStop = true;
835 mThread.notify();
836 }
837 }
838
839 /**
840 * Get the duration the vibrator will be on starting at startIndex until the next time it's
841 * off.
842 */
843 private long getTotalOnDuration(
844 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
845 int i = startIndex;
846 long timing = 0;
847 while(amplitudes[i] != 0) {
848 timing += timings[i++];
849 if (i >= timings.length) {
850 if (repeatIndex >= 0) {
851 i = repeatIndex;
852 } else {
853 break;
854 }
855 }
856 if (i == startIndex) {
857 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400858 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 }
Michael Wright71216972017-01-31 18:33:54 +0000860 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800861 }
Jeff Brown969579b2014-05-20 19:29:29 -0700862 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700865 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800866 public void onReceive(Context context, Intent intent) {
867 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000868 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700869 // When the system is entering a non-interactive state, we want
870 // to cancel vibrations in case a misbehaving app has abandoned
871 // them. However it may happen that the system is currently playing
872 // haptic feedback as part of the transition. So we don't cancel
873 // system vibrations.
874 if (mCurrentVibration != null
875 && !mCurrentVibration.isSystemHapticFeedback()) {
876 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700877 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
880 }
881 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700882
883 @Override
884 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600885 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700886
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700887 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000888 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700889 for (VibrationInfo info : mPreviousVibrations) {
890 pw.print(" ");
891 pw.println(info.toString());
892 }
893 }
894 }
Felipe Lemea5281002017-02-10 15:13:48 -0800895
896 @Override
897 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
898 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
899 throws RemoteException {
900 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
901 }
902
903 private final class VibratorShellCommand extends ShellCommand {
904
905 private static final long MAX_VIBRATION_MS = 200;
906
907 private final IBinder mToken;
908
909 private VibratorShellCommand(IBinder token) {
910 mToken = token;
911 }
912
913 @Override
914 public int onCommand(String cmd) {
915 if ("vibrate".equals(cmd)) {
916 return runVibrate();
917 }
918 return handleDefaultCommands(cmd);
919 }
920
921 private int runVibrate() {
922 final long duration = Long.parseLong(getNextArgRequired());
923 if (duration > MAX_VIBRATION_MS) {
924 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
925 }
926 String description = getNextArg();
927 if (description == null) {
928 description = "Shell command";
929 }
Michael Wright71216972017-01-31 18:33:54 +0000930
931 VibrationEffect effect =
932 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
933 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800934 mToken);
935 return 0;
936 }
937
938 @Override
939 public void onHelp() {
940 try (PrintWriter pw = getOutPrintWriter();) {
941 pw.println("Vibrator commands:");
942 pw.println(" help");
943 pw.println(" Prints this help text.");
944 pw.println("");
945 pw.println(" vibrate duration [description]");
946 pw.println(" Vibrates for duration milliseconds.");
947 pw.println("");
948 }
949 }
950 }
951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952}