blob: 5fe6952fbc66dbaba4cd3e162f872e956aa310ea [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;
jackqdyulei455e90a2017-02-09 15:29:16 -080028import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070029import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070030import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050031import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070033import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.Process;
35import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080036import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.IBinder;
38import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080039import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080040import android.os.ShellCallback;
41import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.os.SystemClock;
Jeff Brownd4935962012-09-25 13:27:20 -070043import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070044import android.os.Vibrator;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070045import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070046import android.provider.Settings;
47import android.provider.Settings.SettingNotFoundException;
Joe Onorato8a9b2202010-02-26 18:56:32 -080048import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070049import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040050import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
Dianne Hackborna06de0f2012-12-11 16:34:47 -080052import com.android.internal.app.IAppOpsService;
53import com.android.internal.app.IBatteryStats;
jackqdyulei455e90a2017-02-09 15:29:16 -080054import com.android.server.power.BatterySaverPolicy.ServiceType;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080055
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070056import java.io.FileDescriptor;
57import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070058import java.util.ArrayList;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070059import java.util.Arrays;
Jeff Brown969579b2014-05-20 19:29:29 -070060import java.util.Iterator;
Patrick Scott18dd5f02009-07-02 11:31:12 -040061import java.util.LinkedList;
62import java.util.ListIterator;
63
Jeff Brown7f6c2312012-04-13 20:38:38 -070064public class VibratorService extends IVibratorService.Stub
65 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050066 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070067 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070068 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050069
Patrick Scott18dd5f02009-07-02 11:31:12 -040070 private final LinkedList<Vibration> mVibrations;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070071 private final LinkedList<VibrationInfo> mPreviousVibrations;
72 private final int mPreviousVibrationsLimit;
Patrick Scott18dd5f02009-07-02 11:31:12 -040073 private Vibration mCurrentVibration;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070074 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070075 private final Handler mH = new Handler();
76
77 private final Context mContext;
78 private final PowerManager.WakeLock mWakeLock;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080079 private final IAppOpsService mAppOpsService;
80 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070081 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -070082 private InputManager mIm;
83
84 volatile VibrateThread mThread;
85
86 // mInputDeviceVibrators lock should be acquired after mVibrations lock, if both are
87 // to be acquired
88 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
89 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
90 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
91
Dianne Hackborna06de0f2012-12-11 16:34:47 -080092 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -070093 private boolean mLowPowerMode;
94 private SettingsObserver mSettingObserver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080095
Jeff Brown7f6c2312012-04-13 20:38:38 -070096 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +020097 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -070098 native static void vibratorOn(long milliseconds);
99 native static void vibratorOff();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400100
Patrick Scott18dd5f02009-07-02 11:31:12 -0400101 private class Vibration implements IBinder.DeathRecipient {
102 private final IBinder mToken;
103 private final long mTimeout;
104 private final long mStartTime;
105 private final long[] mPattern;
106 private final int mRepeat;
John Spurlock7b414672014-07-18 13:02:39 -0400107 private final int mUsageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700108 private final int mUid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400109 private final String mOpPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400110
John Spurlock7b414672014-07-18 13:02:39 -0400111 Vibration(IBinder token, long millis, int usageHint, int uid, String opPkg) {
112 this(token, millis, null, 0, usageHint, uid, opPkg);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400113 }
114
John Spurlock7b414672014-07-18 13:02:39 -0400115 Vibration(IBinder token, long[] pattern, int repeat, int usageHint, int uid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400116 String opPkg) {
John Spurlock7b414672014-07-18 13:02:39 -0400117 this(token, 0, pattern, repeat, usageHint, uid, opPkg);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400118 }
119
120 private Vibration(IBinder token, long millis, long[] pattern,
John Spurlock7b414672014-07-18 13:02:39 -0400121 int repeat, int usageHint, int uid, String opPkg) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400122 mToken = token;
123 mTimeout = millis;
124 mStartTime = SystemClock.uptimeMillis();
125 mPattern = pattern;
126 mRepeat = repeat;
John Spurlock7b414672014-07-18 13:02:39 -0400127 mUsageHint = usageHint;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700128 mUid = uid;
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400129 mOpPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400130 }
131
132 public void binderDied() {
133 synchronized (mVibrations) {
134 mVibrations.remove(this);
135 if (this == mCurrentVibration) {
136 doCancelVibrateLocked();
137 startNextVibrationLocked();
138 }
139 }
140 }
141
142 public boolean hasLongerTimeout(long millis) {
143 if (mTimeout == 0) {
144 // This is a pattern, return false to play the simple
145 // vibration.
146 return false;
147 }
148 if ((mStartTime + mTimeout)
149 < (SystemClock.uptimeMillis() + millis)) {
150 // If this vibration will end before the time passed in, let
151 // the new vibration play.
152 return false;
153 }
154 return true;
155 }
Jeff Brown969579b2014-05-20 19:29:29 -0700156
157 public boolean isSystemHapticFeedback() {
Jorim Jaggi18f18ae2015-09-10 15:48:21 -0700158 return (mUid == Process.SYSTEM_UID || mUid == 0 || SYSTEM_UI_PACKAGE.equals(mOpPkg))
159 && mRepeat < 0;
Jeff Brown969579b2014-05-20 19:29:29 -0700160 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400161 }
162
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700163 private static class VibrationInfo {
164 long timeout;
165 long startTime;
166 long[] pattern;
167 int repeat;
168 int usageHint;
169 int uid;
170 String opPkg;
171
172 public VibrationInfo(long timeout, long startTime, long[] pattern, int repeat,
173 int usageHint, int uid, String opPkg) {
174 this.timeout = timeout;
175 this.startTime = startTime;
176 this.pattern = pattern;
177 this.repeat = repeat;
178 this.usageHint = usageHint;
179 this.uid = uid;
180 this.opPkg = opPkg;
181 }
182
183 @Override
184 public String toString() {
185 return new StringBuilder()
186 .append("timeout: ")
187 .append(timeout)
188 .append(", startTime: ")
189 .append(startTime)
190 .append(", pattern: ")
191 .append(Arrays.toString(pattern))
192 .append(", repeat: ")
193 .append(repeat)
194 .append(", usageHint: ")
195 .append(usageHint)
196 .append(", uid: ")
197 .append(uid)
198 .append(", opPkg: ")
199 .append(opPkg)
200 .toString();
201 }
202 }
203
Mike Lockwood3a322132009-11-24 00:30:52 -0500204 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200205 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 // Reset the hardware to a default state, in case this is a runtime
207 // restart instead of a fresh boot.
208 vibratorOff();
209
210 mContext = context;
211 PowerManager pm = (PowerManager)context.getSystemService(
212 Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700213 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 mWakeLock.setReferenceCounted(true);
215
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800216 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700217 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
218 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800219
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700220 mPreviousVibrationsLimit = mContext.getResources().getInteger(
221 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
222
223 mVibrations = new LinkedList<>();
224 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400225
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800226 IntentFilter filter = new IntentFilter();
227 filter.addAction(Intent.ACTION_SCREEN_OFF);
228 context.registerReceiver(mIntentReceiver, filter);
229 }
230
Jeff Brown7f6c2312012-04-13 20:38:38 -0700231 public void systemReady() {
Yohei Yukawa8ce2a532015-11-25 20:35:04 -0800232 mIm = mContext.getSystemService(InputManager.class);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700233 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700234
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700235 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
236 mPowerManagerInternal.registerLowPowerModeObserver(
237 new PowerManagerInternal.LowPowerModeListener() {
jackqdyulei455e90a2017-02-09 15:29:16 -0800238 @Override
239 public int getServiceType() {
240 return ServiceType.VIBRATION;
241 }
242
243 @Override
244 public void onLowPowerModeChanged(PowerSaveState result) {
245 updateInputDeviceVibrators();
246 }
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700247 });
248
Jeff Brown7f6c2312012-04-13 20:38:38 -0700249 mContext.getContentResolver().registerContentObserver(
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700250 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
251 true, mSettingObserver, UserHandle.USER_ALL);
252
Jeff Brownd4935962012-09-25 13:27:20 -0700253 mContext.registerReceiver(new BroadcastReceiver() {
254 @Override
255 public void onReceive(Context context, Intent intent) {
256 updateInputDeviceVibrators();
257 }
258 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
259
Jeff Brown82065252012-04-16 13:19:05 -0700260 updateInputDeviceVibrators();
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700261 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700262
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700263 private final class SettingsObserver extends ContentObserver {
264 public SettingsObserver(Handler handler) {
265 super(handler);
266 }
267
268 @Override
269 public void onChange(boolean SelfChange) {
270 updateInputDeviceVibrators();
271 }
272 }
273
Jeff Brown82379ba2014-07-25 19:03:28 -0700274 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700275 public boolean hasVibrator() {
276 return doVibratorExists();
277 }
278
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800279 private void verifyIncomingUid(int uid) {
280 if (uid == Binder.getCallingUid()) {
281 return;
282 }
283 if (Binder.getCallingPid() == Process.myPid()) {
284 return;
285 }
286 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
287 Binder.getCallingPid(), Binder.getCallingUid(), null);
288 }
289
Jeff Brown82379ba2014-07-25 19:03:28 -0700290 @Override // Binder call
John Spurlock7b414672014-07-18 13:02:39 -0400291 public void vibrate(int uid, String opPkg, long milliseconds, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400292 IBinder token) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700293 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
294 != PackageManager.PERMISSION_GRANTED) {
295 throw new SecurityException("Requires VIBRATE permission");
296 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800297 verifyIncomingUid(uid);
Patrick Scott24f10762009-08-19 09:03:56 -0400298 // We're running in the system server so we cannot crash. Check for a
299 // timeout of 0 or negative. This will ensure that a vibration has
300 // either a timeout of > 0 or a non-null pattern.
301 if (milliseconds <= 0 || (mCurrentVibration != null
302 && mCurrentVibration.hasLongerTimeout(milliseconds))) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400303 // Ignore this vibration since the current vibration will play for
304 // longer than milliseconds.
305 return;
306 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700307
Jeff Brown82379ba2014-07-25 19:03:28 -0700308 if (DEBUG) {
309 Slog.d(TAG, "Vibrating for " + milliseconds + " ms.");
310 }
311
John Spurlock7b414672014-07-18 13:02:39 -0400312 Vibration vib = new Vibration(token, milliseconds, usageHint, uid, opPkg);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800313
314 final long ident = Binder.clearCallingIdentity();
315 try {
316 synchronized (mVibrations) {
317 removeVibrationLocked(token);
318 doCancelVibrateLocked();
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700319 addToPreviousVibrationsLocked(vib);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800320 startVibrationLocked(vib);
321 }
322 } finally {
323 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400324 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800325 }
326
327 private boolean isAll0(long[] pattern) {
328 int N = pattern.length;
329 for (int i = 0; i < N; i++) {
330 if (pattern[i] != 0) {
331 return false;
332 }
333 }
334 return true;
335 }
336
Jeff Brown82379ba2014-07-25 19:03:28 -0700337 @Override // Binder call
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800338 public void vibratePattern(int uid, String packageName, long[] pattern, int repeat,
John Spurlock7b414672014-07-18 13:02:39 -0400339 int usageHint, IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800340 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
341 != PackageManager.PERMISSION_GRANTED) {
342 throw new SecurityException("Requires VIBRATE permission");
343 }
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800344 verifyIncomingUid(uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 // so wakelock calls will succeed
346 long identity = Binder.clearCallingIdentity();
347 try {
Jeff Brown82379ba2014-07-25 19:03:28 -0700348 if (DEBUG) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 String s = "";
350 int N = pattern.length;
351 for (int i=0; i<N; i++) {
352 s += " " + pattern[i];
353 }
Jeff Brown82379ba2014-07-25 19:03:28 -0700354 Slog.d(TAG, "Vibrating with pattern:" + s);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 }
356
357 // we're running in the server so we can't fail
358 if (pattern == null || pattern.length == 0
359 || isAll0(pattern)
360 || repeat >= pattern.length || token == null) {
361 return;
362 }
363
John Spurlock7b414672014-07-18 13:02:39 -0400364 Vibration vib = new Vibration(token, pattern, repeat, usageHint, uid, packageName);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400365 try {
366 token.linkToDeath(vib, 0);
367 } catch (RemoteException e) {
368 return;
369 }
370
371 synchronized (mVibrations) {
372 removeVibrationLocked(token);
373 doCancelVibrateLocked();
374 if (repeat >= 0) {
375 mVibrations.addFirst(vib);
376 startNextVibrationLocked();
377 } else {
378 // A negative repeat means that this pattern is not meant
379 // to repeat. Treat it like a simple vibration.
Patrick Scott18dd5f02009-07-02 11:31:12 -0400380 startVibrationLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 }
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700382 addToPreviousVibrationsLocked(vib);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 }
384 }
385 finally {
386 Binder.restoreCallingIdentity(identity);
387 }
388 }
389
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700390 private void addToPreviousVibrationsLocked(Vibration vib) {
391 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
392 mPreviousVibrations.removeFirst();
393 }
394 mPreviousVibrations.addLast(new VibratorService.VibrationInfo(vib.mTimeout, vib.mStartTime,
395 vib.mPattern, vib.mRepeat, vib.mUsageHint, vib.mUid, vib.mOpPkg));
396 }
397
Jeff Brown82379ba2014-07-25 19:03:28 -0700398 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400399 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 mContext.enforceCallingOrSelfPermission(
401 android.Manifest.permission.VIBRATE,
402 "cancelVibrate");
403
404 // so wakelock calls will succeed
405 long identity = Binder.clearCallingIdentity();
406 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400407 synchronized (mVibrations) {
408 final Vibration vib = removeVibrationLocked(token);
409 if (vib == mCurrentVibration) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700410 if (DEBUG) {
411 Slog.d(TAG, "Canceling vibration.");
412 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400413 doCancelVibrateLocked();
414 startNextVibrationLocked();
415 }
416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
418 finally {
419 Binder.restoreCallingIdentity(identity);
420 }
421 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700422
Patrick Scott18dd5f02009-07-02 11:31:12 -0400423 private final Runnable mVibrationRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700424 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400425 public void run() {
426 synchronized (mVibrations) {
427 doCancelVibrateLocked();
428 startNextVibrationLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800429 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400430 }
431 };
432
433 // Lock held on mVibrations
434 private void doCancelVibrateLocked() {
435 if (mThread != null) {
436 synchronized (mThread) {
437 mThread.mDone = true;
438 mThread.notify();
439 }
440 mThread = null;
441 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700442 doVibratorOff();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400443 mH.removeCallbacks(mVibrationRunnable);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800444 reportFinishVibrationLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400445 }
446
447 // Lock held on mVibrations
448 private void startNextVibrationLocked() {
449 if (mVibrations.size() <= 0) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800450 reportFinishVibrationLocked();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200451 mCurrentVibration = null;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400452 return;
453 }
Julia Reynolds4357e522016-06-01 14:17:58 -0400454 startVibrationLocked(mVibrations.getFirst());
Patrick Scott18dd5f02009-07-02 11:31:12 -0400455 }
456
457 // Lock held on mVibrations
458 private void startVibrationLocked(final Vibration vib) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800459 try {
John Spurlock7b414672014-07-18 13:02:39 -0400460 if (mLowPowerMode
Jean-Michel Trivi89c3b292014-07-20 11:41:02 -0700461 && vib.mUsageHint != AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Ruchi Kandoi664703d2014-05-09 16:01:31 -0700462 return;
463 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700464
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700465 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
466 !shouldVibrateForRingtone()) {
Julia Reynoldsd28967f2016-04-14 09:37:08 -0400467 return;
468 }
469
John Spurlock1af30c72014-03-10 08:33:35 -0400470 int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
John Spurlock7b414672014-07-18 13:02:39 -0400471 vib.mUsageHint, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400472 if (mode == AppOpsManager.MODE_ALLOWED) {
473 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400474 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg);
John Spurlock1af30c72014-03-10 08:33:35 -0400475 }
Julia Reynolds4357e522016-06-01 14:17:58 -0400476 if (mode == AppOpsManager.MODE_ALLOWED) {
477 mCurrentVibration = vib;
478 } else {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800479 if (mode == AppOpsManager.MODE_ERRORED) {
480 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
481 }
482 mH.post(mVibrationRunnable);
483 return;
484 }
485 } catch (RemoteException e) {
486 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400487 if (vib.mTimeout != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400488 doVibratorOn(vib.mTimeout, vib.mUid, vib.mUsageHint);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400489 mH.postDelayed(mVibrationRunnable, vib.mTimeout);
490 } else {
491 // mThread better be null here. doCancelVibrate should always be
492 // called before startNextVibrationLocked or startVibrationLocked.
493 mThread = new VibrateThread(vib);
494 mThread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 }
496 }
497
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700498 private boolean shouldVibrateForRingtone() {
499 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700500 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700501 // "Also vibrate for calls" Setting in Sound
502 if (Settings.System.getInt(
503 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
504 return ringerMode != AudioManager.RINGER_MODE_SILENT;
505 } else {
506 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
507 }
508 }
509
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800510 private void reportFinishVibrationLocked() {
511 if (mCurrentVibration != null) {
512 try {
Dianne Hackborne98f5db2013-07-17 17:23:25 -0700513 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
514 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid,
Christoph Studer8fd7f1e2014-04-11 17:35:05 -0400515 mCurrentVibration.mOpPkg);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800516 } catch (RemoteException e) {
517 }
518 mCurrentVibration = null;
519 }
520 }
521
Patrick Scott18dd5f02009-07-02 11:31:12 -0400522 // Lock held on mVibrations
523 private Vibration removeVibrationLocked(IBinder token) {
524 ListIterator<Vibration> iter = mVibrations.listIterator(0);
525 while (iter.hasNext()) {
526 Vibration vib = iter.next();
527 if (vib.mToken == token) {
528 iter.remove();
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200529 unlinkVibration(vib);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400530 return vib;
531 }
532 }
533 // We might be looking for a simple vibration which is only stored in
534 // mCurrentVibration.
535 if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200536 unlinkVibration(mCurrentVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400537 return mCurrentVibration;
538 }
539 return null;
540 }
541
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200542 private void unlinkVibration(Vibration vib) {
543 if (vib.mPattern != null) {
544 // If Vibration object has a pattern,
545 // the Vibration object has also been linkedToDeath.
546 vib.mToken.unlinkToDeath(vib, 0);
547 }
548 }
549
Jeff Brown7f6c2312012-04-13 20:38:38 -0700550 private void updateInputDeviceVibrators() {
551 synchronized (mVibrations) {
552 doCancelVibrateLocked();
553
554 synchronized (mInputDeviceVibrators) {
Jeff Brown82065252012-04-16 13:19:05 -0700555 mVibrateInputDevicesSetting = false;
556 try {
Jeff Brownd4935962012-09-25 13:27:20 -0700557 mVibrateInputDevicesSetting = Settings.System.getIntForUser(
558 mContext.getContentResolver(),
559 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
Jeff Brown82065252012-04-16 13:19:05 -0700560 } catch (SettingNotFoundException snfe) {
561 }
562
jackqdyulei455e90a2017-02-09 15:29:16 -0800563 mLowPowerMode = mPowerManagerInternal
564 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700565
Jeff Brown82065252012-04-16 13:19:05 -0700566 if (mVibrateInputDevicesSetting) {
567 if (!mInputDeviceListenerRegistered) {
568 mInputDeviceListenerRegistered = true;
569 mIm.registerInputDeviceListener(this, mH);
570 }
571 } else {
572 if (mInputDeviceListenerRegistered) {
573 mInputDeviceListenerRegistered = false;
574 mIm.unregisterInputDeviceListener(this);
575 }
576 }
577
Jeff Brown7f6c2312012-04-13 20:38:38 -0700578 mInputDeviceVibrators.clear();
579 if (mVibrateInputDevicesSetting) {
580 int[] ids = mIm.getInputDeviceIds();
581 for (int i = 0; i < ids.length; i++) {
582 InputDevice device = mIm.getInputDevice(ids[i]);
583 Vibrator vibrator = device.getVibrator();
584 if (vibrator.hasVibrator()) {
585 mInputDeviceVibrators.add(vibrator);
586 }
587 }
588 }
589 }
590
591 startNextVibrationLocked();
592 }
593 }
594
595 @Override
596 public void onInputDeviceAdded(int deviceId) {
597 updateInputDeviceVibrators();
598 }
599
600 @Override
601 public void onInputDeviceChanged(int deviceId) {
602 updateInputDeviceVibrators();
603 }
604
605 @Override
606 public void onInputDeviceRemoved(int deviceId) {
607 updateInputDeviceVibrators();
608 }
609
610 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700611 // For now, we choose to ignore the presence of input devices that have vibrators
612 // when reporting whether the device has a vibrator. Applications often use this
613 // information to decide whether to enable certain features so they expect the
614 // result of hasVibrator() to be constant. For now, just report whether
615 // the device has a built-in vibrator.
616 //synchronized (mInputDeviceVibrators) {
617 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
618 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800619 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700620 }
621
John Spurlock7b414672014-07-18 13:02:39 -0400622 private void doVibratorOn(long millis, int uid, int usageHint) {
Jeff Brown7f6c2312012-04-13 20:38:38 -0700623 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700624 if (DEBUG) {
625 Slog.d(TAG, "Turning vibrator on for " + millis + " ms.");
626 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800627 try {
628 mBatteryStatsService.noteVibratorOn(uid, millis);
629 mCurVibUid = uid;
630 } catch (RemoteException e) {
631 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700632 final int vibratorCount = mInputDeviceVibrators.size();
633 if (vibratorCount != 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400634 final AudioAttributes attributes = new AudioAttributes.Builder().setUsage(usageHint)
635 .build();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700636 for (int i = 0; i < vibratorCount; i++) {
John Spurlock7b414672014-07-18 13:02:39 -0400637 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700638 }
639 } else {
640 vibratorOn(millis);
641 }
642 }
643 }
644
645 private void doVibratorOff() {
646 synchronized (mInputDeviceVibrators) {
Jeff Brown82379ba2014-07-25 19:03:28 -0700647 if (DEBUG) {
648 Slog.d(TAG, "Turning vibrator off.");
649 }
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800650 if (mCurVibUid >= 0) {
651 try {
652 mBatteryStatsService.noteVibratorOff(mCurVibUid);
653 } catch (RemoteException e) {
654 }
655 mCurVibUid = -1;
656 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700657 final int vibratorCount = mInputDeviceVibrators.size();
658 if (vibratorCount != 0) {
659 for (int i = 0; i < vibratorCount; i++) {
660 mInputDeviceVibrators.get(i).cancel();
661 }
662 } else {
663 vibratorOff();
664 }
665 }
666 }
667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 private class VibrateThread extends Thread {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400669 final Vibration mVibration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 boolean mDone;
Eric Olsenf42f15c2009-10-29 16:42:03 -0700671
Patrick Scott18dd5f02009-07-02 11:31:12 -0400672 VibrateThread(Vibration vib) {
673 mVibration = vib;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700674 mTmpWorkSource.set(vib.mUid);
675 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 mWakeLock.acquire();
677 }
678
679 private void delay(long duration) {
680 if (duration > 0) {
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700681 long bedtime = duration + SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 do {
683 try {
684 this.wait(duration);
685 }
686 catch (InterruptedException e) {
687 }
688 if (mDone) {
689 break;
690 }
Vairavan Srinivasane4c56d92011-03-31 13:32:54 -0700691 duration = bedtime - SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 } while (duration > 0);
693 }
694 }
695
696 public void run() {
697 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
698 synchronized (this) {
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800699 final long[] pattern = mVibration.mPattern;
700 final int len = pattern.length;
701 final int repeat = mVibration.mRepeat;
702 final int uid = mVibration.mUid;
John Spurlock7b414672014-07-18 13:02:39 -0400703 final int usageHint = mVibration.mUsageHint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 int index = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 long duration = 0;
706
707 while (!mDone) {
Eric Olsenf42f15c2009-10-29 16:42:03 -0700708 // add off-time duration to any accumulated on-time duration
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 if (index < len) {
710 duration += pattern[index++];
711 }
712
713 // sleep until it is time to start the vibrator
714 delay(duration);
715 if (mDone) {
716 break;
717 }
718
719 if (index < len) {
720 // read on-time duration and start the vibrator
721 // duration is saved for delay() at top of loop
722 duration = pattern[index++];
723 if (duration > 0) {
John Spurlock7b414672014-07-18 13:02:39 -0400724 VibratorService.this.doVibratorOn(duration, uid, usageHint);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800725 }
726 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400727 if (repeat < 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 break;
729 } else {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400730 index = repeat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 duration = 0;
732 }
733 }
734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 mWakeLock.release();
736 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400737 synchronized (mVibrations) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 if (mThread == this) {
739 mThread = null;
740 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400741 if (!mDone) {
742 // If this vibration finished naturally, start the next
743 // vibration.
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200744 unlinkVibration(mVibration);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400745 startNextVibrationLocked();
746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 }
748 }
Jeff Brown969579b2014-05-20 19:29:29 -0700749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -0700752 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 public void onReceive(Context context, Intent intent) {
754 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400755 synchronized (mVibrations) {
Jeff Brown969579b2014-05-20 19:29:29 -0700756 // When the system is entering a non-interactive state, we want
757 // to cancel vibrations in case a misbehaving app has abandoned
758 // them. However it may happen that the system is currently playing
759 // haptic feedback as part of the transition. So we don't cancel
760 // system vibrations.
761 if (mCurrentVibration != null
762 && !mCurrentVibration.isSystemHapticFeedback()) {
763 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -0700764 }
765
Jeff Brown969579b2014-05-20 19:29:29 -0700766 // Clear all remaining vibrations.
767 Iterator<Vibration> it = mVibrations.iterator();
768 while (it.hasNext()) {
769 Vibration vibration = it.next();
770 if (vibration != mCurrentVibration) {
771 unlinkVibration(vibration);
772 it.remove();
773 }
774 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777 }
778 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700779
780 @Override
781 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
782 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
783 != PackageManager.PERMISSION_GRANTED) {
784
785 pw.println("Permission Denial: can't dump vibrator service from from pid="
786 + Binder.getCallingPid()
787 + ", uid=" + Binder.getCallingUid());
788 return;
789 }
790 pw.println("Previous vibrations:");
791 synchronized (mVibrations) {
792 for (VibrationInfo info : mPreviousVibrations) {
793 pw.print(" ");
794 pw.println(info.toString());
795 }
796 }
797 }
Felipe Lemea5281002017-02-10 15:13:48 -0800798
799 @Override
800 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
801 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
802 throws RemoteException {
803 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
804 }
805
806 private final class VibratorShellCommand extends ShellCommand {
807
808 private static final long MAX_VIBRATION_MS = 200;
809
810 private final IBinder mToken;
811
812 private VibratorShellCommand(IBinder token) {
813 mToken = token;
814 }
815
816 @Override
817 public int onCommand(String cmd) {
818 if ("vibrate".equals(cmd)) {
819 return runVibrate();
820 }
821 return handleDefaultCommands(cmd);
822 }
823
824 private int runVibrate() {
825 final long duration = Long.parseLong(getNextArgRequired());
826 if (duration > MAX_VIBRATION_MS) {
827 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
828 }
829 String description = getNextArg();
830 if (description == null) {
831 description = "Shell command";
832 }
833 vibrate(Binder.getCallingUid(), description, duration, AudioAttributes.USAGE_UNKNOWN,
834 mToken);
835 return 0;
836 }
837
838 @Override
839 public void onHelp() {
840 try (PrintWriter pw = getOutPrintWriter();) {
841 pw.println("Vibrator commands:");
842 pw.println(" help");
843 pw.println(" Prints this help text.");
844 pw.println("");
845 pw.println(" vibrate duration [description]");
846 pw.println(" Vibrates for duration milliseconds.");
847 pw.println("");
848 }
849 }
850 }
851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852}