blob: 545baa02150ca4ed0d8b447932f86d03b55a5c00 [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
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +000019import android.app.ActivityManager;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080020import android.app.AppOpsManager;
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +000021import android.app.IUidObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.BroadcastReceiver;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.pm.PackageManager;
Michael Wright71216972017-01-31 18:33:54 +000027import android.content.res.Resources;
Jeff Brown7f6c2312012-04-13 20:38:38 -070028import android.database.ContentObserver;
29import android.hardware.input.InputManager;
Michael Wrightf268bf52018-02-07 23:23:34 +000030import android.hardware.vibrator.V1_0.EffectStrength;
Michael Wright36d873f2018-01-08 15:54:05 +000031import android.icu.text.DateFormat;
Bookatza7020bd2018-08-28 16:29:35 -070032import android.media.AudioAttributes;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070033import android.media.AudioManager;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070034import android.os.BatteryStats;
Bookatza7020bd2018-08-28 16:29:35 -070035import android.os.Binder;
Michael Wrightc390fbe2018-12-12 19:45:09 +000036import android.os.ExternalVibration;
Joe Onorato95e4f702009-03-24 19:29:09 -070037import android.os.Handler;
Bookatza7020bd2018-08-28 16:29:35 -070038import android.os.IBinder;
Michael Wrightc390fbe2018-12-12 19:45:09 +000039import android.os.IExternalVibratorService;
Mike Lockwood3a322132009-11-24 00:30:52 -050040import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.PowerManager;
Bookatza7020bd2018-08-28 16:29:35 -070042import android.os.PowerManager.ServiceType;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070043import android.os.PowerManagerInternal;
Bookatza7020bd2018-08-28 16:29:35 -070044import android.os.PowerSaveState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.Process;
46import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080047import android.os.ResultReceiver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080048import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080049import android.os.ShellCallback;
50import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.SystemClock;
Alexey Kuzmine59145a2018-02-10 15:19:03 +000052import android.os.Trace;
Jeff Brownd4935962012-09-25 13:27:20 -070053import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +000054import android.os.VibrationEffect;
Bookatza7020bd2018-08-28 16:29:35 -070055import android.os.Vibrator;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070056import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070057import android.provider.Settings;
58import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070059import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080060import android.util.Slog;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +000061import android.util.SparseArray;
Bookatza7020bd2018-08-28 16:29:35 -070062import android.util.StatsLog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070063import android.view.InputDevice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +000065import com.android.internal.annotations.GuardedBy;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080066import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060067import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080068
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070069import java.io.FileDescriptor;
70import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070071import java.util.ArrayList;
Michael Wright36d873f2018-01-08 15:54:05 +000072import java.util.Date;
Bookatza7020bd2018-08-28 16:29:35 -070073import java.util.LinkedList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040074
Jeff Brown7f6c2312012-04-13 20:38:38 -070075public class VibratorService extends IVibratorService.Stub
76 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050077 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070078 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070079 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Michael Wrightc390fbe2018-12-12 19:45:09 +000080 private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050081
Michael Wright36d873f2018-01-08 15:54:05 +000082 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
83
Michael Wrightc390fbe2018-12-12 19:45:09 +000084 // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
85 // and the default intensity for that type of vibration (i.e. current - default).
86 private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
87 private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
88 private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
89 private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
90 private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
91 private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
Michael Wright35a0c672018-01-24 00:32:53 +000092
Michael Wright0dbb5162018-05-25 15:13:36 +010093 // Gamma adjustments for scale levels.
94 private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
95 private static final float SCALE_LOW_GAMMA = 1.5f;
96 private static final float SCALE_NONE_GAMMA = 1.0f;
97 private static final float SCALE_HIGH_GAMMA = 0.5f;
98 private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
99
100 // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
101 // max amplitude.
102 private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
103 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
Michael Wright35a0c672018-01-24 00:32:53 +0000104
105 // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
106 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
107
Michael Wright0dbb5162018-05-25 15:13:36 +0100108
109 // A mapping from the intensity adjustment to the scaling to apply, where the intensity
110 // adjustment is defined as the delta between the default intensity level and the user selected
111 // intensity level. It's important that we apply the scaling on the delta between the two so
112 // that the default intensity level applies no scaling to application provided effects.
113 private final SparseArray<ScaleLevel> mScaleLevels;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700114 private final LinkedList<VibrationInfo> mPreviousVibrations;
115 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -0700116 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +0000117 private final boolean mSupportsAmplitudeControl;
Michael Wrightc390fbe2018-12-12 19:45:09 +0000118 private final boolean mSupportsExternalControl;
Michael Wright71216972017-01-31 18:33:54 +0000119 private final int mDefaultVibrationAmplitude;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000120 private final SparseArray<VibrationEffect> mFallbackEffects;
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000121 private final SparseArray<Integer> mProcStatesCache = new SparseArray();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700122 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700123 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +0000124 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700125
126 private final Context mContext;
127 private final PowerManager.WakeLock mWakeLock;
Svet Ganovf7b47252018-02-26 11:11:27 -0800128 private final AppOpsManager mAppOps;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800129 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700130 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700131 private InputManager mIm;
Michael Wright35a0c672018-01-24 00:32:53 +0000132 private Vibrator mVibrator;
133 private SettingsObserver mSettingObserver;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700134
Michael Wright71216972017-01-31 18:33:54 +0000135 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700136
Michael Wright71216972017-01-31 18:33:54 +0000137 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -0700138 // to be acquired
139 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
140 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
141 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
142
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000143 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000144 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800145 private int mCurVibUid = -1;
Michael Wrightc390fbe2018-12-12 19:45:09 +0000146 private ExternalVibration mCurrentExternalVibration;
147 private boolean mVibratorUnderExternalControl;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700148 private boolean mLowPowerMode;
Michael Wright35a0c672018-01-24 00:32:53 +0000149 private int mHapticFeedbackIntensity;
150 private int mNotificationIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000151 private int mRingIntensity;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800152
Michael Wrightc390fbe2018-12-12 19:45:09 +0000153 static native boolean vibratorExists();
154 static native void vibratorInit();
155 static native void vibratorOn(long milliseconds);
156 static native void vibratorOff();
157 static native boolean vibratorSupportsAmplitudeControl();
158 static native void vibratorSetAmplitude(int amplitude);
159 static native long vibratorPerformEffect(long effect, long strength);
Harpreet "Eli" Sanghaa456f082018-12-14 12:06:10 +0900160 static native boolean vibratorSupportsExternalControl();
161 static native void vibratorSetExternalControl(boolean enabled);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400162
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000163 private final IUidObserver mUidObserver = new IUidObserver.Stub() {
164 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
165 mProcStatesCache.put(uid, procState);
166 }
167
168 @Override public void onUidGone(int uid, boolean disabled) {
169 mProcStatesCache.delete(uid);
170 }
171
172 @Override public void onUidActive(int uid) {
173 }
174
175 @Override public void onUidIdle(int uid, boolean disabled) {
176 }
177
178 @Override public void onUidCachedChanged(int uid, boolean cached) {
179 }
180 };
181
Patrick Scott18dd5f02009-07-02 11:31:12 -0400182 private class Vibration implements IBinder.DeathRecipient {
Michael Wright35a0c672018-01-24 00:32:53 +0000183 public final IBinder token;
Michael Wright36d873f2018-01-08 15:54:05 +0000184 // Start time in CLOCK_BOOTTIME base.
Michael Wright35a0c672018-01-24 00:32:53 +0000185 public final long startTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000186 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
Michael Wright35a0c672018-01-24 00:32:53 +0000187 // with other system events, any duration calculations should be done use startTime so as
Michael Wright36d873f2018-01-08 15:54:05 +0000188 // not to be affected by discontinuities created by RTC adjustments.
Michael Wright35a0c672018-01-24 00:32:53 +0000189 public final long startTimeDebug;
190 public final int usageHint;
191 public final int uid;
192 public final String opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100193 public final String reason;
Michael Wright35a0c672018-01-24 00:32:53 +0000194
195 // The actual effect to be played.
196 public VibrationEffect effect;
197 // The original effect that was requested. This is non-null only when the original effect
198 // differs from the effect that's being played. Typically these two things differ because
199 // the effect was scaled based on the users vibration intensity settings.
200 public VibrationEffect originalEffect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400201
Michael Wright71216972017-01-31 18:33:54 +0000202 private Vibration(IBinder token, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100203 int usageHint, int uid, String opPkg, String reason) {
Michael Wright35a0c672018-01-24 00:32:53 +0000204 this.token = token;
205 this.effect = effect;
206 this.startTime = SystemClock.elapsedRealtime();
207 this.startTimeDebug = System.currentTimeMillis();
208 this.usageHint = usageHint;
209 this.uid = uid;
210 this.opPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100211 this.reason = reason;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400212 }
213
214 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000215 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400216 if (this == mCurrentVibration) {
217 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400218 }
219 }
220 }
221
Michael Wright35a0c672018-01-24 00:32:53 +0000222 public boolean hasTimeoutLongerThan(long millis) {
223 final long duration = effect.getDuration();
224 return duration >= 0 && duration > millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400225 }
Jeff Brown969579b2014-05-20 19:29:29 -0700226
Michael Wright35a0c672018-01-24 00:32:53 +0000227 public boolean isHapticFeedback() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000228 if (VibratorService.this.isHapticFeedback(usageHint)) {
229 return true;
230 }
Michael Wright35a0c672018-01-24 00:32:53 +0000231 if (effect instanceof VibrationEffect.Prebaked) {
232 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
233 switch (prebaked.getId()) {
234 case VibrationEffect.EFFECT_CLICK:
235 case VibrationEffect.EFFECT_DOUBLE_CLICK:
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000236 case VibrationEffect.EFFECT_HEAVY_CLICK:
Michael Wright35a0c672018-01-24 00:32:53 +0000237 case VibrationEffect.EFFECT_TICK:
Michael Wright0dbb5162018-05-25 15:13:36 +0100238 case VibrationEffect.EFFECT_POP:
239 case VibrationEffect.EFFECT_THUD:
Michael Wright35a0c672018-01-24 00:32:53 +0000240 return true;
241 default:
242 Slog.w(TAG, "Unknown prebaked vibration effect, "
243 + "assuming it isn't haptic feedback.");
244 return false;
245 }
Michael Wright71216972017-01-31 18:33:54 +0000246 }
Michael Wright35a0c672018-01-24 00:32:53 +0000247 final long duration = effect.getDuration();
248 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
249 }
250
251 public boolean isNotification() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000252 return VibratorService.this.isNotification(usageHint);
Michael Wright35a0c672018-01-24 00:32:53 +0000253 }
254
255 public boolean isRingtone() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000256 return VibratorService.this.isRingtone(usageHint);
Michael Wright35a0c672018-01-24 00:32:53 +0000257 }
258
259 public boolean isFromSystem() {
260 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
Jeff Brown969579b2014-05-20 19:29:29 -0700261 }
Michael Wright36d873f2018-01-08 15:54:05 +0000262
263 public VibrationInfo toInfo() {
Michael Wright35a0c672018-01-24 00:32:53 +0000264 return new VibrationInfo(
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100265 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg, reason);
Michael Wright36d873f2018-01-08 15:54:05 +0000266 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400267 }
268
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700269 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000270 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000271 private final VibrationEffect mEffect;
Michael Wright35a0c672018-01-24 00:32:53 +0000272 private final VibrationEffect mOriginalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000273 private final int mUsageHint;
274 private final int mUid;
275 private final String mOpPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100276 private final String mReason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700277
Michael Wright36d873f2018-01-08 15:54:05 +0000278 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100279 VibrationEffect originalEffect, int usageHint, int uid,
280 String opPkg, String reason) {
Michael Wright36d873f2018-01-08 15:54:05 +0000281 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000282 mEffect = effect;
Michael Wright35a0c672018-01-24 00:32:53 +0000283 mOriginalEffect = originalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000284 mUsageHint = usageHint;
285 mUid = uid;
286 mOpPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100287 mReason = reason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700288 }
289
290 @Override
291 public String toString() {
292 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000293 .append("startTime: ")
294 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000295 .append(", effect: ")
296 .append(mEffect)
Michael Wright35a0c672018-01-24 00:32:53 +0000297 .append(", originalEffect: ")
298 .append(mOriginalEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700299 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000300 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700301 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000302 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700303 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000304 .append(mOpPkg)
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100305 .append(", reason: ")
306 .append(mReason)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700307 .toString();
308 }
309 }
310
Michael Wright0dbb5162018-05-25 15:13:36 +0100311 private static final class ScaleLevel {
312 public final float gamma;
313 public final int maxAmplitude;
314
315 public ScaleLevel(float gamma) {
316 this(gamma, VibrationEffect.MAX_AMPLITUDE);
317 }
318
319 public ScaleLevel(float gamma, int maxAmplitude) {
320 this.gamma = gamma;
321 this.maxAmplitude = maxAmplitude;
322 }
323
324 @Override
325 public String toString() {
326 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
327 }
328 }
329
Mike Lockwood3a322132009-11-24 00:30:52 -0500330 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200331 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 // Reset the hardware to a default state, in case this is a runtime
333 // restart instead of a fresh boot.
334 vibratorOff();
335
Michael Wright71216972017-01-31 18:33:54 +0000336 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
Michael Wrightc390fbe2018-12-12 19:45:09 +0000337 mSupportsExternalControl = vibratorSupportsExternalControl();
Michael Wright71216972017-01-31 18:33:54 +0000338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000340 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700341 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 mWakeLock.setReferenceCounted(true);
343
Svet Ganovf7b47252018-02-26 11:11:27 -0800344 mAppOps = mContext.getSystemService(AppOpsManager.class);
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700345 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
346 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800347
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700348 mPreviousVibrationsLimit = mContext.getResources().getInteger(
349 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
350
Michael Wright71216972017-01-31 18:33:54 +0000351 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
352 com.android.internal.R.integer.config_defaultVibrationAmplitude);
353
Tyler Freeman319a34a2017-05-04 17:23:35 -0700354 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
355 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
356
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700357 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400358
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 IntentFilter filter = new IntentFilter();
360 filter.addAction(Intent.ACTION_SCREEN_OFF);
361 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000362
Michael Wrightd39cbec2018-04-16 19:35:13 +0100363 VibrationEffect clickEffect = createEffectFromResource(
Michael Wright71216972017-01-31 18:33:54 +0000364 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000365 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000366 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100367 VibrationEffect heavyClickEffect = createEffectFromResource(
368 com.android.internal.R.array.config_longPressVibePattern);
369 VibrationEffect tickEffect = createEffectFromResource(
Michael Wright57d94d92017-05-31 14:44:45 +0100370 com.android.internal.R.array.config_clockTickVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000371
Michael Wright0dbb5162018-05-25 15:13:36 +0100372 mFallbackEffects = new SparseArray<>();
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000373 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
374 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
375 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100376 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
Michael Wright0dbb5162018-05-25 15:13:36 +0100377
378 mScaleLevels = new SparseArray<>();
379 mScaleLevels.put(SCALE_VERY_LOW,
380 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
381 mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
382 mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
383 mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
384 mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
Michael Wrightc390fbe2018-12-12 19:45:09 +0000385
386 ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
Michael Wright57d94d92017-05-31 14:44:45 +0100387 }
388
Michael Wrightd39cbec2018-04-16 19:35:13 +0100389 private VibrationEffect createEffectFromResource(int resId) {
390 long[] timings = getLongIntArray(mContext.getResources(), resId);
391 return createEffectFromTimings(timings);
392 }
393
394 private static VibrationEffect createEffectFromTimings(long[] timings) {
Michael Wright57d94d92017-05-31 14:44:45 +0100395 if (timings == null || timings.length == 0) {
396 return null;
397 } else if (timings.length == 1) {
398 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
399 } else {
400 return VibrationEffect.createWaveform(timings, -1);
401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 }
403
Jeff Brown7f6c2312012-04-13 20:38:38 -0700404 public void systemReady() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000405 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
406 try {
407 mIm = mContext.getSystemService(InputManager.class);
408 mVibrator = mContext.getSystemService(Vibrator.class);
409 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700410
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000411 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
412 mPowerManagerInternal.registerLowPowerModeObserver(
413 new PowerManagerInternal.LowPowerModeListener() {
414 @Override
415 public int getServiceType() {
416 return ServiceType.VIBRATION;
417 }
jackqdyulei455e90a2017-02-09 15:29:16 -0800418
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000419 @Override
420 public void onLowPowerModeChanged(PowerSaveState result) {
421 updateVibrators();
422 }
423 });
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700424
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000425 mContext.getContentResolver().registerContentObserver(
426 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
427 true, mSettingObserver, UserHandle.USER_ALL);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700428
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000429 mContext.getContentResolver().registerContentObserver(
430 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
431 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000432
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000433 mContext.getContentResolver().registerContentObserver(
434 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
435 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000436
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000437 mContext.getContentResolver().registerContentObserver(
438 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
439 true, mSettingObserver, UserHandle.USER_ALL);
440
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000441 mContext.registerReceiver(new BroadcastReceiver() {
442 @Override
443 public void onReceive(Context context, Intent intent) {
444 updateVibrators();
445 }
446 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700447
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000448 try {
449 ActivityManager.getService().registerUidObserver(mUidObserver,
450 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
451 ActivityManager.PROCESS_STATE_UNKNOWN, null);
452 } catch (RemoteException e) {
453 // ignored; both services live in system_server
454 }
455
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000456 updateVibrators();
457 } finally {
458 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
459 }
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700460 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700461
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700462 private final class SettingsObserver extends ContentObserver {
463 public SettingsObserver(Handler handler) {
464 super(handler);
465 }
466
467 @Override
468 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000469 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700470 }
471 }
472
Jeff Brown82379ba2014-07-25 19:03:28 -0700473 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700474 public boolean hasVibrator() {
475 return doVibratorExists();
476 }
477
Michael Wright71216972017-01-31 18:33:54 +0000478 @Override // Binder call
479 public boolean hasAmplitudeControl() {
480 synchronized (mInputDeviceVibrators) {
481 // Input device vibrators don't support amplitude controls yet, but are still used over
482 // the system vibrator when connected.
483 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
484 }
485 }
486
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800487 private void verifyIncomingUid(int uid) {
488 if (uid == Binder.getCallingUid()) {
489 return;
490 }
491 if (Binder.getCallingPid() == Process.myPid()) {
492 return;
493 }
494 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
495 Binder.getCallingPid(), Binder.getCallingUid(), null);
496 }
497
Michael Wright71216972017-01-31 18:33:54 +0000498 /**
499 * Validate the incoming VibrationEffect.
500 *
501 * We can't throw exceptions here since we might be called from some system_server component,
502 * which would bring the whole system down.
503 *
504 * @return whether the VibrationEffect is valid
505 */
506 private static boolean verifyVibrationEffect(VibrationEffect effect) {
507 if (effect == null) {
508 // Effect must not be null.
509 Slog.wtf(TAG, "effect must not be null");
510 return false;
511 }
512 try {
513 effect.validate();
514 } catch (Exception e) {
515 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
516 return false;
517 }
518 return true;
519 }
520
521 private static long[] getLongIntArray(Resources r, int resid) {
522 int[] ar = r.getIntArray(resid);
523 if (ar == null) {
524 return null;
525 }
526 long[] out = new long[ar.length];
527 for (int i = 0; i < ar.length; i++) {
528 out[i] = ar[i];
529 }
530 return out;
531 }
532
Jeff Brown82379ba2014-07-25 19:03:28 -0700533 @Override // Binder call
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100534 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
John Spurlock1af30c72014-03-10 08:33:35 -0400535 IBinder token) {
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100536 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000537 try {
538 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
539 != PackageManager.PERMISSION_GRANTED) {
540 throw new SecurityException("Requires VIBRATE permission");
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000541 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000542 if (token == null) {
543 Slog.e(TAG, "token must not be null");
544 return;
545 }
546 verifyIncomingUid(uid);
547 if (!verifyVibrationEffect(effect)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 return;
549 }
550
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000551 // If our current vibration is longer than the new vibration and is the same amplitude,
552 // then just let the current one finish.
553 synchronized (mLock) {
554 if (effect instanceof VibrationEffect.OneShot
555 && mCurrentVibration != null
556 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
557 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
558 VibrationEffect.OneShot currentOneShot =
559 (VibrationEffect.OneShot) mCurrentVibration.effect;
560 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
561 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
562 if (DEBUG) {
563 Slog.d(TAG,
564 "Ignoring incoming vibration in favor of current vibration");
565 }
566 return;
567 }
568 }
569
Michael Wrightc390fbe2018-12-12 19:45:09 +0000570
571 // If something has external control of the vibrator, assume that it's more
572 // important for now.
573 if (mCurrentExternalVibration != null) {
574 if (DEBUG) {
575 Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
576 }
577 return;
578 }
579
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000580 // If the current vibration is repeating and the incoming one is non-repeating,
581 // then ignore the non-repeating vibration. This is so that we don't cancel
582 // vibrations that are meant to grab the attention of the user, like ringtones and
583 // alarms, in favor of one-shot vibrations that are likely quite short.
584 if (!isRepeatingVibration(effect)
585 && mCurrentVibration != null
586 && isRepeatingVibration(mCurrentVibration.effect)) {
587 if (DEBUG) {
588 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
589 }
590 return;
591 }
592
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100593 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
Alexey Kuzminddebe592019-01-08 16:07:41 +0000594 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
595 > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
Alexey Kuzmine5822992019-01-29 19:50:26 +0000596 && !vib.isNotification() && !vib.isRingtone()) {
Alexey Kuzminddebe592019-01-08 16:07:41 +0000597 Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
598 + uid + " is background");
599 return;
600 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000601 linkVibration(vib);
602 long ident = Binder.clearCallingIdentity();
603 try {
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100604
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000605 doCancelVibrateLocked();
606 startVibrationLocked(vib);
607 addToPreviousVibrationsLocked(vib);
608 } finally {
609 Binder.restoreCallingIdentity(ident);
610 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800611 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000612 } finally {
613 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 }
615 }
616
Michael Wright58c46312017-10-05 14:04:14 -0400617 private static boolean isRepeatingVibration(VibrationEffect effect) {
Michael Wright35a0c672018-01-24 00:32:53 +0000618 return effect.getDuration() == Long.MAX_VALUE;
Michael Wright58c46312017-10-05 14:04:14 -0400619 }
620
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700621 private void addToPreviousVibrationsLocked(Vibration vib) {
622 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
623 mPreviousVibrations.removeFirst();
624 }
Michael Wright36d873f2018-01-08 15:54:05 +0000625 mPreviousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700626 }
627
Jeff Brown82379ba2014-07-25 19:03:28 -0700628 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400629 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 mContext.enforceCallingOrSelfPermission(
631 android.Manifest.permission.VIBRATE,
632 "cancelVibrate");
633
Michael Wright71216972017-01-31 18:33:54 +0000634 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +0000635 if (mCurrentVibration != null && mCurrentVibration.token == token) {
Michael Wright71216972017-01-31 18:33:54 +0000636 if (DEBUG) {
637 Slog.d(TAG, "Canceling vibration.");
638 }
639 long ident = Binder.clearCallingIdentity();
640 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400641 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000642 } finally {
643 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400644 }
645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700648
Michael Wright71216972017-01-31 18:33:54 +0000649 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700650 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400651 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000652 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400653 }
654 };
655
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000656 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400657 private void doCancelVibrateLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000658 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
659 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
660 try {
661 mH.removeCallbacks(mVibrationEndRunnable);
662 if (mThread != null) {
663 mThread.cancel();
664 mThread = null;
665 }
Michael Wrightc390fbe2018-12-12 19:45:09 +0000666 if (mCurrentExternalVibration != null) {
667 mCurrentExternalVibration.mute();
668 mCurrentExternalVibration = null;
669 setVibratorUnderExternalControl(false);
670 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000671 doVibratorOff();
672 reportFinishVibrationLocked();
673 } finally {
674 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400675 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400676 }
677
Michael Wright71216972017-01-31 18:33:54 +0000678 // Callback for whenever the current vibration has finished played out
679 public void onVibrationFinished() {
680 if (DEBUG) {
681 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400682 }
Michael Wright71216972017-01-31 18:33:54 +0000683 synchronized (mLock) {
684 // Make sure the vibration is really done. This also reports that the vibration is
685 // finished.
686 doCancelVibrateLocked();
687 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400688 }
689
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000690 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400691 private void startVibrationLocked(final Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000692 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
693 try {
694 if (!isAllowedToVibrateLocked(vib)) {
695 return;
Michael Wright71216972017-01-31 18:33:54 +0000696 }
Michael Wright71216972017-01-31 18:33:54 +0000697
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000698 final int intensity = getCurrentIntensityLocked(vib);
699 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
700 return;
Michael Wright71216972017-01-31 18:33:54 +0000701 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000702
703 if (vib.isRingtone() && !shouldVibrateForRingtone()) {
704 if (DEBUG) {
705 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
706 }
707 return;
708 }
709
710 final int mode = getAppOpMode(vib);
711 if (mode != AppOpsManager.MODE_ALLOWED) {
712 if (mode == AppOpsManager.MODE_ERRORED) {
713 // We might be getting calls from within system_server, so we don't actually
714 // want to throw a SecurityException here.
715 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
716 }
717 return;
718 }
719 applyVibrationIntensityScalingLocked(vib, intensity);
720 startVibrationInnerLocked(vib);
721 } finally {
722 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +0000723 }
Michael Wright71216972017-01-31 18:33:54 +0000724 }
725
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000726 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000727 private void startVibrationInnerLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000728 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
729 try {
730 mCurrentVibration = vib;
731 if (vib.effect instanceof VibrationEffect.OneShot) {
732 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
733 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
734 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
735 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
736 } else if (vib.effect instanceof VibrationEffect.Waveform) {
737 // mThread better be null here. doCancelVibrate should always be
738 // called before startNextVibrationLocked or startVibrationLocked.
739 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
740 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
741 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
742 mThread.start();
743 } else if (vib.effect instanceof VibrationEffect.Prebaked) {
744 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
745 long timeout = doVibratorPrebakedEffectLocked(vib);
746 if (timeout > 0) {
747 mH.postDelayed(mVibrationEndRunnable, timeout);
748 }
749 } else {
750 Slog.e(TAG, "Unknown vibration type, ignoring");
Michael Wright71216972017-01-31 18:33:54 +0000751 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000752 } finally {
753 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 }
755 }
756
Michael Wright35a0c672018-01-24 00:32:53 +0000757 private boolean isAllowedToVibrateLocked(Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700758 if (!mLowPowerMode) {
759 return true;
760 }
Michael Wright35a0c672018-01-24 00:32:53 +0000761
762 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700763 return true;
764 }
Tyler Freeman319a34a2017-05-04 17:23:35 -0700765
Michael Wright35a0c672018-01-24 00:32:53 +0000766 if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
767 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
768 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700769 return true;
770 }
771
772 return false;
773 }
774
Michael Wright35a0c672018-01-24 00:32:53 +0000775 private int getCurrentIntensityLocked(Vibration vib) {
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000776 if (vib.isRingtone()) {
777 return mRingIntensity;
778 } else if (vib.isNotification()) {
Michael Wright35a0c672018-01-24 00:32:53 +0000779 return mNotificationIntensity;
780 } else if (vib.isHapticFeedback()) {
781 return mHapticFeedbackIntensity;
782 } else {
783 return Vibrator.VIBRATION_INTENSITY_MEDIUM;
784 }
785 }
786
787 /**
788 * Scale the vibration effect by the intensity as appropriate based its intent.
789 */
790 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
791 if (vib.effect instanceof VibrationEffect.Prebaked) {
792 // Prebaked effects are always just a direct translation from intensity to
793 // EffectStrength.
794 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
795 prebaked.setEffectStrength(intensityToEffectStrength(intensity));
796 return;
797 }
798
Michael Wright0dbb5162018-05-25 15:13:36 +0100799 final int defaultIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000800 if (vib.isRingtone()) {
801 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
802 } else if (vib.isNotification()) {
Michael Wright0dbb5162018-05-25 15:13:36 +0100803 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
804 } else if (vib.isHapticFeedback()) {
805 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
Michael Wright35a0c672018-01-24 00:32:53 +0000806 } else {
Michael Wright0dbb5162018-05-25 15:13:36 +0100807 // If we don't know what kind of vibration we're playing then just skip scaling for
808 // now.
809 return;
810 }
811
812 final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
813 if (scale == null) {
814 // We should have scaling levels for all cases, so not being able to scale because of a
815 // missing level is unexpected.
816 Slog.e(TAG, "No configured scaling level!"
817 + " (current=" + intensity + ", default= " + defaultIntensity + ")");
818 return;
Michael Wright35a0c672018-01-24 00:32:53 +0000819 }
820
821 VibrationEffect scaledEffect = null;
822 if (vib.effect instanceof VibrationEffect.OneShot) {
823 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100824 oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100825 scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000826 } else if (vib.effect instanceof VibrationEffect.Waveform) {
827 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100828 waveform = waveform.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100829 scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000830 } else {
831 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
832 }
833
834 if (scaledEffect != null) {
835 vib.originalEffect = vib.effect;
836 vib.effect = scaledEffect;
837 }
838 }
839
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700840 private boolean shouldVibrateForRingtone() {
Michael Wright35a0c672018-01-24 00:32:53 +0000841 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700842 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700843 // "Also vibrate for calls" Setting in Sound
844 if (Settings.System.getInt(
845 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
846 return ringerMode != AudioManager.RINGER_MODE_SILENT;
847 } else {
848 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
849 }
850 }
851
Michael Wright71216972017-01-31 18:33:54 +0000852 private int getAppOpMode(Vibration vib) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800853 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
854 vib.usageHint, vib.uid, vib.opPkg);
855 if (mode == AppOpsManager.MODE_ALLOWED) {
856 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
Michael Wright71216972017-01-31 18:33:54 +0000857 }
858 return mode;
859 }
860
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000861 @GuardedBy("mLock")
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800862 private void reportFinishVibrationLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000863 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
864 try {
865 if (mCurrentVibration != null) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800866 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
867 mCurrentVibration.opPkg);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000868 unlinkVibration(mCurrentVibration);
869 mCurrentVibration = null;
870 }
871 } finally {
872 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800873 }
874 }
875
Michael Wright36d873f2018-01-08 15:54:05 +0000876 private void linkVibration(Vibration vib) {
877 // Only link against waveforms since they potentially don't have a finish if
878 // they're repeating. Let other effects just play out until they're done.
Michael Wright35a0c672018-01-24 00:32:53 +0000879 if (vib.effect instanceof VibrationEffect.Waveform) {
Michael Wright36d873f2018-01-08 15:54:05 +0000880 try {
Michael Wright35a0c672018-01-24 00:32:53 +0000881 vib.token.linkToDeath(vib, 0);
Michael Wright36d873f2018-01-08 15:54:05 +0000882 } catch (RemoteException e) {
883 return;
884 }
885 }
886 }
887
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200888 private void unlinkVibration(Vibration vib) {
Michael Wright35a0c672018-01-24 00:32:53 +0000889 if (vib.effect instanceof VibrationEffect.Waveform) {
890 vib.token.unlinkToDeath(vib, 0);
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200891 }
892 }
893
Michael Wright71216972017-01-31 18:33:54 +0000894 private void updateVibrators() {
895 synchronized (mLock) {
896 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
897 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Michael Wright35a0c672018-01-24 00:32:53 +0000898 updateVibrationIntensityLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700899
Michael Wright71216972017-01-31 18:33:54 +0000900 if (devicesUpdated || lowPowerModeUpdated) {
901 // If the state changes out from under us then just reset.
902 doCancelVibrateLocked();
903 }
904 }
905 }
Jeff Brown82065252012-04-16 13:19:05 -0700906
Michael Wright71216972017-01-31 18:33:54 +0000907 private boolean updateInputDeviceVibratorsLocked() {
908 boolean changed = false;
909 boolean vibrateInputDevices = false;
910 try {
911 vibrateInputDevices = Settings.System.getIntForUser(
912 mContext.getContentResolver(),
913 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
914 } catch (SettingNotFoundException snfe) {
915 }
916 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
917 changed = true;
918 mVibrateInputDevicesSetting = vibrateInputDevices;
919 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700920
Michael Wright71216972017-01-31 18:33:54 +0000921 if (mVibrateInputDevicesSetting) {
922 if (!mInputDeviceListenerRegistered) {
923 mInputDeviceListenerRegistered = true;
924 mIm.registerInputDeviceListener(this, mH);
925 }
926 } else {
927 if (mInputDeviceListenerRegistered) {
928 mInputDeviceListenerRegistered = false;
929 mIm.unregisterInputDeviceListener(this);
930 }
931 }
Jeff Brown82065252012-04-16 13:19:05 -0700932
Michael Wright71216972017-01-31 18:33:54 +0000933 mInputDeviceVibrators.clear();
934 if (mVibrateInputDevicesSetting) {
935 int[] ids = mIm.getInputDeviceIds();
936 for (int i = 0; i < ids.length; i++) {
937 InputDevice device = mIm.getInputDevice(ids[i]);
938 Vibrator vibrator = device.getVibrator();
939 if (vibrator.hasVibrator()) {
940 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700941 }
942 }
Michael Wright71216972017-01-31 18:33:54 +0000943 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700944 }
Michael Wright71216972017-01-31 18:33:54 +0000945 return changed;
946 }
947
948 private boolean updateLowPowerModeLocked() {
949 boolean lowPowerMode = mPowerManagerInternal
950 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
951 if (lowPowerMode != mLowPowerMode) {
952 mLowPowerMode = lowPowerMode;
953 return true;
954 }
955 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700956 }
957
Michael Wright35a0c672018-01-24 00:32:53 +0000958 private void updateVibrationIntensityLocked() {
959 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
960 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
961 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
962 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
963 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
964 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000965 mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
966 Settings.System.RING_VIBRATION_INTENSITY,
967 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
Michael Wright35a0c672018-01-24 00:32:53 +0000968 }
969
Jeff Brown7f6c2312012-04-13 20:38:38 -0700970 @Override
971 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000972 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700973 }
974
975 @Override
976 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000977 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700978 }
979
980 @Override
981 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000982 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700983 }
984
985 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700986 // For now, we choose to ignore the presence of input devices that have vibrators
987 // when reporting whether the device has a vibrator. Applications often use this
988 // information to decide whether to enable certain features so they expect the
989 // result of hasVibrator() to be constant. For now, just report whether
990 // the device has a built-in vibrator.
991 //synchronized (mInputDeviceVibrators) {
992 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
993 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800994 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700995 }
996
Michael Wright71216972017-01-31 18:33:54 +0000997 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000998 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
999 try {
1000 synchronized (mInputDeviceVibrators) {
1001 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
1002 amplitude = mDefaultVibrationAmplitude;
Jeff Brown7f6c2312012-04-13 20:38:38 -07001003 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001004 if (DEBUG) {
1005 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
1006 " with amplitude " + amplitude + ".");
1007 }
1008 noteVibratorOnLocked(uid, millis);
1009 final int vibratorCount = mInputDeviceVibrators.size();
1010 if (vibratorCount != 0) {
1011 final AudioAttributes attributes =
1012 new AudioAttributes.Builder().setUsage(usageHint).build();
1013 for (int i = 0; i < vibratorCount; i++) {
1014 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
1015 }
1016 } else {
1017 // Note: ordering is important here! Many haptic drivers will reset their
1018 // amplitude when enabled, so we always have to enable frst, then set the
1019 // amplitude.
1020 vibratorOn(millis);
1021 doVibratorSetAmplitude(amplitude);
1022 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001023 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001024 } finally {
1025 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001026 }
1027 }
1028
Michael Wright71216972017-01-31 18:33:54 +00001029 private void doVibratorSetAmplitude(int amplitude) {
1030 if (mSupportsAmplitudeControl) {
1031 vibratorSetAmplitude(amplitude);
1032 }
1033 }
1034
Jeff Brown7f6c2312012-04-13 20:38:38 -07001035 private void doVibratorOff() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001036 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
1037 try {
1038 synchronized (mInputDeviceVibrators) {
1039 if (DEBUG) {
1040 Slog.d(TAG, "Turning vibrator off.");
Jeff Brown7f6c2312012-04-13 20:38:38 -07001041 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001042 noteVibratorOffLocked();
1043 final int vibratorCount = mInputDeviceVibrators.size();
1044 if (vibratorCount != 0) {
1045 for (int i = 0; i < vibratorCount; i++) {
1046 mInputDeviceVibrators.get(i).cancel();
1047 }
1048 } else {
1049 vibratorOff();
1050 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001051 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001052 } finally {
1053 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001054 }
1055 }
1056
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +00001057 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +00001058 private long doVibratorPrebakedEffectLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001059 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
1060 try {
1061 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1062 final boolean usingInputDeviceVibrators;
1063 synchronized (mInputDeviceVibrators) {
1064 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
Michael Wright35a0c672018-01-24 00:32:53 +00001065 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001066 // Input devices don't support prebaked effect, so skip trying it with them.
1067 if (!usingInputDeviceVibrators) {
1068 long timeout = vibratorPerformEffect(prebaked.getId(),
1069 prebaked.getEffectStrength());
1070 if (timeout > 0) {
1071 noteVibratorOnLocked(vib.uid, timeout);
1072 return timeout;
1073 }
1074 }
1075 if (!prebaked.shouldFallback()) {
1076 return 0;
1077 }
1078 VibrationEffect effect = getFallbackEffect(prebaked.getId());
1079 if (effect == null) {
1080 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1081 return 0;
1082 }
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001083 Vibration fallbackVib = new Vibration(vib.token, effect, vib.usageHint, vib.uid,
1084 vib.opPkg, vib.reason + " (fallback)");
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001085 final int intensity = getCurrentIntensityLocked(fallbackVib);
1086 linkVibration(fallbackVib);
1087 applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1088 startVibrationInnerLocked(fallbackVib);
Michael Wright35a0c672018-01-24 00:32:53 +00001089 return 0;
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001090 } finally {
1091 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright35a0c672018-01-24 00:32:53 +00001092 }
Michael Wright71216972017-01-31 18:33:54 +00001093 }
Eric Olsenf42f15c2009-10-29 16:42:03 -07001094
Michael Wright36d873f2018-01-08 15:54:05 +00001095 private VibrationEffect getFallbackEffect(int effectId) {
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +00001096 return mFallbackEffects.get(effectId);
Michael Wright36d873f2018-01-08 15:54:05 +00001097 }
1098
Michael Wright35a0c672018-01-24 00:32:53 +00001099 /**
1100 * Return the current desired effect strength.
1101 *
1102 * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1103 */
1104 private static int intensityToEffectStrength(int intensity) {
1105 switch (intensity) {
1106 case Vibrator.VIBRATION_INTENSITY_LOW:
1107 return EffectStrength.LIGHT;
1108 case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1109 return EffectStrength.MEDIUM;
1110 case Vibrator.VIBRATION_INTENSITY_HIGH:
1111 return EffectStrength.STRONG;
1112 default:
1113 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1114 return EffectStrength.STRONG;
1115 }
1116 }
1117
Michael Wrightc390fbe2018-12-12 19:45:09 +00001118 private static boolean isNotification(int usageHint) {
1119 switch (usageHint) {
1120 case AudioAttributes.USAGE_NOTIFICATION:
1121 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
1122 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
1123 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
1124 return true;
1125 default:
1126 return false;
1127 }
1128 }
1129
1130 private static boolean isRingtone(int usageHint) {
1131 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
1132 }
1133
1134 private static boolean isHapticFeedback(int usageHint) {
1135 return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
1136 }
1137
Michael Wright71216972017-01-31 18:33:54 +00001138 private void noteVibratorOnLocked(int uid, long millis) {
1139 try {
1140 mBatteryStatsService.noteVibratorOn(uid, millis);
Bookatza7020bd2018-08-28 16:29:35 -07001141 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null,
1142 StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
Michael Wright71216972017-01-31 18:33:54 +00001143 mCurVibUid = uid;
1144 } catch (RemoteException e) {
1145 }
1146 }
1147
1148 private void noteVibratorOffLocked() {
1149 if (mCurVibUid >= 0) {
1150 try {
1151 mBatteryStatsService.noteVibratorOff(mCurVibUid);
Bookatza7020bd2018-08-28 16:29:35 -07001152 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null,
1153 StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
Michael Wright71216972017-01-31 18:33:54 +00001154 } catch (RemoteException e) { }
1155 mCurVibUid = -1;
1156 }
1157 }
1158
Michael Wrightc390fbe2018-12-12 19:45:09 +00001159 private void setVibratorUnderExternalControl(boolean externalControl) {
1160 if (DEBUG) {
1161 if (externalControl) {
1162 Slog.d(TAG, "Vibrator going under external control.");
1163 } else {
1164 Slog.d(TAG, "Taking back control of vibrator.");
1165 }
1166 }
1167 mVibratorUnderExternalControl = externalControl;
1168 vibratorSetExternalControl(externalControl);
1169 }
1170
Michael Wright71216972017-01-31 18:33:54 +00001171 private class VibrateThread extends Thread {
1172 private final VibrationEffect.Waveform mWaveform;
1173 private final int mUid;
1174 private final int mUsageHint;
1175
1176 private boolean mForceStop;
1177
1178 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1179 mWaveform = waveform;
1180 mUid = uid;
1181 mUsageHint = usageHint;
1182 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001183 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 }
1185
Michael Wright71216972017-01-31 18:33:54 +00001186 private long delayLocked(long duration) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001187 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1188 try {
1189 long durationRemaining = duration;
1190 if (duration > 0) {
1191 final long bedtime = duration + SystemClock.uptimeMillis();
1192 do {
1193 try {
1194 this.wait(durationRemaining);
1195 }
1196 catch (InterruptedException e) { }
1197 if (mForceStop) {
1198 break;
1199 }
1200 durationRemaining = bedtime - SystemClock.uptimeMillis();
1201 } while (durationRemaining > 0);
1202 return duration - durationRemaining;
1203 }
1204 return 0;
1205 } finally {
1206 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001207 }
1208 }
1209
1210 public void run() {
1211 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +00001212 mWakeLock.acquire();
1213 try {
1214 boolean finished = playWaveform();
1215 if (finished) {
1216 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001217 }
Michael Wright71216972017-01-31 18:33:54 +00001218 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001219 mWakeLock.release();
1220 }
Michael Wright71216972017-01-31 18:33:54 +00001221 }
1222
1223 /**
1224 * Play the waveform.
1225 *
1226 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1227 */
1228 public boolean playWaveform() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001229 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1230 try {
1231 synchronized (this) {
1232 final long[] timings = mWaveform.getTimings();
1233 final int[] amplitudes = mWaveform.getAmplitudes();
1234 final int len = timings.length;
1235 final int repeat = mWaveform.getRepeatIndex();
Michael Wright71216972017-01-31 18:33:54 +00001236
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001237 int index = 0;
1238 long onDuration = 0;
1239 while (!mForceStop) {
1240 if (index < len) {
1241 final int amplitude = amplitudes[index];
1242 final long duration = timings[index++];
1243 if (duration <= 0) {
1244 continue;
Michael Wright71216972017-01-31 18:33:54 +00001245 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001246 if (amplitude != 0) {
1247 if (onDuration <= 0) {
1248 // Telling the vibrator to start multiple times usually causes
1249 // effects to feel "choppy" because the motor resets at every on
1250 // command. Instead we figure out how long our next "on" period
1251 // is going to be, tell the motor to stay on for the full
1252 // duration, and then wake up to change the amplitude at the
1253 // appropriate intervals.
1254 onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1255 repeat);
1256 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1257 } else {
1258 doVibratorSetAmplitude(amplitude);
1259 }
1260 }
Michael Wright71216972017-01-31 18:33:54 +00001261
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001262 long waitTime = delayLocked(duration);
1263 if (amplitude != 0) {
1264 onDuration -= waitTime;
1265 }
1266 } else if (repeat < 0) {
1267 break;
1268 } else {
1269 index = repeat;
Michael Wright71216972017-01-31 18:33:54 +00001270 }
Michael Wright71216972017-01-31 18:33:54 +00001271 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001272 return !mForceStop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001274 } finally {
1275 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +00001276 }
1277 }
1278
1279 public void cancel() {
1280 synchronized (this) {
1281 mThread.mForceStop = true;
1282 mThread.notify();
1283 }
1284 }
1285
1286 /**
1287 * Get the duration the vibrator will be on starting at startIndex until the next time it's
1288 * off.
1289 */
1290 private long getTotalOnDuration(
1291 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1292 int i = startIndex;
1293 long timing = 0;
1294 while(amplitudes[i] != 0) {
1295 timing += timings[i++];
1296 if (i >= timings.length) {
1297 if (repeatIndex >= 0) {
1298 i = repeatIndex;
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001299 // prevent infinite loop
1300 repeatIndex = -1;
Michael Wright71216972017-01-31 18:33:54 +00001301 } else {
1302 break;
1303 }
1304 }
1305 if (i == startIndex) {
1306 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -04001307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 }
Michael Wright71216972017-01-31 18:33:54 +00001309 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 }
Jeff Brown969579b2014-05-20 19:29:29 -07001311 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001312
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -07001314 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 public void onReceive(Context context, Intent intent) {
1316 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +00001317 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -07001318 // When the system is entering a non-interactive state, we want
1319 // to cancel vibrations in case a misbehaving app has abandoned
1320 // them. However it may happen that the system is currently playing
1321 // haptic feedback as part of the transition. So we don't cancel
1322 // system vibrations.
1323 if (mCurrentVibration != null
Michael Wright35a0c672018-01-24 00:32:53 +00001324 && !(mCurrentVibration.isHapticFeedback()
1325 && mCurrentVibration.isFromSystem())) {
Jeff Brown969579b2014-05-20 19:29:29 -07001326 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -07001327 }
Patrick Scott18dd5f02009-07-02 11:31:12 -04001328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 }
1330 }
1331 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001332
1333 @Override
1334 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001335 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001336
Michael Wright35a0c672018-01-24 00:32:53 +00001337 pw.println("Vibrator Service:");
Michael Wright71216972017-01-31 18:33:54 +00001338 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +00001339 pw.print(" mCurrentVibration=");
1340 if (mCurrentVibration != null) {
1341 pw.println(mCurrentVibration.toInfo().toString());
1342 } else {
1343 pw.println("null");
1344 }
Michael Wrightc390fbe2018-12-12 19:45:09 +00001345 pw.print(" mCurrentExternalVibration=");
1346 if (mCurrentExternalVibration != null) {
1347 pw.println(mCurrentExternalVibration.toString());
1348 } else {
1349 pw.println("null");
1350 }
1351 pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
Michael Wright35a0c672018-01-24 00:32:53 +00001352 pw.println(" mLowPowerMode=" + mLowPowerMode);
1353 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1354 pw.println(" mNotificationIntensity=" + mNotificationIntensity);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +00001355 pw.println(" mRingIntensity=" + mRingIntensity);
Michael Wright35a0c672018-01-24 00:32:53 +00001356 pw.println("");
1357 pw.println(" Previous vibrations:");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001358 for (VibrationInfo info : mPreviousVibrations) {
Michael Wright35a0c672018-01-24 00:32:53 +00001359 pw.print(" ");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001360 pw.println(info.toString());
1361 }
1362 }
1363 }
Felipe Lemea5281002017-02-10 15:13:48 -08001364
1365 @Override
1366 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1367 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1368 throws RemoteException {
1369 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1370 }
1371
Michael Wrightc390fbe2018-12-12 19:45:09 +00001372 final class ExternalVibratorService extends IExternalVibratorService.Stub {
1373 @Override
1374 public int onExternalVibrationStart(ExternalVibration vib) {
1375 if (!mSupportsExternalControl) {
1376 return SCALE_MUTE;
1377 }
1378 if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
1379 vib.getUid(), -1 /*owningUid*/, true /*exported*/)
1380 != PackageManager.PERMISSION_GRANTED) {
1381 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
1382 + " tried to play externally controlled vibration"
1383 + " without VIBRATE permission, ignoring.");
1384 return SCALE_MUTE;
1385 }
1386
1387 final int scaleLevel;
1388 synchronized (mLock) {
1389 if (!vib.equals(mCurrentExternalVibration)) {
1390 if (mCurrentExternalVibration == null) {
1391 // If we're not under external control right now, then cancel any normal
1392 // vibration that may be playing and ready the vibrator for external
1393 // control.
1394 doCancelVibrateLocked();
1395 setVibratorUnderExternalControl(true);
1396 }
1397 // At this point we either have an externally controlled vibration playing, or
1398 // no vibration playing. Since the interface defines that only one externally
1399 // controlled vibration can play at a time, by returning something other than
1400 // SCALE_MUTE from this function we can be assured that if we are currently
1401 // playing vibration, it will be muted in favor of the new vibration.
1402 //
1403 // Note that this doesn't support multiple concurrent external controls, as we
1404 // would need to mute the old one still if it came from a different controller.
1405 mCurrentExternalVibration = vib;
1406 if (DEBUG) {
1407 Slog.e(TAG, "Playing external vibration: " + vib);
1408 }
1409 }
1410 final int usage = vib.getAudioAttributes().getUsage();
1411 final int defaultIntensity;
1412 final int currentIntensity;
1413 if (isRingtone(usage)) {
1414 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
1415 currentIntensity = mRingIntensity;
1416 } else if (isNotification(usage)) {
1417 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
1418 currentIntensity = mNotificationIntensity;
1419 } else if (isHapticFeedback(usage)) {
1420 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
1421 currentIntensity = mHapticFeedbackIntensity;
1422 } else {
1423 defaultIntensity = 0;
1424 currentIntensity = 0;
1425 }
1426 scaleLevel = currentIntensity - defaultIntensity;
1427 }
1428 if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
1429 return scaleLevel;
1430 } else {
1431 // Presumably we want to play this but something about our scaling has gone
1432 // wrong, so just play with no scaling.
1433 Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
1434 + scaleLevel + " for vibration " + vib);
1435 return SCALE_NONE;
1436 }
1437 }
1438
1439 @Override
1440 public void onExternalVibrationStop(ExternalVibration vib) {
1441 synchronized (mLock) {
1442 if (vib.equals(mCurrentExternalVibration)) {
1443 mCurrentExternalVibration = null;
1444 setVibratorUnderExternalControl(false);
1445 if (DEBUG) {
1446 Slog.e(TAG, "Stopping external vibration" + vib);
1447 }
1448 }
1449 }
1450 }
1451 }
1452
Felipe Lemea5281002017-02-10 15:13:48 -08001453 private final class VibratorShellCommand extends ShellCommand {
1454
Felipe Lemea5281002017-02-10 15:13:48 -08001455 private final IBinder mToken;
1456
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001457 private final class CommonOptions {
1458 public boolean force = false;
1459 public void check(String opt) {
1460 switch (opt) {
1461 case "-f":
1462 force = true;
1463 break;
1464 }
1465 }
1466 }
1467
Felipe Lemea5281002017-02-10 15:13:48 -08001468 private VibratorShellCommand(IBinder token) {
1469 mToken = token;
1470 }
1471
1472 @Override
1473 public int onCommand(String cmd) {
1474 if ("vibrate".equals(cmd)) {
1475 return runVibrate();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001476 } else if ("waveform".equals(cmd)) {
1477 return runWaveform();
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001478 } else if ("prebaked".equals(cmd)) {
1479 return runPrebaked();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001480 } else if ("cancel".equals(cmd)) {
1481 cancelVibrate(mToken);
1482 return 0;
Felipe Lemea5281002017-02-10 15:13:48 -08001483 }
1484 return handleDefaultCommands(cmd);
1485 }
1486
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001487 private boolean checkDoNotDisturb(CommonOptions opts) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001488 try {
1489 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1490 Settings.Global.ZEN_MODE);
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001491 if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001492 try (PrintWriter pw = getOutPrintWriter();) {
1493 pw.print("Ignoring because device is on DND mode ");
1494 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1495 zenMode));
1496 return true;
1497 }
1498 }
1499 } catch (SettingNotFoundException e) {
1500 // ignore
1501 }
1502
1503 return false;
1504 }
1505
Felipe Lemea5281002017-02-10 15:13:48 -08001506 private int runVibrate() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001507 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001508 try {
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001509 CommonOptions commonOptions = new CommonOptions();
1510
1511 String opt;
1512 while ((opt = getNextOption()) != null) {
1513 commonOptions.check(opt);
1514 }
1515
1516 if (checkDoNotDisturb(commonOptions)) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001517 return 0;
Felipe Leme5e2e6322017-07-14 17:25:59 -07001518 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001519
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001520 final long duration = Long.parseLong(getNextArgRequired());
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001521 String description = getNextArg();
1522 if (description == null) {
1523 description = "Shell command";
1524 }
Michael Wright71216972017-01-31 18:33:54 +00001525
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001526 VibrationEffect effect =
1527 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1528 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001529 "Shell Command", mToken);
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001530 return 0;
1531 } finally {
1532 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1533 }
Felipe Lemea5281002017-02-10 15:13:48 -08001534 }
1535
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001536 private int runWaveform() {
1537 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
1538 try {
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001539 String description = "Shell command";
1540 int repeat = -1;
1541 ArrayList<Integer> amplitudesList = null;
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001542 CommonOptions commonOptions = new CommonOptions();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001543
1544 String opt;
1545 while ((opt = getNextOption()) != null) {
1546 switch (opt) {
1547 case "-d":
1548 description = getNextArgRequired();
1549 break;
1550 case "-r":
1551 repeat = Integer.parseInt(getNextArgRequired());
1552 break;
1553 case "-a":
1554 if (amplitudesList == null) {
1555 amplitudesList = new ArrayList<Integer>();
1556 }
1557 break;
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001558 default:
1559 commonOptions.check(opt);
1560 break;
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001561 }
1562 }
1563
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001564 if (checkDoNotDisturb(commonOptions)) {
1565 return 0;
1566 }
1567
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001568 ArrayList<Long> timingsList = new ArrayList<Long>();
1569
1570 String arg;
1571 while ((arg = getNextArg()) != null) {
1572 if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
1573 amplitudesList.add(Integer.parseInt(arg));
1574 } else {
1575 timingsList.add(Long.parseLong(arg));
1576 }
1577 }
1578
1579 VibrationEffect effect;
1580 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
1581 if (amplitudesList == null) {
1582 effect = VibrationEffect.createWaveform(timings, repeat);
1583 } else {
1584 int[] amplitudes =
1585 amplitudesList.stream().mapToInt(Integer::intValue).toArray();
1586 effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
1587 }
1588 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1589 "Shell Command", mToken);
1590 return 0;
1591 } finally {
1592 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1593 }
1594 }
1595
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001596 private int runPrebaked() {
1597 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
1598 try {
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001599 CommonOptions commonOptions = new CommonOptions();
1600
1601 String opt;
1602 while ((opt = getNextOption()) != null) {
1603 commonOptions.check(opt);
1604 }
1605
1606 if (checkDoNotDisturb(commonOptions)) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001607 return 0;
1608 }
1609
1610 final int id = Integer.parseInt(getNextArgRequired());
1611
1612 String description = getNextArg();
1613 if (description == null) {
1614 description = "Shell command";
1615 }
1616
1617 VibrationEffect effect =
1618 VibrationEffect.get(id, false);
1619 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1620 "Shell Command", mToken);
1621 return 0;
1622 } finally {
1623 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1624 }
1625 }
1626
Felipe Lemea5281002017-02-10 15:13:48 -08001627 @Override
1628 public void onHelp() {
1629 try (PrintWriter pw = getOutPrintWriter();) {
1630 pw.println("Vibrator commands:");
1631 pw.println(" help");
1632 pw.println(" Prints this help text.");
1633 pw.println("");
1634 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001635 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1636 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001637 pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
1638 pw.println(" Vibrates for durations and amplitudes in list;");
1639 pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
1640 pw.println(" If -r is provided, the waveform loops back to the specified");
1641 pw.println(" index (e.g. 0 loops from the beginning)");
1642 pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
1643 pw.println(" otherwise, it accepts durations only and alternates off/on");
1644 pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001645 pw.println(" prebaked effect-id [description]");
1646 pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
1647 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001648 pw.println(" cancel");
1649 pw.println(" Cancels any active vibration");
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001650 pw.println("Common Options:");
1651 pw.println(" -f - Force. Ignore Do Not Disturb setting.");
Felipe Lemea5281002017-02-10 15:13:48 -08001652 pw.println("");
1653 }
1654 }
1655 }
1656
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657}