blob: 0e51fda0f39f5ac54672fc5d06e60631b28e6e7c [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;
Makoto Onuki2eccd022017-11-01 13:44:23 -070030import android.os.PowerManager.ServiceType;
jackqdyulei455e90a2017-02-09 15:29:16 -080031import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070032import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070033import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050034import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070036import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.Process;
38import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080039import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.IBinder;
41import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080042import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080043import android.os.ShellCallback;
44import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070046import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070047import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000048import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070049import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070050import android.provider.Settings;
51import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070052import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080053import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070054import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040055import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Dianne Hackborna06de0f2012-12-11 16:34:47 -080057import com.android.internal.app.IAppOpsService;
58import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060059import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080060
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070061import java.io.FileDescriptor;
62import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070063import java.util.ArrayList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040064import java.util.LinkedList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040065
Jeff Brown7f6c2312012-04-13 20:38:38 -070066public class VibratorService extends IVibratorService.Stub
67 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050068 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070069 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070070 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050071
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070072 private final LinkedList<VibrationInfo> mPreviousVibrations;
73 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -070074 private final boolean mAllowPriorityVibrationsInLowPowerMode;
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
Tyler Freeman319a34a2017-05-04 17:23:35 -0700215 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
216 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
217
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700218 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 IntentFilter filter = new IntentFilter();
221 filter.addAction(Intent.ACTION_SCREEN_OFF);
222 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000223
224 long[] clickEffectTimings = getLongIntArray(context.getResources(),
225 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright57d94d92017-05-31 14:44:45 +0100226 VibrationEffect clickEffect = createEffect(clickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000227 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
228 new long[] {0, 30, 100, 30} /*timings*/, -1);
Michael Wright57d94d92017-05-31 14:44:45 +0100229 long[] tickEffectTimings = getLongIntArray(context.getResources(),
230 com.android.internal.R.array.config_clockTickVibePattern);
231 VibrationEffect tickEffect = createEffect(tickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000232
Michael Wright57d94d92017-05-31 14:44:45 +0100233 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
234 }
235
236 private static VibrationEffect createEffect(long[] timings) {
237 if (timings == null || timings.length == 0) {
238 return null;
239 } else if (timings.length == 1) {
240 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
241 } else {
242 return VibrationEffect.createWaveform(timings, -1);
243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 }
245
Jeff Brown7f6c2312012-04-13 20:38:38 -0700246 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800247 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700248 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700249
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700250 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
251 mPowerManagerInternal.registerLowPowerModeObserver(
252 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800253 @Override
254 public int getServiceType() {
255 return ServiceType.VIBRATION;
256 }
257
258 @Override
259 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000260 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800261 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700262 });
263
Jeff Brown7f6c2312012-04-13 20:38:38 -0700264 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700265 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
266 true, mSettingObserver, UserHandle.USER_ALL);
267
Jeff Brownd4935962012-09-25 13:27:20 -0700268 mContext.registerReceiver(new BroadcastReceiver() {
269 @Override
270 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000271 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700272 }
273 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
274
Michael Wright71216972017-01-31 18:33:54 +0000275 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700276 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700277
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700278 private final class SettingsObserver extends ContentObserver {
279 public SettingsObserver(Handler handler) {
280 super(handler);
281 }
282
283 @Override
284 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000285 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700286 }
287 }
288
Jeff Brown82379ba2014-07-25 19:03:28 -0700289 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700290 public boolean hasVibrator() {
291 return doVibratorExists();
292 }
293
Michael Wright71216972017-01-31 18:33:54 +0000294 @Override // Binder call
295 public boolean hasAmplitudeControl() {
296 synchronized (mInputDeviceVibrators) {
297 // Input device vibrators don't support amplitude controls yet, but are still used over
298 // the system vibrator when connected.
299 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
300 }
301 }
302
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800303 private void verifyIncomingUid(int uid) {
304 if (uid == Binder.getCallingUid()) {
305 return;
306 }
307 if (Binder.getCallingPid() == Process.myPid()) {
308 return;
309 }
310 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
311 Binder.getCallingPid(), Binder.getCallingUid(), null);
312 }
313
Michael Wright71216972017-01-31 18:33:54 +0000314 /**
315 * Validate the incoming VibrationEffect.
316 *
317 * We can't throw exceptions here since we might be called from some system_server component,
318 * which would bring the whole system down.
319 *
320 * @return whether the VibrationEffect is valid
321 */
322 private static boolean verifyVibrationEffect(VibrationEffect effect) {
323 if (effect == null) {
324 // Effect must not be null.
325 Slog.wtf(TAG, "effect must not be null");
326 return false;
327 }
328 try {
329 effect.validate();
330 } catch (Exception e) {
331 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
332 return false;
333 }
334 return true;
335 }
336
337 private static long[] getLongIntArray(Resources r, int resid) {
338 int[] ar = r.getIntArray(resid);
339 if (ar == null) {
340 return null;
341 }
342 long[] out = new long[ar.length];
343 for (int i = 0; i < ar.length; i++) {
344 out[i] = ar[i];
345 }
346 return out;
347 }
348
Jeff Brown82379ba2014-07-25 19:03:28 -0700349 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000350 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400351 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700352 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
353 != PackageManager.PERMISSION_GRANTED) {
354 throw new SecurityException("Requires VIBRATE permission");
355 }
Michael Wright71216972017-01-31 18:33:54 +0000356 if (token == null) {
357 Slog.e(TAG, "token must not be null");
358 return;
359 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800360 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000361 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400362 return;
363 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700364
Michael Wright71216972017-01-31 18:33:54 +0000365 // If our current vibration is longer than the new vibration and is the same amplitude,
366 // then just let the current one finish.
367 if (effect instanceof VibrationEffect.OneShot
368 && mCurrentVibration != null
369 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
370 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
371 VibrationEffect.OneShot currentOneShot =
372 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
373 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
374 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
375 if (DEBUG) {
Michael Wright58c46312017-10-05 14:04:14 -0400376 Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 return;
379 }
Michael Wright71216972017-01-31 18:33:54 +0000380 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381
Michael Wright58c46312017-10-05 14:04:14 -0400382 // If the current vibration is repeating and the incoming one is non-repeating, then ignore
383 // the non-repeating vibration. This is so that we don't cancel vibrations that are meant
384 // to grab the attention of the user, like ringtones and alarms, in favor of one-shot
385 // vibrations that are likely quite short.
386 if (!isRepeatingVibration(effect)
387 && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) {
388 if (DEBUG) {
389 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
390 }
391 return;
392 }
393
Michael Wright71216972017-01-31 18:33:54 +0000394 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
395
396 // Only link against waveforms since they potentially don't have a finish if
397 // they're repeating. Let other effects just play out until they're done.
398 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400399 try {
400 token.linkToDeath(vib, 0);
401 } catch (RemoteException e) {
402 return;
403 }
Michael Wright71216972017-01-31 18:33:54 +0000404 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400405
Michael Wright71216972017-01-31 18:33:54 +0000406
407 long ident = Binder.clearCallingIdentity();
408 try {
409 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400410 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000411 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700412 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 }
Michael Wright71216972017-01-31 18:33:54 +0000414 } finally {
415 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417 }
418
Michael Wright58c46312017-10-05 14:04:14 -0400419 private static boolean isRepeatingVibration(VibrationEffect effect) {
420 if (effect instanceof VibrationEffect.Waveform) {
421 final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
422 if (waveform.getRepeatIndex() >= 0) {
423 return true;
424 }
425 }
426 return false;
427 }
428
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700429 private void addToPreviousVibrationsLocked(Vibration vib) {
430 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
431 mPreviousVibrations.removeFirst();
432 }
Michael Wright71216972017-01-31 18:33:54 +0000433 mPreviousVibrations.addLast(new VibrationInfo(
434 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700435 }
436
Jeff Brown82379ba2014-07-25 19:03:28 -0700437 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400438 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 mContext.enforceCallingOrSelfPermission(
440 android.Manifest.permission.VIBRATE,
441 "cancelVibrate");
442
Michael Wright71216972017-01-31 18:33:54 +0000443 synchronized (mLock) {
444 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
445 if (DEBUG) {
446 Slog.d(TAG, "Canceling vibration.");
447 }
448 long ident = Binder.clearCallingIdentity();
449 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400450 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000451 } finally {
452 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400453 }
454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800456 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700457
Michael Wright71216972017-01-31 18:33:54 +0000458 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700459 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400460 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000461 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400462 }
463 };
464
Patrick Scott18dd5f02009-07-02 11:31:12 -0400465 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000466 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400467 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000468 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400469 mThread = null;
470 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700471 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800472 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400473 }
474
Michael Wright71216972017-01-31 18:33:54 +0000475 // Callback for whenever the current vibration has finished played out
476 public void onVibrationFinished() {
477 if (DEBUG) {
478 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400479 }
Michael Wright71216972017-01-31 18:33:54 +0000480 synchronized (mLock) {
481 // Make sure the vibration is really done. This also reports that the vibration is
482 // finished.
483 doCancelVibrateLocked();
484 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400485 }
486
Patrick Scott18dd5f02009-07-02 11:31:12 -0400487 private void startVibrationLocked(final Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700488 if (!isAllowedToVibrate(vib)) {
Michael Wright71216972017-01-31 18:33:54 +0000489 if (DEBUG) {
490 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700491 }
Michael Wright71216972017-01-31 18:33:54 +0000492 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800493 }
Michael Wright71216972017-01-31 18:33:54 +0000494
495 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
496 !shouldVibrateForRingtone()) {
497 if (DEBUG) {
498 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
499 }
500 return;
501 }
502
503 final int mode = getAppOpMode(vib);
504 if (mode != AppOpsManager.MODE_ALLOWED) {
505 if (mode == AppOpsManager.MODE_ERRORED) {
506 // We might be getting calls from within system_server, so we don't actually want
507 // to throw a SecurityException here.
508 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
509 }
510 return;
511 }
512 startVibrationInnerLocked(vib);
513 }
514
515 private void startVibrationInnerLocked(Vibration vib) {
516 mCurrentVibration = vib;
517 if (vib.mEffect instanceof VibrationEffect.OneShot) {
518 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
519 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
520 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
521 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400522 // mThread better be null here. doCancelVibrate should always be
523 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000524 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
525 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400526 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000527 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
528 long timeout = doVibratorPrebakedEffectLocked(vib);
529 if (timeout > 0) {
530 mH.postDelayed(mVibrationEndRunnable, timeout);
531 }
532 } else {
533 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 }
535 }
536
Tyler Freeman319a34a2017-05-04 17:23:35 -0700537 private boolean isAllowedToVibrate(Vibration vib) {
538 if (!mLowPowerMode) {
539 return true;
540 }
541 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
542 return true;
543 }
544 if (!mAllowPriorityVibrationsInLowPowerMode) {
545 return false;
546 }
547 if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
548 vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
549 vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
550
551 return true;
552 }
553
554 return false;
555 }
556
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700557 private boolean shouldVibrateForRingtone() {
558 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700559 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700560 // "Also vibrate for calls" Setting in Sound
561 if (Settings.System.getInt(
562 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
563 return ringerMode != AudioManager.RINGER_MODE_SILENT;
564 } else {
565 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
566 }
567 }
568
Michael Wright71216972017-01-31 18:33:54 +0000569 private int getAppOpMode(Vibration vib) {
570 int mode;
571 try {
572 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
573 vib.mUsageHint, vib.mUid, vib.mOpPkg);
574 if (mode == AppOpsManager.MODE_ALLOWED) {
575 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
576 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
577 }
578 } catch (RemoteException e) {
579 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
580 mode = AppOpsManager.MODE_IGNORED;
581 }
582 return mode;
583 }
584
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800585 private void reportFinishVibrationLocked() {
586 if (mCurrentVibration != null) {
587 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700588 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
589 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400590 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000591 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800592 mCurrentVibration = null;
593 }
594 }
595
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200596 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000597 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200598 vib.mToken.unlinkToDeath(vib, 0);
599 }
600 }
601
Michael Wright71216972017-01-31 18:33:54 +0000602 private void updateVibrators() {
603 synchronized (mLock) {
604 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
605 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700606
Michael Wright71216972017-01-31 18:33:54 +0000607 if (devicesUpdated || lowPowerModeUpdated) {
608 // If the state changes out from under us then just reset.
609 doCancelVibrateLocked();
610 }
611 }
612 }
Jeff Brown82065252012-04-16 13:19:05 -0700613
Michael Wright71216972017-01-31 18:33:54 +0000614 private boolean updateInputDeviceVibratorsLocked() {
615 boolean changed = false;
616 boolean vibrateInputDevices = false;
617 try {
618 vibrateInputDevices = Settings.System.getIntForUser(
619 mContext.getContentResolver(),
620 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
621 } catch (SettingNotFoundException snfe) {
622 }
623 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
624 changed = true;
625 mVibrateInputDevicesSetting = vibrateInputDevices;
626 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700627
Michael Wright71216972017-01-31 18:33:54 +0000628 if (mVibrateInputDevicesSetting) {
629 if (!mInputDeviceListenerRegistered) {
630 mInputDeviceListenerRegistered = true;
631 mIm.registerInputDeviceListener(this, mH);
632 }
633 } else {
634 if (mInputDeviceListenerRegistered) {
635 mInputDeviceListenerRegistered = false;
636 mIm.unregisterInputDeviceListener(this);
637 }
638 }
Jeff Brown82065252012-04-16 13:19:05 -0700639
Michael Wright71216972017-01-31 18:33:54 +0000640 mInputDeviceVibrators.clear();
641 if (mVibrateInputDevicesSetting) {
642 int[] ids = mIm.getInputDeviceIds();
643 for (int i = 0; i < ids.length; i++) {
644 InputDevice device = mIm.getInputDevice(ids[i]);
645 Vibrator vibrator = device.getVibrator();
646 if (vibrator.hasVibrator()) {
647 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700648 }
649 }
Michael Wright71216972017-01-31 18:33:54 +0000650 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700651 }
Michael Wright71216972017-01-31 18:33:54 +0000652 return changed;
653 }
654
655 private boolean updateLowPowerModeLocked() {
656 boolean lowPowerMode = mPowerManagerInternal
657 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
658 if (lowPowerMode != mLowPowerMode) {
659 mLowPowerMode = lowPowerMode;
660 return true;
661 }
662 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700663 }
664
665 @Override
666 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000667 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700668 }
669
670 @Override
671 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000672 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700673 }
674
675 @Override
676 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000677 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700678 }
679
680 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700681 // For now, we choose to ignore the presence of input devices that have vibrators
682 // when reporting whether the device has a vibrator. Applications often use this
683 // information to decide whether to enable certain features so they expect the
684 // result of hasVibrator() to be constant. For now, just report whether
685 // the device has a built-in vibrator.
686 //synchronized (mInputDeviceVibrators) {
687 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
688 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800689 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700690 }
691
Michael Wright71216972017-01-31 18:33:54 +0000692 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700693 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000694 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
695 amplitude = mDefaultVibrationAmplitude;
696 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700697 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000698 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
699 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700700 }
Michael Wright71216972017-01-31 18:33:54 +0000701 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700702 final int vibratorCount = mInputDeviceVibrators.size();
703 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000704 final AudioAttributes attributes =
705 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700706 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400707 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700708 }
709 } else {
Michael Wright71216972017-01-31 18:33:54 +0000710 // Note: ordering is important here! Many haptic drivers will reset their amplitude
711 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700712 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000713 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700714 }
715 }
716 }
717
Michael Wright71216972017-01-31 18:33:54 +0000718 private void doVibratorSetAmplitude(int amplitude) {
719 if (mSupportsAmplitudeControl) {
720 vibratorSetAmplitude(amplitude);
721 }
722 }
723
Jeff Brown7f6c2312012-04-13 20:38:38 -0700724 private void doVibratorOff() {
725 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700726 if (DEBUG) {
727 Slog.d(TAG, "Turning vibrator off.");
728 }
Michael Wright71216972017-01-31 18:33:54 +0000729 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700730 final int vibratorCount = mInputDeviceVibrators.size();
731 if (vibratorCount != 0) {
732 for (int i = 0; i < vibratorCount; i++) {
733 mInputDeviceVibrators.get(i).cancel();
734 }
735 } else {
736 vibratorOff();
737 }
738 }
739 }
740
Michael Wright71216972017-01-31 18:33:54 +0000741 private long doVibratorPrebakedEffectLocked(Vibration vib) {
742 synchronized (mInputDeviceVibrators) {
743 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
744 // Input devices don't support prebaked effect, so skip trying it with them.
745 final int vibratorCount = mInputDeviceVibrators.size();
746 if (vibratorCount == 0) {
747 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
748 if (timeout > 0) {
749 noteVibratorOnLocked(vib.mUid, timeout);
750 return timeout;
751 }
752 }
Michael Wrightdc2b3be2017-08-02 20:44:45 +0100753 if (!prebaked.shouldFallback()) {
754 return 0;
755 }
Michael Wright71216972017-01-31 18:33:54 +0000756 final int id = prebaked.getId();
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700757 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Michael Wright71216972017-01-31 18:33:54 +0000758 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
759 return 0;
760 }
761 VibrationEffect effect = mFallbackEffects[id];
762 Vibration fallbackVib =
763 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
764 startVibrationInnerLocked(fallbackVib);
765 }
766 return 0;
767 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700768
Michael Wright71216972017-01-31 18:33:54 +0000769 private void noteVibratorOnLocked(int uid, long millis) {
770 try {
771 mBatteryStatsService.noteVibratorOn(uid, millis);
772 mCurVibUid = uid;
773 } catch (RemoteException e) {
774 }
775 }
776
777 private void noteVibratorOffLocked() {
778 if (mCurVibUid >= 0) {
779 try {
780 mBatteryStatsService.noteVibratorOff(mCurVibUid);
781 } catch (RemoteException e) { }
782 mCurVibUid = -1;
783 }
784 }
785
786 private class VibrateThread extends Thread {
787 private final VibrationEffect.Waveform mWaveform;
788 private final int mUid;
789 private final int mUsageHint;
790
791 private boolean mForceStop;
792
793 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
794 mWaveform = waveform;
795 mUid = uid;
796 mUsageHint = usageHint;
797 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700798 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 }
800
Michael Wright71216972017-01-31 18:33:54 +0000801 private long delayLocked(long duration) {
802 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000804 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 do {
806 try {
Michael Wright71216972017-01-31 18:33:54 +0000807 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
Michael Wright71216972017-01-31 18:33:54 +0000809 catch (InterruptedException e) { }
810 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800811 break;
812 }
Michael Wright71216972017-01-31 18:33:54 +0000813 durationRemaining = bedtime - SystemClock.uptimeMillis();
814 } while (durationRemaining > 0);
815 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 }
Michael Wright71216972017-01-31 18:33:54 +0000817 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800818 }
819
820 public void run() {
821 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000822 mWakeLock.acquire();
823 try {
824 boolean finished = playWaveform();
825 if (finished) {
826 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
Michael Wright71216972017-01-31 18:33:54 +0000828 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 mWakeLock.release();
830 }
Michael Wright71216972017-01-31 18:33:54 +0000831 }
832
833 /**
834 * Play the waveform.
835 *
836 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
837 */
838 public boolean playWaveform() {
839 synchronized (this) {
840 final long[] timings = mWaveform.getTimings();
841 final int[] amplitudes = mWaveform.getAmplitudes();
842 final int len = timings.length;
843 final int repeat = mWaveform.getRepeatIndex();
844
845 int index = 0;
846 long onDuration = 0;
847 while (!mForceStop) {
848 if (index < len) {
849 final int amplitude = amplitudes[index];
850 final long duration = timings[index++];
851 if (duration <= 0) {
852 continue;
853 }
854 if (amplitude != 0) {
855 if (onDuration <= 0) {
856 // Telling the vibrator to start multiple times usually causes
857 // effects to feel "choppy" because the motor resets at every on
858 // command. Instead we figure out how long our next "on" period is
859 // going to be, tell the motor to stay on for the full duration,
860 // and then wake up to change the amplitude at the appropriate
861 // intervals.
862 onDuration =
863 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
864 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
865 } else {
866 doVibratorSetAmplitude(amplitude);
867 }
868 }
869
870 long waitTime = delayLocked(duration);
871 if (amplitude != 0) {
872 onDuration -= waitTime;
873 }
874 } else if (repeat < 0) {
875 break;
876 } else {
877 index = repeat;
878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 }
Michael Wright71216972017-01-31 18:33:54 +0000880 return !mForceStop;
881 }
882 }
883
884 public void cancel() {
885 synchronized (this) {
886 mThread.mForceStop = true;
887 mThread.notify();
888 }
889 }
890
891 /**
892 * Get the duration the vibrator will be on starting at startIndex until the next time it's
893 * off.
894 */
895 private long getTotalOnDuration(
896 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
897 int i = startIndex;
898 long timing = 0;
899 while(amplitudes[i] != 0) {
900 timing += timings[i++];
901 if (i >= timings.length) {
902 if (repeatIndex >= 0) {
903 i = repeatIndex;
904 } else {
905 break;
906 }
907 }
908 if (i == startIndex) {
909 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 }
Michael Wright71216972017-01-31 18:33:54 +0000912 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 }
Jeff Brown969579b2014-05-20 19:29:29 -0700914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800916 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700917 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 public void onReceive(Context context, Intent intent) {
919 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000920 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700921 // When the system is entering a non-interactive state, we want
922 // to cancel vibrations in case a misbehaving app has abandoned
923 // them. However it may happen that the system is currently playing
924 // haptic feedback as part of the transition. So we don't cancel
925 // system vibrations.
926 if (mCurrentVibration != null
927 && !mCurrentVibration.isSystemHapticFeedback()) {
928 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700929 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800931 }
932 }
933 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700934
935 @Override
936 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600937 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700938
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700939 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000940 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700941 for (VibrationInfo info : mPreviousVibrations) {
942 pw.print(" ");
943 pw.println(info.toString());
944 }
945 }
946 }
Felipe Lemea5281002017-02-10 15:13:48 -0800947
948 @Override
949 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
950 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
951 throws RemoteException {
952 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
953 }
954
955 private final class VibratorShellCommand extends ShellCommand {
956
957 private static final long MAX_VIBRATION_MS = 200;
958
959 private final IBinder mToken;
960
961 private VibratorShellCommand(IBinder token) {
962 mToken = token;
963 }
964
965 @Override
966 public int onCommand(String cmd) {
967 if ("vibrate".equals(cmd)) {
968 return runVibrate();
969 }
970 return handleDefaultCommands(cmd);
971 }
972
973 private int runVibrate() {
Felipe Leme5e2e6322017-07-14 17:25:59 -0700974 try {
975 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
976 Settings.Global.ZEN_MODE);
977 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
978 try (PrintWriter pw = getOutPrintWriter();) {
979 pw.print("Ignoring because device is on DND mode ");
980 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
981 zenMode));
982 return 0;
983 }
984 }
985 } catch (SettingNotFoundException e) {
986 // ignore
987 }
988
Felipe Lemea5281002017-02-10 15:13:48 -0800989 final long duration = Long.parseLong(getNextArgRequired());
990 if (duration > MAX_VIBRATION_MS) {
991 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
992 }
993 String description = getNextArg();
994 if (description == null) {
995 description = "Shell command";
996 }
Michael Wright71216972017-01-31 18:33:54 +0000997
998 VibrationEffect effect =
999 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1000 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -08001001 mToken);
1002 return 0;
1003 }
1004
1005 @Override
1006 public void onHelp() {
1007 try (PrintWriter pw = getOutPrintWriter();) {
1008 pw.println("Vibrator commands:");
1009 pw.println(" help");
1010 pw.println(" Prints this help text.");
1011 pw.println("");
1012 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001013 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1014 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -08001015 pw.println("");
1016 }
1017 }
1018 }
1019
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020}