blob: 752c44a6f59b92ae002239dfa958955dbf03cf1c [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
Michael Wright71216972017-01-31 18:33:54 +000025import android.content.res.Resources;
Jeff Brown7f6c2312012-04-13 20:38:38 -070026import android.database.ContentObserver;
27import android.hardware.input.InputManager;
Michael Wrightf268bf52018-02-07 23:23:34 +000028import android.hardware.vibrator.V1_0.EffectStrength;
Michael Wright36d873f2018-01-08 15:54:05 +000029import android.icu.text.DateFormat;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070030import android.media.AudioManager;
Makoto Onuki2eccd022017-11-01 13:44:23 -070031import android.os.PowerManager.ServiceType;
jackqdyulei455e90a2017-02-09 15:29:16 -080032import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070033import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070034import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050035import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070037import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Process;
39import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080040import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.IBinder;
42import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080044import android.os.ShellCallback;
45import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.SystemClock;
Alexey Kuzmine59145a2018-02-10 15:19:03 +000047import android.os.Trace;
Jeff Brownd4935962012-09-25 13:27:20 -070048import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070049import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000050import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070051import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070052import android.provider.Settings;
53import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070054import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080055import android.util.Slog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070056import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040057import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +000059import com.android.internal.annotations.GuardedBy;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080060import com.android.internal.app.IAppOpsService;
61import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060062import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080063
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070064import java.io.FileDescriptor;
65import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070066import java.util.ArrayList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040067import java.util.LinkedList;
Michael Wright36d873f2018-01-08 15:54:05 +000068import java.util.Date;
Patrick Scott18dd5f02009-07-02 11:31:12 -040069
Jeff Brown7f6c2312012-04-13 20:38:38 -070070public class VibratorService extends IVibratorService.Stub
71 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050072 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070073 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070074 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050075
Michael Wright36d873f2018-01-08 15:54:05 +000076 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
77
Michael Wright35a0c672018-01-24 00:32:53 +000078 private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f;
79 private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f;
80 private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f;
81 private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f;
82
83 private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255
84 private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255
85
86 // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
87 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
88
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070089 private final LinkedList<VibrationInfo> mPreviousVibrations;
90 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -070091 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +000092 private final boolean mSupportsAmplitudeControl;
93 private final int mDefaultVibrationAmplitude;
94 private final VibrationEffect[] mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070095 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -070096 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +000097 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -070098
99 private final Context mContext;
100 private final PowerManager.WakeLock mWakeLock;
Svet Ganovf7b47252018-02-26 11:11:27 -0800101 private final AppOpsManager mAppOps;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800102 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700103 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700104 private InputManager mIm;
Michael Wright35a0c672018-01-24 00:32:53 +0000105 private Vibrator mVibrator;
106 private SettingsObserver mSettingObserver;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700107
Michael Wright71216972017-01-31 18:33:54 +0000108 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700109
Michael Wright71216972017-01-31 18:33:54 +0000110 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -0700111 // to be acquired
112 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
113 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
114 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
115
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000116 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000117 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800118 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700119 private boolean mLowPowerMode;
Michael Wright35a0c672018-01-24 00:32:53 +0000120 private int mHapticFeedbackIntensity;
121 private int mNotificationIntensity;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800122
Jeff Brown7f6c2312012-04-13 20:38:38 -0700123 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200124 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700125 native static void vibratorOn(long milliseconds);
126 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000127 native static boolean vibratorSupportsAmplitudeControl();
128 native static void vibratorSetAmplitude(int amplitude);
129 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400130
Patrick Scott18dd5f02009-07-02 11:31:12 -0400131 private class Vibration implements IBinder.DeathRecipient {
Michael Wright35a0c672018-01-24 00:32:53 +0000132 public final IBinder token;
Michael Wright36d873f2018-01-08 15:54:05 +0000133 // Start time in CLOCK_BOOTTIME base.
Michael Wright35a0c672018-01-24 00:32:53 +0000134 public final long startTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000135 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
Michael Wright35a0c672018-01-24 00:32:53 +0000136 // with other system events, any duration calculations should be done use startTime so as
Michael Wright36d873f2018-01-08 15:54:05 +0000137 // not to be affected by discontinuities created by RTC adjustments.
Michael Wright35a0c672018-01-24 00:32:53 +0000138 public final long startTimeDebug;
139 public final int usageHint;
140 public final int uid;
141 public final String opPkg;
142
143 // The actual effect to be played.
144 public VibrationEffect effect;
145 // The original effect that was requested. This is non-null only when the original effect
146 // differs from the effect that's being played. Typically these two things differ because
147 // the effect was scaled based on the users vibration intensity settings.
148 public VibrationEffect originalEffect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400149
Michael Wright71216972017-01-31 18:33:54 +0000150 private Vibration(IBinder token, VibrationEffect effect,
151 int usageHint, int uid, String opPkg) {
Michael Wright35a0c672018-01-24 00:32:53 +0000152 this.token = token;
153 this.effect = effect;
154 this.startTime = SystemClock.elapsedRealtime();
155 this.startTimeDebug = System.currentTimeMillis();
156 this.usageHint = usageHint;
157 this.uid = uid;
158 this.opPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400159 }
160
161 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000162 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400163 if (this == mCurrentVibration) {
164 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400165 }
166 }
167 }
168
Michael Wright35a0c672018-01-24 00:32:53 +0000169 public boolean hasTimeoutLongerThan(long millis) {
170 final long duration = effect.getDuration();
171 return duration >= 0 && duration > millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400172 }
Jeff Brown969579b2014-05-20 19:29:29 -0700173
Michael Wright35a0c672018-01-24 00:32:53 +0000174 public boolean isHapticFeedback() {
175 if (effect instanceof VibrationEffect.Prebaked) {
176 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
177 switch (prebaked.getId()) {
178 case VibrationEffect.EFFECT_CLICK:
179 case VibrationEffect.EFFECT_DOUBLE_CLICK:
180 case VibrationEffect.EFFECT_TICK:
181 return true;
182 default:
183 Slog.w(TAG, "Unknown prebaked vibration effect, "
184 + "assuming it isn't haptic feedback.");
185 return false;
186 }
Michael Wright71216972017-01-31 18:33:54 +0000187 }
Michael Wright35a0c672018-01-24 00:32:53 +0000188 final long duration = effect.getDuration();
189 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
190 }
191
192 public boolean isNotification() {
193 switch (usageHint) {
194 case AudioAttributes.USAGE_NOTIFICATION:
195 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
196 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
197 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
198 return true;
199 default:
200 return false;
201 }
202 }
203
204 public boolean isRingtone() {
205 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
206 }
207
208 public boolean isFromSystem() {
209 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
Jeff Brown969579b2014-05-20 19:29:29 -0700210 }
Michael Wright36d873f2018-01-08 15:54:05 +0000211
212 public VibrationInfo toInfo() {
Michael Wright35a0c672018-01-24 00:32:53 +0000213 return new VibrationInfo(
214 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg);
Michael Wright36d873f2018-01-08 15:54:05 +0000215 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400216 }
217
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700218 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000219 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000220 private final VibrationEffect mEffect;
Michael Wright35a0c672018-01-24 00:32:53 +0000221 private final VibrationEffect mOriginalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000222 private final int mUsageHint;
223 private final int mUid;
224 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700225
Michael Wright36d873f2018-01-08 15:54:05 +0000226 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Michael Wright35a0c672018-01-24 00:32:53 +0000227 VibrationEffect originalEffect, int usageHint, int uid, String opPkg) {
Michael Wright36d873f2018-01-08 15:54:05 +0000228 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000229 mEffect = effect;
Michael Wright35a0c672018-01-24 00:32:53 +0000230 mOriginalEffect = originalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000231 mUsageHint = usageHint;
232 mUid = uid;
233 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700234 }
235
236 @Override
237 public String toString() {
238 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000239 .append("startTime: ")
240 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000241 .append(", effect: ")
242 .append(mEffect)
Michael Wright35a0c672018-01-24 00:32:53 +0000243 .append(", originalEffect: ")
244 .append(mOriginalEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700245 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000246 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700247 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000248 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700249 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000250 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700251 .toString();
252 }
253 }
254
Mike Lockwood3a322132009-11-24 00:30:52 -0500255 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200256 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 // Reset the hardware to a default state, in case this is a runtime
258 // restart instead of a fresh boot.
259 vibratorOff();
260
Michael Wright71216972017-01-31 18:33:54 +0000261 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000264 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700265 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 mWakeLock.setReferenceCounted(true);
267
Svet Ganovf7b47252018-02-26 11:11:27 -0800268 mAppOps = mContext.getSystemService(AppOpsManager.class);
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700269 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
270 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800271
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700272 mPreviousVibrationsLimit = mContext.getResources().getInteger(
273 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
274
Michael Wright71216972017-01-31 18:33:54 +0000275 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
276 com.android.internal.R.integer.config_defaultVibrationAmplitude);
277
Tyler Freeman319a34a2017-05-04 17:23:35 -0700278 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
279 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
280
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700281 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 IntentFilter filter = new IntentFilter();
284 filter.addAction(Intent.ACTION_SCREEN_OFF);
285 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000286
287 long[] clickEffectTimings = getLongIntArray(context.getResources(),
288 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright57d94d92017-05-31 14:44:45 +0100289 VibrationEffect clickEffect = createEffect(clickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000290 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000291 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wright57d94d92017-05-31 14:44:45 +0100292 long[] tickEffectTimings = getLongIntArray(context.getResources(),
293 com.android.internal.R.array.config_clockTickVibePattern);
294 VibrationEffect tickEffect = createEffect(tickEffectTimings);
Michael Wright71216972017-01-31 18:33:54 +0000295
Michael Wright57d94d92017-05-31 14:44:45 +0100296 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect };
297 }
298
299 private static VibrationEffect createEffect(long[] timings) {
300 if (timings == null || timings.length == 0) {
301 return null;
302 } else if (timings.length == 1) {
303 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
304 } else {
305 return VibrationEffect.createWaveform(timings, -1);
306 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 }
308
Jeff Brown7f6c2312012-04-13 20:38:38 -0700309 public void systemReady() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000310 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
311 try {
312 mIm = mContext.getSystemService(InputManager.class);
313 mVibrator = mContext.getSystemService(Vibrator.class);
314 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700315
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000316 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
317 mPowerManagerInternal.registerLowPowerModeObserver(
318 new PowerManagerInternal.LowPowerModeListener() {
319 @Override
320 public int getServiceType() {
321 return ServiceType.VIBRATION;
322 }
jackqdyulei455e90a2017-02-09 15:29:16 -0800323
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000324 @Override
325 public void onLowPowerModeChanged(PowerSaveState result) {
326 updateVibrators();
327 }
328 });
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700329
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000330 mContext.getContentResolver().registerContentObserver(
331 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
332 true, mSettingObserver, UserHandle.USER_ALL);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700333
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000334 mContext.getContentResolver().registerContentObserver(
335 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
336 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000337
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000338 mContext.getContentResolver().registerContentObserver(
339 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
340 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000341
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000342 mContext.registerReceiver(new BroadcastReceiver() {
343 @Override
344 public void onReceive(Context context, Intent intent) {
345 updateVibrators();
346 }
347 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700348
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000349 updateVibrators();
350 } finally {
351 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
352 }
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700353 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700354
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700355 private final class SettingsObserver extends ContentObserver {
356 public SettingsObserver(Handler handler) {
357 super(handler);
358 }
359
360 @Override
361 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000362 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700363 }
364 }
365
Jeff Brown82379ba2014-07-25 19:03:28 -0700366 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700367 public boolean hasVibrator() {
368 return doVibratorExists();
369 }
370
Michael Wright71216972017-01-31 18:33:54 +0000371 @Override // Binder call
372 public boolean hasAmplitudeControl() {
373 synchronized (mInputDeviceVibrators) {
374 // Input device vibrators don't support amplitude controls yet, but are still used over
375 // the system vibrator when connected.
376 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
377 }
378 }
379
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800380 private void verifyIncomingUid(int uid) {
381 if (uid == Binder.getCallingUid()) {
382 return;
383 }
384 if (Binder.getCallingPid() == Process.myPid()) {
385 return;
386 }
387 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
388 Binder.getCallingPid(), Binder.getCallingUid(), null);
389 }
390
Michael Wright71216972017-01-31 18:33:54 +0000391 /**
392 * Validate the incoming VibrationEffect.
393 *
394 * We can't throw exceptions here since we might be called from some system_server component,
395 * which would bring the whole system down.
396 *
397 * @return whether the VibrationEffect is valid
398 */
399 private static boolean verifyVibrationEffect(VibrationEffect effect) {
400 if (effect == null) {
401 // Effect must not be null.
402 Slog.wtf(TAG, "effect must not be null");
403 return false;
404 }
405 try {
406 effect.validate();
407 } catch (Exception e) {
408 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
409 return false;
410 }
411 return true;
412 }
413
414 private static long[] getLongIntArray(Resources r, int resid) {
415 int[] ar = r.getIntArray(resid);
416 if (ar == null) {
417 return null;
418 }
419 long[] out = new long[ar.length];
420 for (int i = 0; i < ar.length; i++) {
421 out[i] = ar[i];
422 }
423 return out;
424 }
425
Jeff Brown82379ba2014-07-25 19:03:28 -0700426 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000427 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400428 IBinder token) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000429 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate");
430 try {
431 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
432 != PackageManager.PERMISSION_GRANTED) {
433 throw new SecurityException("Requires VIBRATE permission");
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000434 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000435 if (token == null) {
436 Slog.e(TAG, "token must not be null");
437 return;
438 }
439 verifyIncomingUid(uid);
440 if (!verifyVibrationEffect(effect)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 return;
442 }
443
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000444 // If our current vibration is longer than the new vibration and is the same amplitude,
445 // then just let the current one finish.
446 synchronized (mLock) {
447 if (effect instanceof VibrationEffect.OneShot
448 && mCurrentVibration != null
449 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
450 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
451 VibrationEffect.OneShot currentOneShot =
452 (VibrationEffect.OneShot) mCurrentVibration.effect;
453 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
454 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
455 if (DEBUG) {
456 Slog.d(TAG,
457 "Ignoring incoming vibration in favor of current vibration");
458 }
459 return;
460 }
461 }
462
463 // If the current vibration is repeating and the incoming one is non-repeating,
464 // then ignore the non-repeating vibration. This is so that we don't cancel
465 // vibrations that are meant to grab the attention of the user, like ringtones and
466 // alarms, in favor of one-shot vibrations that are likely quite short.
467 if (!isRepeatingVibration(effect)
468 && mCurrentVibration != null
469 && isRepeatingVibration(mCurrentVibration.effect)) {
470 if (DEBUG) {
471 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
472 }
473 return;
474 }
475
476 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
477 linkVibration(vib);
478 long ident = Binder.clearCallingIdentity();
479 try {
480 doCancelVibrateLocked();
481 startVibrationLocked(vib);
482 addToPreviousVibrationsLocked(vib);
483 } finally {
484 Binder.restoreCallingIdentity(ident);
485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000487 } finally {
488 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 }
491
Michael Wright58c46312017-10-05 14:04:14 -0400492 private static boolean isRepeatingVibration(VibrationEffect effect) {
Michael Wright35a0c672018-01-24 00:32:53 +0000493 return effect.getDuration() == Long.MAX_VALUE;
Michael Wright58c46312017-10-05 14:04:14 -0400494 }
495
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700496 private void addToPreviousVibrationsLocked(Vibration vib) {
497 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
498 mPreviousVibrations.removeFirst();
499 }
Michael Wright36d873f2018-01-08 15:54:05 +0000500 mPreviousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700501 }
502
Jeff Brown82379ba2014-07-25 19:03:28 -0700503 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400504 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 mContext.enforceCallingOrSelfPermission(
506 android.Manifest.permission.VIBRATE,
507 "cancelVibrate");
508
Michael Wright71216972017-01-31 18:33:54 +0000509 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +0000510 if (mCurrentVibration != null && mCurrentVibration.token == token) {
Michael Wright71216972017-01-31 18:33:54 +0000511 if (DEBUG) {
512 Slog.d(TAG, "Canceling vibration.");
513 }
514 long ident = Binder.clearCallingIdentity();
515 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400516 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000517 } finally {
518 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400519 }
520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800521 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800522 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700523
Michael Wright71216972017-01-31 18:33:54 +0000524 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700525 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400526 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000527 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400528 }
529 };
530
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000531 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400532 private void doCancelVibrateLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000533 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
534 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
535 try {
536 mH.removeCallbacks(mVibrationEndRunnable);
537 if (mThread != null) {
538 mThread.cancel();
539 mThread = null;
540 }
541 doVibratorOff();
542 reportFinishVibrationLocked();
543 } finally {
544 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400545 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400546 }
547
Michael Wright71216972017-01-31 18:33:54 +0000548 // Callback for whenever the current vibration has finished played out
549 public void onVibrationFinished() {
550 if (DEBUG) {
551 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400552 }
Michael Wright71216972017-01-31 18:33:54 +0000553 synchronized (mLock) {
554 // Make sure the vibration is really done. This also reports that the vibration is
555 // finished.
556 doCancelVibrateLocked();
557 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400558 }
559
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000560 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400561 private void startVibrationLocked(final Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000562 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
563 try {
564 if (!isAllowedToVibrateLocked(vib)) {
565 return;
Michael Wright71216972017-01-31 18:33:54 +0000566 }
Michael Wright71216972017-01-31 18:33:54 +0000567
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000568 final int intensity = getCurrentIntensityLocked(vib);
569 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
570 return;
Michael Wright71216972017-01-31 18:33:54 +0000571 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000572
573 if (vib.isRingtone() && !shouldVibrateForRingtone()) {
574 if (DEBUG) {
575 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
576 }
577 return;
578 }
579
580 final int mode = getAppOpMode(vib);
581 if (mode != AppOpsManager.MODE_ALLOWED) {
582 if (mode == AppOpsManager.MODE_ERRORED) {
583 // We might be getting calls from within system_server, so we don't actually
584 // want to throw a SecurityException here.
585 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
586 }
587 return;
588 }
589 applyVibrationIntensityScalingLocked(vib, intensity);
590 startVibrationInnerLocked(vib);
591 } finally {
592 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +0000593 }
Michael Wright71216972017-01-31 18:33:54 +0000594 }
595
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000596 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000597 private void startVibrationInnerLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000598 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
599 try {
600 mCurrentVibration = vib;
601 if (vib.effect instanceof VibrationEffect.OneShot) {
602 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
603 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
604 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
605 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
606 } else if (vib.effect instanceof VibrationEffect.Waveform) {
607 // mThread better be null here. doCancelVibrate should always be
608 // called before startNextVibrationLocked or startVibrationLocked.
609 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
610 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
611 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
612 mThread.start();
613 } else if (vib.effect instanceof VibrationEffect.Prebaked) {
614 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
615 long timeout = doVibratorPrebakedEffectLocked(vib);
616 if (timeout > 0) {
617 mH.postDelayed(mVibrationEndRunnable, timeout);
618 }
619 } else {
620 Slog.e(TAG, "Unknown vibration type, ignoring");
Michael Wright71216972017-01-31 18:33:54 +0000621 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000622 } finally {
623 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 }
625 }
626
Michael Wright35a0c672018-01-24 00:32:53 +0000627 private boolean isAllowedToVibrateLocked(Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700628 if (!mLowPowerMode) {
629 return true;
630 }
Michael Wright35a0c672018-01-24 00:32:53 +0000631
632 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700633 return true;
634 }
Tyler Freeman319a34a2017-05-04 17:23:35 -0700635
Michael Wright35a0c672018-01-24 00:32:53 +0000636 if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
637 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
638 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700639 return true;
640 }
641
642 return false;
643 }
644
Michael Wright35a0c672018-01-24 00:32:53 +0000645 private int getCurrentIntensityLocked(Vibration vib) {
646 if (vib.isNotification() || vib.isRingtone()){
647 return mNotificationIntensity;
648 } else if (vib.isHapticFeedback()) {
649 return mHapticFeedbackIntensity;
650 } else {
651 return Vibrator.VIBRATION_INTENSITY_MEDIUM;
652 }
653 }
654
655 /**
656 * Scale the vibration effect by the intensity as appropriate based its intent.
657 */
658 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
659 if (vib.effect instanceof VibrationEffect.Prebaked) {
660 // Prebaked effects are always just a direct translation from intensity to
661 // EffectStrength.
662 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
663 prebaked.setEffectStrength(intensityToEffectStrength(intensity));
664 return;
665 }
666
667 final float gamma;
668 final int maxAmplitude;
669 if (vib.isNotification() || vib.isRingtone()) {
670 if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
671 gamma = GAMMA_SCALE_FACTOR_MINIMUM;
672 maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY;
673 } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) {
674 gamma = GAMMA_SCALE_FACTOR_LOW;
675 maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
676 } else {
677 gamma = GAMMA_SCALE_FACTOR_NONE;
678 maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
679 }
680 } else {
681 if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
682 gamma = GAMMA_SCALE_FACTOR_LOW;
683 maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
684 } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) {
685 gamma = GAMMA_SCALE_FACTOR_HIGH;
686 maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
687 } else {
688 gamma = GAMMA_SCALE_FACTOR_NONE;
689 maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
690 }
691 }
692
693 VibrationEffect scaledEffect = null;
694 if (vib.effect instanceof VibrationEffect.OneShot) {
695 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
696 scaledEffect = oneShot.scale(gamma, maxAmplitude);
697 } else if (vib.effect instanceof VibrationEffect.Waveform) {
698 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
699 scaledEffect = waveform.scale(gamma, maxAmplitude);
700 } else {
701 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
702 }
703
704 if (scaledEffect != null) {
705 vib.originalEffect = vib.effect;
706 vib.effect = scaledEffect;
707 }
708 }
709
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700710 private boolean shouldVibrateForRingtone() {
Michael Wright35a0c672018-01-24 00:32:53 +0000711 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700712 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700713 // "Also vibrate for calls" Setting in Sound
714 if (Settings.System.getInt(
715 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
716 return ringerMode != AudioManager.RINGER_MODE_SILENT;
717 } else {
718 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
719 }
720 }
721
Michael Wright71216972017-01-31 18:33:54 +0000722 private int getAppOpMode(Vibration vib) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800723 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
724 vib.usageHint, vib.uid, vib.opPkg);
725 if (mode == AppOpsManager.MODE_ALLOWED) {
726 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
Michael Wright71216972017-01-31 18:33:54 +0000727 }
728 return mode;
729 }
730
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000731 @GuardedBy("mLock")
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800732 private void reportFinishVibrationLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000733 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
734 try {
735 if (mCurrentVibration != null) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800736 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
737 mCurrentVibration.opPkg);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000738 unlinkVibration(mCurrentVibration);
739 mCurrentVibration = null;
740 }
741 } finally {
742 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800743 }
744 }
745
Michael Wright36d873f2018-01-08 15:54:05 +0000746 private void linkVibration(Vibration vib) {
747 // Only link against waveforms since they potentially don't have a finish if
748 // they're repeating. Let other effects just play out until they're done.
Michael Wright35a0c672018-01-24 00:32:53 +0000749 if (vib.effect instanceof VibrationEffect.Waveform) {
Michael Wright36d873f2018-01-08 15:54:05 +0000750 try {
Michael Wright35a0c672018-01-24 00:32:53 +0000751 vib.token.linkToDeath(vib, 0);
Michael Wright36d873f2018-01-08 15:54:05 +0000752 } catch (RemoteException e) {
753 return;
754 }
755 }
756 }
757
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200758 private void unlinkVibration(Vibration vib) {
Michael Wright35a0c672018-01-24 00:32:53 +0000759 if (vib.effect instanceof VibrationEffect.Waveform) {
760 vib.token.unlinkToDeath(vib, 0);
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200761 }
762 }
763
Michael Wright71216972017-01-31 18:33:54 +0000764 private void updateVibrators() {
765 synchronized (mLock) {
766 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
767 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Michael Wright35a0c672018-01-24 00:32:53 +0000768 updateVibrationIntensityLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700769
Michael Wright71216972017-01-31 18:33:54 +0000770 if (devicesUpdated || lowPowerModeUpdated) {
771 // If the state changes out from under us then just reset.
772 doCancelVibrateLocked();
773 }
774 }
775 }
Jeff Brown82065252012-04-16 13:19:05 -0700776
Michael Wright71216972017-01-31 18:33:54 +0000777 private boolean updateInputDeviceVibratorsLocked() {
778 boolean changed = false;
779 boolean vibrateInputDevices = false;
780 try {
781 vibrateInputDevices = Settings.System.getIntForUser(
782 mContext.getContentResolver(),
783 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
784 } catch (SettingNotFoundException snfe) {
785 }
786 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
787 changed = true;
788 mVibrateInputDevicesSetting = vibrateInputDevices;
789 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700790
Michael Wright71216972017-01-31 18:33:54 +0000791 if (mVibrateInputDevicesSetting) {
792 if (!mInputDeviceListenerRegistered) {
793 mInputDeviceListenerRegistered = true;
794 mIm.registerInputDeviceListener(this, mH);
795 }
796 } else {
797 if (mInputDeviceListenerRegistered) {
798 mInputDeviceListenerRegistered = false;
799 mIm.unregisterInputDeviceListener(this);
800 }
801 }
Jeff Brown82065252012-04-16 13:19:05 -0700802
Michael Wright71216972017-01-31 18:33:54 +0000803 mInputDeviceVibrators.clear();
804 if (mVibrateInputDevicesSetting) {
805 int[] ids = mIm.getInputDeviceIds();
806 for (int i = 0; i < ids.length; i++) {
807 InputDevice device = mIm.getInputDevice(ids[i]);
808 Vibrator vibrator = device.getVibrator();
809 if (vibrator.hasVibrator()) {
810 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700811 }
812 }
Michael Wright71216972017-01-31 18:33:54 +0000813 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700814 }
Michael Wright71216972017-01-31 18:33:54 +0000815 return changed;
816 }
817
818 private boolean updateLowPowerModeLocked() {
819 boolean lowPowerMode = mPowerManagerInternal
820 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
821 if (lowPowerMode != mLowPowerMode) {
822 mLowPowerMode = lowPowerMode;
823 return true;
824 }
825 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700826 }
827
Michael Wright35a0c672018-01-24 00:32:53 +0000828 private void updateVibrationIntensityLocked() {
829 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
830 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
831 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
832 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
833 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
834 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
835 }
836
Jeff Brown7f6c2312012-04-13 20:38:38 -0700837 @Override
838 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000839 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700840 }
841
842 @Override
843 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000844 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700845 }
846
847 @Override
848 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000849 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700850 }
851
852 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700853 // For now, we choose to ignore the presence of input devices that have vibrators
854 // when reporting whether the device has a vibrator. Applications often use this
855 // information to decide whether to enable certain features so they expect the
856 // result of hasVibrator() to be constant. For now, just report whether
857 // the device has a built-in vibrator.
858 //synchronized (mInputDeviceVibrators) {
859 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
860 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800861 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700862 }
863
Michael Wright71216972017-01-31 18:33:54 +0000864 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000865 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
866 try {
867 synchronized (mInputDeviceVibrators) {
868 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
869 amplitude = mDefaultVibrationAmplitude;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700870 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000871 if (DEBUG) {
872 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
873 " with amplitude " + amplitude + ".");
874 }
875 noteVibratorOnLocked(uid, millis);
876 final int vibratorCount = mInputDeviceVibrators.size();
877 if (vibratorCount != 0) {
878 final AudioAttributes attributes =
879 new AudioAttributes.Builder().setUsage(usageHint).build();
880 for (int i = 0; i < vibratorCount; i++) {
881 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
882 }
883 } else {
884 // Note: ordering is important here! Many haptic drivers will reset their
885 // amplitude when enabled, so we always have to enable frst, then set the
886 // amplitude.
887 vibratorOn(millis);
888 doVibratorSetAmplitude(amplitude);
889 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700890 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000891 } finally {
892 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700893 }
894 }
895
Michael Wright71216972017-01-31 18:33:54 +0000896 private void doVibratorSetAmplitude(int amplitude) {
897 if (mSupportsAmplitudeControl) {
898 vibratorSetAmplitude(amplitude);
899 }
900 }
901
Jeff Brown7f6c2312012-04-13 20:38:38 -0700902 private void doVibratorOff() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000903 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
904 try {
905 synchronized (mInputDeviceVibrators) {
906 if (DEBUG) {
907 Slog.d(TAG, "Turning vibrator off.");
Jeff Brown7f6c2312012-04-13 20:38:38 -0700908 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000909 noteVibratorOffLocked();
910 final int vibratorCount = mInputDeviceVibrators.size();
911 if (vibratorCount != 0) {
912 for (int i = 0; i < vibratorCount; i++) {
913 mInputDeviceVibrators.get(i).cancel();
914 }
915 } else {
916 vibratorOff();
917 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700918 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000919 } finally {
920 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700921 }
922 }
923
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000924 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000925 private long doVibratorPrebakedEffectLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000926 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
927 try {
928 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
929 final boolean usingInputDeviceVibrators;
930 synchronized (mInputDeviceVibrators) {
931 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
Michael Wright35a0c672018-01-24 00:32:53 +0000932 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000933 // Input devices don't support prebaked effect, so skip trying it with them.
934 if (!usingInputDeviceVibrators) {
935 long timeout = vibratorPerformEffect(prebaked.getId(),
936 prebaked.getEffectStrength());
937 if (timeout > 0) {
938 noteVibratorOnLocked(vib.uid, timeout);
939 return timeout;
940 }
941 }
942 if (!prebaked.shouldFallback()) {
943 return 0;
944 }
945 VibrationEffect effect = getFallbackEffect(prebaked.getId());
946 if (effect == null) {
947 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
948 return 0;
949 }
950 Vibration fallbackVib =
951 new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
952 final int intensity = getCurrentIntensityLocked(fallbackVib);
953 linkVibration(fallbackVib);
954 applyVibrationIntensityScalingLocked(fallbackVib, intensity);
955 startVibrationInnerLocked(fallbackVib);
Michael Wright35a0c672018-01-24 00:32:53 +0000956 return 0;
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000957 } finally {
958 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright35a0c672018-01-24 00:32:53 +0000959 }
Michael Wright71216972017-01-31 18:33:54 +0000960 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700961
Michael Wright36d873f2018-01-08 15:54:05 +0000962 private VibrationEffect getFallbackEffect(int effectId) {
963 if (effectId < 0 || effectId >= mFallbackEffects.length) {
964 return null;
965 }
966 return mFallbackEffects[effectId];
967 }
968
Michael Wright35a0c672018-01-24 00:32:53 +0000969 /**
970 * Return the current desired effect strength.
971 *
972 * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
973 */
974 private static int intensityToEffectStrength(int intensity) {
975 switch (intensity) {
976 case Vibrator.VIBRATION_INTENSITY_LOW:
977 return EffectStrength.LIGHT;
978 case Vibrator.VIBRATION_INTENSITY_MEDIUM:
979 return EffectStrength.MEDIUM;
980 case Vibrator.VIBRATION_INTENSITY_HIGH:
981 return EffectStrength.STRONG;
982 default:
983 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
984 return EffectStrength.STRONG;
985 }
986 }
987
Michael Wright71216972017-01-31 18:33:54 +0000988 private void noteVibratorOnLocked(int uid, long millis) {
989 try {
990 mBatteryStatsService.noteVibratorOn(uid, millis);
991 mCurVibUid = uid;
992 } catch (RemoteException e) {
993 }
994 }
995
996 private void noteVibratorOffLocked() {
997 if (mCurVibUid >= 0) {
998 try {
999 mBatteryStatsService.noteVibratorOff(mCurVibUid);
1000 } catch (RemoteException e) { }
1001 mCurVibUid = -1;
1002 }
1003 }
1004
1005 private class VibrateThread extends Thread {
1006 private final VibrationEffect.Waveform mWaveform;
1007 private final int mUid;
1008 private final int mUsageHint;
1009
1010 private boolean mForceStop;
1011
1012 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1013 mWaveform = waveform;
1014 mUid = uid;
1015 mUsageHint = usageHint;
1016 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001017 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 }
1019
Michael Wright71216972017-01-31 18:33:54 +00001020 private long delayLocked(long duration) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001021 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1022 try {
1023 long durationRemaining = duration;
1024 if (duration > 0) {
1025 final long bedtime = duration + SystemClock.uptimeMillis();
1026 do {
1027 try {
1028 this.wait(durationRemaining);
1029 }
1030 catch (InterruptedException e) { }
1031 if (mForceStop) {
1032 break;
1033 }
1034 durationRemaining = bedtime - SystemClock.uptimeMillis();
1035 } while (durationRemaining > 0);
1036 return duration - durationRemaining;
1037 }
1038 return 0;
1039 } finally {
1040 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042 }
1043
1044 public void run() {
1045 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +00001046 mWakeLock.acquire();
1047 try {
1048 boolean finished = playWaveform();
1049 if (finished) {
1050 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 }
Michael Wright71216972017-01-31 18:33:54 +00001052 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 mWakeLock.release();
1054 }
Michael Wright71216972017-01-31 18:33:54 +00001055 }
1056
1057 /**
1058 * Play the waveform.
1059 *
1060 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1061 */
1062 public boolean playWaveform() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001063 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1064 try {
1065 synchronized (this) {
1066 final long[] timings = mWaveform.getTimings();
1067 final int[] amplitudes = mWaveform.getAmplitudes();
1068 final int len = timings.length;
1069 final int repeat = mWaveform.getRepeatIndex();
Michael Wright71216972017-01-31 18:33:54 +00001070
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001071 int index = 0;
1072 long onDuration = 0;
1073 while (!mForceStop) {
1074 if (index < len) {
1075 final int amplitude = amplitudes[index];
1076 final long duration = timings[index++];
1077 if (duration <= 0) {
1078 continue;
Michael Wright71216972017-01-31 18:33:54 +00001079 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001080 if (amplitude != 0) {
1081 if (onDuration <= 0) {
1082 // Telling the vibrator to start multiple times usually causes
1083 // effects to feel "choppy" because the motor resets at every on
1084 // command. Instead we figure out how long our next "on" period
1085 // is going to be, tell the motor to stay on for the full
1086 // duration, and then wake up to change the amplitude at the
1087 // appropriate intervals.
1088 onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1089 repeat);
1090 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1091 } else {
1092 doVibratorSetAmplitude(amplitude);
1093 }
1094 }
Michael Wright71216972017-01-31 18:33:54 +00001095
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001096 long waitTime = delayLocked(duration);
1097 if (amplitude != 0) {
1098 onDuration -= waitTime;
1099 }
1100 } else if (repeat < 0) {
1101 break;
1102 } else {
1103 index = repeat;
Michael Wright71216972017-01-31 18:33:54 +00001104 }
Michael Wright71216972017-01-31 18:33:54 +00001105 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001106 return !mForceStop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001108 } finally {
1109 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +00001110 }
1111 }
1112
1113 public void cancel() {
1114 synchronized (this) {
1115 mThread.mForceStop = true;
1116 mThread.notify();
1117 }
1118 }
1119
1120 /**
1121 * Get the duration the vibrator will be on starting at startIndex until the next time it's
1122 * off.
1123 */
1124 private long getTotalOnDuration(
1125 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1126 int i = startIndex;
1127 long timing = 0;
1128 while(amplitudes[i] != 0) {
1129 timing += timings[i++];
1130 if (i >= timings.length) {
1131 if (repeatIndex >= 0) {
1132 i = repeatIndex;
1133 } else {
1134 break;
1135 }
1136 }
1137 if (i == startIndex) {
1138 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -04001139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 }
Michael Wright71216972017-01-31 18:33:54 +00001141 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 }
Jeff Brown969579b2014-05-20 19:29:29 -07001143 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001145 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -07001146 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001147 public void onReceive(Context context, Intent intent) {
1148 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +00001149 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -07001150 // When the system is entering a non-interactive state, we want
1151 // to cancel vibrations in case a misbehaving app has abandoned
1152 // them. However it may happen that the system is currently playing
1153 // haptic feedback as part of the transition. So we don't cancel
1154 // system vibrations.
1155 if (mCurrentVibration != null
Michael Wright35a0c672018-01-24 00:32:53 +00001156 && !(mCurrentVibration.isHapticFeedback()
1157 && mCurrentVibration.isFromSystem())) {
Jeff Brown969579b2014-05-20 19:29:29 -07001158 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -07001159 }
Patrick Scott18dd5f02009-07-02 11:31:12 -04001160 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001161 }
1162 }
1163 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001164
1165 @Override
1166 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001167 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001168
Michael Wright35a0c672018-01-24 00:32:53 +00001169 pw.println("Vibrator Service:");
Michael Wright71216972017-01-31 18:33:54 +00001170 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +00001171 pw.print(" mCurrentVibration=");
1172 if (mCurrentVibration != null) {
1173 pw.println(mCurrentVibration.toInfo().toString());
1174 } else {
1175 pw.println("null");
1176 }
1177 pw.println(" mLowPowerMode=" + mLowPowerMode);
1178 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1179 pw.println(" mNotificationIntensity=" + mNotificationIntensity);
1180 pw.println("");
1181 pw.println(" Previous vibrations:");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001182 for (VibrationInfo info : mPreviousVibrations) {
Michael Wright35a0c672018-01-24 00:32:53 +00001183 pw.print(" ");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001184 pw.println(info.toString());
1185 }
1186 }
1187 }
Felipe Lemea5281002017-02-10 15:13:48 -08001188
1189 @Override
1190 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1191 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1192 throws RemoteException {
1193 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1194 }
1195
1196 private final class VibratorShellCommand extends ShellCommand {
1197
1198 private static final long MAX_VIBRATION_MS = 200;
1199
1200 private final IBinder mToken;
1201
1202 private VibratorShellCommand(IBinder token) {
1203 mToken = token;
1204 }
1205
1206 @Override
1207 public int onCommand(String cmd) {
1208 if ("vibrate".equals(cmd)) {
1209 return runVibrate();
1210 }
1211 return handleDefaultCommands(cmd);
1212 }
1213
1214 private int runVibrate() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001215 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001216 try {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001217 try {
1218 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1219 Settings.Global.ZEN_MODE);
1220 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
1221 try (PrintWriter pw = getOutPrintWriter();) {
1222 pw.print("Ignoring because device is on DND mode ");
1223 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1224 zenMode));
1225 return 0;
1226 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001227 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001228 } catch (SettingNotFoundException e) {
1229 // ignore
Felipe Leme5e2e6322017-07-14 17:25:59 -07001230 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001231
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001232 final long duration = Long.parseLong(getNextArgRequired());
1233 if (duration > MAX_VIBRATION_MS) {
1234 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
1235 }
1236 String description = getNextArg();
1237 if (description == null) {
1238 description = "Shell command";
1239 }
Michael Wright71216972017-01-31 18:33:54 +00001240
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001241 VibrationEffect effect =
1242 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1243 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1244 mToken);
1245 return 0;
1246 } finally {
1247 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1248 }
Felipe Lemea5281002017-02-10 15:13:48 -08001249 }
1250
1251 @Override
1252 public void onHelp() {
1253 try (PrintWriter pw = getOutPrintWriter();) {
1254 pw.println("Vibrator commands:");
1255 pw.println(" help");
1256 pw.println(" Prints this help text.");
1257 pw.println("");
1258 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001259 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1260 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -08001261 pw.println("");
1262 }
1263 }
1264 }
1265
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266}