blob: 473384081656baf78c55b3f5eb1d8eee364ffcf3 [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;
Felipe Leme5e2e6322017-07-14 17:25:59 -070051import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080052import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070053import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040054import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
Dianne Hackborna06de0f2012-12-11 16:34:47 -080056import com.android.internal.app.IAppOpsService;
57import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060058import com.android.internal.util.DumpUtils;
jackqdyulei455e90a2017-02-09 15:29:16 -080059import com.android.server.power.BatterySaverPolicy.ServiceType;
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) {
376 Slog.e(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 Wright71216972017-01-31 18:33:54 +0000382 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
383
384 // Only link against waveforms since they potentially don't have a finish if
385 // they're repeating. Let other effects just play out until they're done.
386 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400387 try {
388 token.linkToDeath(vib, 0);
389 } catch (RemoteException e) {
390 return;
391 }
Michael Wright71216972017-01-31 18:33:54 +0000392 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400393
Michael Wright71216972017-01-31 18:33:54 +0000394
395 long ident = Binder.clearCallingIdentity();
396 try {
397 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400398 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000399 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700400 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
Michael Wright71216972017-01-31 18:33:54 +0000402 } finally {
403 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 }
405 }
406
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700407 private void addToPreviousVibrationsLocked(Vibration vib) {
408 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
409 mPreviousVibrations.removeFirst();
410 }
Michael Wright71216972017-01-31 18:33:54 +0000411 mPreviousVibrations.addLast(new VibrationInfo(
412 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700413 }
414
Jeff Brown82379ba2014-07-25 19:03:28 -0700415 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400416 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 mContext.enforceCallingOrSelfPermission(
418 android.Manifest.permission.VIBRATE,
419 "cancelVibrate");
420
Michael Wright71216972017-01-31 18:33:54 +0000421 synchronized (mLock) {
422 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
423 if (DEBUG) {
424 Slog.d(TAG, "Canceling vibration.");
425 }
426 long ident = Binder.clearCallingIdentity();
427 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400428 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000429 } finally {
430 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400431 }
432 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700435
Michael Wright71216972017-01-31 18:33:54 +0000436 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700437 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400438 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000439 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400440 }
441 };
442
Patrick Scott18dd5f02009-07-02 11:31:12 -0400443 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000444 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400445 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000446 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400447 mThread = null;
448 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700449 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800450 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400451 }
452
Michael Wright71216972017-01-31 18:33:54 +0000453 // Callback for whenever the current vibration has finished played out
454 public void onVibrationFinished() {
455 if (DEBUG) {
456 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400457 }
Michael Wright71216972017-01-31 18:33:54 +0000458 synchronized (mLock) {
459 // Make sure the vibration is really done. This also reports that the vibration is
460 // finished.
461 doCancelVibrateLocked();
462 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400463 }
464
Patrick Scott18dd5f02009-07-02 11:31:12 -0400465 private void startVibrationLocked(final Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700466 if (!isAllowedToVibrate(vib)) {
Michael Wright71216972017-01-31 18:33:54 +0000467 if (DEBUG) {
468 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700469 }
Michael Wright71216972017-01-31 18:33:54 +0000470 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800471 }
Michael Wright71216972017-01-31 18:33:54 +0000472
473 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
474 !shouldVibrateForRingtone()) {
475 if (DEBUG) {
476 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
477 }
478 return;
479 }
480
481 final int mode = getAppOpMode(vib);
482 if (mode != AppOpsManager.MODE_ALLOWED) {
483 if (mode == AppOpsManager.MODE_ERRORED) {
484 // We might be getting calls from within system_server, so we don't actually want
485 // to throw a SecurityException here.
486 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
487 }
488 return;
489 }
490 startVibrationInnerLocked(vib);
491 }
492
493 private void startVibrationInnerLocked(Vibration vib) {
494 mCurrentVibration = vib;
495 if (vib.mEffect instanceof VibrationEffect.OneShot) {
496 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
497 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
498 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
499 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400500 // mThread better be null here. doCancelVibrate should always be
501 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000502 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
503 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400504 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000505 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
506 long timeout = doVibratorPrebakedEffectLocked(vib);
507 if (timeout > 0) {
508 mH.postDelayed(mVibrationEndRunnable, timeout);
509 }
510 } else {
511 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 }
513 }
514
Tyler Freeman319a34a2017-05-04 17:23:35 -0700515 private boolean isAllowedToVibrate(Vibration vib) {
516 if (!mLowPowerMode) {
517 return true;
518 }
519 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
520 return true;
521 }
522 if (!mAllowPriorityVibrationsInLowPowerMode) {
523 return false;
524 }
525 if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
526 vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
527 vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
528
529 return true;
530 }
531
532 return false;
533 }
534
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700535 private boolean shouldVibrateForRingtone() {
536 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700537 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700538 // "Also vibrate for calls" Setting in Sound
539 if (Settings.System.getInt(
540 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
541 return ringerMode != AudioManager.RINGER_MODE_SILENT;
542 } else {
543 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
544 }
545 }
546
Michael Wright71216972017-01-31 18:33:54 +0000547 private int getAppOpMode(Vibration vib) {
548 int mode;
549 try {
550 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
551 vib.mUsageHint, vib.mUid, vib.mOpPkg);
552 if (mode == AppOpsManager.MODE_ALLOWED) {
553 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
554 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
555 }
556 } catch (RemoteException e) {
557 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
558 mode = AppOpsManager.MODE_IGNORED;
559 }
560 return mode;
561 }
562
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800563 private void reportFinishVibrationLocked() {
564 if (mCurrentVibration != null) {
565 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700566 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
567 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400568 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000569 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800570 mCurrentVibration = null;
571 }
572 }
573
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200574 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000575 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200576 vib.mToken.unlinkToDeath(vib, 0);
577 }
578 }
579
Michael Wright71216972017-01-31 18:33:54 +0000580 private void updateVibrators() {
581 synchronized (mLock) {
582 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
583 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700584
Michael Wright71216972017-01-31 18:33:54 +0000585 if (devicesUpdated || lowPowerModeUpdated) {
586 // If the state changes out from under us then just reset.
587 doCancelVibrateLocked();
588 }
589 }
590 }
Jeff Brown82065252012-04-16 13:19:05 -0700591
Michael Wright71216972017-01-31 18:33:54 +0000592 private boolean updateInputDeviceVibratorsLocked() {
593 boolean changed = false;
594 boolean vibrateInputDevices = false;
595 try {
596 vibrateInputDevices = Settings.System.getIntForUser(
597 mContext.getContentResolver(),
598 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
599 } catch (SettingNotFoundException snfe) {
600 }
601 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
602 changed = true;
603 mVibrateInputDevicesSetting = vibrateInputDevices;
604 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700605
Michael Wright71216972017-01-31 18:33:54 +0000606 if (mVibrateInputDevicesSetting) {
607 if (!mInputDeviceListenerRegistered) {
608 mInputDeviceListenerRegistered = true;
609 mIm.registerInputDeviceListener(this, mH);
610 }
611 } else {
612 if (mInputDeviceListenerRegistered) {
613 mInputDeviceListenerRegistered = false;
614 mIm.unregisterInputDeviceListener(this);
615 }
616 }
Jeff Brown82065252012-04-16 13:19:05 -0700617
Michael Wright71216972017-01-31 18:33:54 +0000618 mInputDeviceVibrators.clear();
619 if (mVibrateInputDevicesSetting) {
620 int[] ids = mIm.getInputDeviceIds();
621 for (int i = 0; i < ids.length; i++) {
622 InputDevice device = mIm.getInputDevice(ids[i]);
623 Vibrator vibrator = device.getVibrator();
624 if (vibrator.hasVibrator()) {
625 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700626 }
627 }
Michael Wright71216972017-01-31 18:33:54 +0000628 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700629 }
Michael Wright71216972017-01-31 18:33:54 +0000630 return changed;
631 }
632
633 private boolean updateLowPowerModeLocked() {
634 boolean lowPowerMode = mPowerManagerInternal
635 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
636 if (lowPowerMode != mLowPowerMode) {
637 mLowPowerMode = lowPowerMode;
638 return true;
639 }
640 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700641 }
642
643 @Override
644 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000645 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700646 }
647
648 @Override
649 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000650 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700651 }
652
653 @Override
654 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000655 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700656 }
657
658 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700659 // For now, we choose to ignore the presence of input devices that have vibrators
660 // when reporting whether the device has a vibrator. Applications often use this
661 // information to decide whether to enable certain features so they expect the
662 // result of hasVibrator() to be constant. For now, just report whether
663 // the device has a built-in vibrator.
664 //synchronized (mInputDeviceVibrators) {
665 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
666 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800667 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700668 }
669
Michael Wright71216972017-01-31 18:33:54 +0000670 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700671 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000672 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
673 amplitude = mDefaultVibrationAmplitude;
674 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700675 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000676 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
677 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700678 }
Michael Wright71216972017-01-31 18:33:54 +0000679 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700680 final int vibratorCount = mInputDeviceVibrators.size();
681 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000682 final AudioAttributes attributes =
683 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700684 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400685 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700686 }
687 } else {
Michael Wright71216972017-01-31 18:33:54 +0000688 // Note: ordering is important here! Many haptic drivers will reset their amplitude
689 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700690 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000691 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700692 }
693 }
694 }
695
Michael Wright71216972017-01-31 18:33:54 +0000696 private void doVibratorSetAmplitude(int amplitude) {
697 if (mSupportsAmplitudeControl) {
698 vibratorSetAmplitude(amplitude);
699 }
700 }
701
Jeff Brown7f6c2312012-04-13 20:38:38 -0700702 private void doVibratorOff() {
703 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700704 if (DEBUG) {
705 Slog.d(TAG, "Turning vibrator off.");
706 }
Michael Wright71216972017-01-31 18:33:54 +0000707 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700708 final int vibratorCount = mInputDeviceVibrators.size();
709 if (vibratorCount != 0) {
710 for (int i = 0; i < vibratorCount; i++) {
711 mInputDeviceVibrators.get(i).cancel();
712 }
713 } else {
714 vibratorOff();
715 }
716 }
717 }
718
Michael Wright71216972017-01-31 18:33:54 +0000719 private long doVibratorPrebakedEffectLocked(Vibration vib) {
720 synchronized (mInputDeviceVibrators) {
721 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
722 // Input devices don't support prebaked effect, so skip trying it with them.
723 final int vibratorCount = mInputDeviceVibrators.size();
724 if (vibratorCount == 0) {
725 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
726 if (timeout > 0) {
727 noteVibratorOnLocked(vib.mUid, timeout);
728 return timeout;
729 }
730 }
731 final int id = prebaked.getId();
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700732 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Michael Wright71216972017-01-31 18:33:54 +0000733 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
734 return 0;
735 }
736 VibrationEffect effect = mFallbackEffects[id];
737 Vibration fallbackVib =
738 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
739 startVibrationInnerLocked(fallbackVib);
740 }
741 return 0;
742 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700743
Michael Wright71216972017-01-31 18:33:54 +0000744 private void noteVibratorOnLocked(int uid, long millis) {
745 try {
746 mBatteryStatsService.noteVibratorOn(uid, millis);
747 mCurVibUid = uid;
748 } catch (RemoteException e) {
749 }
750 }
751
752 private void noteVibratorOffLocked() {
753 if (mCurVibUid >= 0) {
754 try {
755 mBatteryStatsService.noteVibratorOff(mCurVibUid);
756 } catch (RemoteException e) { }
757 mCurVibUid = -1;
758 }
759 }
760
761 private class VibrateThread extends Thread {
762 private final VibrationEffect.Waveform mWaveform;
763 private final int mUid;
764 private final int mUsageHint;
765
766 private boolean mForceStop;
767
768 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
769 mWaveform = waveform;
770 mUid = uid;
771 mUsageHint = usageHint;
772 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700773 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 }
775
Michael Wright71216972017-01-31 18:33:54 +0000776 private long delayLocked(long duration) {
777 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000779 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 do {
781 try {
Michael Wright71216972017-01-31 18:33:54 +0000782 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 }
Michael Wright71216972017-01-31 18:33:54 +0000784 catch (InterruptedException e) { }
785 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 break;
787 }
Michael Wright71216972017-01-31 18:33:54 +0000788 durationRemaining = bedtime - SystemClock.uptimeMillis();
789 } while (durationRemaining > 0);
790 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 }
Michael Wright71216972017-01-31 18:33:54 +0000792 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 }
794
795 public void run() {
796 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000797 mWakeLock.acquire();
798 try {
799 boolean finished = playWaveform();
800 if (finished) {
801 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
Michael Wright71216972017-01-31 18:33:54 +0000803 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 mWakeLock.release();
805 }
Michael Wright71216972017-01-31 18:33:54 +0000806 }
807
808 /**
809 * Play the waveform.
810 *
811 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
812 */
813 public boolean playWaveform() {
814 synchronized (this) {
815 final long[] timings = mWaveform.getTimings();
816 final int[] amplitudes = mWaveform.getAmplitudes();
817 final int len = timings.length;
818 final int repeat = mWaveform.getRepeatIndex();
819
820 int index = 0;
821 long onDuration = 0;
822 while (!mForceStop) {
823 if (index < len) {
824 final int amplitude = amplitudes[index];
825 final long duration = timings[index++];
826 if (duration <= 0) {
827 continue;
828 }
829 if (amplitude != 0) {
830 if (onDuration <= 0) {
831 // Telling the vibrator to start multiple times usually causes
832 // effects to feel "choppy" because the motor resets at every on
833 // command. Instead we figure out how long our next "on" period is
834 // going to be, tell the motor to stay on for the full duration,
835 // and then wake up to change the amplitude at the appropriate
836 // intervals.
837 onDuration =
838 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
839 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
840 } else {
841 doVibratorSetAmplitude(amplitude);
842 }
843 }
844
845 long waitTime = delayLocked(duration);
846 if (amplitude != 0) {
847 onDuration -= waitTime;
848 }
849 } else if (repeat < 0) {
850 break;
851 } else {
852 index = repeat;
853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
Michael Wright71216972017-01-31 18:33:54 +0000855 return !mForceStop;
856 }
857 }
858
859 public void cancel() {
860 synchronized (this) {
861 mThread.mForceStop = true;
862 mThread.notify();
863 }
864 }
865
866 /**
867 * Get the duration the vibrator will be on starting at startIndex until the next time it's
868 * off.
869 */
870 private long getTotalOnDuration(
871 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
872 int i = startIndex;
873 long timing = 0;
874 while(amplitudes[i] != 0) {
875 timing += timings[i++];
876 if (i >= timings.length) {
877 if (repeatIndex >= 0) {
878 i = repeatIndex;
879 } else {
880 break;
881 }
882 }
883 if (i == startIndex) {
884 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 }
Michael Wright71216972017-01-31 18:33:54 +0000887 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 }
Jeff Brown969579b2014-05-20 19:29:29 -0700889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700892 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 public void onReceive(Context context, Intent intent) {
894 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000895 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700896 // When the system is entering a non-interactive state, we want
897 // to cancel vibrations in case a misbehaving app has abandoned
898 // them. However it may happen that the system is currently playing
899 // haptic feedback as part of the transition. So we don't cancel
900 // system vibrations.
901 if (mCurrentVibration != null
902 && !mCurrentVibration.isSystemHapticFeedback()) {
903 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700904 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400905 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 }
907 }
908 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700909
910 @Override
911 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600912 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700913
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700914 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000915 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700916 for (VibrationInfo info : mPreviousVibrations) {
917 pw.print(" ");
918 pw.println(info.toString());
919 }
920 }
921 }
Felipe Lemea5281002017-02-10 15:13:48 -0800922
923 @Override
924 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
925 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
926 throws RemoteException {
927 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
928 }
929
930 private final class VibratorShellCommand extends ShellCommand {
931
932 private static final long MAX_VIBRATION_MS = 200;
933
934 private final IBinder mToken;
935
936 private VibratorShellCommand(IBinder token) {
937 mToken = token;
938 }
939
940 @Override
941 public int onCommand(String cmd) {
942 if ("vibrate".equals(cmd)) {
943 return runVibrate();
944 }
945 return handleDefaultCommands(cmd);
946 }
947
948 private int runVibrate() {
Felipe Leme5e2e6322017-07-14 17:25:59 -0700949 try {
950 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
951 Settings.Global.ZEN_MODE);
952 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
953 try (PrintWriter pw = getOutPrintWriter();) {
954 pw.print("Ignoring because device is on DND mode ");
955 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
956 zenMode));
957 return 0;
958 }
959 }
960 } catch (SettingNotFoundException e) {
961 // ignore
962 }
963
Felipe Lemea5281002017-02-10 15:13:48 -0800964 final long duration = Long.parseLong(getNextArgRequired());
965 if (duration > MAX_VIBRATION_MS) {
966 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
967 }
968 String description = getNextArg();
969 if (description == null) {
970 description = "Shell command";
971 }
Michael Wright71216972017-01-31 18:33:54 +0000972
973 VibrationEffect effect =
974 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
975 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800976 mToken);
977 return 0;
978 }
979
980 @Override
981 public void onHelp() {
982 try (PrintWriter pw = getOutPrintWriter();) {
983 pw.println("Vibrator commands:");
984 pw.println(" help");
985 pw.println(" Prints this help text.");
986 pw.println("");
987 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -0700988 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
989 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -0800990 pw.println("");
991 }
992 }
993 }
994
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995}