blob: 046eb761d1c066f1403daa3931125643d1c1414d [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 }
Michael Wrightdc2b3be2017-08-02 20:44:45 +0100731 if (!prebaked.shouldFallback()) {
732 return 0;
733 }
Michael Wright71216972017-01-31 18:33:54 +0000734 final int id = prebaked.getId();
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700735 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Michael Wright71216972017-01-31 18:33:54 +0000736 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
737 return 0;
738 }
739 VibrationEffect effect = mFallbackEffects[id];
740 Vibration fallbackVib =
741 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
742 startVibrationInnerLocked(fallbackVib);
743 }
744 return 0;
745 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700746
Michael Wright71216972017-01-31 18:33:54 +0000747 private void noteVibratorOnLocked(int uid, long millis) {
748 try {
749 mBatteryStatsService.noteVibratorOn(uid, millis);
750 mCurVibUid = uid;
751 } catch (RemoteException e) {
752 }
753 }
754
755 private void noteVibratorOffLocked() {
756 if (mCurVibUid >= 0) {
757 try {
758 mBatteryStatsService.noteVibratorOff(mCurVibUid);
759 } catch (RemoteException e) { }
760 mCurVibUid = -1;
761 }
762 }
763
764 private class VibrateThread extends Thread {
765 private final VibrationEffect.Waveform mWaveform;
766 private final int mUid;
767 private final int mUsageHint;
768
769 private boolean mForceStop;
770
771 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
772 mWaveform = waveform;
773 mUid = uid;
774 mUsageHint = usageHint;
775 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700776 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 }
778
Michael Wright71216972017-01-31 18:33:54 +0000779 private long delayLocked(long duration) {
780 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800781 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000782 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 do {
784 try {
Michael Wright71216972017-01-31 18:33:54 +0000785 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 }
Michael Wright71216972017-01-31 18:33:54 +0000787 catch (InterruptedException e) { }
788 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 break;
790 }
Michael Wright71216972017-01-31 18:33:54 +0000791 durationRemaining = bedtime - SystemClock.uptimeMillis();
792 } while (durationRemaining > 0);
793 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794 }
Michael Wright71216972017-01-31 18:33:54 +0000795 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 }
797
798 public void run() {
799 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000800 mWakeLock.acquire();
801 try {
802 boolean finished = playWaveform();
803 if (finished) {
804 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
Michael Wright71216972017-01-31 18:33:54 +0000806 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 mWakeLock.release();
808 }
Michael Wright71216972017-01-31 18:33:54 +0000809 }
810
811 /**
812 * Play the waveform.
813 *
814 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
815 */
816 public boolean playWaveform() {
817 synchronized (this) {
818 final long[] timings = mWaveform.getTimings();
819 final int[] amplitudes = mWaveform.getAmplitudes();
820 final int len = timings.length;
821 final int repeat = mWaveform.getRepeatIndex();
822
823 int index = 0;
824 long onDuration = 0;
825 while (!mForceStop) {
826 if (index < len) {
827 final int amplitude = amplitudes[index];
828 final long duration = timings[index++];
829 if (duration <= 0) {
830 continue;
831 }
832 if (amplitude != 0) {
833 if (onDuration <= 0) {
834 // Telling the vibrator to start multiple times usually causes
835 // effects to feel "choppy" because the motor resets at every on
836 // command. Instead we figure out how long our next "on" period is
837 // going to be, tell the motor to stay on for the full duration,
838 // and then wake up to change the amplitude at the appropriate
839 // intervals.
840 onDuration =
841 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
842 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
843 } else {
844 doVibratorSetAmplitude(amplitude);
845 }
846 }
847
848 long waitTime = delayLocked(duration);
849 if (amplitude != 0) {
850 onDuration -= waitTime;
851 }
852 } else if (repeat < 0) {
853 break;
854 } else {
855 index = repeat;
856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
Michael Wright71216972017-01-31 18:33:54 +0000858 return !mForceStop;
859 }
860 }
861
862 public void cancel() {
863 synchronized (this) {
864 mThread.mForceStop = true;
865 mThread.notify();
866 }
867 }
868
869 /**
870 * Get the duration the vibrator will be on starting at startIndex until the next time it's
871 * off.
872 */
873 private long getTotalOnDuration(
874 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
875 int i = startIndex;
876 long timing = 0;
877 while(amplitudes[i] != 0) {
878 timing += timings[i++];
879 if (i >= timings.length) {
880 if (repeatIndex >= 0) {
881 i = repeatIndex;
882 } else {
883 break;
884 }
885 }
886 if (i == startIndex) {
887 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400888 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800889 }
Michael Wright71216972017-01-31 18:33:54 +0000890 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 }
Jeff Brown969579b2014-05-20 19:29:29 -0700892 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800894 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700895 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800896 public void onReceive(Context context, Intent intent) {
897 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000898 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700899 // When the system is entering a non-interactive state, we want
900 // to cancel vibrations in case a misbehaving app has abandoned
901 // them. However it may happen that the system is currently playing
902 // haptic feedback as part of the transition. So we don't cancel
903 // system vibrations.
904 if (mCurrentVibration != null
905 && !mCurrentVibration.isSystemHapticFeedback()) {
906 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700907 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400908 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 }
910 }
911 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700912
913 @Override
914 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600915 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700916
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700917 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000918 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700919 for (VibrationInfo info : mPreviousVibrations) {
920 pw.print(" ");
921 pw.println(info.toString());
922 }
923 }
924 }
Felipe Lemea5281002017-02-10 15:13:48 -0800925
926 @Override
927 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
928 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
929 throws RemoteException {
930 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
931 }
932
933 private final class VibratorShellCommand extends ShellCommand {
934
935 private static final long MAX_VIBRATION_MS = 200;
936
937 private final IBinder mToken;
938
939 private VibratorShellCommand(IBinder token) {
940 mToken = token;
941 }
942
943 @Override
944 public int onCommand(String cmd) {
945 if ("vibrate".equals(cmd)) {
946 return runVibrate();
947 }
948 return handleDefaultCommands(cmd);
949 }
950
951 private int runVibrate() {
Felipe Leme5e2e6322017-07-14 17:25:59 -0700952 try {
953 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
954 Settings.Global.ZEN_MODE);
955 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
956 try (PrintWriter pw = getOutPrintWriter();) {
957 pw.print("Ignoring because device is on DND mode ");
958 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
959 zenMode));
960 return 0;
961 }
962 }
963 } catch (SettingNotFoundException e) {
964 // ignore
965 }
966
Felipe Lemea5281002017-02-10 15:13:48 -0800967 final long duration = Long.parseLong(getNextArgRequired());
968 if (duration > MAX_VIBRATION_MS) {
969 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
970 }
971 String description = getNextArg();
972 if (description == null) {
973 description = "Shell command";
974 }
Michael Wright71216972017-01-31 18:33:54 +0000975
976 VibrationEffect effect =
977 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
978 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800979 mToken);
980 return 0;
981 }
982
983 @Override
984 public void onHelp() {
985 try (PrintWriter pw = getOutPrintWriter();) {
986 pw.println("Vibrator commands:");
987 pw.println(" help");
988 pw.println(" Prints this help text.");
989 pw.println("");
990 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -0700991 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
992 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -0800993 pw.println("");
994 }
995 }
996 }
997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998}