blob: 4db60d536bdd5d0916cdde7ab72db8f3d23cab25 [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;
Jeff Brown7f6c2312012-04-13 20:38:38 -070025import android.database.ContentObserver;
26import android.hardware.input.InputManager;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070027import android.media.AudioManager;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070028import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070029import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050030import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070032import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.Process;
34import android.os.RemoteException;
35import android.os.IBinder;
36import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080037import android.os.ServiceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070039import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070040import android.os.Vibrator;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070041import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070042import android.provider.Settings;
43import android.provider.Settings.SettingNotFoundException;
Joe Onorato8a9b2202010-02-26 18:56:32 -080044import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070045import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040046import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
Dianne Hackborna06de0f2012-12-11 16:34:47 -080048import com.android.internal.app.IAppOpsService;
49import com.android.internal.app.IBatteryStats;
50
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070051import java.io.FileDescriptor;
52import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070053import java.util.ArrayList;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070054import java.util.Arrays;
Jeff Brown969579b2014-05-20 19:29:29 -070055import java.util.Iterator;
Patrick Scott18dd5f02009-07-02 11:31:12 -040056import java.util.LinkedList;
57import java.util.ListIterator;
58
Jeff Brown7f6c2312012-04-13 20:38:38 -070059public class VibratorService extends IVibratorService.Stub
60 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050061 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070062 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070063 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050064
Patrick Scott18dd5f02009-07-02 11:31:12 -040065 private final LinkedList<Vibration> mVibrations;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070066 private final LinkedList<VibrationInfo> mPreviousVibrations;
67 private final int mPreviousVibrationsLimit;
Patrick Scott18dd5f02009-07-02 11:31:12 -040068 private Vibration mCurrentVibration;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070069 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070070 private final Handler mH = new Handler();
71
72 private final Context mContext;
73 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080074 private final IAppOpsService mAppOpsService;
75 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070076 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070077 private InputManager mIm;
78
79 volatile VibrateThread mThread;
80
81 // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
82 // to be acquired
83 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
84 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
85 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
86
Dianne Hackborna06de0f2012-12-11 16:34:47 -080087 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -070088 private boolean mLowPowerMode;
89 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080090
Jeff Brown7f6c2312012-04-13 20:38:38 -070091 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +020092 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -070093 native static void vibratorOn(long milliseconds);
94 native static void vibratorOff();
Patrick Scott18dd5f02009-07-02 11:31:12 -040095
Patrick Scott18dd5f02009-07-02 11:31:12 -040096 private class Vibration implements IBinder.DeathRecipient {
97 private final IBinder mToken;
98 private final long mTimeout;
99 private final long mStartTime;
100 private final long[] mPattern;
101 private final int mRepeat;
John Spurlock7b414672014-07-18 13:02:39 -0400102 private final int mUsageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700103 private final int mUid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400104 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400105
John Spurlock7b414672014-07-18 13:02:39 -0400106 Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg) {
107 this(token, millis, null, 0, usageHint, uid, opPkg);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400108 }
109
John Spurlock7b414672014-07-18 13:02:39 -0400110 Vibration(IBinder token, long[] pattern, int repeat, int usageHint, int uid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400111 String opPkg) {
John Spurlock7b414672014-07-18 13:02:39 -0400112 this(token, 0, pattern, repeat, usageHint, uid, opPkg);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400113 }
114
115 private Vibration(IBinder token, long millis, long[] pattern,
John Spurlock7b414672014-07-18 13:02:39 -0400116 int repeat, int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400117 mToken = token;
118 mTimeout = millis;
119 mStartTime = SystemClock.uptimeMillis();
120 mPattern = pattern;
121 mRepeat = repeat;
John Spurlock7b414672014-07-18 13:02:39 -0400122 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700123 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400124 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400125 }
126
127 public void binderDied() {
128 synchronized (mVibrations) {
129 mVibrations.remove(this);
130 if (this == mCurrentVibration) {
131 doCancelVibrateLocked();
132 startNextVibrationLocked();
133 }
134 }
135 }
136
137 public boolean hasLongerTimeout(long millis) {
138 if (mTimeout == 0) {
139 // This is a pattern, return false to play the simple
140 // vibration.
141 return false;
142 }
143 if ((mStartTime + mTimeout)
144 < (SystemClock.uptimeMillis() + millis)) {
145 // If this vibration will end before the time passed in, let
146 // the new vibration play.
147 return false;
148 }
149 return true;
150 }
Jeff Brown969579b2014-05-20 19:29:29 -0700151
152 public boolean isSystemHapticFeedback() {
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700153 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
154 && mRepeat < 0;
Jeff Brown969579b2014-05-20 19:29:29 -0700155 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400156 }
157
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700158 private static class VibrationInfo {
159 long timeout;
160 long startTime;
161 long[] pattern;
162 int repeat;
163 int usageHint;
164 int uid;
165 String opPkg;
166
167 public VibrationInfo(long timeout, long startTime, long[] pattern, int repeat,
168 int usageHint, int uid, String opPkg) {
169 this.timeout = timeout;
170 this.startTime = startTime;
171 this.pattern = pattern;
172 this.repeat = repeat;
173 this.usageHint = usageHint;
174 this.uid = uid;
175 this.opPkg = opPkg;
176 }
177
178 @Override
179 public String toString() {
180 return new StringBuilder()
181 .append("timeout: ")
182 .append(timeout)
183 .append(", startTime: ")
184 .append(startTime)
185 .append(", pattern: ")
186 .append(Arrays.toString(pattern))
187 .append(", repeat: ")
188 .append(repeat)
189 .append(", usageHint: ")
190 .append(usageHint)
191 .append(", uid: ")
192 .append(uid)
193 .append(", opPkg: ")
194 .append(opPkg)
195 .toString();
196 }
197 }
198
Mike Lockwood3a322132009-11-24 00:30:52 -0500199 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200200 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 // Reset the hardware to a default state, in case this is a runtime
202 // restart instead of a fresh boot.
203 vibratorOff();
204
205 mContext = context;
206 PowerManager pm = (PowerManager)context.getSystemService(
207 Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700208 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 mWakeLock.setReferenceCounted(true);
210
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800211 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700212 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
213 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800214
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700215 mPreviousVibrationsLimit = mContext.getResources().getInteger(
216 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
217
218 mVibrations = new LinkedList<>();
219 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 IntentFilter filter = new IntentFilter();
222 filter.addAction(Intent.ACTION_SCREEN_OFF);
223 context.registerReceiver(mIntentReceiver, filter);
224 }
225
Jeff Brown7f6c2312012-04-13 20:38:38 -0700226 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800227 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700228 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700229
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700230 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
231 mPowerManagerInternal.registerLowPowerModeObserver(
232 new PowerManagerInternal.LowPowerModeListener() {
233 @Override
234 public void onLowPowerModeChanged(boolean enabled) {
235 updateInputDeviceVibrators();
236 }
237 });
238
Jeff Brown7f6c2312012-04-13 20:38:38 -0700239 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700240 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
241 true, mSettingObserver, UserHandle.USER_ALL);
242
Jeff Brownd4935962012-09-25 13:27:20 -0700243 mContext.registerReceiver(new BroadcastReceiver() {
244 @Override
245 public void onReceive(Context context, Intent intent) {
246 updateInputDeviceVibrators();
247 }
248 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
249
Jeff Brown82065252012-04-16 13:19:05 -0700250 updateInputDeviceVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700251 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700252
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700253 private final class SettingsObserver extends ContentObserver {
254 public SettingsObserver(Handler handler) {
255 super(handler);
256 }
257
258 @Override
259 public void onChange(boolean SelfChange) {
260 updateInputDeviceVibrators();
261 }
262 }
263
Jeff Brown82379ba2014-07-25 19:03:28 -0700264 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700265 public boolean hasVibrator() {
266 return doVibratorExists();
267 }
268
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800269 private void verifyIncomingUid(int uid) {
270 if (uid == Binder.getCallingUid()) {
271 return;
272 }
273 if (Binder.getCallingPid() == Process.myPid()) {
274 return;
275 }
276 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
277 Binder.getCallingPid(), Binder.getCallingUid(), null);
278 }
279
Jeff Brown82379ba2014-07-25 19:03:28 -0700280 @Override // Binder call
John Spurlock7b414672014-07-18 13:02:39 -0400281 public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400282 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700283 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
284 != PackageManager.PERMISSION_GRANTED) {
285 throw new SecurityException("Requires VIBRATE permission");
286 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800287 verifyIncomingUid(uid);
Patrick Scott24f10762009-08-19 09:03:56 -0400288 // We're running in the system server so we cannot crash. Check for a
289 // timeout of 0 or negative. This will ensure that a vibration has
290 // either a timeout of > 0 or a non-null pattern.
291 if (milliseconds <= 0 || (mCurrentVibration != null
292 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400293 // Ignore this vibration since the current vibration will play for
294 // longer than milliseconds.
295 return;
296 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700297
Jeff Brown82379ba2014-07-25 19:03:28 -0700298 if (DEBUG) {
299 Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
300 }
301
John Spurlock7b414672014-07-18 13:02:39 -0400302 Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800303
304 final long ident = Binder.clearCallingIdentity();
305 try {
306 synchronized (mVibrations) {
307 removeVibrationLocked(token);
308 doCancelVibrateLocked();
309 mCurrentVibration = vib;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700310 addToPreviousVibrationsLocked(vib);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800311 startVibrationLocked(vib);
312 }
313 } finally {
314 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
317
318 private boolean isAll0(long[] pattern) {
319 int N = pattern.length;
320 for (int i = 0; i < N; i++) {
321 if (pattern[i] != 0) {
322 return false;
323 }
324 }
325 return true;
326 }
327
Jeff Brown82379ba2014-07-25 19:03:28 -0700328 @Override // Binder call
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800329 public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
John Spurlock7b414672014-07-18 13:02:39 -0400330 int usageHint, IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
332 != PackageManager.PERMISSION_GRANTED) {
333 throw new SecurityException("Requires VIBRATE permission");
334 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800335 verifyIncomingUid(uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 // so wakelock calls will succeed
337 long identity = Binder.clearCallingIdentity();
338 try {
Jeff Brown82379ba2014-07-25 19:03:28 -0700339 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 String s = "";
341 int N = pattern.length;
342 for (int i=0; i<N; i++) {
343 s += " " + pattern[i];
344 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700345 Slog.d(TAG, "Vibrating with pattern:" + s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 }
347
348 // we're running in the server so we can't fail
349 if (pattern == null || pattern.length == 0
350 || isAll0(pattern)
351 || repeat >= pattern.length || token == null) {
352 return;
353 }
354
John Spurlock7b414672014-07-18 13:02:39 -0400355 Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400356 try {
357 token.linkToDeath(vib, 0);
358 } catch (RemoteException e) {
359 return;
360 }
361
362 synchronized (mVibrations) {
363 removeVibrationLocked(token);
364 doCancelVibrateLocked();
365 if (repeat >= 0) {
366 mVibrations.addFirst(vib);
367 startNextVibrationLocked();
368 } else {
369 // A negative repeat means that this pattern is not meant
370 // to repeat. Treat it like a simple vibration.
371 mCurrentVibration = vib;
372 startVibrationLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700374 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 }
376 }
377 finally {
378 Binder.restoreCallingIdentity(identity);
379 }
380 }
381
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700382 private void addToPreviousVibrationsLocked(Vibration vib) {
383 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
384 mPreviousVibrations.removeFirst();
385 }
386 mPreviousVibrations.addLast(new VibratorService.VibrationInfo(vib.mTimeout, vib.mStartTime,
387 vib.mPattern, vib.mRepeat, vib.mUsageHint, vib.mUid, vib.mOpPkg));
388 }
389
Jeff Brown82379ba2014-07-25 19:03:28 -0700390 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400391 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 mContext.enforceCallingOrSelfPermission(
393 android.Manifest.permission.VIBRATE,
394 "cancelVibrate");
395
396 // so wakelock calls will succeed
397 long identity = Binder.clearCallingIdentity();
398 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400399 synchronized (mVibrations) {
400 final Vibration vib = removeVibrationLocked(token);
401 if (vib == mCurrentVibration) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700402 if (DEBUG) {
403 Slog.d(TAG, "Canceling vibration.");
404 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400405 doCancelVibrateLocked();
406 startNextVibrationLocked();
407 }
408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 }
410 finally {
411 Binder.restoreCallingIdentity(identity);
412 }
413 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700414
Patrick Scott18dd5f02009-07-02 11:31:12 -0400415 private final Runnable mVibrationRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700416 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400417 public void run() {
418 synchronized (mVibrations) {
419 doCancelVibrateLocked();
420 startNextVibrationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400422 }
423 };
424
425 // Lock held on mVibrations
426 private void doCancelVibrateLocked() {
427 if (mThread != null) {
428 synchronized (mThread) {
429 mThread.mDone = true;
430 mThread.notify();
431 }
432 mThread = null;
433 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700434 doVibratorOff();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400435 mH.removeCallbacks(mVibrationRunnable);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800436 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400437 }
438
439 // Lock held on mVibrations
440 private void startNextVibrationLocked() {
441 if (mVibrations.size() <= 0) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800442 reportFinishVibrationLocked();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200443 mCurrentVibration = null;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400444 return;
445 }
446 mCurrentVibration = mVibrations.getFirst();
447 startVibrationLocked(mCurrentVibration);
448 }
449
450 // Lock held on mVibrations
451 private void startVibrationLocked(final Vibration vib) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800452 try {
John Spurlock7b414672014-07-18 13:02:39 -0400453 if (mLowPowerMode
Jean-Michel Trivi89c3b292014-07-20 11:41:02 -0700454 && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700455 return;
456 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700457
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700458 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
459 !shouldVibrateForRingtone()) {
Julia Reynoldsd28967f2016-04-14 09:37:08 -0400460 return;
461 }
462
John Spurlock1af30c72014-03-10 08:33:35 -0400463 int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
John Spurlock7b414672014-07-18 13:02:39 -0400464 vib.mUsageHint, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400465 if (mode == AppOpsManager.MODE_ALLOWED) {
466 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400467 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400468 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800469 if (mode != AppOpsManager.MODE_ALLOWED) {
470 if (mode == AppOpsManager.MODE_ERRORED) {
471 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
472 }
473 mH.post(mVibrationRunnable);
474 return;
475 }
476 } catch (RemoteException e) {
477 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400478 if (vib.mTimeout != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400479 doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400480 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
481 } else {
482 // mThread better be null here. doCancelVibrate should always be
483 // called before startNextVibrationLocked or startVibrationLocked.
484 mThread = new VibrateThread(vib);
485 mThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
487 }
488
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700489 private boolean shouldVibrateForRingtone() {
490 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
491 int ringerMode = audioManager.getRingerMode();
492 // "Also vibrate for calls" Setting in Sound
493 if (Settings.System.getInt(
494 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
495 return ringerMode != AudioManager.RINGER_MODE_SILENT;
496 } else {
497 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
498 }
499 }
500
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800501 private void reportFinishVibrationLocked() {
502 if (mCurrentVibration != null) {
503 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700504 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
505 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400506 mCurrentVibration.mOpPkg);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800507 } catch (RemoteException e) {
508 }
509 mCurrentVibration = null;
510 }
511 }
512
Patrick Scott18dd5f02009-07-02 11:31:12 -0400513 // Lock held on mVibrations
514 private Vibration removeVibrationLocked(IBinder token) {
515 ListIterator<Vibration> iter = mVibrations.listIterator(0);
516 while (iter.hasNext()) {
517 Vibration vib = iter.next();
518 if (vib.mToken == token) {
519 iter.remove();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200520 unlinkVibration(vib);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400521 return vib;
522 }
523 }
524 // We might be looking for a simple vibration which is only stored in
525 // mCurrentVibration.
526 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200527 unlinkVibration(mCurrentVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400528 return mCurrentVibration;
529 }
530 return null;
531 }
532
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200533 private void unlinkVibration(Vibration vib) {
534 if (vib.mPattern != null) {
535 // If Vibration object has a pattern,
536 // the Vibration object has also been linkedToDeath.
537 vib.mToken.unlinkToDeath(vib, 0);
538 }
539 }
540
Jeff Brown7f6c2312012-04-13 20:38:38 -0700541 private void updateInputDeviceVibrators() {
542 synchronized (mVibrations) {
543 doCancelVibrateLocked();
544
545 synchronized (mInputDeviceVibrators) {
Jeff Brown82065252012-04-16 13:19:05 -0700546 mVibrateInputDevicesSetting = false;
547 try {
Jeff Brownd4935962012-09-25 13:27:20 -0700548 mVibrateInputDevicesSetting = Settings.System.getIntForUser(
549 mContext.getContentResolver(),
550 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
Jeff Brown82065252012-04-16 13:19:05 -0700551 } catch (SettingNotFoundException snfe) {
552 }
553
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700554 mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700555
Jeff Brown82065252012-04-16 13:19:05 -0700556 if (mVibrateInputDevicesSetting) {
557 if (!mInputDeviceListenerRegistered) {
558 mInputDeviceListenerRegistered = true;
559 mIm.registerInputDeviceListener(this, mH);
560 }
561 } else {
562 if (mInputDeviceListenerRegistered) {
563 mInputDeviceListenerRegistered = false;
564 mIm.unregisterInputDeviceListener(this);
565 }
566 }
567
Jeff Brown7f6c2312012-04-13 20:38:38 -0700568 mInputDeviceVibrators.clear();
569 if (mVibrateInputDevicesSetting) {
570 int[] ids = mIm.getInputDeviceIds();
571 for (int i = 0; i < ids.length; i++) {
572 InputDevice device = mIm.getInputDevice(ids[i]);
573 Vibrator vibrator = device.getVibrator();
574 if (vibrator.hasVibrator()) {
575 mInputDeviceVibrators.add(vibrator);
576 }
577 }
578 }
579 }
580
581 startNextVibrationLocked();
582 }
583 }
584
585 @Override
586 public void onInputDeviceAdded(int deviceId) {
587 updateInputDeviceVibrators();
588 }
589
590 @Override
591 public void onInputDeviceChanged(int deviceId) {
592 updateInputDeviceVibrators();
593 }
594
595 @Override
596 public void onInputDeviceRemoved(int deviceId) {
597 updateInputDeviceVibrators();
598 }
599
600 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700601 // For now, we choose to ignore the presence of input devices that have vibrators
602 // when reporting whether the device has a vibrator. Applications often use this
603 // information to decide whether to enable certain features so they expect the
604 // result of hasVibrator() to be constant. For now, just report whether
605 // the device has a built-in vibrator.
606 //synchronized (mInputDeviceVibrators) {
607 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
608 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800609 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700610 }
611
John Spurlock7b414672014-07-18 13:02:39 -0400612 private void doVibratorOn(long millis, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700613 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700614 if (DEBUG) {
615 Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
616 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800617 try {
618 mBatteryStatsService.noteVibratorOn(uid, millis);
619 mCurVibUid = uid;
620 } catch (RemoteException e) {
621 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700622 final int vibratorCount = mInputDeviceVibrators.size();
623 if (vibratorCount != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400624 final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
625 .build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700626 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400627 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700628 }
629 } else {
630 vibratorOn(millis);
631 }
632 }
633 }
634
635 private void doVibratorOff() {
636 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700637 if (DEBUG) {
638 Slog.d(TAG, "Turning vibrator off.");
639 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800640 if (mCurVibUid >= 0) {
641 try {
642 mBatteryStatsService.noteVibratorOff(mCurVibUid);
643 } catch (RemoteException e) {
644 }
645 mCurVibUid = -1;
646 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700647 final int vibratorCount = mInputDeviceVibrators.size();
648 if (vibratorCount != 0) {
649 for (int i = 0; i < vibratorCount; i++) {
650 mInputDeviceVibrators.get(i).cancel();
651 }
652 } else {
653 vibratorOff();
654 }
655 }
656 }
657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 private class VibrateThread extends Thread {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400659 final Vibration mVibration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 boolean mDone;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700661
Patrick Scott18dd5f02009-07-02 11:31:12 -0400662 VibrateThread(Vibration vib) {
663 mVibration = vib;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700664 mTmpWorkSource.set(vib.mUid);
665 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 mWakeLock.acquire();
667 }
668
669 private void delay(long duration) {
670 if (duration > 0) {
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700671 long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 do {
673 try {
674 this.wait(duration);
675 }
676 catch (InterruptedException e) {
677 }
678 if (mDone) {
679 break;
680 }
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700681 duration = bedtime - SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 } while (duration > 0);
683 }
684 }
685
686 public void run() {
687 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
688 synchronized (this) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800689 final long[] pattern = mVibration.mPattern;
690 final int len = pattern.length;
691 final int repeat = mVibration.mRepeat;
692 final int uid = mVibration.mUid;
John Spurlock7b414672014-07-18 13:02:39 -0400693 final int usageHint = mVibration.mUsageHint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 int index = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 long duration = 0;
696
697 while (!mDone) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700698 // add off-time duration to any accumulated on-time duration
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 if (index < len) {
700 duration += pattern[index++];
701 }
702
703 // sleep until it is time to start the vibrator
704 delay(duration);
705 if (mDone) {
706 break;
707 }
708
709 if (index < len) {
710 // read on-time duration and start the vibrator
711 // duration is saved for delay() at top of loop
712 duration = pattern[index++];
713 if (duration > 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400714 VibratorService.this.doVibratorOn(duration, uid, usageHint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
716 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400717 if (repeat < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 break;
719 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400720 index = repeat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800721 duration = 0;
722 }
723 }
724 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 mWakeLock.release();
726 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400727 synchronized (mVibrations) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 if (mThread == this) {
729 mThread = null;
730 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400731 if (!mDone) {
732 // If this vibration finished naturally, start the next
733 // vibration.
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200734 unlinkVibration(mVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400735 startNextVibrationLocked();
736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800737 }
738 }
Jeff Brown969579b2014-05-20 19:29:29 -0700739 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700742 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 public void onReceive(Context context, Intent intent) {
744 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400745 synchronized (mVibrations) {
Jeff Brown969579b2014-05-20 19:29:29 -0700746 // When the system is entering a non-interactive state, we want
747 // to cancel vibrations in case a misbehaving app has abandoned
748 // them. However it may happen that the system is currently playing
749 // haptic feedback as part of the transition. So we don't cancel
750 // system vibrations.
751 if (mCurrentVibration != null
752 && !mCurrentVibration.isSystemHapticFeedback()) {
753 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700754 }
755
Jeff Brown969579b2014-05-20 19:29:29 -0700756 // Clear all remaining vibrations.
757 Iterator<Vibration> it = mVibrations.iterator();
758 while (it.hasNext()) {
759 Vibration vibration = it.next();
760 if (vibration != mCurrentVibration) {
761 unlinkVibration(vibration);
762 it.remove();
763 }
764 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400765 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
767 }
768 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700769
770 @Override
771 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
772 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
773 != PackageManager.PERMISSION_GRANTED) {
774
775 pw.println("Permission Denial: can't dump vibrator service from from pid="
776 + Binder.getCallingPid()
777 + ", uid=" + Binder.getCallingUid());
778 return;
779 }
780 pw.println("Previous vibrations:");
781 synchronized (mVibrations) {
782 for (VibrationInfo info : mPreviousVibrations) {
783 pw.print(" ");
784 pw.println(info.toString());
785 }
786 }
787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788}