blob: ea6d435c7ba5581d2f2fadbe27ea56e024332cb5 [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;
Joe Onorato95e4f702009-03-24 19:29:09 -070036import android.os.Handler;
Bookatza7020bd2018-08-28 16:29:35 -070037import android.os.IBinder;
Mike Lockwood3a322132009-11-24 00:30:52 -050038import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.os.PowerManager;
Bookatza7020bd2018-08-28 16:29:35 -070040import android.os.PowerManager.ServiceType;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070041import android.os.PowerManagerInternal;
Bookatza7020bd2018-08-28 16:29:35 -070042import android.os.PowerSaveState;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Process;
44import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080045import android.os.ResultReceiver;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080046import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080047import android.os.ShellCallback;
48import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.SystemClock;
Alexey Kuzmine59145a2018-02-10 15:19:03 +000050import android.os.Trace;
Jeff Brownd4935962012-09-25 13:27:20 -070051import android.os.UserHandle;
Michael Wright71216972017-01-31 18:33:54 +000052import android.os.VibrationEffect;
Bookatza7020bd2018-08-28 16:29:35 -070053import android.os.Vibrator;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070055import android.provider.Settings;
56import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070057import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080058import android.util.Slog;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +000059import android.util.SparseArray;
Bookatza7020bd2018-08-28 16:29:35 -070060import android.util.StatsLog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070061import android.view.InputDevice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +000063import com.android.internal.annotations.GuardedBy;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080064import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060065import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080066
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070067import java.io.FileDescriptor;
68import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070069import java.util.ArrayList;
Michael Wright36d873f2018-01-08 15:54:05 +000070import java.util.Date;
Bookatza7020bd2018-08-28 16:29:35 -070071import java.util.LinkedList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040072
Jeff Brown7f6c2312012-04-13 20:38:38 -070073public class VibratorService extends IVibratorService.Stub
74 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050075 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070076 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070077 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050078
Michael Wright36d873f2018-01-08 15:54:05 +000079 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
80
Michael Wright0dbb5162018-05-25 15:13:36 +010081 // Scale levels. Each level is defined as the delta between the current setting and the default
82 // intensity for that type of vibration (i.e. current - default).
83 private static final int SCALE_VERY_LOW = -2;
84 private static final int SCALE_LOW = -1;
85 private static final int SCALE_NONE = 0;
86 private static final int SCALE_HIGH = 1;
87 private static final int SCALE_VERY_HIGH = 2;
Michael Wright35a0c672018-01-24 00:32:53 +000088
Michael Wright0dbb5162018-05-25 15:13:36 +010089 // Gamma adjustments for scale levels.
90 private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
91 private static final float SCALE_LOW_GAMMA = 1.5f;
92 private static final float SCALE_NONE_GAMMA = 1.0f;
93 private static final float SCALE_HIGH_GAMMA = 0.5f;
94 private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
95
96 // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
97 // max amplitude.
98 private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
99 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
Michael Wright35a0c672018-01-24 00:32:53 +0000100
101 // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
102 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
103
Michael Wright0dbb5162018-05-25 15:13:36 +0100104
105 // A mapping from the intensity adjustment to the scaling to apply, where the intensity
106 // adjustment is defined as the delta between the default intensity level and the user selected
107 // intensity level. It's important that we apply the scaling on the delta between the two so
108 // that the default intensity level applies no scaling to application provided effects.
109 private final SparseArray<ScaleLevel> mScaleLevels;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700110 private final LinkedList<VibrationInfo> mPreviousVibrations;
111 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -0700112 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +0000113 private final boolean mSupportsAmplitudeControl;
114 private final int mDefaultVibrationAmplitude;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000115 private final SparseArray<VibrationEffect> mFallbackEffects;
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000116 private final SparseArray<Integer> mProcStatesCache = new SparseArray();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700117 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700118 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +0000119 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700120
121 private final Context mContext;
122 private final PowerManager.WakeLock mWakeLock;
Svet Ganovf7b47252018-02-26 11:11:27 -0800123 private final AppOpsManager mAppOps;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800124 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700125 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700126 private InputManager mIm;
Michael Wright35a0c672018-01-24 00:32:53 +0000127 private Vibrator mVibrator;
128 private SettingsObserver mSettingObserver;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700129
Michael Wright71216972017-01-31 18:33:54 +0000130 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700131
Michael Wright71216972017-01-31 18:33:54 +0000132 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -0700133 // to be acquired
134 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
135 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
136 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
137
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000138 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000139 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800140 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700141 private boolean mLowPowerMode;
Michael Wright35a0c672018-01-24 00:32:53 +0000142 private int mHapticFeedbackIntensity;
143 private int mNotificationIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000144 private int mRingIntensity;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800145
Jeff Brown7f6c2312012-04-13 20:38:38 -0700146 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200147 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700148 native static void vibratorOn(long milliseconds);
149 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000150 native static boolean vibratorSupportsAmplitudeControl();
151 native static void vibratorSetAmplitude(int amplitude);
152 native static long vibratorPerformEffect(long effect, long strength);
Harpreet "Eli" Sanghaa456f082018-12-14 12:06:10 +0900153 static native boolean vibratorSupportsExternalControl();
154 static native void vibratorSetExternalControl(boolean enabled);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400155
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000156 private final IUidObserver mUidObserver = new IUidObserver.Stub() {
157 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
158 mProcStatesCache.put(uid, procState);
159 }
160
161 @Override public void onUidGone(int uid, boolean disabled) {
162 mProcStatesCache.delete(uid);
163 }
164
165 @Override public void onUidActive(int uid) {
166 }
167
168 @Override public void onUidIdle(int uid, boolean disabled) {
169 }
170
171 @Override public void onUidCachedChanged(int uid, boolean cached) {
172 }
173 };
174
Patrick Scott18dd5f02009-07-02 11:31:12 -0400175 private class Vibration implements IBinder.DeathRecipient {
Michael Wright35a0c672018-01-24 00:32:53 +0000176 public final IBinder token;
Michael Wright36d873f2018-01-08 15:54:05 +0000177 // Start time in CLOCK_BOOTTIME base.
Michael Wright35a0c672018-01-24 00:32:53 +0000178 public final long startTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000179 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
Michael Wright35a0c672018-01-24 00:32:53 +0000180 // with other system events, any duration calculations should be done use startTime so as
Michael Wright36d873f2018-01-08 15:54:05 +0000181 // not to be affected by discontinuities created by RTC adjustments.
Michael Wright35a0c672018-01-24 00:32:53 +0000182 public final long startTimeDebug;
183 public final int usageHint;
184 public final int uid;
185 public final String opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100186 public final String reason;
Michael Wright35a0c672018-01-24 00:32:53 +0000187
188 // The actual effect to be played.
189 public VibrationEffect effect;
190 // The original effect that was requested. This is non-null only when the original effect
191 // differs from the effect that's being played. Typically these two things differ because
192 // the effect was scaled based on the users vibration intensity settings.
193 public VibrationEffect originalEffect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400194
Michael Wright71216972017-01-31 18:33:54 +0000195 private Vibration(IBinder token, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100196 int usageHint, int uid, String opPkg, String reason) {
Michael Wright35a0c672018-01-24 00:32:53 +0000197 this.token = token;
198 this.effect = effect;
199 this.startTime = SystemClock.elapsedRealtime();
200 this.startTimeDebug = System.currentTimeMillis();
201 this.usageHint = usageHint;
202 this.uid = uid;
203 this.opPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100204 this.reason = reason;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400205 }
206
207 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000208 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400209 if (this == mCurrentVibration) {
210 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400211 }
212 }
213 }
214
Michael Wright35a0c672018-01-24 00:32:53 +0000215 public boolean hasTimeoutLongerThan(long millis) {
216 final long duration = effect.getDuration();
217 return duration >= 0 && duration > millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400218 }
Jeff Brown969579b2014-05-20 19:29:29 -0700219
Michael Wright35a0c672018-01-24 00:32:53 +0000220 public boolean isHapticFeedback() {
221 if (effect instanceof VibrationEffect.Prebaked) {
222 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
223 switch (prebaked.getId()) {
224 case VibrationEffect.EFFECT_CLICK:
225 case VibrationEffect.EFFECT_DOUBLE_CLICK:
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000226 case VibrationEffect.EFFECT_HEAVY_CLICK:
Michael Wright35a0c672018-01-24 00:32:53 +0000227 case VibrationEffect.EFFECT_TICK:
Michael Wright0dbb5162018-05-25 15:13:36 +0100228 case VibrationEffect.EFFECT_POP:
229 case VibrationEffect.EFFECT_THUD:
Michael Wright35a0c672018-01-24 00:32:53 +0000230 return true;
231 default:
232 Slog.w(TAG, "Unknown prebaked vibration effect, "
233 + "assuming it isn't haptic feedback.");
234 return false;
235 }
Michael Wright71216972017-01-31 18:33:54 +0000236 }
Michael Wright35a0c672018-01-24 00:32:53 +0000237 final long duration = effect.getDuration();
238 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
239 }
240
241 public boolean isNotification() {
242 switch (usageHint) {
243 case AudioAttributes.USAGE_NOTIFICATION:
244 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
245 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
246 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
247 return true;
248 default:
249 return false;
250 }
251 }
252
253 public boolean isRingtone() {
254 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
255 }
256
257 public boolean isFromSystem() {
258 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
Jeff Brown969579b2014-05-20 19:29:29 -0700259 }
Michael Wright36d873f2018-01-08 15:54:05 +0000260
261 public VibrationInfo toInfo() {
Michael Wright35a0c672018-01-24 00:32:53 +0000262 return new VibrationInfo(
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100263 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg, reason);
Michael Wright36d873f2018-01-08 15:54:05 +0000264 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400265 }
266
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700267 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000268 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000269 private final VibrationEffect mEffect;
Michael Wright35a0c672018-01-24 00:32:53 +0000270 private final VibrationEffect mOriginalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000271 private final int mUsageHint;
272 private final int mUid;
273 private final String mOpPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100274 private final String mReason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700275
Michael Wright36d873f2018-01-08 15:54:05 +0000276 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100277 VibrationEffect originalEffect, int usageHint, int uid,
278 String opPkg, String reason) {
Michael Wright36d873f2018-01-08 15:54:05 +0000279 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000280 mEffect = effect;
Michael Wright35a0c672018-01-24 00:32:53 +0000281 mOriginalEffect = originalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000282 mUsageHint = usageHint;
283 mUid = uid;
284 mOpPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100285 mReason = reason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700286 }
287
288 @Override
289 public String toString() {
290 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000291 .append("startTime: ")
292 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000293 .append(", effect: ")
294 .append(mEffect)
Michael Wright35a0c672018-01-24 00:32:53 +0000295 .append(", originalEffect: ")
296 .append(mOriginalEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700297 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000298 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700299 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000300 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700301 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000302 .append(mOpPkg)
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100303 .append(", reason: ")
304 .append(mReason)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700305 .toString();
306 }
307 }
308
Michael Wright0dbb5162018-05-25 15:13:36 +0100309 private static final class ScaleLevel {
310 public final float gamma;
311 public final int maxAmplitude;
312
313 public ScaleLevel(float gamma) {
314 this(gamma, VibrationEffect.MAX_AMPLITUDE);
315 }
316
317 public ScaleLevel(float gamma, int maxAmplitude) {
318 this.gamma = gamma;
319 this.maxAmplitude = maxAmplitude;
320 }
321
322 @Override
323 public String toString() {
324 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
325 }
326 }
327
Mike Lockwood3a322132009-11-24 00:30:52 -0500328 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200329 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 // Reset the hardware to a default state, in case this is a runtime
331 // restart instead of a fresh boot.
332 vibratorOff();
333
Michael Wright71216972017-01-31 18:33:54 +0000334 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000337 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700338 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 mWakeLock.setReferenceCounted(true);
340
Svet Ganovf7b47252018-02-26 11:11:27 -0800341 mAppOps = mContext.getSystemService(AppOpsManager.class);
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700342 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
343 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800344
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700345 mPreviousVibrationsLimit = mContext.getResources().getInteger(
346 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
347
Michael Wright71216972017-01-31 18:33:54 +0000348 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
349 com.android.internal.R.integer.config_defaultVibrationAmplitude);
350
Tyler Freeman319a34a2017-05-04 17:23:35 -0700351 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
352 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
353
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700354 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 IntentFilter filter = new IntentFilter();
357 filter.addAction(Intent.ACTION_SCREEN_OFF);
358 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000359
Michael Wrightd39cbec2018-04-16 19:35:13 +0100360 VibrationEffect clickEffect = createEffectFromResource(
Michael Wright71216972017-01-31 18:33:54 +0000361 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000362 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000363 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100364 VibrationEffect heavyClickEffect = createEffectFromResource(
365 com.android.internal.R.array.config_longPressVibePattern);
366 VibrationEffect tickEffect = createEffectFromResource(
Michael Wright57d94d92017-05-31 14:44:45 +0100367 com.android.internal.R.array.config_clockTickVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000368
Michael Wright0dbb5162018-05-25 15:13:36 +0100369 mFallbackEffects = new SparseArray<>();
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000370 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
371 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
372 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100373 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
Michael Wright0dbb5162018-05-25 15:13:36 +0100374
375 mScaleLevels = new SparseArray<>();
376 mScaleLevels.put(SCALE_VERY_LOW,
377 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
378 mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
379 mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
380 mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
381 mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
Michael Wright57d94d92017-05-31 14:44:45 +0100382 }
383
Michael Wrightd39cbec2018-04-16 19:35:13 +0100384 private VibrationEffect createEffectFromResource(int resId) {
385 long[] timings = getLongIntArray(mContext.getResources(), resId);
386 return createEffectFromTimings(timings);
387 }
388
389 private static VibrationEffect createEffectFromTimings(long[] timings) {
Michael Wright57d94d92017-05-31 14:44:45 +0100390 if (timings == null || timings.length == 0) {
391 return null;
392 } else if (timings.length == 1) {
393 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
394 } else {
395 return VibrationEffect.createWaveform(timings, -1);
396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 }
398
Jeff Brown7f6c2312012-04-13 20:38:38 -0700399 public void systemReady() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000400 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
401 try {
402 mIm = mContext.getSystemService(InputManager.class);
403 mVibrator = mContext.getSystemService(Vibrator.class);
404 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700405
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000406 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
407 mPowerManagerInternal.registerLowPowerModeObserver(
408 new PowerManagerInternal.LowPowerModeListener() {
409 @Override
410 public int getServiceType() {
411 return ServiceType.VIBRATION;
412 }
jackqdyulei455e90a2017-02-09 15:29:16 -0800413
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000414 @Override
415 public void onLowPowerModeChanged(PowerSaveState result) {
416 updateVibrators();
417 }
418 });
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700419
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000420 mContext.getContentResolver().registerContentObserver(
421 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
422 true, mSettingObserver, UserHandle.USER_ALL);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700423
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000424 mContext.getContentResolver().registerContentObserver(
425 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
426 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000427
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000428 mContext.getContentResolver().registerContentObserver(
429 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
430 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000431
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000432 mContext.getContentResolver().registerContentObserver(
433 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
434 true, mSettingObserver, UserHandle.USER_ALL);
435
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000436 mContext.registerReceiver(new BroadcastReceiver() {
437 @Override
438 public void onReceive(Context context, Intent intent) {
439 updateVibrators();
440 }
441 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700442
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000443 try {
444 ActivityManager.getService().registerUidObserver(mUidObserver,
445 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
446 ActivityManager.PROCESS_STATE_UNKNOWN, null);
447 } catch (RemoteException e) {
448 // ignored; both services live in system_server
449 }
450
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000451 updateVibrators();
452 } finally {
453 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
454 }
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700455 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700456
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700457 private final class SettingsObserver extends ContentObserver {
458 public SettingsObserver(Handler handler) {
459 super(handler);
460 }
461
462 @Override
463 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000464 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700465 }
466 }
467
Jeff Brown82379ba2014-07-25 19:03:28 -0700468 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700469 public boolean hasVibrator() {
470 return doVibratorExists();
471 }
472
Michael Wright71216972017-01-31 18:33:54 +0000473 @Override // Binder call
474 public boolean hasAmplitudeControl() {
475 synchronized (mInputDeviceVibrators) {
476 // Input device vibrators don't support amplitude controls yet, but are still used over
477 // the system vibrator when connected.
478 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
479 }
480 }
481
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800482 private void verifyIncomingUid(int uid) {
483 if (uid == Binder.getCallingUid()) {
484 return;
485 }
486 if (Binder.getCallingPid() == Process.myPid()) {
487 return;
488 }
489 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
490 Binder.getCallingPid(), Binder.getCallingUid(), null);
491 }
492
Michael Wright71216972017-01-31 18:33:54 +0000493 /**
494 * Validate the incoming VibrationEffect.
495 *
496 * We can't throw exceptions here since we might be called from some system_server component,
497 * which would bring the whole system down.
498 *
499 * @return whether the VibrationEffect is valid
500 */
501 private static boolean verifyVibrationEffect(VibrationEffect effect) {
502 if (effect == null) {
503 // Effect must not be null.
504 Slog.wtf(TAG, "effect must not be null");
505 return false;
506 }
507 try {
508 effect.validate();
509 } catch (Exception e) {
510 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
511 return false;
512 }
513 return true;
514 }
515
516 private static long[] getLongIntArray(Resources r, int resid) {
517 int[] ar = r.getIntArray(resid);
518 if (ar == null) {
519 return null;
520 }
521 long[] out = new long[ar.length];
522 for (int i = 0; i < ar.length; i++) {
523 out[i] = ar[i];
524 }
525 return out;
526 }
527
Jeff Brown82379ba2014-07-25 19:03:28 -0700528 @Override // Binder call
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100529 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
John Spurlock1af30c72014-03-10 08:33:35 -0400530 IBinder token) {
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100531 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000532 try {
533 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
534 != PackageManager.PERMISSION_GRANTED) {
535 throw new SecurityException("Requires VIBRATE permission");
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000536 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000537 if (token == null) {
538 Slog.e(TAG, "token must not be null");
539 return;
540 }
541 verifyIncomingUid(uid);
542 if (!verifyVibrationEffect(effect)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 return;
544 }
545
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000546 // If our current vibration is longer than the new vibration and is the same amplitude,
547 // then just let the current one finish.
548 synchronized (mLock) {
549 if (effect instanceof VibrationEffect.OneShot
550 && mCurrentVibration != null
551 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
552 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
553 VibrationEffect.OneShot currentOneShot =
554 (VibrationEffect.OneShot) mCurrentVibration.effect;
555 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
556 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
557 if (DEBUG) {
558 Slog.d(TAG,
559 "Ignoring incoming vibration in favor of current vibration");
560 }
561 return;
562 }
563 }
564
565 // If the current vibration is repeating and the incoming one is non-repeating,
566 // then ignore the non-repeating vibration. This is so that we don't cancel
567 // vibrations that are meant to grab the attention of the user, like ringtones and
568 // alarms, in favor of one-shot vibrations that are likely quite short.
569 if (!isRepeatingVibration(effect)
570 && mCurrentVibration != null
571 && isRepeatingVibration(mCurrentVibration.effect)) {
572 if (DEBUG) {
573 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
574 }
575 return;
576 }
577
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100578 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
Alexey Kuzminddebe592019-01-08 16:07:41 +0000579 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
580 > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
581 && vib.isHapticFeedback()) {
582 Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
583 + uid + " is background");
584 return;
585 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000586 linkVibration(vib);
587 long ident = Binder.clearCallingIdentity();
588 try {
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100589
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000590 doCancelVibrateLocked();
591 startVibrationLocked(vib);
592 addToPreviousVibrationsLocked(vib);
593 } finally {
594 Binder.restoreCallingIdentity(ident);
595 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000597 } finally {
598 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 }
600 }
601
Michael Wright58c46312017-10-05 14:04:14 -0400602 private static boolean isRepeatingVibration(VibrationEffect effect) {
Michael Wright35a0c672018-01-24 00:32:53 +0000603 return effect.getDuration() == Long.MAX_VALUE;
Michael Wright58c46312017-10-05 14:04:14 -0400604 }
605
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700606 private void addToPreviousVibrationsLocked(Vibration vib) {
607 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
608 mPreviousVibrations.removeFirst();
609 }
Michael Wright36d873f2018-01-08 15:54:05 +0000610 mPreviousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700611 }
612
Jeff Brown82379ba2014-07-25 19:03:28 -0700613 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400614 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 mContext.enforceCallingOrSelfPermission(
616 android.Manifest.permission.VIBRATE,
617 "cancelVibrate");
618
Michael Wright71216972017-01-31 18:33:54 +0000619 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +0000620 if (mCurrentVibration != null && mCurrentVibration.token == token) {
Michael Wright71216972017-01-31 18:33:54 +0000621 if (DEBUG) {
622 Slog.d(TAG, "Canceling vibration.");
623 }
624 long ident = Binder.clearCallingIdentity();
625 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400626 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000627 } finally {
628 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400629 }
630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700633
Michael Wright71216972017-01-31 18:33:54 +0000634 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700635 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400636 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000637 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400638 }
639 };
640
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000641 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400642 private void doCancelVibrateLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000643 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
644 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
645 try {
646 mH.removeCallbacks(mVibrationEndRunnable);
647 if (mThread != null) {
648 mThread.cancel();
649 mThread = null;
650 }
651 doVibratorOff();
652 reportFinishVibrationLocked();
653 } finally {
654 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400655 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400656 }
657
Michael Wright71216972017-01-31 18:33:54 +0000658 // Callback for whenever the current vibration has finished played out
659 public void onVibrationFinished() {
660 if (DEBUG) {
661 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400662 }
Michael Wright71216972017-01-31 18:33:54 +0000663 synchronized (mLock) {
664 // Make sure the vibration is really done. This also reports that the vibration is
665 // finished.
666 doCancelVibrateLocked();
667 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400668 }
669
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000670 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400671 private void startVibrationLocked(final Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000672 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
673 try {
674 if (!isAllowedToVibrateLocked(vib)) {
675 return;
Michael Wright71216972017-01-31 18:33:54 +0000676 }
Michael Wright71216972017-01-31 18:33:54 +0000677
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000678 final int intensity = getCurrentIntensityLocked(vib);
679 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
680 return;
Michael Wright71216972017-01-31 18:33:54 +0000681 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000682
683 if (vib.isRingtone() && !shouldVibrateForRingtone()) {
684 if (DEBUG) {
685 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
686 }
687 return;
688 }
689
690 final int mode = getAppOpMode(vib);
691 if (mode != AppOpsManager.MODE_ALLOWED) {
692 if (mode == AppOpsManager.MODE_ERRORED) {
693 // We might be getting calls from within system_server, so we don't actually
694 // want to throw a SecurityException here.
695 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
696 }
697 return;
698 }
699 applyVibrationIntensityScalingLocked(vib, intensity);
700 startVibrationInnerLocked(vib);
701 } finally {
702 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +0000703 }
Michael Wright71216972017-01-31 18:33:54 +0000704 }
705
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000706 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000707 private void startVibrationInnerLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000708 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
709 try {
710 mCurrentVibration = vib;
711 if (vib.effect instanceof VibrationEffect.OneShot) {
712 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
713 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
714 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
715 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
716 } else if (vib.effect instanceof VibrationEffect.Waveform) {
717 // mThread better be null here. doCancelVibrate should always be
718 // called before startNextVibrationLocked or startVibrationLocked.
719 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
720 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
721 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
722 mThread.start();
723 } else if (vib.effect instanceof VibrationEffect.Prebaked) {
724 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
725 long timeout = doVibratorPrebakedEffectLocked(vib);
726 if (timeout > 0) {
727 mH.postDelayed(mVibrationEndRunnable, timeout);
728 }
729 } else {
730 Slog.e(TAG, "Unknown vibration type, ignoring");
Michael Wright71216972017-01-31 18:33:54 +0000731 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000732 } finally {
733 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 }
735 }
736
Michael Wright35a0c672018-01-24 00:32:53 +0000737 private boolean isAllowedToVibrateLocked(Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700738 if (!mLowPowerMode) {
739 return true;
740 }
Michael Wright35a0c672018-01-24 00:32:53 +0000741
742 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700743 return true;
744 }
Tyler Freeman319a34a2017-05-04 17:23:35 -0700745
Michael Wright35a0c672018-01-24 00:32:53 +0000746 if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
747 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
748 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700749 return true;
750 }
751
752 return false;
753 }
754
Michael Wright35a0c672018-01-24 00:32:53 +0000755 private int getCurrentIntensityLocked(Vibration vib) {
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000756 if (vib.isRingtone()) {
757 return mRingIntensity;
758 } else if (vib.isNotification()) {
Michael Wright35a0c672018-01-24 00:32:53 +0000759 return mNotificationIntensity;
760 } else if (vib.isHapticFeedback()) {
761 return mHapticFeedbackIntensity;
762 } else {
763 return Vibrator.VIBRATION_INTENSITY_MEDIUM;
764 }
765 }
766
767 /**
768 * Scale the vibration effect by the intensity as appropriate based its intent.
769 */
770 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
771 if (vib.effect instanceof VibrationEffect.Prebaked) {
772 // Prebaked effects are always just a direct translation from intensity to
773 // EffectStrength.
774 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
775 prebaked.setEffectStrength(intensityToEffectStrength(intensity));
776 return;
777 }
778
Michael Wright0dbb5162018-05-25 15:13:36 +0100779 final int defaultIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000780 if (vib.isRingtone()) {
781 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
782 } else if (vib.isNotification()) {
Michael Wright0dbb5162018-05-25 15:13:36 +0100783 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
784 } else if (vib.isHapticFeedback()) {
785 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
Michael Wright35a0c672018-01-24 00:32:53 +0000786 } else {
Michael Wright0dbb5162018-05-25 15:13:36 +0100787 // If we don't know what kind of vibration we're playing then just skip scaling for
788 // now.
789 return;
790 }
791
792 final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
793 if (scale == null) {
794 // We should have scaling levels for all cases, so not being able to scale because of a
795 // missing level is unexpected.
796 Slog.e(TAG, "No configured scaling level!"
797 + " (current=" + intensity + ", default= " + defaultIntensity + ")");
798 return;
Michael Wright35a0c672018-01-24 00:32:53 +0000799 }
800
801 VibrationEffect scaledEffect = null;
802 if (vib.effect instanceof VibrationEffect.OneShot) {
803 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100804 oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100805 scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000806 } else if (vib.effect instanceof VibrationEffect.Waveform) {
807 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100808 waveform = waveform.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100809 scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000810 } else {
811 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
812 }
813
814 if (scaledEffect != null) {
815 vib.originalEffect = vib.effect;
816 vib.effect = scaledEffect;
817 }
818 }
819
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700820 private boolean shouldVibrateForRingtone() {
Michael Wright35a0c672018-01-24 00:32:53 +0000821 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700822 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700823 // "Also vibrate for calls" Setting in Sound
824 if (Settings.System.getInt(
825 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
826 return ringerMode != AudioManager.RINGER_MODE_SILENT;
827 } else {
828 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
829 }
830 }
831
Michael Wright71216972017-01-31 18:33:54 +0000832 private int getAppOpMode(Vibration vib) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800833 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
834 vib.usageHint, vib.uid, vib.opPkg);
835 if (mode == AppOpsManager.MODE_ALLOWED) {
836 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
Michael Wright71216972017-01-31 18:33:54 +0000837 }
838 return mode;
839 }
840
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000841 @GuardedBy("mLock")
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800842 private void reportFinishVibrationLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000843 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
844 try {
845 if (mCurrentVibration != null) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800846 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
847 mCurrentVibration.opPkg);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000848 unlinkVibration(mCurrentVibration);
849 mCurrentVibration = null;
850 }
851 } finally {
852 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800853 }
854 }
855
Michael Wright36d873f2018-01-08 15:54:05 +0000856 private void linkVibration(Vibration vib) {
857 // Only link against waveforms since they potentially don't have a finish if
858 // they're repeating. Let other effects just play out until they're done.
Michael Wright35a0c672018-01-24 00:32:53 +0000859 if (vib.effect instanceof VibrationEffect.Waveform) {
Michael Wright36d873f2018-01-08 15:54:05 +0000860 try {
Michael Wright35a0c672018-01-24 00:32:53 +0000861 vib.token.linkToDeath(vib, 0);
Michael Wright36d873f2018-01-08 15:54:05 +0000862 } catch (RemoteException e) {
863 return;
864 }
865 }
866 }
867
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200868 private void unlinkVibration(Vibration vib) {
Michael Wright35a0c672018-01-24 00:32:53 +0000869 if (vib.effect instanceof VibrationEffect.Waveform) {
870 vib.token.unlinkToDeath(vib, 0);
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200871 }
872 }
873
Michael Wright71216972017-01-31 18:33:54 +0000874 private void updateVibrators() {
875 synchronized (mLock) {
876 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
877 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Michael Wright35a0c672018-01-24 00:32:53 +0000878 updateVibrationIntensityLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700879
Michael Wright71216972017-01-31 18:33:54 +0000880 if (devicesUpdated || lowPowerModeUpdated) {
881 // If the state changes out from under us then just reset.
882 doCancelVibrateLocked();
883 }
884 }
885 }
Jeff Brown82065252012-04-16 13:19:05 -0700886
Michael Wright71216972017-01-31 18:33:54 +0000887 private boolean updateInputDeviceVibratorsLocked() {
888 boolean changed = false;
889 boolean vibrateInputDevices = false;
890 try {
891 vibrateInputDevices = Settings.System.getIntForUser(
892 mContext.getContentResolver(),
893 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
894 } catch (SettingNotFoundException snfe) {
895 }
896 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
897 changed = true;
898 mVibrateInputDevicesSetting = vibrateInputDevices;
899 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700900
Michael Wright71216972017-01-31 18:33:54 +0000901 if (mVibrateInputDevicesSetting) {
902 if (!mInputDeviceListenerRegistered) {
903 mInputDeviceListenerRegistered = true;
904 mIm.registerInputDeviceListener(this, mH);
905 }
906 } else {
907 if (mInputDeviceListenerRegistered) {
908 mInputDeviceListenerRegistered = false;
909 mIm.unregisterInputDeviceListener(this);
910 }
911 }
Jeff Brown82065252012-04-16 13:19:05 -0700912
Michael Wright71216972017-01-31 18:33:54 +0000913 mInputDeviceVibrators.clear();
914 if (mVibrateInputDevicesSetting) {
915 int[] ids = mIm.getInputDeviceIds();
916 for (int i = 0; i < ids.length; i++) {
917 InputDevice device = mIm.getInputDevice(ids[i]);
918 Vibrator vibrator = device.getVibrator();
919 if (vibrator.hasVibrator()) {
920 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700921 }
922 }
Michael Wright71216972017-01-31 18:33:54 +0000923 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700924 }
Michael Wright71216972017-01-31 18:33:54 +0000925 return changed;
926 }
927
928 private boolean updateLowPowerModeLocked() {
929 boolean lowPowerMode = mPowerManagerInternal
930 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
931 if (lowPowerMode != mLowPowerMode) {
932 mLowPowerMode = lowPowerMode;
933 return true;
934 }
935 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700936 }
937
Michael Wright35a0c672018-01-24 00:32:53 +0000938 private void updateVibrationIntensityLocked() {
939 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
940 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
941 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
942 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
943 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
944 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000945 mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
946 Settings.System.RING_VIBRATION_INTENSITY,
947 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
Michael Wright35a0c672018-01-24 00:32:53 +0000948 }
949
Jeff Brown7f6c2312012-04-13 20:38:38 -0700950 @Override
951 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000952 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700953 }
954
955 @Override
956 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000957 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700958 }
959
960 @Override
961 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000962 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700963 }
964
965 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700966 // For now, we choose to ignore the presence of input devices that have vibrators
967 // when reporting whether the device has a vibrator. Applications often use this
968 // information to decide whether to enable certain features so they expect the
969 // result of hasVibrator() to be constant. For now, just report whether
970 // the device has a built-in vibrator.
971 //synchronized (mInputDeviceVibrators) {
972 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
973 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800974 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700975 }
976
Michael Wright71216972017-01-31 18:33:54 +0000977 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000978 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
979 try {
980 synchronized (mInputDeviceVibrators) {
981 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
982 amplitude = mDefaultVibrationAmplitude;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700983 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000984 if (DEBUG) {
985 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
986 " with amplitude " + amplitude + ".");
987 }
988 noteVibratorOnLocked(uid, millis);
989 final int vibratorCount = mInputDeviceVibrators.size();
990 if (vibratorCount != 0) {
991 final AudioAttributes attributes =
992 new AudioAttributes.Builder().setUsage(usageHint).build();
993 for (int i = 0; i < vibratorCount; i++) {
994 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
995 }
996 } else {
997 // Note: ordering is important here! Many haptic drivers will reset their
998 // amplitude when enabled, so we always have to enable frst, then set the
999 // amplitude.
1000 vibratorOn(millis);
1001 doVibratorSetAmplitude(amplitude);
1002 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001003 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001004 } finally {
1005 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001006 }
1007 }
1008
Michael Wright71216972017-01-31 18:33:54 +00001009 private void doVibratorSetAmplitude(int amplitude) {
1010 if (mSupportsAmplitudeControl) {
1011 vibratorSetAmplitude(amplitude);
1012 }
1013 }
1014
Jeff Brown7f6c2312012-04-13 20:38:38 -07001015 private void doVibratorOff() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001016 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
1017 try {
1018 synchronized (mInputDeviceVibrators) {
1019 if (DEBUG) {
1020 Slog.d(TAG, "Turning vibrator off.");
Jeff Brown7f6c2312012-04-13 20:38:38 -07001021 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001022 noteVibratorOffLocked();
1023 final int vibratorCount = mInputDeviceVibrators.size();
1024 if (vibratorCount != 0) {
1025 for (int i = 0; i < vibratorCount; i++) {
1026 mInputDeviceVibrators.get(i).cancel();
1027 }
1028 } else {
1029 vibratorOff();
1030 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001031 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001032 } finally {
1033 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001034 }
1035 }
1036
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +00001037 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +00001038 private long doVibratorPrebakedEffectLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001039 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
1040 try {
1041 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1042 final boolean usingInputDeviceVibrators;
1043 synchronized (mInputDeviceVibrators) {
1044 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
Michael Wright35a0c672018-01-24 00:32:53 +00001045 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001046 // Input devices don't support prebaked effect, so skip trying it with them.
1047 if (!usingInputDeviceVibrators) {
1048 long timeout = vibratorPerformEffect(prebaked.getId(),
1049 prebaked.getEffectStrength());
1050 if (timeout > 0) {
1051 noteVibratorOnLocked(vib.uid, timeout);
1052 return timeout;
1053 }
1054 }
1055 if (!prebaked.shouldFallback()) {
1056 return 0;
1057 }
1058 VibrationEffect effect = getFallbackEffect(prebaked.getId());
1059 if (effect == null) {
1060 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1061 return 0;
1062 }
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001063 Vibration fallbackVib = new Vibration(vib.token, effect, vib.usageHint, vib.uid,
1064 vib.opPkg, vib.reason + " (fallback)");
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001065 final int intensity = getCurrentIntensityLocked(fallbackVib);
1066 linkVibration(fallbackVib);
1067 applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1068 startVibrationInnerLocked(fallbackVib);
Michael Wright35a0c672018-01-24 00:32:53 +00001069 return 0;
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001070 } finally {
1071 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright35a0c672018-01-24 00:32:53 +00001072 }
Michael Wright71216972017-01-31 18:33:54 +00001073 }
Eric Olsenf42f15c2009-10-29 16:42:03 -07001074
Michael Wright36d873f2018-01-08 15:54:05 +00001075 private VibrationEffect getFallbackEffect(int effectId) {
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +00001076 return mFallbackEffects.get(effectId);
Michael Wright36d873f2018-01-08 15:54:05 +00001077 }
1078
Michael Wright35a0c672018-01-24 00:32:53 +00001079 /**
1080 * Return the current desired effect strength.
1081 *
1082 * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1083 */
1084 private static int intensityToEffectStrength(int intensity) {
1085 switch (intensity) {
1086 case Vibrator.VIBRATION_INTENSITY_LOW:
1087 return EffectStrength.LIGHT;
1088 case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1089 return EffectStrength.MEDIUM;
1090 case Vibrator.VIBRATION_INTENSITY_HIGH:
1091 return EffectStrength.STRONG;
1092 default:
1093 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1094 return EffectStrength.STRONG;
1095 }
1096 }
1097
Michael Wright71216972017-01-31 18:33:54 +00001098 private void noteVibratorOnLocked(int uid, long millis) {
1099 try {
1100 mBatteryStatsService.noteVibratorOn(uid, millis);
Bookatza7020bd2018-08-28 16:29:35 -07001101 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null,
1102 StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
Michael Wright71216972017-01-31 18:33:54 +00001103 mCurVibUid = uid;
1104 } catch (RemoteException e) {
1105 }
1106 }
1107
1108 private void noteVibratorOffLocked() {
1109 if (mCurVibUid >= 0) {
1110 try {
1111 mBatteryStatsService.noteVibratorOff(mCurVibUid);
Bookatza7020bd2018-08-28 16:29:35 -07001112 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null,
1113 StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
Michael Wright71216972017-01-31 18:33:54 +00001114 } catch (RemoteException e) { }
1115 mCurVibUid = -1;
1116 }
1117 }
1118
1119 private class VibrateThread extends Thread {
1120 private final VibrationEffect.Waveform mWaveform;
1121 private final int mUid;
1122 private final int mUsageHint;
1123
1124 private boolean mForceStop;
1125
1126 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1127 mWaveform = waveform;
1128 mUid = uid;
1129 mUsageHint = usageHint;
1130 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001131 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 }
1133
Michael Wright71216972017-01-31 18:33:54 +00001134 private long delayLocked(long duration) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001135 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1136 try {
1137 long durationRemaining = duration;
1138 if (duration > 0) {
1139 final long bedtime = duration + SystemClock.uptimeMillis();
1140 do {
1141 try {
1142 this.wait(durationRemaining);
1143 }
1144 catch (InterruptedException e) { }
1145 if (mForceStop) {
1146 break;
1147 }
1148 durationRemaining = bedtime - SystemClock.uptimeMillis();
1149 } while (durationRemaining > 0);
1150 return duration - durationRemaining;
1151 }
1152 return 0;
1153 } finally {
1154 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
1156 }
1157
1158 public void run() {
1159 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +00001160 mWakeLock.acquire();
1161 try {
1162 boolean finished = playWaveform();
1163 if (finished) {
1164 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001165 }
Michael Wright71216972017-01-31 18:33:54 +00001166 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 mWakeLock.release();
1168 }
Michael Wright71216972017-01-31 18:33:54 +00001169 }
1170
1171 /**
1172 * Play the waveform.
1173 *
1174 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1175 */
1176 public boolean playWaveform() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001177 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1178 try {
1179 synchronized (this) {
1180 final long[] timings = mWaveform.getTimings();
1181 final int[] amplitudes = mWaveform.getAmplitudes();
1182 final int len = timings.length;
1183 final int repeat = mWaveform.getRepeatIndex();
Michael Wright71216972017-01-31 18:33:54 +00001184
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001185 int index = 0;
1186 long onDuration = 0;
1187 while (!mForceStop) {
1188 if (index < len) {
1189 final int amplitude = amplitudes[index];
1190 final long duration = timings[index++];
1191 if (duration <= 0) {
1192 continue;
Michael Wright71216972017-01-31 18:33:54 +00001193 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001194 if (amplitude != 0) {
1195 if (onDuration <= 0) {
1196 // Telling the vibrator to start multiple times usually causes
1197 // effects to feel "choppy" because the motor resets at every on
1198 // command. Instead we figure out how long our next "on" period
1199 // is going to be, tell the motor to stay on for the full
1200 // duration, and then wake up to change the amplitude at the
1201 // appropriate intervals.
1202 onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1203 repeat);
1204 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1205 } else {
1206 doVibratorSetAmplitude(amplitude);
1207 }
1208 }
Michael Wright71216972017-01-31 18:33:54 +00001209
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001210 long waitTime = delayLocked(duration);
1211 if (amplitude != 0) {
1212 onDuration -= waitTime;
1213 }
1214 } else if (repeat < 0) {
1215 break;
1216 } else {
1217 index = repeat;
Michael Wright71216972017-01-31 18:33:54 +00001218 }
Michael Wright71216972017-01-31 18:33:54 +00001219 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001220 return !mForceStop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001221 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001222 } finally {
1223 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +00001224 }
1225 }
1226
1227 public void cancel() {
1228 synchronized (this) {
1229 mThread.mForceStop = true;
1230 mThread.notify();
1231 }
1232 }
1233
1234 /**
1235 * Get the duration the vibrator will be on starting at startIndex until the next time it's
1236 * off.
1237 */
1238 private long getTotalOnDuration(
1239 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1240 int i = startIndex;
1241 long timing = 0;
1242 while(amplitudes[i] != 0) {
1243 timing += timings[i++];
1244 if (i >= timings.length) {
1245 if (repeatIndex >= 0) {
1246 i = repeatIndex;
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001247 // prevent infinite loop
1248 repeatIndex = -1;
Michael Wright71216972017-01-31 18:33:54 +00001249 } else {
1250 break;
1251 }
1252 }
1253 if (i == startIndex) {
1254 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -04001255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 }
Michael Wright71216972017-01-31 18:33:54 +00001257 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001258 }
Jeff Brown969579b2014-05-20 19:29:29 -07001259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -07001262 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001263 public void onReceive(Context context, Intent intent) {
1264 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +00001265 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -07001266 // When the system is entering a non-interactive state, we want
1267 // to cancel vibrations in case a misbehaving app has abandoned
1268 // them. However it may happen that the system is currently playing
1269 // haptic feedback as part of the transition. So we don't cancel
1270 // system vibrations.
1271 if (mCurrentVibration != null
Michael Wright35a0c672018-01-24 00:32:53 +00001272 && !(mCurrentVibration.isHapticFeedback()
1273 && mCurrentVibration.isFromSystem())) {
Jeff Brown969579b2014-05-20 19:29:29 -07001274 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -07001275 }
Patrick Scott18dd5f02009-07-02 11:31:12 -04001276 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
1278 }
1279 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001280
1281 @Override
1282 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001283 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001284
Michael Wright35a0c672018-01-24 00:32:53 +00001285 pw.println("Vibrator Service:");
Michael Wright71216972017-01-31 18:33:54 +00001286 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +00001287 pw.print(" mCurrentVibration=");
1288 if (mCurrentVibration != null) {
1289 pw.println(mCurrentVibration.toInfo().toString());
1290 } else {
1291 pw.println("null");
1292 }
1293 pw.println(" mLowPowerMode=" + mLowPowerMode);
1294 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1295 pw.println(" mNotificationIntensity=" + mNotificationIntensity);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +00001296 pw.println(" mRingIntensity=" + mRingIntensity);
Michael Wright35a0c672018-01-24 00:32:53 +00001297 pw.println("");
1298 pw.println(" Previous vibrations:");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001299 for (VibrationInfo info : mPreviousVibrations) {
Michael Wright35a0c672018-01-24 00:32:53 +00001300 pw.print(" ");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001301 pw.println(info.toString());
1302 }
1303 }
1304 }
Felipe Lemea5281002017-02-10 15:13:48 -08001305
1306 @Override
1307 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1308 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1309 throws RemoteException {
1310 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1311 }
1312
1313 private final class VibratorShellCommand extends ShellCommand {
1314
Felipe Lemea5281002017-02-10 15:13:48 -08001315 private final IBinder mToken;
1316
1317 private VibratorShellCommand(IBinder token) {
1318 mToken = token;
1319 }
1320
1321 @Override
1322 public int onCommand(String cmd) {
1323 if ("vibrate".equals(cmd)) {
1324 return runVibrate();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001325 } else if ("waveform".equals(cmd)) {
1326 return runWaveform();
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001327 } else if ("prebaked".equals(cmd)) {
1328 return runPrebaked();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001329 } else if ("cancel".equals(cmd)) {
1330 cancelVibrate(mToken);
1331 return 0;
Felipe Lemea5281002017-02-10 15:13:48 -08001332 }
1333 return handleDefaultCommands(cmd);
1334 }
1335
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001336 private boolean checkDoNotDisturb() {
1337 try {
1338 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1339 Settings.Global.ZEN_MODE);
1340 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
1341 try (PrintWriter pw = getOutPrintWriter();) {
1342 pw.print("Ignoring because device is on DND mode ");
1343 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1344 zenMode));
1345 return true;
1346 }
1347 }
1348 } catch (SettingNotFoundException e) {
1349 // ignore
1350 }
1351
1352 return false;
1353 }
1354
Felipe Lemea5281002017-02-10 15:13:48 -08001355 private int runVibrate() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001356 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001357 try {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001358 if (checkDoNotDisturb()) {
1359 return 0;
Felipe Leme5e2e6322017-07-14 17:25:59 -07001360 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001361
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001362 final long duration = Long.parseLong(getNextArgRequired());
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001363 String description = getNextArg();
1364 if (description == null) {
1365 description = "Shell command";
1366 }
Michael Wright71216972017-01-31 18:33:54 +00001367
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001368 VibrationEffect effect =
1369 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1370 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001371 "Shell Command", mToken);
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001372 return 0;
1373 } finally {
1374 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1375 }
Felipe Lemea5281002017-02-10 15:13:48 -08001376 }
1377
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001378 private int runWaveform() {
1379 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
1380 try {
1381 if (checkDoNotDisturb()) {
1382 return 0;
1383 }
1384
1385 String description = "Shell command";
1386 int repeat = -1;
1387 ArrayList<Integer> amplitudesList = null;
1388
1389 String opt;
1390 while ((opt = getNextOption()) != null) {
1391 switch (opt) {
1392 case "-d":
1393 description = getNextArgRequired();
1394 break;
1395 case "-r":
1396 repeat = Integer.parseInt(getNextArgRequired());
1397 break;
1398 case "-a":
1399 if (amplitudesList == null) {
1400 amplitudesList = new ArrayList<Integer>();
1401 }
1402 break;
1403 }
1404 }
1405
1406 ArrayList<Long> timingsList = new ArrayList<Long>();
1407
1408 String arg;
1409 while ((arg = getNextArg()) != null) {
1410 if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
1411 amplitudesList.add(Integer.parseInt(arg));
1412 } else {
1413 timingsList.add(Long.parseLong(arg));
1414 }
1415 }
1416
1417 VibrationEffect effect;
1418 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
1419 if (amplitudesList == null) {
1420 effect = VibrationEffect.createWaveform(timings, repeat);
1421 } else {
1422 int[] amplitudes =
1423 amplitudesList.stream().mapToInt(Integer::intValue).toArray();
1424 effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
1425 }
1426 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1427 "Shell Command", mToken);
1428 return 0;
1429 } finally {
1430 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1431 }
1432 }
1433
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001434 private int runPrebaked() {
1435 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
1436 try {
1437 if (checkDoNotDisturb()) {
1438 return 0;
1439 }
1440
1441 final int id = Integer.parseInt(getNextArgRequired());
1442
1443 String description = getNextArg();
1444 if (description == null) {
1445 description = "Shell command";
1446 }
1447
1448 VibrationEffect effect =
1449 VibrationEffect.get(id, false);
1450 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1451 "Shell Command", mToken);
1452 return 0;
1453 } finally {
1454 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1455 }
1456 }
1457
Felipe Lemea5281002017-02-10 15:13:48 -08001458 @Override
1459 public void onHelp() {
1460 try (PrintWriter pw = getOutPrintWriter();) {
1461 pw.println("Vibrator commands:");
1462 pw.println(" help");
1463 pw.println(" Prints this help text.");
1464 pw.println("");
1465 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001466 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1467 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001468 pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
1469 pw.println(" Vibrates for durations and amplitudes in list;");
1470 pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
1471 pw.println(" If -r is provided, the waveform loops back to the specified");
1472 pw.println(" index (e.g. 0 loops from the beginning)");
1473 pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
1474 pw.println(" otherwise, it accepts durations only and alternates off/on");
1475 pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001476 pw.println(" prebaked effect-id [description]");
1477 pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
1478 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001479 pw.println(" cancel");
1480 pw.println(" Cancels any active vibration");
Felipe Lemea5281002017-02-10 15:13:48 -08001481 pw.println("");
1482 }
1483 }
1484 }
1485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486}