blob: ab036c7163d322b0d4852f8a875a04a03cc939c2 [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();
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700309 addToPreviousVibrationsLocked(vib);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800310 startVibrationLocked(vib);
311 }
312 } finally {
313 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 private boolean isAll0(long[] pattern) {
318 int N = pattern.length;
319 for (int i = 0; i < N; i++) {
320 if (pattern[i] != 0) {
321 return false;
322 }
323 }
324 return true;
325 }
326
Jeff Brown82379ba2014-07-25 19:03:28 -0700327 @Override // Binder call
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800328 public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
John Spurlock7b414672014-07-18 13:02:39 -0400329 int usageHint, IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
331 != PackageManager.PERMISSION_GRANTED) {
332 throw new SecurityException("Requires VIBRATE permission");
333 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800334 verifyIncomingUid(uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 // so wakelock calls will succeed
336 long identity = Binder.clearCallingIdentity();
337 try {
Jeff Brown82379ba2014-07-25 19:03:28 -0700338 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 String s = "";
340 int N = pattern.length;
341 for (int i=0; i<N; i++) {
342 s += " " + pattern[i];
343 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700344 Slog.d(TAG, "Vibrating with pattern:" + s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 }
346
347 // we're running in the server so we can't fail
348 if (pattern == null || pattern.length == 0
349 || isAll0(pattern)
350 || repeat >= pattern.length || token == null) {
351 return;
352 }
353
John Spurlock7b414672014-07-18 13:02:39 -0400354 Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400355 try {
356 token.linkToDeath(vib, 0);
357 } catch (RemoteException e) {
358 return;
359 }
360
361 synchronized (mVibrations) {
362 removeVibrationLocked(token);
363 doCancelVibrateLocked();
364 if (repeat >= 0) {
365 mVibrations.addFirst(vib);
366 startNextVibrationLocked();
367 } else {
368 // A negative repeat means that this pattern is not meant
369 // to repeat. Treat it like a simple vibration.
Patrick Scott18dd5f02009-07-02 11:31:12 -0400370 startVibrationLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 }
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700372 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
374 }
375 finally {
376 Binder.restoreCallingIdentity(identity);
377 }
378 }
379
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700380 private void addToPreviousVibrationsLocked(Vibration vib) {
381 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
382 mPreviousVibrations.removeFirst();
383 }
384 mPreviousVibrations.addLast(new VibratorService.VibrationInfo(vib.mTimeout, vib.mStartTime,
385 vib.mPattern, vib.mRepeat, vib.mUsageHint, vib.mUid, vib.mOpPkg));
386 }
387
Jeff Brown82379ba2014-07-25 19:03:28 -0700388 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400389 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 mContext.enforceCallingOrSelfPermission(
391 android.Manifest.permission.VIBRATE,
392 "cancelVibrate");
393
394 // so wakelock calls will succeed
395 long identity = Binder.clearCallingIdentity();
396 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400397 synchronized (mVibrations) {
398 final Vibration vib = removeVibrationLocked(token);
399 if (vib == mCurrentVibration) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700400 if (DEBUG) {
401 Slog.d(TAG, "Canceling vibration.");
402 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400403 doCancelVibrateLocked();
404 startNextVibrationLocked();
405 }
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
408 finally {
409 Binder.restoreCallingIdentity(identity);
410 }
411 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700412
Patrick Scott18dd5f02009-07-02 11:31:12 -0400413 private final Runnable mVibrationRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700414 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400415 public void run() {
416 synchronized (mVibrations) {
417 doCancelVibrateLocked();
418 startNextVibrationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400420 }
421 };
422
423 // Lock held on mVibrations
424 private void doCancelVibrateLocked() {
425 if (mThread != null) {
426 synchronized (mThread) {
427 mThread.mDone = true;
428 mThread.notify();
429 }
430 mThread = null;
431 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700432 doVibratorOff();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400433 mH.removeCallbacks(mVibrationRunnable);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800434 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400435 }
436
437 // Lock held on mVibrations
438 private void startNextVibrationLocked() {
439 if (mVibrations.size() <= 0) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800440 reportFinishVibrationLocked();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200441 mCurrentVibration = null;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400442 return;
443 }
Julia Reynolds4357e522016-06-01 14:17:58 -0400444 startVibrationLocked(mVibrations.getFirst());
Patrick Scott18dd5f02009-07-02 11:31:12 -0400445 }
446
447 // Lock held on mVibrations
448 private void startVibrationLocked(final Vibration vib) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800449 try {
John Spurlock7b414672014-07-18 13:02:39 -0400450 if (mLowPowerMode
Jean-Michel Trivi89c3b292014-07-20 11:41:02 -0700451 && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700452 return;
453 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700454
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700455 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
456 !shouldVibrateForRingtone()) {
Julia Reynoldsd28967f2016-04-14 09:37:08 -0400457 return;
458 }
459
John Spurlock1af30c72014-03-10 08:33:35 -0400460 int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
John Spurlock7b414672014-07-18 13:02:39 -0400461 vib.mUsageHint, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400462 if (mode == AppOpsManager.MODE_ALLOWED) {
463 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400464 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400465 }
Julia Reynolds4357e522016-06-01 14:17:58 -0400466 if (mode == AppOpsManager.MODE_ALLOWED) {
467 mCurrentVibration = vib;
468 } else {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800469 if (mode == AppOpsManager.MODE_ERRORED) {
470 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
471 }
472 mH.post(mVibrationRunnable);
473 return;
474 }
475 } catch (RemoteException e) {
476 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400477 if (vib.mTimeout != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400478 doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400479 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
480 } else {
481 // mThread better be null here. doCancelVibrate should always be
482 // called before startNextVibrationLocked or startVibrationLocked.
483 mThread = new VibrateThread(vib);
484 mThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
486 }
487
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700488 private boolean shouldVibrateForRingtone() {
489 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700490 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700491 // "Also vibrate for calls" Setting in Sound
492 if (Settings.System.getInt(
493 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
494 return ringerMode != AudioManager.RINGER_MODE_SILENT;
495 } else {
496 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
497 }
498 }
499
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800500 private void reportFinishVibrationLocked() {
501 if (mCurrentVibration != null) {
502 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700503 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
504 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400505 mCurrentVibration.mOpPkg);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800506 } catch (RemoteException e) {
507 }
508 mCurrentVibration = null;
509 }
510 }
511
Patrick Scott18dd5f02009-07-02 11:31:12 -0400512 // Lock held on mVibrations
513 private Vibration removeVibrationLocked(IBinder token) {
514 ListIterator<Vibration> iter = mVibrations.listIterator(0);
515 while (iter.hasNext()) {
516 Vibration vib = iter.next();
517 if (vib.mToken == token) {
518 iter.remove();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200519 unlinkVibration(vib);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400520 return vib;
521 }
522 }
523 // We might be looking for a simple vibration which is only stored in
524 // mCurrentVibration.
525 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200526 unlinkVibration(mCurrentVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400527 return mCurrentVibration;
528 }
529 return null;
530 }
531
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200532 private void unlinkVibration(Vibration vib) {
533 if (vib.mPattern != null) {
534 // If Vibration object has a pattern,
535 // the Vibration object has also been linkedToDeath.
536 vib.mToken.unlinkToDeath(vib, 0);
537 }
538 }
539
Jeff Brown7f6c2312012-04-13 20:38:38 -0700540 private void updateInputDeviceVibrators() {
541 synchronized (mVibrations) {
542 doCancelVibrateLocked();
543
544 synchronized (mInputDeviceVibrators) {
Jeff Brown82065252012-04-16 13:19:05 -0700545 mVibrateInputDevicesSetting = false;
546 try {
Jeff Brownd4935962012-09-25 13:27:20 -0700547 mVibrateInputDevicesSetting = Settings.System.getIntForUser(
548 mContext.getContentResolver(),
549 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
Jeff Brown82065252012-04-16 13:19:05 -0700550 } catch (SettingNotFoundException snfe) {
551 }
552
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700553 mLowPowerMode = mPowerManagerInternal.getLowPowerModeEnabled();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700554
Jeff Brown82065252012-04-16 13:19:05 -0700555 if (mVibrateInputDevicesSetting) {
556 if (!mInputDeviceListenerRegistered) {
557 mInputDeviceListenerRegistered = true;
558 mIm.registerInputDeviceListener(this, mH);
559 }
560 } else {
561 if (mInputDeviceListenerRegistered) {
562 mInputDeviceListenerRegistered = false;
563 mIm.unregisterInputDeviceListener(this);
564 }
565 }
566
Jeff Brown7f6c2312012-04-13 20:38:38 -0700567 mInputDeviceVibrators.clear();
568 if (mVibrateInputDevicesSetting) {
569 int[] ids = mIm.getInputDeviceIds();
570 for (int i = 0; i < ids.length; i++) {
571 InputDevice device = mIm.getInputDevice(ids[i]);
572 Vibrator vibrator = device.getVibrator();
573 if (vibrator.hasVibrator()) {
574 mInputDeviceVibrators.add(vibrator);
575 }
576 }
577 }
578 }
579
580 startNextVibrationLocked();
581 }
582 }
583
584 @Override
585 public void onInputDeviceAdded(int deviceId) {
586 updateInputDeviceVibrators();
587 }
588
589 @Override
590 public void onInputDeviceChanged(int deviceId) {
591 updateInputDeviceVibrators();
592 }
593
594 @Override
595 public void onInputDeviceRemoved(int deviceId) {
596 updateInputDeviceVibrators();
597 }
598
599 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700600 // For now, we choose to ignore the presence of input devices that have vibrators
601 // when reporting whether the device has a vibrator. Applications often use this
602 // information to decide whether to enable certain features so they expect the
603 // result of hasVibrator() to be constant. For now, just report whether
604 // the device has a built-in vibrator.
605 //synchronized (mInputDeviceVibrators) {
606 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
607 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800608 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700609 }
610
John Spurlock7b414672014-07-18 13:02:39 -0400611 private void doVibratorOn(long millis, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700612 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700613 if (DEBUG) {
614 Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
615 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800616 try {
617 mBatteryStatsService.noteVibratorOn(uid, millis);
618 mCurVibUid = uid;
619 } catch (RemoteException e) {
620 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700621 final int vibratorCount = mInputDeviceVibrators.size();
622 if (vibratorCount != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400623 final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
624 .build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700625 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400626 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700627 }
628 } else {
629 vibratorOn(millis);
630 }
631 }
632 }
633
634 private void doVibratorOff() {
635 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700636 if (DEBUG) {
637 Slog.d(TAG, "Turning vibrator off.");
638 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800639 if (mCurVibUid >= 0) {
640 try {
641 mBatteryStatsService.noteVibratorOff(mCurVibUid);
642 } catch (RemoteException e) {
643 }
644 mCurVibUid = -1;
645 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700646 final int vibratorCount = mInputDeviceVibrators.size();
647 if (vibratorCount != 0) {
648 for (int i = 0; i < vibratorCount; i++) {
649 mInputDeviceVibrators.get(i).cancel();
650 }
651 } else {
652 vibratorOff();
653 }
654 }
655 }
656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 private class VibrateThread extends Thread {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400658 final Vibration mVibration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 boolean mDone;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700660
Patrick Scott18dd5f02009-07-02 11:31:12 -0400661 VibrateThread(Vibration vib) {
662 mVibration = vib;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700663 mTmpWorkSource.set(vib.mUid);
664 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 mWakeLock.acquire();
666 }
667
668 private void delay(long duration) {
669 if (duration > 0) {
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700670 long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 do {
672 try {
673 this.wait(duration);
674 }
675 catch (InterruptedException e) {
676 }
677 if (mDone) {
678 break;
679 }
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700680 duration = bedtime - SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 } while (duration > 0);
682 }
683 }
684
685 public void run() {
686 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
687 synchronized (this) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800688 final long[] pattern = mVibration.mPattern;
689 final int len = pattern.length;
690 final int repeat = mVibration.mRepeat;
691 final int uid = mVibration.mUid;
John Spurlock7b414672014-07-18 13:02:39 -0400692 final int usageHint = mVibration.mUsageHint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 int index = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800694 long duration = 0;
695
696 while (!mDone) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700697 // add off-time duration to any accumulated on-time duration
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 if (index < len) {
699 duration += pattern[index++];
700 }
701
702 // sleep until it is time to start the vibrator
703 delay(duration);
704 if (mDone) {
705 break;
706 }
707
708 if (index < len) {
709 // read on-time duration and start the vibrator
710 // duration is saved for delay() at top of loop
711 duration = pattern[index++];
712 if (duration > 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400713 VibratorService.this.doVibratorOn(duration, uid, usageHint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
715 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400716 if (repeat < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 break;
718 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400719 index = repeat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 duration = 0;
721 }
722 }
723 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 mWakeLock.release();
725 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400726 synchronized (mVibrations) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 if (mThread == this) {
728 mThread = null;
729 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400730 if (!mDone) {
731 // If this vibration finished naturally, start the next
732 // vibration.
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200733 unlinkVibration(mVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400734 startNextVibrationLocked();
735 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 }
737 }
Jeff Brown969579b2014-05-20 19:29:29 -0700738 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700741 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 public void onReceive(Context context, Intent intent) {
743 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400744 synchronized (mVibrations) {
Jeff Brown969579b2014-05-20 19:29:29 -0700745 // When the system is entering a non-interactive state, we want
746 // to cancel vibrations in case a misbehaving app has abandoned
747 // them. However it may happen that the system is currently playing
748 // haptic feedback as part of the transition. So we don't cancel
749 // system vibrations.
750 if (mCurrentVibration != null
751 && !mCurrentVibration.isSystemHapticFeedback()) {
752 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700753 }
754
Jeff Brown969579b2014-05-20 19:29:29 -0700755 // Clear all remaining vibrations.
756 Iterator<Vibration> it = mVibrations.iterator();
757 while (it.hasNext()) {
758 Vibration vibration = it.next();
759 if (vibration != mCurrentVibration) {
760 unlinkVibration(vibration);
761 it.remove();
762 }
763 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400764 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 }
766 }
767 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700768
769 @Override
770 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
771 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
772 != PackageManager.PERMISSION_GRANTED) {
773
774 pw.println("Permission Denial: can't dump vibrator service from from pid="
775 + Binder.getCallingPid()
776 + ", uid=" + Binder.getCallingUid());
777 return;
778 }
779 pw.println("Previous vibrations:");
780 synchronized (mVibrations) {
781 for (VibrationInfo info : mPreviousVibrations) {
782 pw.print(" ");
783 pw.println(info.toString());
784 }
785 }
786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787}