blob: c1cda985a9ba7d2ac6cd8f783a5f19e458ffd5c2 [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;
Michael Wright36d873f2018-01-08 15:54:05 +000029import android.icu.text.DateFormat;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070030import android.media.AudioManager;
Makoto Onuki2eccd022017-11-01 13:44:23 -070031import android.os.PowerManager.ServiceType;
jackqdyulei455e90a2017-02-09 15:29:16 -080032import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070033import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070034import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050035import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070037import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Process;
39import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080040import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.IBinder;
42import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080044import android.os.ShellCallback;
45import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070047import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070048import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000049import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070050import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070051import android.provider.Settings;
52import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070053import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080054import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070055import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040056import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057
Dianne Hackborna06de0f2012-12-11 16:34:47 -080058import com.android.internal.app.IAppOpsService;
59import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060060import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080061
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070062import java.io.FileDescriptor;
63import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070064import java.util.ArrayList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040065import java.util.LinkedList;
Michael Wright36d873f2018-01-08 15:54:05 +000066import java.util.Date;
Patrick Scott18dd5f02009-07-02 11:31:12 -040067
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
Michael Wright36d873f2018-01-08 15:54:05 +000074 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
75
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070076 private final LinkedList<VibrationInfo> mPreviousVibrations;
77 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -070078 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +000079 private final boolean mSupportsAmplitudeControl;
80 private final int mDefaultVibrationAmplitude;
81 private final VibrationEffect[] mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070082 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070083 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +000084 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -070085
86 private final Context mContext;
87 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080088 private final IAppOpsService mAppOpsService;
89 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070090 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070091 private InputManager mIm;
92
Michael Wright71216972017-01-31 18:33:54 +000093 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -070094
Michael Wright71216972017-01-31 18:33:54 +000095 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -070096 // to be acquired
97 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
98 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
99 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
100
Michael Wright71216972017-01-31 18:33:54 +0000101 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800102 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700103 private boolean mLowPowerMode;
104 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800105
Jeff Brown7f6c2312012-04-13 20:38:38 -0700106 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200107 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700108 native static void vibratorOn(long milliseconds);
109 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000110 native static boolean vibratorSupportsAmplitudeControl();
111 native static void vibratorSetAmplitude(int amplitude);
112 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400113
Patrick Scott18dd5f02009-07-02 11:31:12 -0400114 private class Vibration implements IBinder.DeathRecipient {
115 private final IBinder mToken;
Michael Wright71216972017-01-31 18:33:54 +0000116 private final VibrationEffect mEffect;
Michael Wright36d873f2018-01-08 15:54:05 +0000117 // Start time in CLOCK_BOOTTIME base.
Michael Wright71216972017-01-31 18:33:54 +0000118 private final long mStartTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000119 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
120 // with other system events, any duration calculations should be done use mStartTime so as
121 // not to be affected by discontinuities created by RTC adjustments.
122 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000123 private final int mUsageHint;
124 private final int mUid;
125 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400126
Michael Wright71216972017-01-31 18:33:54 +0000127 private Vibration(IBinder token, VibrationEffect effect,
128 int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400129 mToken = token;
Michael Wright71216972017-01-31 18:33:54 +0000130 mEffect = effect;
Michael Wright36d873f2018-01-08 15:54:05 +0000131 mStartTime = SystemClock.elapsedRealtime();
132 mStartTimeDebug = System.currentTimeMillis();
John Spurlock7b414672014-07-18 13:02:39 -0400133 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700134 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400135 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400136 }
137
138 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000139 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400140 if (this == mCurrentVibration) {
141 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400142 }
143 }
144 }
145
146 public boolean hasLongerTimeout(long millis) {
Michael Wright71216972017-01-31 18:33:54 +0000147 // If the current effect is a one shot vibration that will end after the given timeout
148 // for the new one shot vibration, then just let the current vibration finish. All
149 // other effect types will get pre-empted.
150 if (mEffect instanceof VibrationEffect.OneShot) {
151 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) mEffect;
152 return mStartTime + oneShot.getTiming() > SystemClock.uptimeMillis() + millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400153 }
Michael Wright71216972017-01-31 18:33:54 +0000154 return false;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400155 }
Jeff Brown969579b2014-05-20 19:29:29 -0700156
157 public boolean isSystemHapticFeedback() {
Michael Wright71216972017-01-31 18:33:54 +0000158 boolean repeating = false;
159 if (mEffect instanceof VibrationEffect.Waveform) {
160 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) mEffect;
161 repeating = (waveform.getRepeatIndex() < 0);
162 }
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700163 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
Michael Wright71216972017-01-31 18:33:54 +0000164 && !repeating;
Jeff Brown969579b2014-05-20 19:29:29 -0700165 }
Michael Wright36d873f2018-01-08 15:54:05 +0000166
167 public VibrationInfo toInfo() {
168 return new VibrationInfo(mStartTimeDebug, mEffect, mUsageHint, mUid, mOpPkg);
169 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400170 }
171
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700172 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000173 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000174 private final VibrationEffect mEffect;
175 private final int mUsageHint;
176 private final int mUid;
177 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700178
Michael Wright36d873f2018-01-08 15:54:05 +0000179 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700180 int usageHint, int uid, String opPkg) {
Michael Wright36d873f2018-01-08 15:54:05 +0000181 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000182 mEffect = effect;
183 mUsageHint = usageHint;
184 mUid = uid;
185 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700186 }
187
188 @Override
189 public String toString() {
190 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000191 .append("startTime: ")
192 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000193 .append(", effect: ")
194 .append(mEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700195 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000196 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700197 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000198 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700199 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000200 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700201 .toString();
202 }
203 }
204
Mike Lockwood3a322132009-11-24 00:30:52 -0500205 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200206 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 // Reset the hardware to a default state, in case this is a runtime
208 // restart instead of a fresh boot.
209 vibratorOff();
210
Michael Wright71216972017-01-31 18:33:54 +0000211 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000214 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700215 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 mWakeLock.setReferenceCounted(true);
217
Michael Wright71216972017-01-31 18:33:54 +0000218 mAppOpsService =
219 IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700220 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
221 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800222
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700223 mPreviousVibrationsLimit = mContext.getResources().getInteger(
224 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
225
Michael Wright71216972017-01-31 18:33:54 +0000226 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
227 com.android.internal.R.integer.config_defaultVibrationAmplitude);
228
Tyler Freeman319a34a2017-05-04 17:23:35 -0700229 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
230 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
231
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700232 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 IntentFilter filter = new IntentFilter();
235 filter.addAction(Intent.ACTION_SCREEN_OFF);
236 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000237
238 long[] clickEffectTimings = getLongIntArray(context.getResources(),
239 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright57d94d92017-05-31 14:44:45 +0100240 VibrationEffect clickEffect = createEffect(clickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000241 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Michael Wright36d873f2018-01-08 15:54:05 +0000242 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wright57d94d92017-05-31 14:44:45 +0100243 long[] tickEffectTimings = getLongIntArray(context.getResources(),
244 com.android.internal.R.array.config_clockTickVibePattern);
245 VibrationEffect tickEffect = createEffect(tickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000246
Michael Wright57d94d92017-05-31 14:44:45 +0100247 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
248 }
249
250 private static VibrationEffect createEffect(long[] timings) {
251 if (timings == null || timings.length == 0) {
252 return null;
253 } else if (timings.length == 1) {
254 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
255 } else {
256 return VibrationEffect.createWaveform(timings, -1);
257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 }
259
Jeff Brown7f6c2312012-04-13 20:38:38 -0700260 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800261 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700262 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700263
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700264 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
265 mPowerManagerInternal.registerLowPowerModeObserver(
266 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800267 @Override
268 public int getServiceType() {
269 return ServiceType.VIBRATION;
270 }
271
272 @Override
273 public void onLowPowerModeChanged(PowerSaveState result) {
Michael Wright71216972017-01-31 18:33:54 +0000274 updateVibrators();
jackqdyulei455e90a2017-02-09 15:29:16 -0800275 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700276 });
277
Jeff Brown7f6c2312012-04-13 20:38:38 -0700278 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700279 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
280 true, mSettingObserver, UserHandle.USER_ALL);
281
Jeff Brownd4935962012-09-25 13:27:20 -0700282 mContext.registerReceiver(new BroadcastReceiver() {
283 @Override
284 public void onReceive(Context context, Intent intent) {
Michael Wright71216972017-01-31 18:33:54 +0000285 updateVibrators();
Jeff Brownd4935962012-09-25 13:27:20 -0700286 }
287 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
288
Michael Wright71216972017-01-31 18:33:54 +0000289 updateVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700290 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700291
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700292 private final class SettingsObserver extends ContentObserver {
293 public SettingsObserver(Handler handler) {
294 super(handler);
295 }
296
297 @Override
298 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000299 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700300 }
301 }
302
Jeff Brown82379ba2014-07-25 19:03:28 -0700303 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700304 public boolean hasVibrator() {
305 return doVibratorExists();
306 }
307
Michael Wright71216972017-01-31 18:33:54 +0000308 @Override // Binder call
309 public boolean hasAmplitudeControl() {
310 synchronized (mInputDeviceVibrators) {
311 // Input device vibrators don't support amplitude controls yet, but are still used over
312 // the system vibrator when connected.
313 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
314 }
315 }
316
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800317 private void verifyIncomingUid(int uid) {
318 if (uid == Binder.getCallingUid()) {
319 return;
320 }
321 if (Binder.getCallingPid() == Process.myPid()) {
322 return;
323 }
324 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
325 Binder.getCallingPid(), Binder.getCallingUid(), null);
326 }
327
Michael Wright71216972017-01-31 18:33:54 +0000328 /**
329 * Validate the incoming VibrationEffect.
330 *
331 * We can't throw exceptions here since we might be called from some system_server component,
332 * which would bring the whole system down.
333 *
334 * @return whether the VibrationEffect is valid
335 */
336 private static boolean verifyVibrationEffect(VibrationEffect effect) {
337 if (effect == null) {
338 // Effect must not be null.
339 Slog.wtf(TAG, "effect must not be null");
340 return false;
341 }
342 try {
343 effect.validate();
344 } catch (Exception e) {
345 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
346 return false;
347 }
348 return true;
349 }
350
351 private static long[] getLongIntArray(Resources r, int resid) {
352 int[] ar = r.getIntArray(resid);
353 if (ar == null) {
354 return null;
355 }
356 long[] out = new long[ar.length];
357 for (int i = 0; i < ar.length; i++) {
358 out[i] = ar[i];
359 }
360 return out;
361 }
362
Jeff Brown82379ba2014-07-25 19:03:28 -0700363 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000364 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400365 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700366 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
367 != PackageManager.PERMISSION_GRANTED) {
368 throw new SecurityException("Requires VIBRATE permission");
369 }
Michael Wright71216972017-01-31 18:33:54 +0000370 if (token == null) {
371 Slog.e(TAG, "token must not be null");
372 return;
373 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800374 verifyIncomingUid(uid);
Michael Wright71216972017-01-31 18:33:54 +0000375 if (!verifyVibrationEffect(effect)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400376 return;
377 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700378
Michael Wright71216972017-01-31 18:33:54 +0000379 // If our current vibration is longer than the new vibration and is the same amplitude,
380 // then just let the current one finish.
381 if (effect instanceof VibrationEffect.OneShot
382 && mCurrentVibration != null
383 && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
384 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
385 VibrationEffect.OneShot currentOneShot =
386 (VibrationEffect.OneShot) mCurrentVibration.mEffect;
387 if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
388 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
389 if (DEBUG) {
Michael Wright58c46312017-10-05 14:04:14 -0400390 Slog.d(TAG, "Ignoring incoming vibration in favor of current vibration");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 return;
393 }
Michael Wright71216972017-01-31 18:33:54 +0000394 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395
Michael Wright58c46312017-10-05 14:04:14 -0400396 // If the current vibration is repeating and the incoming one is non-repeating, then ignore
397 // the non-repeating vibration. This is so that we don't cancel vibrations that are meant
398 // to grab the attention of the user, like ringtones and alarms, in favor of one-shot
399 // vibrations that are likely quite short.
400 if (!isRepeatingVibration(effect)
401 && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) {
402 if (DEBUG) {
403 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
404 }
405 return;
406 }
407
Michael Wright71216972017-01-31 18:33:54 +0000408 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
Michael Wright36d873f2018-01-08 15:54:05 +0000409 linkVibration(vib);
Michael Wright71216972017-01-31 18:33:54 +0000410
411 long ident = Binder.clearCallingIdentity();
412 try {
413 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400414 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000415 startVibrationLocked(vib);
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700416 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
Michael Wright71216972017-01-31 18:33:54 +0000418 } finally {
419 Binder.restoreCallingIdentity(ident);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 }
421 }
422
Michael Wright58c46312017-10-05 14:04:14 -0400423 private static boolean isRepeatingVibration(VibrationEffect effect) {
424 if (effect instanceof VibrationEffect.Waveform) {
425 final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect;
426 if (waveform.getRepeatIndex() >= 0) {
427 return true;
428 }
429 }
430 return false;
431 }
432
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700433 private void addToPreviousVibrationsLocked(Vibration vib) {
434 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
435 mPreviousVibrations.removeFirst();
436 }
Michael Wright36d873f2018-01-08 15:54:05 +0000437 mPreviousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700438 }
439
Jeff Brown82379ba2014-07-25 19:03:28 -0700440 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400441 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 mContext.enforceCallingOrSelfPermission(
443 android.Manifest.permission.VIBRATE,
444 "cancelVibrate");
445
Michael Wright71216972017-01-31 18:33:54 +0000446 synchronized (mLock) {
447 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
448 if (DEBUG) {
449 Slog.d(TAG, "Canceling vibration.");
450 }
451 long ident = Binder.clearCallingIdentity();
452 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400453 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000454 } finally {
455 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400456 }
457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700460
Michael Wright71216972017-01-31 18:33:54 +0000461 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700462 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400463 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000464 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400465 }
466 };
467
Patrick Scott18dd5f02009-07-02 11:31:12 -0400468 private void doCancelVibrateLocked() {
Michael Wright71216972017-01-31 18:33:54 +0000469 mH.removeCallbacks(mVibrationEndRunnable);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400470 if (mThread != null) {
Michael Wright71216972017-01-31 18:33:54 +0000471 mThread.cancel();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400472 mThread = null;
473 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700474 doVibratorOff();
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800475 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400476 }
477
Michael Wright71216972017-01-31 18:33:54 +0000478 // Callback for whenever the current vibration has finished played out
479 public void onVibrationFinished() {
480 if (DEBUG) {
481 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400482 }
Michael Wright71216972017-01-31 18:33:54 +0000483 synchronized (mLock) {
484 // Make sure the vibration is really done. This also reports that the vibration is
485 // finished.
486 doCancelVibrateLocked();
487 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400488 }
489
Patrick Scott18dd5f02009-07-02 11:31:12 -0400490 private void startVibrationLocked(final Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700491 if (!isAllowedToVibrate(vib)) {
Michael Wright71216972017-01-31 18:33:54 +0000492 if (DEBUG) {
493 Slog.e(TAG, "Vibrate ignored, low power mode");
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700494 }
Michael Wright71216972017-01-31 18:33:54 +0000495 return;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800496 }
Michael Wright71216972017-01-31 18:33:54 +0000497
498 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
499 !shouldVibrateForRingtone()) {
500 if (DEBUG) {
501 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
502 }
503 return;
504 }
505
506 final int mode = getAppOpMode(vib);
507 if (mode != AppOpsManager.MODE_ALLOWED) {
508 if (mode == AppOpsManager.MODE_ERRORED) {
509 // We might be getting calls from within system_server, so we don't actually want
510 // to throw a SecurityException here.
511 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
512 }
513 return;
514 }
515 startVibrationInnerLocked(vib);
516 }
517
518 private void startVibrationInnerLocked(Vibration vib) {
519 mCurrentVibration = vib;
520 if (vib.mEffect instanceof VibrationEffect.OneShot) {
521 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
522 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
523 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());
524 } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400525 // mThread better be null here. doCancelVibrate should always be
526 // called before startNextVibrationLocked or startVibrationLocked.
Michael Wright71216972017-01-31 18:33:54 +0000527 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
528 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400529 mThread.start();
Michael Wright71216972017-01-31 18:33:54 +0000530 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
531 long timeout = doVibratorPrebakedEffectLocked(vib);
532 if (timeout > 0) {
533 mH.postDelayed(mVibrationEndRunnable, timeout);
534 }
535 } else {
536 Slog.e(TAG, "Unknown vibration type, ignoring");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538 }
539
Tyler Freeman319a34a2017-05-04 17:23:35 -0700540 private boolean isAllowedToVibrate(Vibration vib) {
541 if (!mLowPowerMode) {
542 return true;
543 }
544 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
545 return true;
546 }
547 if (!mAllowPriorityVibrationsInLowPowerMode) {
548 return false;
549 }
550 if (vib.mUsageHint == AudioAttributes.USAGE_ALARM ||
551 vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
552 vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
553
554 return true;
555 }
556
557 return false;
558 }
559
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700560 private boolean shouldVibrateForRingtone() {
561 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700562 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700563 // "Also vibrate for calls" Setting in Sound
564 if (Settings.System.getInt(
565 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
566 return ringerMode != AudioManager.RINGER_MODE_SILENT;
567 } else {
568 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
569 }
570 }
571
Michael Wright71216972017-01-31 18:33:54 +0000572 private int getAppOpMode(Vibration vib) {
573 int mode;
574 try {
575 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
576 vib.mUsageHint, vib.mUid, vib.mOpPkg);
577 if (mode == AppOpsManager.MODE_ALLOWED) {
578 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
579 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
580 }
581 } catch (RemoteException e) {
582 Slog.e(TAG, "Failed to get appop mode for vibration!", e);
583 mode = AppOpsManager.MODE_IGNORED;
584 }
585 return mode;
586 }
587
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800588 private void reportFinishVibrationLocked() {
589 if (mCurrentVibration != null) {
590 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700591 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
592 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400593 mCurrentVibration.mOpPkg);
Michael Wright71216972017-01-31 18:33:54 +0000594 } catch (RemoteException e) { }
Michael Wright36d873f2018-01-08 15:54:05 +0000595 unlinkVibration(mCurrentVibration);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800596 mCurrentVibration = null;
597 }
598 }
599
Michael Wright36d873f2018-01-08 15:54:05 +0000600 private void linkVibration(Vibration vib) {
601 // Only link against waveforms since they potentially don't have a finish if
602 // they're repeating. Let other effects just play out until they're done.
603 if (vib.mEffect instanceof VibrationEffect.Waveform) {
604 try {
605 vib.mToken.linkToDeath(vib, 0);
606 } catch (RemoteException e) {
607 return;
608 }
609 }
610 }
611
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200612 private void unlinkVibration(Vibration vib) {
Michael Wright71216972017-01-31 18:33:54 +0000613 if (vib.mEffect instanceof VibrationEffect.Waveform) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200614 vib.mToken.unlinkToDeath(vib, 0);
615 }
616 }
617
Michael Wright71216972017-01-31 18:33:54 +0000618 private void updateVibrators() {
619 synchronized (mLock) {
620 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
621 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700622
Michael Wright71216972017-01-31 18:33:54 +0000623 if (devicesUpdated || lowPowerModeUpdated) {
624 // If the state changes out from under us then just reset.
625 doCancelVibrateLocked();
626 }
627 }
628 }
Jeff Brown82065252012-04-16 13:19:05 -0700629
Michael Wright71216972017-01-31 18:33:54 +0000630 private boolean updateInputDeviceVibratorsLocked() {
631 boolean changed = false;
632 boolean vibrateInputDevices = false;
633 try {
634 vibrateInputDevices = Settings.System.getIntForUser(
635 mContext.getContentResolver(),
636 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
637 } catch (SettingNotFoundException snfe) {
638 }
639 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
640 changed = true;
641 mVibrateInputDevicesSetting = vibrateInputDevices;
642 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700643
Michael Wright71216972017-01-31 18:33:54 +0000644 if (mVibrateInputDevicesSetting) {
645 if (!mInputDeviceListenerRegistered) {
646 mInputDeviceListenerRegistered = true;
647 mIm.registerInputDeviceListener(this, mH);
648 }
649 } else {
650 if (mInputDeviceListenerRegistered) {
651 mInputDeviceListenerRegistered = false;
652 mIm.unregisterInputDeviceListener(this);
653 }
654 }
Jeff Brown82065252012-04-16 13:19:05 -0700655
Michael Wright71216972017-01-31 18:33:54 +0000656 mInputDeviceVibrators.clear();
657 if (mVibrateInputDevicesSetting) {
658 int[] ids = mIm.getInputDeviceIds();
659 for (int i = 0; i < ids.length; i++) {
660 InputDevice device = mIm.getInputDevice(ids[i]);
661 Vibrator vibrator = device.getVibrator();
662 if (vibrator.hasVibrator()) {
663 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700664 }
665 }
Michael Wright71216972017-01-31 18:33:54 +0000666 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700667 }
Michael Wright71216972017-01-31 18:33:54 +0000668 return changed;
669 }
670
671 private boolean updateLowPowerModeLocked() {
672 boolean lowPowerMode = mPowerManagerInternal
673 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
674 if (lowPowerMode != mLowPowerMode) {
675 mLowPowerMode = lowPowerMode;
676 return true;
677 }
678 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700679 }
680
681 @Override
682 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000683 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700684 }
685
686 @Override
687 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000688 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700689 }
690
691 @Override
692 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000693 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700694 }
695
696 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700697 // For now, we choose to ignore the presence of input devices that have vibrators
698 // when reporting whether the device has a vibrator. Applications often use this
699 // information to decide whether to enable certain features so they expect the
700 // result of hasVibrator() to be constant. For now, just report whether
701 // the device has a built-in vibrator.
702 //synchronized (mInputDeviceVibrators) {
703 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
704 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800705 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700706 }
707
Michael Wright71216972017-01-31 18:33:54 +0000708 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700709 synchronized (mInputDeviceVibrators) {
Michael Wright71216972017-01-31 18:33:54 +0000710 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
711 amplitude = mDefaultVibrationAmplitude;
712 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700713 if (DEBUG) {
Michael Wright71216972017-01-31 18:33:54 +0000714 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
715 " with amplitude " + amplitude + ".");
Jeff Brown82379ba2014-07-25 19:03:28 -0700716 }
Michael Wright71216972017-01-31 18:33:54 +0000717 noteVibratorOnLocked(uid, millis);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700718 final int vibratorCount = mInputDeviceVibrators.size();
719 if (vibratorCount != 0) {
Michael Wright71216972017-01-31 18:33:54 +0000720 final AudioAttributes attributes =
721 new AudioAttributes.Builder().setUsage(usageHint).build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700722 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400723 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700724 }
725 } else {
Michael Wright71216972017-01-31 18:33:54 +0000726 // Note: ordering is important here! Many haptic drivers will reset their amplitude
727 // when enabled, so we always have to enable frst, then set the amplitude.
Jeff Brown7f6c2312012-04-13 20:38:38 -0700728 vibratorOn(millis);
Michael Wright71216972017-01-31 18:33:54 +0000729 doVibratorSetAmplitude(amplitude);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700730 }
731 }
732 }
733
Michael Wright71216972017-01-31 18:33:54 +0000734 private void doVibratorSetAmplitude(int amplitude) {
735 if (mSupportsAmplitudeControl) {
736 vibratorSetAmplitude(amplitude);
737 }
738 }
739
Jeff Brown7f6c2312012-04-13 20:38:38 -0700740 private void doVibratorOff() {
741 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700742 if (DEBUG) {
743 Slog.d(TAG, "Turning vibrator off.");
744 }
Michael Wright71216972017-01-31 18:33:54 +0000745 noteVibratorOffLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700746 final int vibratorCount = mInputDeviceVibrators.size();
747 if (vibratorCount != 0) {
748 for (int i = 0; i < vibratorCount; i++) {
749 mInputDeviceVibrators.get(i).cancel();
750 }
751 } else {
752 vibratorOff();
753 }
754 }
755 }
756
Michael Wright71216972017-01-31 18:33:54 +0000757 private long doVibratorPrebakedEffectLocked(Vibration vib) {
758 synchronized (mInputDeviceVibrators) {
759 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect;
760 // Input devices don't support prebaked effect, so skip trying it with them.
Michael Wright36d873f2018-01-08 15:54:05 +0000761 if (mInputDeviceVibrators.isEmpty()) {
Michael Wright71216972017-01-31 18:33:54 +0000762 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM);
763 if (timeout > 0) {
764 noteVibratorOnLocked(vib.mUid, timeout);
765 return timeout;
766 }
767 }
Michael Wrightdc2b3be2017-08-02 20:44:45 +0100768 if (!prebaked.shouldFallback()) {
769 return 0;
770 }
Michael Wright36d873f2018-01-08 15:54:05 +0000771 VibrationEffect effect = getFallbackEffect(prebaked.getId());
772 if (effect == null) {
Michael Wright71216972017-01-31 18:33:54 +0000773 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
774 return 0;
775 }
Michael Wright71216972017-01-31 18:33:54 +0000776 Vibration fallbackVib =
777 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg);
778 startVibrationInnerLocked(fallbackVib);
779 }
780 return 0;
781 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700782
Michael Wright36d873f2018-01-08 15:54:05 +0000783 private VibrationEffect getFallbackEffect(int effectId) {
784 if (effectId < 0 || effectId >= mFallbackEffects.length) {
785 return null;
786 }
787 return mFallbackEffects[effectId];
788 }
789
Michael Wright71216972017-01-31 18:33:54 +0000790 private void noteVibratorOnLocked(int uid, long millis) {
791 try {
792 mBatteryStatsService.noteVibratorOn(uid, millis);
793 mCurVibUid = uid;
794 } catch (RemoteException e) {
795 }
796 }
797
798 private void noteVibratorOffLocked() {
799 if (mCurVibUid >= 0) {
800 try {
801 mBatteryStatsService.noteVibratorOff(mCurVibUid);
802 } catch (RemoteException e) { }
803 mCurVibUid = -1;
804 }
805 }
806
807 private class VibrateThread extends Thread {
808 private final VibrationEffect.Waveform mWaveform;
809 private final int mUid;
810 private final int mUsageHint;
811
812 private boolean mForceStop;
813
814 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
815 mWaveform = waveform;
816 mUid = uid;
817 mUsageHint = usageHint;
818 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700819 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800820 }
821
Michael Wright71216972017-01-31 18:33:54 +0000822 private long delayLocked(long duration) {
823 long durationRemaining = duration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 if (duration > 0) {
Michael Wright71216972017-01-31 18:33:54 +0000825 final long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800826 do {
827 try {
Michael Wright71216972017-01-31 18:33:54 +0000828 this.wait(durationRemaining);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
Michael Wright71216972017-01-31 18:33:54 +0000830 catch (InterruptedException e) { }
831 if (mForceStop) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 break;
833 }
Michael Wright71216972017-01-31 18:33:54 +0000834 durationRemaining = bedtime - SystemClock.uptimeMillis();
835 } while (durationRemaining > 0);
836 return duration - durationRemaining;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
Michael Wright71216972017-01-31 18:33:54 +0000838 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 }
840
841 public void run() {
842 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +0000843 mWakeLock.acquire();
844 try {
845 boolean finished = playWaveform();
846 if (finished) {
847 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800848 }
Michael Wright71216972017-01-31 18:33:54 +0000849 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800850 mWakeLock.release();
851 }
Michael Wright71216972017-01-31 18:33:54 +0000852 }
853
854 /**
855 * Play the waveform.
856 *
857 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
858 */
859 public boolean playWaveform() {
860 synchronized (this) {
861 final long[] timings = mWaveform.getTimings();
862 final int[] amplitudes = mWaveform.getAmplitudes();
863 final int len = timings.length;
864 final int repeat = mWaveform.getRepeatIndex();
865
866 int index = 0;
867 long onDuration = 0;
868 while (!mForceStop) {
869 if (index < len) {
870 final int amplitude = amplitudes[index];
871 final long duration = timings[index++];
872 if (duration <= 0) {
873 continue;
874 }
875 if (amplitude != 0) {
876 if (onDuration <= 0) {
877 // Telling the vibrator to start multiple times usually causes
878 // effects to feel "choppy" because the motor resets at every on
879 // command. Instead we figure out how long our next "on" period is
880 // going to be, tell the motor to stay on for the full duration,
881 // and then wake up to change the amplitude at the appropriate
882 // intervals.
883 onDuration =
884 getTotalOnDuration(timings, amplitudes, index - 1, repeat);
885 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
886 } else {
887 doVibratorSetAmplitude(amplitude);
888 }
889 }
890
891 long waitTime = delayLocked(duration);
892 if (amplitude != 0) {
893 onDuration -= waitTime;
894 }
895 } else if (repeat < 0) {
896 break;
897 } else {
898 index = repeat;
899 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 }
Michael Wright71216972017-01-31 18:33:54 +0000901 return !mForceStop;
902 }
903 }
904
905 public void cancel() {
906 synchronized (this) {
907 mThread.mForceStop = true;
908 mThread.notify();
909 }
910 }
911
912 /**
913 * Get the duration the vibrator will be on starting at startIndex until the next time it's
914 * off.
915 */
916 private long getTotalOnDuration(
917 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
918 int i = startIndex;
919 long timing = 0;
920 while(amplitudes[i] != 0) {
921 timing += timings[i++];
922 if (i >= timings.length) {
923 if (repeatIndex >= 0) {
924 i = repeatIndex;
925 } else {
926 break;
927 }
928 }
929 if (i == startIndex) {
930 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400931 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 }
Michael Wright71216972017-01-31 18:33:54 +0000933 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
Jeff Brown969579b2014-05-20 19:29:29 -0700935 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800937 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700938 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 public void onReceive(Context context, Intent intent) {
940 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +0000941 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -0700942 // When the system is entering a non-interactive state, we want
943 // to cancel vibrations in case a misbehaving app has abandoned
944 // them. However it may happen that the system is currently playing
945 // haptic feedback as part of the transition. So we don't cancel
946 // system vibrations.
947 if (mCurrentVibration != null
948 && !mCurrentVibration.isSystemHapticFeedback()) {
949 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700950 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400951 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 }
953 }
954 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700955
956 @Override
957 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600958 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700959
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700960 pw.println("Previous vibrations:");
Michael Wright71216972017-01-31 18:33:54 +0000961 synchronized (mLock) {
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700962 for (VibrationInfo info : mPreviousVibrations) {
963 pw.print(" ");
964 pw.println(info.toString());
965 }
966 }
967 }
Felipe Lemea5281002017-02-10 15:13:48 -0800968
969 @Override
970 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
971 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
972 throws RemoteException {
973 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
974 }
975
976 private final class VibratorShellCommand extends ShellCommand {
977
978 private static final long MAX_VIBRATION_MS = 200;
979
980 private final IBinder mToken;
981
982 private VibratorShellCommand(IBinder token) {
983 mToken = token;
984 }
985
986 @Override
987 public int onCommand(String cmd) {
988 if ("vibrate".equals(cmd)) {
989 return runVibrate();
990 }
991 return handleDefaultCommands(cmd);
992 }
993
994 private int runVibrate() {
Felipe Leme5e2e6322017-07-14 17:25:59 -0700995 try {
996 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
997 Settings.Global.ZEN_MODE);
998 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
999 try (PrintWriter pw = getOutPrintWriter();) {
1000 pw.print("Ignoring because device is on DND mode ");
1001 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1002 zenMode));
1003 return 0;
1004 }
1005 }
1006 } catch (SettingNotFoundException e) {
1007 // ignore
1008 }
1009
Felipe Lemea5281002017-02-10 15:13:48 -08001010 final long duration = Long.parseLong(getNextArgRequired());
1011 if (duration > MAX_VIBRATION_MS) {
1012 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
1013 }
1014 String description = getNextArg();
1015 if (description == null) {
1016 description = "Shell command";
1017 }
Michael Wright71216972017-01-31 18:33:54 +00001018
1019 VibrationEffect effect =
1020 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1021 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Felipe Lemea5281002017-02-10 15:13:48 -08001022 mToken);
1023 return 0;
1024 }
1025
1026 @Override
1027 public void onHelp() {
1028 try (PrintWriter pw = getOutPrintWriter();) {
1029 pw.println("Vibrator commands:");
1030 pw.println(" help");
1031 pw.println(" Prints this help text.");
1032 pw.println("");
1033 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001034 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1035 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -08001036 pw.println("");
1037 }
1038 }
1039 }
1040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041}