blob: 16e63b3e0e8fbc371e376d6c0dc8713530b159d4 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
Michael Wright71216972017-01-31 18:33:54 +000025import android.content.res.Resources;
Jeff Brown7f6c2312012-04-13 20:38:38 -070026import android.database.ContentObserver;
27import android.hardware.input.InputManager;
Michael Wright71216972017-01-31 18:33:54 +000028import android.hardware.vibrator.V1_0.Constants.EffectStrength;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070029import android.media.AudioManager;
jackqdyulei455e90a2017-02-09 15:29:16 -080030import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070031import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070032import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050033import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070035import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.Process;
37import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080038import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.os.IBinder;
40import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080041import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080042import android.os.ShellCallback;
43import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070045import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070046import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000047import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070048import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070049import android.provider.Settings;
50import android.provider.Settings.SettingNotFoundException;
Joe Onorato8a9b2202010-02-26 18:56:32 -080051import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070052import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040053import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
Dianne Hackborna06de0f2012-12-11 16:34:47 -080055import com.android.internal.app.IAppOpsService;
56import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060057import com.android.internal.util.DumpUtils;
jackqdyulei455e90a2017-02-09 15:29:16 -080058import com.android.server.power.BatterySaverPolicy.ServiceType;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080059
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070060import java.io.FileDescriptor;
61import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070062import java.util.ArrayList;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070063import java.util.Arrays;
Jeff Brown969579b2014-05-20 19:29:29 -070064import java.util.Iterator;
Patrick Scott18dd5f02009-07-02 11:31:12 -040065import java.util.LinkedList;
66import java.util.ListIterator;
67
Jeff Brown7f6c2312012-04-13 20:38:38 -070068public class VibratorService extends IVibratorService.Stub
69 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050070 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070071 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070072 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050073
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070074 private final LinkedList<VibrationInfo> mPreviousVibrations;
75 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -070076 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +000077 private final boolean mSupportsAmplitudeControl;
78 private final int mDefaultVibrationAmplitude;
79 private final VibrationEffect[] mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070080 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070081 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +000082 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -070083
84 private final Context mContext;
85 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080086 private final IAppOpsService mAppOpsService;
87 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070088 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070089 private InputManager mIm;
90
Michael Wright71216972017-01-31 18:33:54 +000091 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -070092
Michael Wright71216972017-01-31 18:33:54 +000093 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -070094 // to be acquired
95 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
96 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
97 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
98
Michael Wright71216972017-01-31 18:33:54 +000099 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800100 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700101 private boolean mLowPowerMode;
102 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800103
Jeff Brown7f6c2312012-04-13 20:38:38 -0700104 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200105 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700106 native static void vibratorOn(long milliseconds);
107 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000108 native static boolean vibratorSupportsAmplitudeControl();
109 native static void vibratorSetAmplitude(int amplitude);
110 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400111
Patrick Scott18dd5f02009-07-02 11:31:12 -0400112 private class Vibration implements IBinder.DeathRecipient {
113 private final IBinder mToken;
Michael Wright71216972017-01-31 18:33:54 +0000114 private final VibrationEffect mEffect;
115 private final long mStartTime;
116 private final int mUsageHint;
117 private final int mUid;
118 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400119
Michael Wright71216972017-01-31 18:33:54 +0000120 private Vibration(IBinder token, VibrationEffect effect,
121 int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400122 mToken = token;
Michael Wright71216972017-01-31 18:33:54 +0000123 mEffect = effect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400124 mStartTime = SystemClock.uptimeMillis();
John Spurlock7b414672014-07-18 13:02:39 -0400125 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700126 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400127 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400128 }
129
130 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000131 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400132 if (this == mCurrentVibration) {
133 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400134 }
135 }
136 }
137
138 public boolean hasLongerTimeout(long millis) {
Michael Wright71216972017-01-31 18:33:54 +0000139 // If the current effect is a one shot vibration that will end after the given timeout
140 // for the new one shot vibration, then just let the current vibration finish. All
141 // other effect types will get pre-empted.
142 if (mEffect instanceof VibrationEffect.OneShot) {
143 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
144 return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400145 }
Michael Wright71216972017-01-31 18:33:54 +0000146 return false;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400147 }
Jeff Brown969579b2014-05-20 19:29:29 -0700148
149 public boolean isSystemHapticFeedback() {
Michael Wright71216972017-01-31 18:33:54 +0000150 boolean repeating = false;
151 if (mEffect instanceof VibrationEffect.Waveform) {
152 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
153 repeating = (waveform.getRepeatIndex() < 0);
154 }
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700155 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
Michael Wright71216972017-01-31 18:33:54 +0000156 && !repeating;
Jeff Brown969579b2014-05-20 19:29:29 -0700157 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400158 }
159
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700160 private static class VibrationInfo {
Michael Wright71216972017-01-31 18:33:54 +0000161 private final long mStartTime;
162 private final VibrationEffect mEffect;
163 private final int mUsageHint;
164 private final int mUid;
165 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700166
Michael Wright71216972017-01-31 18:33:54 +0000167 public VibrationInfo(long startTime, VibrationEffect effect,
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700168 int usageHint, int uid, String opPkg) {
Michael Wright71216972017-01-31 18:33:54 +0000169 mStartTime = startTime;
170 mEffect = effect;
171 mUsageHint = usageHint;
172 mUid = uid;
173 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700174 }
175
176 @Override
177 public String toString() {
178 return new StringBuilder()
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700179 .append(", startTime: ")
Michael Wright71216972017-01-31 18:33:54 +0000180 .append(mStartTime)
181 .append(", effect: ")
182 .append(mEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700183 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000184 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700185 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000186 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700187 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000188 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700189 .toString();
190 }
191 }
192
Mike Lockwood3a322132009-11-24 00:30:52 -0500193 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200194 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 // Reset the hardware to a default state, in case this is a runtime
196 // restart instead of a fresh boot.
197 vibratorOff();
198
Michael Wright71216972017-01-31 18:33:54 +0000199 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000202 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700203 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 mWakeLock.setReferenceCounted(true);
205
Michael Wright71216972017-01-31 18:33:54 +0000206 mAppOpsService =
207 IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700208 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
209 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800210
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700211 mPreviousVibrationsLimit = mContext.getResources().getInteger(
212 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
213
Michael Wright71216972017-01-31 18:33:54 +0000214 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
215 com.android.internal.R.integer.config_defaultVibrationAmplitude);
216
Tyler Freeman319a34a2017-05-04 17:23:35 -0700217 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
218 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
219
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700220 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 IntentFilter filter = new IntentFilter();
223 filter.addAction(Intent.ACTION_SCREEN_OFF);
224 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000225
226 long[] clickEffectTimings = getLongIntArray(context.getResources(),
227 com.android.internal.R.array.config_virtualKeyVibePattern);
Erik Wolsheimerb97ae352017-05-22 16:58:18 -0700228 VibrationEffect clickEffect;
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700229 if (clickEffectTimings.length == 0) {
230 clickEffect = null;
231 } else if (clickEffectTimings.length == 1) {
Erik Wolsheimerb97ae352017-05-22 16:58:18 -0700232 clickEffect = VibrationEffect.createOneShot(
233 clickEffectTimings[0], VibrationEffect.DEFAULT_AMPLITUDE);
234 } else {
235 clickEffect = VibrationEffect.createWaveform(clickEffectTimings, -1);
236 }
Michael Wright71216972017-01-31 18:33:54 +0000237 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
238 new long[] {0, 30, 100, 30} /*timings*/, -1);
239
240 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800241 }
242
Jeff Brown7f6c2312012-04-13 20:38:38 -0700243 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800244 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700245 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700246
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700247 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
248 mPowerManagerInternal.registerLowPowerModeObserver(
249 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800250 @Override
251 public int getServiceType() {
252 return ServiceType.VIBRATION;
253 }
254
255 @Override
256 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000257 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800258 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700259 });
260
Jeff Brown7f6c2312012-04-13 20:38:38 -0700261 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700262 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
263 true, mSettingObserver, UserHandle.USER_ALL);
264
Jeff Brownd4935962012-09-25 13:27:20 -0700265 mContext.registerReceiver(new BroadcastReceiver() {
266 @Override
267 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000268 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700269 }
270 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
271
Michael Wright71216972017-01-31 18:33:54 +0000272 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700273 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700274
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700275 private final class SettingsObserver extends ContentObserver {
276 public SettingsObserver(Handler handler) {
277 super(handler);
278 }
279
280 @Override
281 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000282 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700283 }
284 }
285
Jeff Brown82379ba2014-07-25 19:03:28 -0700286 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700287 public boolean hasVibrator() {
288 return doVibratorExists();
289 }
290
Michael Wright71216972017-01-31 18:33:54 +0000291 @Override // Binder call
292 public boolean hasAmplitudeControl() {
293 synchronized (mInputDeviceVibrators) {
294 // Input device vibrators don't support amplitude controls yet, but are still used over
295 // the system vibrator when connected.
296 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
297 }
298 }
299
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800300 private void verifyIncomingUid(int uid) {
301 if (uid == Binder.getCallingUid()) {
302 return;
303 }
304 if (Binder.getCallingPid() == Process.myPid()) {
305 return;
306 }
307 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
308 Binder.getCallingPid(), Binder.getCallingUid(), null);
309 }
310
Michael Wright71216972017-01-31 18:33:54 +0000311 /**
312 * Validate the incoming VibrationEffect.
313 *
314 * We can't throw exceptions here since we might be called from some system_server component,
315 * which would bring the whole system down.
316 *
317 * @return whether the VibrationEffect is valid
318 */
319 private static boolean verifyVibrationEffect(VibrationEffect effect) {
320 if (effect == null) {
321 // Effect must not be null.
322 Slog.wtf(TAG, "effect must not be null");
323 return false;
324 }
325 try {
326 effect.validate();
327 } catch (Exception e) {
328 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
329 return false;
330 }
331 return true;
332 }
333
334 private static long[] getLongIntArray(Resources r, int resid) {
335 int[] ar = r.getIntArray(resid);
336 if (ar == null) {
337 return null;
338 }
339 long[] out = new long[ar.length];
340 for (int i = 0; i < ar.length; i++) {
341 out[i] = ar[i];
342 }
343 return out;
344 }
345
Jeff Brown82379ba2014-07-25 19:03:28 -0700346 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000347 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400348 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700349 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
350 != PackageManager.PERMISSION_GRANTED) {
351 throw new SecurityException("Requires VIBRATE permission");
352 }
Michael Wright71216972017-01-31 18:33:54 +0000353 if (token == null) {
354 Slog.e(TAG, "token must not be null");
355 return;
356 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800357 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000358 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400359 return;
360 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700361
Michael Wright71216972017-01-31 18:33:54 +0000362 // If our current vibration is longer than the new vibration and is the same amplitude,
363 // then just let the current one finish.
364 if (effect instanceof VibrationEffect.OneShot
365 && mCurrentVibration != null
366 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
367 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
368 VibrationEffect.OneShot currentOneShot =
369 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
370 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
371 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
372 if (DEBUG) {
373 Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 return;
376 }
Michael Wright71216972017-01-31 18:33:54 +0000377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378
Michael Wright71216972017-01-31 18:33:54 +0000379 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
380
381 // Only link against waveforms since they potentially don't have a finish if
382 // they're repeating. Let other effects just play out until they're done.
383 if (effect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400384 try {
385 token.linkToDeath(vib, 0);
386 } catch (RemoteException e) {
387 return;
388 }
Michael Wright71216972017-01-31 18:33:54 +0000389 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400390
Michael Wright71216972017-01-31 18:33:54 +0000391
392 long ident = Binder.clearCallingIdentity();
393 try {
394 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400395 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000396 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700397 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 }
Michael Wright71216972017-01-31 18:33:54 +0000399 } finally {
400 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 }
402 }
403
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700404 private void addToPreviousVibrationsLocked(Vibration vib) {
405 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
406 mPreviousVibrations.removeFirst();
407 }
Michael Wright71216972017-01-31 18:33:54 +0000408 mPreviousVibrations.addLast(new VibrationInfo(
409 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg));
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700410 }
411
Jeff Brown82379ba2014-07-25 19:03:28 -0700412 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400413 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 mContext.enforceCallingOrSelfPermission(
415 android.Manifest.permission.VIBRATE,
416 "cancelVibrate");
417
Michael Wright71216972017-01-31 18:33:54 +0000418 synchronized (mLock) {
419 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
420 if (DEBUG) {
421 Slog.d(TAG, "Canceling vibration.");
422 }
423 long ident = Binder.clearCallingIdentity();
424 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400425 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000426 } finally {
427 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400428 }
429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700432
Michael Wright71216972017-01-31 18:33:54 +0000433 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700434 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400435 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000436 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400437 }
438 };
439
Patrick Scott18dd5f02009-07-02 11:31:12 -0400440 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000441 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400442 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000443 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400444 mThread = null;
445 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700446 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800447 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400448 }
449
Michael Wright71216972017-01-31 18:33:54 +0000450 // Callback for whenever the current vibration has finished played out
451 public void onVibrationFinished() {
452 if (DEBUG) {
453 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400454 }
Michael Wright71216972017-01-31 18:33:54 +0000455 synchronized (mLock) {
456 // Make sure the vibration is really done. This also reports that the vibration is
457 // finished.
458 doCancelVibrateLocked();
459 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400460 }
461
Patrick Scott18dd5f02009-07-02 11:31:12 -0400462 private void startVibrationLocked(final Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700463 if (!isAllowedToVibrate(vib)) {
Michael Wright71216972017-01-31 18:33:54 +0000464 if (DEBUG) {
465 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700466 }
Michael Wright71216972017-01-31 18:33:54 +0000467 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800468 }
Michael Wright71216972017-01-31 18:33:54 +0000469
470 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
471 !shouldVibrateForRingtone()) {
472 if (DEBUG) {
473 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
474 }
475 return;
476 }
477
478 final int mode = getAppOpMode(vib);
479 if (mode != AppOpsManager.MODE_ALLOWED) {
480 if (mode == AppOpsManager.MODE_ERRORED) {
481 // We might be getting calls from within system_server, so we don't actually want
482 // to throw a SecurityException here.
483 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
484 }
485 return;
486 }
487 startVibrationInnerLocked(vib);
488 }
489
490 private void startVibrationInnerLocked(Vibration vib) {
491 mCurrentVibration = vib;
492 if (vib.mEffect instanceof VibrationEffect.OneShot) {
493 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
494 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
495 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
496 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400497 // mThread better be null here. doCancelVibrate should always be
498 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000499 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
500 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400501 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000502 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
503 long timeout = doVibratorPrebakedEffectLocked(vib);
504 if (timeout > 0) {
505 mH.postDelayed(mVibrationEndRunnable, timeout);
506 }
507 } else {
508 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 }
510 }
511
Tyler Freeman319a34a2017-05-04 17:23:35 -0700512 private boolean isAllowedToVibrate(Vibration vib) {
513 if (!mLowPowerMode) {
514 return true;
515 }
516 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
517 return true;
518 }
519 if (!mAllowPriorityVibrationsInLowPowerMode) {
520 return false;
521 }
522 if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
523 vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
524 vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
525
526 return true;
527 }
528
529 return false;
530 }
531
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700532 private boolean shouldVibrateForRingtone() {
533 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700534 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700535 // "Also vibrate for calls" Setting in Sound
536 if (Settings.System.getInt(
537 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
538 return ringerMode != AudioManager.RINGER_MODE_SILENT;
539 } else {
540 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
541 }
542 }
543
Michael Wright71216972017-01-31 18:33:54 +0000544 private int getAppOpMode(Vibration vib) {
545 int mode;
546 try {
547 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
548 vib.mUsageHint, vib.mUid, vib.mOpPkg);
549 if (mode == AppOpsManager.MODE_ALLOWED) {
550 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
551 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
552 }
553 } catch (RemoteException e) {
554 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
555 mode = AppOpsManager.MODE_IGNORED;
556 }
557 return mode;
558 }
559
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800560 private void reportFinishVibrationLocked() {
561 if (mCurrentVibration != null) {
562 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700563 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
564 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400565 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000566 } catch (RemoteException e) { }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800567 mCurrentVibration = null;
568 }
569 }
570
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200571 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000572 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200573 vib.mToken.unlinkToDeath(vib, 0);
574 }
575 }
576
Michael Wright71216972017-01-31 18:33:54 +0000577 private void updateVibrators() {
578 synchronized (mLock) {
579 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
580 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700581
Michael Wright71216972017-01-31 18:33:54 +0000582 if (devicesUpdated || lowPowerModeUpdated) {
583 // If the state changes out from under us then just reset.
584 doCancelVibrateLocked();
585 }
586 }
587 }
Jeff Brown82065252012-04-16 13:19:05 -0700588
Michael Wright71216972017-01-31 18:33:54 +0000589 private boolean updateInputDeviceVibratorsLocked() {
590 boolean changed = false;
591 boolean vibrateInputDevices = false;
592 try {
593 vibrateInputDevices = Settings.System.getIntForUser(
594 mContext.getContentResolver(),
595 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
596 } catch (SettingNotFoundException snfe) {
597 }
598 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
599 changed = true;
600 mVibrateInputDevicesSetting = vibrateInputDevices;
601 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700602
Michael Wright71216972017-01-31 18:33:54 +0000603 if (mVibrateInputDevicesSetting) {
604 if (!mInputDeviceListenerRegistered) {
605 mInputDeviceListenerRegistered = true;
606 mIm.registerInputDeviceListener(this, mH);
607 }
608 } else {
609 if (mInputDeviceListenerRegistered) {
610 mInputDeviceListenerRegistered = false;
611 mIm.unregisterInputDeviceListener(this);
612 }
613 }
Jeff Brown82065252012-04-16 13:19:05 -0700614
Michael Wright71216972017-01-31 18:33:54 +0000615 mInputDeviceVibrators.clear();
616 if (mVibrateInputDevicesSetting) {
617 int[] ids = mIm.getInputDeviceIds();
618 for (int i = 0; i < ids.length; i++) {
619 InputDevice device = mIm.getInputDevice(ids[i]);
620 Vibrator vibrator = device.getVibrator();
621 if (vibrator.hasVibrator()) {
622 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700623 }
624 }
Michael Wright71216972017-01-31 18:33:54 +0000625 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700626 }
Michael Wright71216972017-01-31 18:33:54 +0000627 return changed;
628 }
629
630 private boolean updateLowPowerModeLocked() {
631 boolean lowPowerMode = mPowerManagerInternal
632 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
633 if (lowPowerMode != mLowPowerMode) {
634 mLowPowerMode = lowPowerMode;
635 return true;
636 }
637 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700638 }
639
640 @Override
641 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000642 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700643 }
644
645 @Override
646 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000647 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700648 }
649
650 @Override
651 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000652 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700653 }
654
655 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700656 // For now, we choose to ignore the presence of input devices that have vibrators
657 // when reporting whether the device has a vibrator. Applications often use this
658 // information to decide whether to enable certain features so they expect the
659 // result of hasVibrator() to be constant. For now, just report whether
660 // the device has a built-in vibrator.
661 //synchronized (mInputDeviceVibrators) {
662 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
663 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800664 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700665 }
666
Michael Wright71216972017-01-31 18:33:54 +0000667 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700668 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000669 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
670 amplitude = mDefaultVibrationAmplitude;
671 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700672 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000673 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
674 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700675 }
Michael Wright71216972017-01-31 18:33:54 +0000676 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700677 final int vibratorCount = mInputDeviceVibrators.size();
678 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000679 final AudioAttributes attributes =
680 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700681 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400682 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700683 }
684 } else {
Michael Wright71216972017-01-31 18:33:54 +0000685 // Note: ordering is important here! Many haptic drivers will reset their amplitude
686 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700687 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000688 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700689 }
690 }
691 }
692
Michael Wright71216972017-01-31 18:33:54 +0000693 private void doVibratorSetAmplitude(int amplitude) {
694 if (mSupportsAmplitudeControl) {
695 vibratorSetAmplitude(amplitude);
696 }
697 }
698
Jeff Brown7f6c2312012-04-13 20:38:38 -0700699 private void doVibratorOff() {
700 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700701 if (DEBUG) {
702 Slog.d(TAG, "Turning vibrator off.");
703 }
Michael Wright71216972017-01-31 18:33:54 +0000704 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700705 final int vibratorCount = mInputDeviceVibrators.size();
706 if (vibratorCount != 0) {
707 for (int i = 0; i < vibratorCount; i++) {
708 mInputDeviceVibrators.get(i).cancel();
709 }
710 } else {
711 vibratorOff();
712 }
713 }
714 }
715
Michael Wright71216972017-01-31 18:33:54 +0000716 private long doVibratorPrebakedEffectLocked(Vibration vib) {
717 synchronized (mInputDeviceVibrators) {
718 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
719 // Input devices don't support prebaked effect, so skip trying it with them.
720 final int vibratorCount = mInputDeviceVibrators.size();
721 if (vibratorCount == 0) {
722 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
723 if (timeout > 0) {
724 noteVibratorOnLocked(vib.mUid, timeout);
725 return timeout;
726 }
727 }
728 final int id = prebaked.getId();
Erik Wolsheimer017939e2017-05-24 11:18:25 -0700729 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) {
Michael Wright71216972017-01-31 18:33:54 +0000730 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
731 return 0;
732 }
733 VibrationEffect effect = mFallbackEffects[id];
734 Vibration fallbackVib =
735 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
736 startVibrationInnerLocked(fallbackVib);
737 }
738 return 0;
739 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700740
Michael Wright71216972017-01-31 18:33:54 +0000741 private void noteVibratorOnLocked(int uid, long millis) {
742 try {
743 mBatteryStatsService.noteVibratorOn(uid, millis);
744 mCurVibUid = uid;
745 } catch (RemoteException e) {
746 }
747 }
748
749 private void noteVibratorOffLocked() {
750 if (mCurVibUid >= 0) {
751 try {
752 mBatteryStatsService.noteVibratorOff(mCurVibUid);
753 } catch (RemoteException e) { }
754 mCurVibUid = -1;
755 }
756 }
757
758 private class VibrateThread extends Thread {
759 private final VibrationEffect.Waveform mWaveform;
760 private final int mUid;
761 private final int mUsageHint;
762
763 private boolean mForceStop;
764
765 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
766 mWaveform = waveform;
767 mUid = uid;
768 mUsageHint = usageHint;
769 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700770 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 }
772
Michael Wright71216972017-01-31 18:33:54 +0000773 private long delayLocked(long duration) {
774 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000776 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 do {
778 try {
Michael Wright71216972017-01-31 18:33:54 +0000779 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
Michael Wright71216972017-01-31 18:33:54 +0000781 catch (InterruptedException e) { }
782 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 break;
784 }
Michael Wright71216972017-01-31 18:33:54 +0000785 durationRemaining = bedtime - SystemClock.uptimeMillis();
786 } while (durationRemaining > 0);
787 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 }
Michael Wright71216972017-01-31 18:33:54 +0000789 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 }
791
792 public void run() {
793 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000794 mWakeLock.acquire();
795 try {
796 boolean finished = playWaveform();
797 if (finished) {
798 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 }
Michael Wright71216972017-01-31 18:33:54 +0000800 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 mWakeLock.release();
802 }
Michael Wright71216972017-01-31 18:33:54 +0000803 }
804
805 /**
806 * Play the waveform.
807 *
808 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
809 */
810 public boolean playWaveform() {
811 synchronized (this) {
812 final long[] timings = mWaveform.getTimings();
813 final int[] amplitudes = mWaveform.getAmplitudes();
814 final int len = timings.length;
815 final int repeat = mWaveform.getRepeatIndex();
816
817 int index = 0;
818 long onDuration = 0;
819 while (!mForceStop) {
820 if (index < len) {
821 final int amplitude = amplitudes[index];
822 final long duration = timings[index++];
823 if (duration <= 0) {
824 continue;
825 }
826 if (amplitude != 0) {
827 if (onDuration <= 0) {
828 // Telling the vibrator to start multiple times usually causes
829 // effects to feel "choppy" because the motor resets at every on
830 // command. Instead we figure out how long our next "on" period is
831 // going to be, tell the motor to stay on for the full duration,
832 // and then wake up to change the amplitude at the appropriate
833 // intervals.
834 onDuration =
835 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
836 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
837 } else {
838 doVibratorSetAmplitude(amplitude);
839 }
840 }
841
842 long waitTime = delayLocked(duration);
843 if (amplitude != 0) {
844 onDuration -= waitTime;
845 }
846 } else if (repeat < 0) {
847 break;
848 } else {
849 index = repeat;
850 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
Michael Wright71216972017-01-31 18:33:54 +0000852 return !mForceStop;
853 }
854 }
855
856 public void cancel() {
857 synchronized (this) {
858 mThread.mForceStop = true;
859 mThread.notify();
860 }
861 }
862
863 /**
864 * Get the duration the vibrator will be on starting at startIndex until the next time it's
865 * off.
866 */
867 private long getTotalOnDuration(
868 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
869 int i = startIndex;
870 long timing = 0;
871 while(amplitudes[i] != 0) {
872 timing += timings[i++];
873 if (i >= timings.length) {
874 if (repeatIndex >= 0) {
875 i = repeatIndex;
876 } else {
877 break;
878 }
879 }
880 if (i == startIndex) {
881 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 }
Michael Wright71216972017-01-31 18:33:54 +0000884 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
Jeff Brown969579b2014-05-20 19:29:29 -0700886 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700889 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890 public void onReceive(Context context, Intent intent) {
891 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000892 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700893 // When the system is entering a non-interactive state, we want
894 // to cancel vibrations in case a misbehaving app has abandoned
895 // them. However it may happen that the system is currently playing
896 // haptic feedback as part of the transition. So we don't cancel
897 // system vibrations.
898 if (mCurrentVibration != null
899 && !mCurrentVibration.isSystemHapticFeedback()) {
900 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700901 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904 }
905 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700906
907 @Override
908 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600909 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700910
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700911 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000912 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700913 for (VibrationInfo info : mPreviousVibrations) {
914 pw.print(" ");
915 pw.println(info.toString());
916 }
917 }
918 }
Felipe Lemea5281002017-02-10 15:13:48 -0800919
920 @Override
921 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
922 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
923 throws RemoteException {
924 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
925 }
926
927 private final class VibratorShellCommand extends ShellCommand {
928
929 private static final long MAX_VIBRATION_MS = 200;
930
931 private final IBinder mToken;
932
933 private VibratorShellCommand(IBinder token) {
934 mToken = token;
935 }
936
937 @Override
938 public int onCommand(String cmd) {
939 if ("vibrate".equals(cmd)) {
940 return runVibrate();
941 }
942 return handleDefaultCommands(cmd);
943 }
944
945 private int runVibrate() {
946 final long duration = Long.parseLong(getNextArgRequired());
947 if (duration > MAX_VIBRATION_MS) {
948 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
949 }
950 String description = getNextArg();
951 if (description == null) {
952 description = "Shell command";
953 }
Michael Wright71216972017-01-31 18:33:54 +0000954
955 VibrationEffect effect =
956 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
957 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -0800958 mToken);
959 return 0;
960 }
961
962 @Override
963 public void onHelp() {
964 try (PrintWriter pw = getOutPrintWriter();) {
965 pw.println("Vibrator commands:");
966 pw.println(" help");
967 pw.println(" Prints this help text.");
968 pw.println("");
969 pw.println(" vibrate duration [description]");
970 pw.println(" Vibrates for duration milliseconds.");
971 pw.println("");
972 }
973 }
974 }
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976}