blob: 6eb9f0c7a6bc06439ed811216615703335be45d5 [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;
Yiwen Chenf8e46d72019-05-23 22:02:54 -070057import android.provider.DeviceConfig;
Jeff Brown7f6c2312012-04-13 20:38:38 -070058import android.provider.Settings;
59import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070060import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +000062import android.util.SparseArray;
Bookatza7020bd2018-08-28 16:29:35 -070063import android.util.StatsLog;
Jeff Brown7f6c2312012-04-13 20:38:38 -070064import android.view.InputDevice;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +000066import com.android.internal.annotations.GuardedBy;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080067import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060068import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080069
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070070import java.io.FileDescriptor;
71import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070072import java.util.ArrayList;
Michael Wright36d873f2018-01-08 15:54:05 +000073import java.util.Date;
Bookatza7020bd2018-08-28 16:29:35 -070074import java.util.LinkedList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040075
Jeff Brown7f6c2312012-04-13 20:38:38 -070076public class VibratorService extends IVibratorService.Stub
77 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050078 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070079 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070080 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Michael Wrightc390fbe2018-12-12 19:45:09 +000081 private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
Yiwen Chenf8e46d72019-05-23 22:02:54 -070082 private static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050083
Michael Wright36d873f2018-01-08 15:54:05 +000084 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
85
Michael Wrightc390fbe2018-12-12 19:45:09 +000086 // Scale levels. Each level, except MUTE, is defined as the delta between the current setting
87 // and the default intensity for that type of vibration (i.e. current - default).
88 private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100
89 private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2
90 private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1
91 private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0
92 private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1
93 private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2
Michael Wright35a0c672018-01-24 00:32:53 +000094
Michael Wright0dbb5162018-05-25 15:13:36 +010095 // Gamma adjustments for scale levels.
96 private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
97 private static final float SCALE_LOW_GAMMA = 1.5f;
98 private static final float SCALE_NONE_GAMMA = 1.0f;
99 private static final float SCALE_HIGH_GAMMA = 0.5f;
100 private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
101
102 // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
103 // max amplitude.
104 private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
105 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
Michael Wright35a0c672018-01-24 00:32:53 +0000106
107 // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
108 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
109
Michael Wright0dbb5162018-05-25 15:13:36 +0100110
111 // A mapping from the intensity adjustment to the scaling to apply, where the intensity
112 // adjustment is defined as the delta between the default intensity level and the user selected
113 // intensity level. It's important that we apply the scaling on the delta between the two so
114 // that the default intensity level applies no scaling to application provided effects.
115 private final SparseArray<ScaleLevel> mScaleLevels;
Arthur Hung85ed7da2019-03-05 13:58:19 +0800116 private final LinkedList<VibrationInfo> mPreviousRingVibrations;
117 private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100118 private final LinkedList<VibrationInfo> mPreviousAlarmVibrations;
Alexey Kuzmind8b0f782019-06-05 17:20:26 +0100119 private final LinkedList<ExternalVibration> mPreviousExternalVibrations;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700120 private final LinkedList<VibrationInfo> mPreviousVibrations;
121 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -0700122 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +0000123 private final boolean mSupportsAmplitudeControl;
Michael Wrightc390fbe2018-12-12 19:45:09 +0000124 private final boolean mSupportsExternalControl;
Michael Wright71216972017-01-31 18:33:54 +0000125 private final int mDefaultVibrationAmplitude;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000126 private final SparseArray<VibrationEffect> mFallbackEffects;
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000127 private final SparseArray<Integer> mProcStatesCache = new SparseArray();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700128 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700129 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +0000130 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700131
132 private final Context mContext;
133 private final PowerManager.WakeLock mWakeLock;
Svet Ganovf7b47252018-02-26 11:11:27 -0800134 private final AppOpsManager mAppOps;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800135 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700136 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700137 private InputManager mIm;
Michael Wright35a0c672018-01-24 00:32:53 +0000138 private Vibrator mVibrator;
139 private SettingsObserver mSettingObserver;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700140
Michael Wright71216972017-01-31 18:33:54 +0000141 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700142
Michael Wright71216972017-01-31 18:33:54 +0000143 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -0700144 // to be acquired
145 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
146 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
147 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
148
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000149 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000150 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800151 private int mCurVibUid = -1;
Michael Wrightc390fbe2018-12-12 19:45:09 +0000152 private ExternalVibration mCurrentExternalVibration;
153 private boolean mVibratorUnderExternalControl;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700154 private boolean mLowPowerMode;
Michael Wright35a0c672018-01-24 00:32:53 +0000155 private int mHapticFeedbackIntensity;
156 private int mNotificationIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000157 private int mRingIntensity;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800158
Michael Wrightc390fbe2018-12-12 19:45:09 +0000159 static native boolean vibratorExists();
160 static native void vibratorInit();
161 static native void vibratorOn(long milliseconds);
162 static native void vibratorOff();
163 static native boolean vibratorSupportsAmplitudeControl();
164 static native void vibratorSetAmplitude(int amplitude);
165 static native long vibratorPerformEffect(long effect, long strength);
Harpreet "Eli" Sanghaa456f082018-12-14 12:06:10 +0900166 static native boolean vibratorSupportsExternalControl();
167 static native void vibratorSetExternalControl(boolean enabled);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400168
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000169 private final IUidObserver mUidObserver = new IUidObserver.Stub() {
170 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) {
171 mProcStatesCache.put(uid, procState);
172 }
173
174 @Override public void onUidGone(int uid, boolean disabled) {
175 mProcStatesCache.delete(uid);
176 }
177
178 @Override public void onUidActive(int uid) {
179 }
180
181 @Override public void onUidIdle(int uid, boolean disabled) {
182 }
183
184 @Override public void onUidCachedChanged(int uid, boolean cached) {
185 }
186 };
187
Patrick Scott18dd5f02009-07-02 11:31:12 -0400188 private class Vibration implements IBinder.DeathRecipient {
Michael Wright35a0c672018-01-24 00:32:53 +0000189 public final IBinder token;
Michael Wright36d873f2018-01-08 15:54:05 +0000190 // Start time in CLOCK_BOOTTIME base.
Michael Wright35a0c672018-01-24 00:32:53 +0000191 public final long startTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000192 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
Michael Wright35a0c672018-01-24 00:32:53 +0000193 // with other system events, any duration calculations should be done use startTime so as
Michael Wright36d873f2018-01-08 15:54:05 +0000194 // not to be affected by discontinuities created by RTC adjustments.
Michael Wright35a0c672018-01-24 00:32:53 +0000195 public final long startTimeDebug;
196 public final int usageHint;
197 public final int uid;
198 public final String opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100199 public final String reason;
Michael Wright35a0c672018-01-24 00:32:53 +0000200
201 // The actual effect to be played.
202 public VibrationEffect effect;
203 // The original effect that was requested. This is non-null only when the original effect
204 // differs from the effect that's being played. Typically these two things differ because
205 // the effect was scaled based on the users vibration intensity settings.
206 public VibrationEffect originalEffect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400207
Michael Wright71216972017-01-31 18:33:54 +0000208 private Vibration(IBinder token, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100209 int usageHint, int uid, String opPkg, String reason) {
Michael Wright35a0c672018-01-24 00:32:53 +0000210 this.token = token;
211 this.effect = effect;
212 this.startTime = SystemClock.elapsedRealtime();
213 this.startTimeDebug = System.currentTimeMillis();
214 this.usageHint = usageHint;
215 this.uid = uid;
216 this.opPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100217 this.reason = reason;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400218 }
219
220 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000221 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400222 if (this == mCurrentVibration) {
223 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400224 }
225 }
226 }
227
Michael Wright35a0c672018-01-24 00:32:53 +0000228 public boolean hasTimeoutLongerThan(long millis) {
229 final long duration = effect.getDuration();
230 return duration >= 0 && duration > millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400231 }
Jeff Brown969579b2014-05-20 19:29:29 -0700232
Michael Wright35a0c672018-01-24 00:32:53 +0000233 public boolean isHapticFeedback() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000234 if (VibratorService.this.isHapticFeedback(usageHint)) {
235 return true;
236 }
Michael Wright35a0c672018-01-24 00:32:53 +0000237 if (effect instanceof VibrationEffect.Prebaked) {
238 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
239 switch (prebaked.getId()) {
240 case VibrationEffect.EFFECT_CLICK:
241 case VibrationEffect.EFFECT_DOUBLE_CLICK:
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000242 case VibrationEffect.EFFECT_HEAVY_CLICK:
Alexey Kuzmina2112a32019-04-04 18:39:38 +0100243 case VibrationEffect.EFFECT_TEXTURE_TICK:
Michael Wright35a0c672018-01-24 00:32:53 +0000244 case VibrationEffect.EFFECT_TICK:
Michael Wright0dbb5162018-05-25 15:13:36 +0100245 case VibrationEffect.EFFECT_POP:
246 case VibrationEffect.EFFECT_THUD:
Michael Wright35a0c672018-01-24 00:32:53 +0000247 return true;
248 default:
249 Slog.w(TAG, "Unknown prebaked vibration effect, "
250 + "assuming it isn't haptic feedback.");
251 return false;
252 }
Michael Wright71216972017-01-31 18:33:54 +0000253 }
Michael Wright35a0c672018-01-24 00:32:53 +0000254 final long duration = effect.getDuration();
255 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
256 }
257
258 public boolean isNotification() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000259 return VibratorService.this.isNotification(usageHint);
Michael Wright35a0c672018-01-24 00:32:53 +0000260 }
261
262 public boolean isRingtone() {
Michael Wrightc390fbe2018-12-12 19:45:09 +0000263 return VibratorService.this.isRingtone(usageHint);
Michael Wright35a0c672018-01-24 00:32:53 +0000264 }
265
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100266 public boolean isAlarm() {
267 return VibratorService.this.isAlarm(usageHint);
268 }
269
Michael Wright35a0c672018-01-24 00:32:53 +0000270 public boolean isFromSystem() {
271 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
Jeff Brown969579b2014-05-20 19:29:29 -0700272 }
Michael Wright36d873f2018-01-08 15:54:05 +0000273
274 public VibrationInfo toInfo() {
Michael Wright35a0c672018-01-24 00:32:53 +0000275 return new VibrationInfo(
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100276 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg, reason);
Michael Wright36d873f2018-01-08 15:54:05 +0000277 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400278 }
279
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700280 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000281 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000282 private final VibrationEffect mEffect;
Michael Wright35a0c672018-01-24 00:32:53 +0000283 private final VibrationEffect mOriginalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000284 private final int mUsageHint;
285 private final int mUid;
286 private final String mOpPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100287 private final String mReason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700288
Michael Wright36d873f2018-01-08 15:54:05 +0000289 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100290 VibrationEffect originalEffect, int usageHint, int uid,
291 String opPkg, String reason) {
Michael Wright36d873f2018-01-08 15:54:05 +0000292 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000293 mEffect = effect;
Michael Wright35a0c672018-01-24 00:32:53 +0000294 mOriginalEffect = originalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000295 mUsageHint = usageHint;
296 mUid = uid;
297 mOpPkg = opPkg;
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100298 mReason = reason;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700299 }
300
301 @Override
302 public String toString() {
303 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000304 .append("startTime: ")
305 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000306 .append(", effect: ")
307 .append(mEffect)
Michael Wright35a0c672018-01-24 00:32:53 +0000308 .append(", originalEffect: ")
309 .append(mOriginalEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700310 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000311 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700312 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000313 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700314 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000315 .append(mOpPkg)
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100316 .append(", reason: ")
317 .append(mReason)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700318 .toString();
319 }
320 }
321
Michael Wright0dbb5162018-05-25 15:13:36 +0100322 private static final class ScaleLevel {
323 public final float gamma;
324 public final int maxAmplitude;
325
326 public ScaleLevel(float gamma) {
327 this(gamma, VibrationEffect.MAX_AMPLITUDE);
328 }
329
330 public ScaleLevel(float gamma, int maxAmplitude) {
331 this.gamma = gamma;
332 this.maxAmplitude = maxAmplitude;
333 }
334
335 @Override
336 public String toString() {
337 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
338 }
339 }
340
Mike Lockwood3a322132009-11-24 00:30:52 -0500341 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200342 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 // Reset the hardware to a default state, in case this is a runtime
344 // restart instead of a fresh boot.
345 vibratorOff();
346
Michael Wright71216972017-01-31 18:33:54 +0000347 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
Michael Wrightc390fbe2018-12-12 19:45:09 +0000348 mSupportsExternalControl = vibratorSupportsExternalControl();
Michael Wright71216972017-01-31 18:33:54 +0000349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000351 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700352 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 mWakeLock.setReferenceCounted(true);
354
Svet Ganovf7b47252018-02-26 11:11:27 -0800355 mAppOps = mContext.getSystemService(AppOpsManager.class);
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700356 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
357 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800358
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700359 mPreviousVibrationsLimit = mContext.getResources().getInteger(
360 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
361
Michael Wright71216972017-01-31 18:33:54 +0000362 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
363 com.android.internal.R.integer.config_defaultVibrationAmplitude);
364
Tyler Freeman319a34a2017-05-04 17:23:35 -0700365 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
366 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
367
Arthur Hung85ed7da2019-03-05 13:58:19 +0800368 mPreviousRingVibrations = new LinkedList<>();
369 mPreviousNotificationVibrations = new LinkedList<>();
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100370 mPreviousAlarmVibrations = new LinkedList<>();
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700371 mPreviousVibrations = new LinkedList<>();
Alexey Kuzmind8b0f782019-06-05 17:20:26 +0100372 mPreviousExternalVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400373
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 IntentFilter filter = new IntentFilter();
375 filter.addAction(Intent.ACTION_SCREEN_OFF);
376 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000377
Michael Wrightd39cbec2018-04-16 19:35:13 +0100378 VibrationEffect clickEffect = createEffectFromResource(
Michael Wright71216972017-01-31 18:33:54 +0000379 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000380 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000381 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100382 VibrationEffect heavyClickEffect = createEffectFromResource(
383 com.android.internal.R.array.config_longPressVibePattern);
384 VibrationEffect tickEffect = createEffectFromResource(
Michael Wright57d94d92017-05-31 14:44:45 +0100385 com.android.internal.R.array.config_clockTickVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000386
Michael Wright0dbb5162018-05-25 15:13:36 +0100387 mFallbackEffects = new SparseArray<>();
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000388 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
389 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
390 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100391 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
Michael Wright0dbb5162018-05-25 15:13:36 +0100392
Alexey Kuzmina2112a32019-04-04 18:39:38 +0100393 mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK,
394 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false));
395
Michael Wright0dbb5162018-05-25 15:13:36 +0100396 mScaleLevels = new SparseArray<>();
397 mScaleLevels.put(SCALE_VERY_LOW,
398 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
399 mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
400 mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
401 mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
402 mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
Michael Wrightc390fbe2018-12-12 19:45:09 +0000403
404 ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService());
Michael Wright57d94d92017-05-31 14:44:45 +0100405 }
406
Michael Wrightd39cbec2018-04-16 19:35:13 +0100407 private VibrationEffect createEffectFromResource(int resId) {
408 long[] timings = getLongIntArray(mContext.getResources(), resId);
409 return createEffectFromTimings(timings);
410 }
411
412 private static VibrationEffect createEffectFromTimings(long[] timings) {
Michael Wright57d94d92017-05-31 14:44:45 +0100413 if (timings == null || timings.length == 0) {
414 return null;
415 } else if (timings.length == 1) {
416 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
417 } else {
418 return VibrationEffect.createWaveform(timings, -1);
419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 }
421
Jeff Brown7f6c2312012-04-13 20:38:38 -0700422 public void systemReady() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000423 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
424 try {
425 mIm = mContext.getSystemService(InputManager.class);
426 mVibrator = mContext.getSystemService(Vibrator.class);
427 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700428
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000429 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
430 mPowerManagerInternal.registerLowPowerModeObserver(
431 new PowerManagerInternal.LowPowerModeListener() {
432 @Override
433 public int getServiceType() {
434 return ServiceType.VIBRATION;
435 }
jackqdyulei455e90a2017-02-09 15:29:16 -0800436
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000437 @Override
438 public void onLowPowerModeChanged(PowerSaveState result) {
439 updateVibrators();
440 }
441 });
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700442
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000443 mContext.getContentResolver().registerContentObserver(
444 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
445 true, mSettingObserver, UserHandle.USER_ALL);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700446
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000447 mContext.getContentResolver().registerContentObserver(
448 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
449 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000450
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000451 mContext.getContentResolver().registerContentObserver(
452 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
453 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000454
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000455 mContext.getContentResolver().registerContentObserver(
456 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
457 true, mSettingObserver, UserHandle.USER_ALL);
458
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000459 mContext.registerReceiver(new BroadcastReceiver() {
460 @Override
461 public void onReceive(Context context, Intent intent) {
462 updateVibrators();
463 }
464 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700465
Alexey Kuzmin3fe97b02018-12-12 14:21:55 +0000466 try {
467 ActivityManager.getService().registerUidObserver(mUidObserver,
468 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE,
469 ActivityManager.PROCESS_STATE_UNKNOWN, null);
470 } catch (RemoteException e) {
471 // ignored; both services live in system_server
472 }
473
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000474 updateVibrators();
475 } finally {
476 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
477 }
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700478 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700479
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700480 private final class SettingsObserver extends ContentObserver {
481 public SettingsObserver(Handler handler) {
482 super(handler);
483 }
484
485 @Override
486 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000487 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700488 }
489 }
490
Jeff Brown82379ba2014-07-25 19:03:28 -0700491 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700492 public boolean hasVibrator() {
493 return doVibratorExists();
494 }
495
Michael Wright71216972017-01-31 18:33:54 +0000496 @Override // Binder call
497 public boolean hasAmplitudeControl() {
498 synchronized (mInputDeviceVibrators) {
499 // Input device vibrators don't support amplitude controls yet, but are still used over
500 // the system vibrator when connected.
501 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
502 }
503 }
504
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800505 private void verifyIncomingUid(int uid) {
506 if (uid == Binder.getCallingUid()) {
507 return;
508 }
509 if (Binder.getCallingPid() == Process.myPid()) {
510 return;
511 }
512 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
513 Binder.getCallingPid(), Binder.getCallingUid(), null);
514 }
515
Michael Wright71216972017-01-31 18:33:54 +0000516 /**
517 * Validate the incoming VibrationEffect.
518 *
519 * We can't throw exceptions here since we might be called from some system_server component,
520 * which would bring the whole system down.
521 *
522 * @return whether the VibrationEffect is valid
523 */
524 private static boolean verifyVibrationEffect(VibrationEffect effect) {
525 if (effect == null) {
526 // Effect must not be null.
527 Slog.wtf(TAG, "effect must not be null");
528 return false;
529 }
530 try {
531 effect.validate();
532 } catch (Exception e) {
533 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
534 return false;
535 }
536 return true;
537 }
538
539 private static long[] getLongIntArray(Resources r, int resid) {
540 int[] ar = r.getIntArray(resid);
541 if (ar == null) {
542 return null;
543 }
544 long[] out = new long[ar.length];
545 for (int i = 0; i < ar.length; i++) {
546 out[i] = ar[i];
547 }
548 return out;
549 }
550
Jeff Brown82379ba2014-07-25 19:03:28 -0700551 @Override // Binder call
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100552 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, String reason,
John Spurlock1af30c72014-03-10 08:33:35 -0400553 IBinder token) {
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100554 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000555 try {
556 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
557 != PackageManager.PERMISSION_GRANTED) {
558 throw new SecurityException("Requires VIBRATE permission");
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000559 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000560 if (token == null) {
561 Slog.e(TAG, "token must not be null");
562 return;
563 }
564 verifyIncomingUid(uid);
565 if (!verifyVibrationEffect(effect)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 return;
567 }
568
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000569 // If our current vibration is longer than the new vibration and is the same amplitude,
570 // then just let the current one finish.
571 synchronized (mLock) {
572 if (effect instanceof VibrationEffect.OneShot
573 && mCurrentVibration != null
574 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
575 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
576 VibrationEffect.OneShot currentOneShot =
577 (VibrationEffect.OneShot) mCurrentVibration.effect;
578 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
579 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
580 if (DEBUG) {
581 Slog.d(TAG,
582 "Ignoring incoming vibration in favor of current vibration");
583 }
584 return;
585 }
586 }
587
Michael Wrightc390fbe2018-12-12 19:45:09 +0000588
589 // If something has external control of the vibrator, assume that it's more
590 // important for now.
591 if (mCurrentExternalVibration != null) {
592 if (DEBUG) {
593 Slog.d(TAG, "Ignoring incoming vibration for current external vibration");
594 }
595 return;
596 }
597
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000598 // If the current vibration is repeating and the incoming one is non-repeating,
599 // then ignore the non-repeating vibration. This is so that we don't cancel
600 // vibrations that are meant to grab the attention of the user, like ringtones and
601 // alarms, in favor of one-shot vibrations that are likely quite short.
602 if (!isRepeatingVibration(effect)
603 && mCurrentVibration != null
604 && isRepeatingVibration(mCurrentVibration.effect)) {
605 if (DEBUG) {
606 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
607 }
608 return;
609 }
610
Alexey Kuzmine1f06b82018-06-20 17:48:43 +0100611 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg, reason);
Alexey Kuzminddebe592019-01-08 16:07:41 +0000612 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
613 > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100614 && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) {
Arthur Hungd8a71c92019-02-26 14:40:17 +0800615 Slog.e(TAG, "Ignoring incoming vibration as process with"
616 + " uid = " + uid + " is background,"
617 + " usage = " + AudioAttributes.usageToString(vib.usageHint));
Alexey Kuzminddebe592019-01-08 16:07:41 +0000618 return;
619 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000620 linkVibration(vib);
621 long ident = Binder.clearCallingIdentity();
622 try {
623 doCancelVibrateLocked();
624 startVibrationLocked(vib);
625 addToPreviousVibrationsLocked(vib);
626 } finally {
627 Binder.restoreCallingIdentity(ident);
628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000630 } finally {
631 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 }
633 }
634
Michael Wright58c46312017-10-05 14:04:14 -0400635 private static boolean isRepeatingVibration(VibrationEffect effect) {
Michael Wright35a0c672018-01-24 00:32:53 +0000636 return effect.getDuration() == Long.MAX_VALUE;
Michael Wright58c46312017-10-05 14:04:14 -0400637 }
638
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700639 private void addToPreviousVibrationsLocked(Vibration vib) {
Arthur Hung85ed7da2019-03-05 13:58:19 +0800640 final LinkedList<VibrationInfo> previousVibrations;
641 if (vib.isRingtone()) {
642 previousVibrations = mPreviousRingVibrations;
643 } else if (vib.isNotification()) {
644 previousVibrations = mPreviousNotificationVibrations;
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100645 } else if (vib.isAlarm()) {
646 previousVibrations = mPreviousAlarmVibrations;
Arthur Hung85ed7da2019-03-05 13:58:19 +0800647 } else {
648 previousVibrations = mPreviousVibrations;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700649 }
Arthur Hung85ed7da2019-03-05 13:58:19 +0800650
651 if (previousVibrations.size() > mPreviousVibrationsLimit) {
652 previousVibrations.removeFirst();
653 }
654 previousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700655 }
656
Jeff Brown82379ba2014-07-25 19:03:28 -0700657 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400658 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 mContext.enforceCallingOrSelfPermission(
660 android.Manifest.permission.VIBRATE,
661 "cancelVibrate");
662
Michael Wright71216972017-01-31 18:33:54 +0000663 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +0000664 if (mCurrentVibration != null && mCurrentVibration.token == token) {
Michael Wright71216972017-01-31 18:33:54 +0000665 if (DEBUG) {
666 Slog.d(TAG, "Canceling vibration.");
667 }
668 long ident = Binder.clearCallingIdentity();
669 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400670 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000671 } finally {
672 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400673 }
674 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700677
Michael Wright71216972017-01-31 18:33:54 +0000678 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700679 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400680 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000681 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400682 }
683 };
684
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000685 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400686 private void doCancelVibrateLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000687 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
688 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
689 try {
690 mH.removeCallbacks(mVibrationEndRunnable);
691 if (mThread != null) {
692 mThread.cancel();
693 mThread = null;
694 }
Michael Wrightc390fbe2018-12-12 19:45:09 +0000695 if (mCurrentExternalVibration != null) {
696 mCurrentExternalVibration.mute();
697 mCurrentExternalVibration = null;
698 setVibratorUnderExternalControl(false);
699 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000700 doVibratorOff();
701 reportFinishVibrationLocked();
702 } finally {
703 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400704 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400705 }
706
Michael Wright71216972017-01-31 18:33:54 +0000707 // Callback for whenever the current vibration has finished played out
708 public void onVibrationFinished() {
709 if (DEBUG) {
710 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400711 }
Michael Wright71216972017-01-31 18:33:54 +0000712 synchronized (mLock) {
713 // Make sure the vibration is really done. This also reports that the vibration is
714 // finished.
715 doCancelVibrateLocked();
716 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400717 }
718
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000719 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400720 private void startVibrationLocked(final Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000721 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
722 try {
723 if (!isAllowedToVibrateLocked(vib)) {
724 return;
Michael Wright71216972017-01-31 18:33:54 +0000725 }
Michael Wright71216972017-01-31 18:33:54 +0000726
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000727 final int intensity = getCurrentIntensityLocked(vib);
728 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
729 return;
Michael Wright71216972017-01-31 18:33:54 +0000730 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000731
732 if (vib.isRingtone() && !shouldVibrateForRingtone()) {
733 if (DEBUG) {
734 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
735 }
736 return;
737 }
738
739 final int mode = getAppOpMode(vib);
740 if (mode != AppOpsManager.MODE_ALLOWED) {
741 if (mode == AppOpsManager.MODE_ERRORED) {
742 // We might be getting calls from within system_server, so we don't actually
743 // want to throw a SecurityException here.
744 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
745 }
746 return;
747 }
748 applyVibrationIntensityScalingLocked(vib, intensity);
749 startVibrationInnerLocked(vib);
750 } finally {
751 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +0000752 }
Michael Wright71216972017-01-31 18:33:54 +0000753 }
754
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000755 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000756 private void startVibrationInnerLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000757 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
758 try {
759 mCurrentVibration = vib;
760 if (vib.effect instanceof VibrationEffect.OneShot) {
761 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
762 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
763 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
764 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
765 } else if (vib.effect instanceof VibrationEffect.Waveform) {
766 // mThread better be null here. doCancelVibrate should always be
767 // called before startNextVibrationLocked or startVibrationLocked.
768 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
769 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
770 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
771 mThread.start();
772 } else if (vib.effect instanceof VibrationEffect.Prebaked) {
773 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
774 long timeout = doVibratorPrebakedEffectLocked(vib);
775 if (timeout > 0) {
776 mH.postDelayed(mVibrationEndRunnable, timeout);
777 }
778 } else {
779 Slog.e(TAG, "Unknown vibration type, ignoring");
Michael Wright71216972017-01-31 18:33:54 +0000780 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000781 } finally {
782 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 }
784 }
785
Michael Wright35a0c672018-01-24 00:32:53 +0000786 private boolean isAllowedToVibrateLocked(Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700787 if (!mLowPowerMode) {
788 return true;
789 }
Michael Wright35a0c672018-01-24 00:32:53 +0000790
791 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700792 return true;
793 }
Tyler Freeman319a34a2017-05-04 17:23:35 -0700794
Michael Wright35a0c672018-01-24 00:32:53 +0000795 if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
796 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
797 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700798 return true;
799 }
800
801 return false;
802 }
803
Michael Wright35a0c672018-01-24 00:32:53 +0000804 private int getCurrentIntensityLocked(Vibration vib) {
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000805 if (vib.isRingtone()) {
806 return mRingIntensity;
807 } else if (vib.isNotification()) {
Michael Wright35a0c672018-01-24 00:32:53 +0000808 return mNotificationIntensity;
809 } else if (vib.isHapticFeedback()) {
810 return mHapticFeedbackIntensity;
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100811 } else if (vib.isAlarm()) {
812 return Vibrator.VIBRATION_INTENSITY_HIGH;
Michael Wright35a0c672018-01-24 00:32:53 +0000813 } else {
814 return Vibrator.VIBRATION_INTENSITY_MEDIUM;
815 }
816 }
817
818 /**
819 * Scale the vibration effect by the intensity as appropriate based its intent.
820 */
821 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
822 if (vib.effect instanceof VibrationEffect.Prebaked) {
823 // Prebaked effects are always just a direct translation from intensity to
824 // EffectStrength.
825 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
826 prebaked.setEffectStrength(intensityToEffectStrength(intensity));
827 return;
828 }
829
Michael Wright0dbb5162018-05-25 15:13:36 +0100830 final int defaultIntensity;
Alexey Kuzminccdaebb2018-12-10 12:02:51 +0000831 if (vib.isRingtone()) {
832 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
833 } else if (vib.isNotification()) {
Michael Wright0dbb5162018-05-25 15:13:36 +0100834 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
835 } else if (vib.isHapticFeedback()) {
836 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
Alexey Kuzmin082a59a2019-04-04 12:01:48 +0100837 } else if (vib.isAlarm()) {
838 defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
Michael Wright35a0c672018-01-24 00:32:53 +0000839 } else {
Michael Wright0dbb5162018-05-25 15:13:36 +0100840 // If we don't know what kind of vibration we're playing then just skip scaling for
841 // now.
842 return;
843 }
844
845 final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
846 if (scale == null) {
847 // We should have scaling levels for all cases, so not being able to scale because of a
848 // missing level is unexpected.
849 Slog.e(TAG, "No configured scaling level!"
850 + " (current=" + intensity + ", default= " + defaultIntensity + ")");
851 return;
Michael Wright35a0c672018-01-24 00:32:53 +0000852 }
853
854 VibrationEffect scaledEffect = null;
855 if (vib.effect instanceof VibrationEffect.OneShot) {
856 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100857 oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100858 scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000859 } else if (vib.effect instanceof VibrationEffect.Waveform) {
860 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100861 waveform = waveform.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100862 scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000863 } else {
864 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
865 }
866
867 if (scaledEffect != null) {
868 vib.originalEffect = vib.effect;
869 vib.effect = scaledEffect;
870 }
871 }
872
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700873 private boolean shouldVibrateForRingtone() {
Michael Wright35a0c672018-01-24 00:32:53 +0000874 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700875 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700876 // "Also vibrate for calls" Setting in Sound
877 if (Settings.System.getInt(
878 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
879 return ringerMode != AudioManager.RINGER_MODE_SILENT;
Yiwen Chenf8e46d72019-05-23 22:02:54 -0700880 } else if (Settings.Global.getInt(
881 mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0
882 && DeviceConfig.getBoolean(
883 DeviceConfig.NAMESPACE_TELEPHONY, RAMPING_RINGER_ENABLED, false)) {
884 return ringerMode != AudioManager.RINGER_MODE_SILENT;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700885 } else {
886 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
887 }
888 }
889
Michael Wright71216972017-01-31 18:33:54 +0000890 private int getAppOpMode(Vibration vib) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800891 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
892 vib.usageHint, vib.uid, vib.opPkg);
893 if (mode == AppOpsManager.MODE_ALLOWED) {
894 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
Michael Wright71216972017-01-31 18:33:54 +0000895 }
896 return mode;
897 }
898
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000899 @GuardedBy("mLock")
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800900 private void reportFinishVibrationLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000901 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
902 try {
903 if (mCurrentVibration != null) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800904 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
905 mCurrentVibration.opPkg);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000906 unlinkVibration(mCurrentVibration);
907 mCurrentVibration = null;
908 }
909 } finally {
910 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800911 }
912 }
913
Michael Wright36d873f2018-01-08 15:54:05 +0000914 private void linkVibration(Vibration vib) {
915 // Only link against waveforms since they potentially don't have a finish if
916 // they're repeating. Let other effects just play out until they're done.
Michael Wright35a0c672018-01-24 00:32:53 +0000917 if (vib.effect instanceof VibrationEffect.Waveform) {
Michael Wright36d873f2018-01-08 15:54:05 +0000918 try {
Michael Wright35a0c672018-01-24 00:32:53 +0000919 vib.token.linkToDeath(vib, 0);
Michael Wright36d873f2018-01-08 15:54:05 +0000920 } catch (RemoteException e) {
921 return;
922 }
923 }
924 }
925
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200926 private void unlinkVibration(Vibration vib) {
Michael Wright35a0c672018-01-24 00:32:53 +0000927 if (vib.effect instanceof VibrationEffect.Waveform) {
928 vib.token.unlinkToDeath(vib, 0);
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200929 }
930 }
931
Michael Wright71216972017-01-31 18:33:54 +0000932 private void updateVibrators() {
933 synchronized (mLock) {
934 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
935 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Michael Wright35a0c672018-01-24 00:32:53 +0000936 updateVibrationIntensityLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700937
Michael Wright71216972017-01-31 18:33:54 +0000938 if (devicesUpdated || lowPowerModeUpdated) {
939 // If the state changes out from under us then just reset.
940 doCancelVibrateLocked();
941 }
942 }
943 }
Jeff Brown82065252012-04-16 13:19:05 -0700944
Michael Wright71216972017-01-31 18:33:54 +0000945 private boolean updateInputDeviceVibratorsLocked() {
946 boolean changed = false;
947 boolean vibrateInputDevices = false;
948 try {
949 vibrateInputDevices = Settings.System.getIntForUser(
950 mContext.getContentResolver(),
951 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
952 } catch (SettingNotFoundException snfe) {
953 }
954 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
955 changed = true;
956 mVibrateInputDevicesSetting = vibrateInputDevices;
957 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700958
Michael Wright71216972017-01-31 18:33:54 +0000959 if (mVibrateInputDevicesSetting) {
960 if (!mInputDeviceListenerRegistered) {
961 mInputDeviceListenerRegistered = true;
962 mIm.registerInputDeviceListener(this, mH);
963 }
964 } else {
965 if (mInputDeviceListenerRegistered) {
966 mInputDeviceListenerRegistered = false;
967 mIm.unregisterInputDeviceListener(this);
968 }
969 }
Jeff Brown82065252012-04-16 13:19:05 -0700970
Michael Wright71216972017-01-31 18:33:54 +0000971 mInputDeviceVibrators.clear();
972 if (mVibrateInputDevicesSetting) {
973 int[] ids = mIm.getInputDeviceIds();
974 for (int i = 0; i < ids.length; i++) {
975 InputDevice device = mIm.getInputDevice(ids[i]);
976 Vibrator vibrator = device.getVibrator();
977 if (vibrator.hasVibrator()) {
978 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700979 }
980 }
Michael Wright71216972017-01-31 18:33:54 +0000981 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700982 }
Michael Wright71216972017-01-31 18:33:54 +0000983 return changed;
984 }
985
986 private boolean updateLowPowerModeLocked() {
987 boolean lowPowerMode = mPowerManagerInternal
988 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
989 if (lowPowerMode != mLowPowerMode) {
990 mLowPowerMode = lowPowerMode;
991 return true;
992 }
993 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700994 }
995
Michael Wright35a0c672018-01-24 00:32:53 +0000996 private void updateVibrationIntensityLocked() {
997 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
998 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
999 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
1000 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1001 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
1002 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +00001003 mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
1004 Settings.System.RING_VIBRATION_INTENSITY,
1005 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
Michael Wright35a0c672018-01-24 00:32:53 +00001006 }
1007
Jeff Brown7f6c2312012-04-13 20:38:38 -07001008 @Override
1009 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +00001010 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -07001011 }
1012
1013 @Override
1014 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +00001015 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -07001016 }
1017
1018 @Override
1019 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +00001020 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -07001021 }
1022
1023 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -07001024 // For now, we choose to ignore the presence of input devices that have vibrators
1025 // when reporting whether the device has a vibrator. Applications often use this
1026 // information to decide whether to enable certain features so they expect the
1027 // result of hasVibrator() to be constant. For now, just report whether
1028 // the device has a built-in vibrator.
1029 //synchronized (mInputDeviceVibrators) {
1030 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
1031 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -08001032 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -07001033 }
1034
Michael Wright71216972017-01-31 18:33:54 +00001035 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001036 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
1037 try {
1038 synchronized (mInputDeviceVibrators) {
1039 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
1040 amplitude = mDefaultVibrationAmplitude;
Jeff Brown7f6c2312012-04-13 20:38:38 -07001041 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001042 if (DEBUG) {
1043 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
1044 " with amplitude " + amplitude + ".");
1045 }
1046 noteVibratorOnLocked(uid, millis);
1047 final int vibratorCount = mInputDeviceVibrators.size();
1048 if (vibratorCount != 0) {
1049 final AudioAttributes attributes =
1050 new AudioAttributes.Builder().setUsage(usageHint).build();
1051 for (int i = 0; i < vibratorCount; i++) {
1052 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
1053 }
1054 } else {
1055 // Note: ordering is important here! Many haptic drivers will reset their
1056 // amplitude when enabled, so we always have to enable frst, then set the
1057 // amplitude.
1058 vibratorOn(millis);
1059 doVibratorSetAmplitude(amplitude);
1060 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001061 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001062 } finally {
1063 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001064 }
1065 }
1066
Michael Wright71216972017-01-31 18:33:54 +00001067 private void doVibratorSetAmplitude(int amplitude) {
1068 if (mSupportsAmplitudeControl) {
1069 vibratorSetAmplitude(amplitude);
1070 }
1071 }
1072
Jeff Brown7f6c2312012-04-13 20:38:38 -07001073 private void doVibratorOff() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001074 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
1075 try {
1076 synchronized (mInputDeviceVibrators) {
1077 if (DEBUG) {
1078 Slog.d(TAG, "Turning vibrator off.");
Jeff Brown7f6c2312012-04-13 20:38:38 -07001079 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001080 noteVibratorOffLocked();
1081 final int vibratorCount = mInputDeviceVibrators.size();
1082 if (vibratorCount != 0) {
1083 for (int i = 0; i < vibratorCount; i++) {
1084 mInputDeviceVibrators.get(i).cancel();
1085 }
1086 } else {
1087 vibratorOff();
1088 }
Jeff Brown7f6c2312012-04-13 20:38:38 -07001089 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001090 } finally {
1091 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -07001092 }
1093 }
1094
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +00001095 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +00001096 private long doVibratorPrebakedEffectLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001097 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
1098 try {
1099 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
1100 final boolean usingInputDeviceVibrators;
1101 synchronized (mInputDeviceVibrators) {
1102 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
Michael Wright35a0c672018-01-24 00:32:53 +00001103 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001104 // Input devices don't support prebaked effect, so skip trying it with them.
1105 if (!usingInputDeviceVibrators) {
1106 long timeout = vibratorPerformEffect(prebaked.getId(),
1107 prebaked.getEffectStrength());
1108 if (timeout > 0) {
1109 noteVibratorOnLocked(vib.uid, timeout);
1110 return timeout;
1111 }
1112 }
1113 if (!prebaked.shouldFallback()) {
1114 return 0;
1115 }
1116 VibrationEffect effect = getFallbackEffect(prebaked.getId());
1117 if (effect == null) {
1118 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1119 return 0;
1120 }
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001121 Vibration fallbackVib = new Vibration(vib.token, effect, vib.usageHint, vib.uid,
1122 vib.opPkg, vib.reason + " (fallback)");
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001123 final int intensity = getCurrentIntensityLocked(fallbackVib);
1124 linkVibration(fallbackVib);
1125 applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1126 startVibrationInnerLocked(fallbackVib);
Michael Wright35a0c672018-01-24 00:32:53 +00001127 return 0;
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001128 } finally {
1129 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright35a0c672018-01-24 00:32:53 +00001130 }
Michael Wright71216972017-01-31 18:33:54 +00001131 }
Eric Olsenf42f15c2009-10-29 16:42:03 -07001132
Michael Wright36d873f2018-01-08 15:54:05 +00001133 private VibrationEffect getFallbackEffect(int effectId) {
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +00001134 return mFallbackEffects.get(effectId);
Michael Wright36d873f2018-01-08 15:54:05 +00001135 }
1136
Michael Wright35a0c672018-01-24 00:32:53 +00001137 /**
1138 * Return the current desired effect strength.
1139 *
1140 * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1141 */
1142 private static int intensityToEffectStrength(int intensity) {
1143 switch (intensity) {
1144 case Vibrator.VIBRATION_INTENSITY_LOW:
1145 return EffectStrength.LIGHT;
1146 case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1147 return EffectStrength.MEDIUM;
1148 case Vibrator.VIBRATION_INTENSITY_HIGH:
1149 return EffectStrength.STRONG;
1150 default:
1151 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1152 return EffectStrength.STRONG;
1153 }
1154 }
1155
Michael Wrightc390fbe2018-12-12 19:45:09 +00001156 private static boolean isNotification(int usageHint) {
1157 switch (usageHint) {
1158 case AudioAttributes.USAGE_NOTIFICATION:
1159 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
1160 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
1161 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
1162 return true;
1163 default:
1164 return false;
1165 }
1166 }
1167
1168 private static boolean isRingtone(int usageHint) {
1169 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
1170 }
1171
1172 private static boolean isHapticFeedback(int usageHint) {
1173 return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
1174 }
1175
Alexey Kuzmin082a59a2019-04-04 12:01:48 +01001176 private static boolean isAlarm(int usageHint) {
1177 return usageHint == AudioAttributes.USAGE_ALARM;
1178 }
1179
Michael Wright71216972017-01-31 18:33:54 +00001180 private void noteVibratorOnLocked(int uid, long millis) {
1181 try {
1182 mBatteryStatsService.noteVibratorOn(uid, millis);
Bookatza7020bd2018-08-28 16:29:35 -07001183 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null,
1184 StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis);
Michael Wright71216972017-01-31 18:33:54 +00001185 mCurVibUid = uid;
1186 } catch (RemoteException e) {
1187 }
1188 }
1189
1190 private void noteVibratorOffLocked() {
1191 if (mCurVibUid >= 0) {
1192 try {
1193 mBatteryStatsService.noteVibratorOff(mCurVibUid);
Bookatza7020bd2018-08-28 16:29:35 -07001194 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null,
1195 StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0);
Michael Wright71216972017-01-31 18:33:54 +00001196 } catch (RemoteException e) { }
1197 mCurVibUid = -1;
1198 }
1199 }
1200
Michael Wrightc390fbe2018-12-12 19:45:09 +00001201 private void setVibratorUnderExternalControl(boolean externalControl) {
1202 if (DEBUG) {
1203 if (externalControl) {
1204 Slog.d(TAG, "Vibrator going under external control.");
1205 } else {
1206 Slog.d(TAG, "Taking back control of vibrator.");
1207 }
1208 }
1209 mVibratorUnderExternalControl = externalControl;
1210 vibratorSetExternalControl(externalControl);
1211 }
1212
Michael Wright71216972017-01-31 18:33:54 +00001213 private class VibrateThread extends Thread {
1214 private final VibrationEffect.Waveform mWaveform;
1215 private final int mUid;
1216 private final int mUsageHint;
1217
1218 private boolean mForceStop;
1219
1220 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1221 mWaveform = waveform;
1222 mUid = uid;
1223 mUsageHint = usageHint;
1224 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001225 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 }
1227
Michael Wright71216972017-01-31 18:33:54 +00001228 private long delayLocked(long duration) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001229 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1230 try {
1231 long durationRemaining = duration;
1232 if (duration > 0) {
1233 final long bedtime = duration + SystemClock.uptimeMillis();
1234 do {
1235 try {
1236 this.wait(durationRemaining);
1237 }
1238 catch (InterruptedException e) { }
1239 if (mForceStop) {
1240 break;
1241 }
1242 durationRemaining = bedtime - SystemClock.uptimeMillis();
1243 } while (durationRemaining > 0);
1244 return duration - durationRemaining;
1245 }
1246 return 0;
1247 } finally {
1248 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
1250 }
1251
1252 public void run() {
1253 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +00001254 mWakeLock.acquire();
1255 try {
1256 boolean finished = playWaveform();
1257 if (finished) {
1258 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 }
Michael Wright71216972017-01-31 18:33:54 +00001260 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 mWakeLock.release();
1262 }
Michael Wright71216972017-01-31 18:33:54 +00001263 }
1264
1265 /**
1266 * Play the waveform.
1267 *
1268 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1269 */
1270 public boolean playWaveform() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001271 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1272 try {
1273 synchronized (this) {
1274 final long[] timings = mWaveform.getTimings();
1275 final int[] amplitudes = mWaveform.getAmplitudes();
1276 final int len = timings.length;
1277 final int repeat = mWaveform.getRepeatIndex();
Michael Wright71216972017-01-31 18:33:54 +00001278
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001279 int index = 0;
1280 long onDuration = 0;
1281 while (!mForceStop) {
1282 if (index < len) {
1283 final int amplitude = amplitudes[index];
1284 final long duration = timings[index++];
1285 if (duration <= 0) {
1286 continue;
Michael Wright71216972017-01-31 18:33:54 +00001287 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001288 if (amplitude != 0) {
1289 if (onDuration <= 0) {
1290 // Telling the vibrator to start multiple times usually causes
1291 // effects to feel "choppy" because the motor resets at every on
1292 // command. Instead we figure out how long our next "on" period
1293 // is going to be, tell the motor to stay on for the full
1294 // duration, and then wake up to change the amplitude at the
1295 // appropriate intervals.
1296 onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1297 repeat);
1298 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1299 } else {
1300 doVibratorSetAmplitude(amplitude);
1301 }
1302 }
Michael Wright71216972017-01-31 18:33:54 +00001303
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001304 long waitTime = delayLocked(duration);
1305 if (amplitude != 0) {
1306 onDuration -= waitTime;
1307 }
1308 } else if (repeat < 0) {
1309 break;
1310 } else {
1311 index = repeat;
Michael Wright71216972017-01-31 18:33:54 +00001312 }
Michael Wright71216972017-01-31 18:33:54 +00001313 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001314 return !mForceStop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001315 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001316 } finally {
1317 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +00001318 }
1319 }
1320
1321 public void cancel() {
1322 synchronized (this) {
1323 mThread.mForceStop = true;
1324 mThread.notify();
1325 }
1326 }
1327
1328 /**
1329 * Get the duration the vibrator will be on starting at startIndex until the next time it's
1330 * off.
1331 */
1332 private long getTotalOnDuration(
1333 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1334 int i = startIndex;
1335 long timing = 0;
1336 while(amplitudes[i] != 0) {
1337 timing += timings[i++];
1338 if (i >= timings.length) {
1339 if (repeatIndex >= 0) {
1340 i = repeatIndex;
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001341 // prevent infinite loop
1342 repeatIndex = -1;
Michael Wright71216972017-01-31 18:33:54 +00001343 } else {
1344 break;
1345 }
1346 }
1347 if (i == startIndex) {
1348 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -04001349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 }
Michael Wright71216972017-01-31 18:33:54 +00001351 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
Jeff Brown969579b2014-05-20 19:29:29 -07001353 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -07001356 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 public void onReceive(Context context, Intent intent) {
1358 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +00001359 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -07001360 // When the system is entering a non-interactive state, we want
1361 // to cancel vibrations in case a misbehaving app has abandoned
1362 // them. However it may happen that the system is currently playing
1363 // haptic feedback as part of the transition. So we don't cancel
1364 // system vibrations.
1365 if (mCurrentVibration != null
Michael Wright35a0c672018-01-24 00:32:53 +00001366 && !(mCurrentVibration.isHapticFeedback()
1367 && mCurrentVibration.isFromSystem())) {
Jeff Brown969579b2014-05-20 19:29:29 -07001368 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -07001369 }
Patrick Scott18dd5f02009-07-02 11:31:12 -04001370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
1372 }
1373 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001374
1375 @Override
1376 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001377 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001378
Michael Wright35a0c672018-01-24 00:32:53 +00001379 pw.println("Vibrator Service:");
Michael Wright71216972017-01-31 18:33:54 +00001380 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +00001381 pw.print(" mCurrentVibration=");
1382 if (mCurrentVibration != null) {
1383 pw.println(mCurrentVibration.toInfo().toString());
1384 } else {
1385 pw.println("null");
1386 }
Michael Wrightc390fbe2018-12-12 19:45:09 +00001387 pw.print(" mCurrentExternalVibration=");
1388 if (mCurrentExternalVibration != null) {
1389 pw.println(mCurrentExternalVibration.toString());
1390 } else {
1391 pw.println("null");
1392 }
1393 pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl);
Michael Wright35a0c672018-01-24 00:32:53 +00001394 pw.println(" mLowPowerMode=" + mLowPowerMode);
1395 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1396 pw.println(" mNotificationIntensity=" + mNotificationIntensity);
Alexey Kuzminccdaebb2018-12-10 12:02:51 +00001397 pw.println(" mRingIntensity=" + mRingIntensity);
Michael Wright35a0c672018-01-24 00:32:53 +00001398 pw.println("");
Arthur Hung85ed7da2019-03-05 13:58:19 +08001399 pw.println(" Previous ring vibrations:");
1400 for (VibrationInfo info : mPreviousRingVibrations) {
1401 pw.print(" ");
1402 pw.println(info.toString());
1403 }
1404
1405 pw.println(" Previous notification vibrations:");
1406 for (VibrationInfo info : mPreviousNotificationVibrations) {
1407 pw.print(" ");
1408 pw.println(info.toString());
1409 }
1410
Alexey Kuzmin082a59a2019-04-04 12:01:48 +01001411 pw.println(" Previous alarm vibrations:");
1412 for (VibrationInfo info : mPreviousAlarmVibrations) {
1413 pw.print(" ");
1414 pw.println(info.toString());
1415 }
1416
Michael Wright35a0c672018-01-24 00:32:53 +00001417 pw.println(" Previous vibrations:");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001418 for (VibrationInfo info : mPreviousVibrations) {
Michael Wright35a0c672018-01-24 00:32:53 +00001419 pw.print(" ");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001420 pw.println(info.toString());
1421 }
Alexey Kuzmind8b0f782019-06-05 17:20:26 +01001422
1423 pw.println(" Previous external vibrations:");
1424 for (ExternalVibration vib : mPreviousExternalVibrations) {
1425 pw.print(" ");
1426 pw.println(vib.toString());
1427 }
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001428 }
1429 }
Felipe Lemea5281002017-02-10 15:13:48 -08001430
1431 @Override
1432 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1433 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1434 throws RemoteException {
1435 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1436 }
1437
Michael Wrightc390fbe2018-12-12 19:45:09 +00001438 final class ExternalVibratorService extends IExternalVibratorService.Stub {
Alexey Kuzmin13381542019-06-05 17:23:43 +01001439 ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient;
1440
Michael Wrightc390fbe2018-12-12 19:45:09 +00001441 @Override
1442 public int onExternalVibrationStart(ExternalVibration vib) {
1443 if (!mSupportsExternalControl) {
1444 return SCALE_MUTE;
1445 }
1446 if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE,
1447 vib.getUid(), -1 /*owningUid*/, true /*exported*/)
1448 != PackageManager.PERMISSION_GRANTED) {
1449 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid()
1450 + " tried to play externally controlled vibration"
1451 + " without VIBRATE permission, ignoring.");
1452 return SCALE_MUTE;
1453 }
1454
1455 final int scaleLevel;
1456 synchronized (mLock) {
1457 if (!vib.equals(mCurrentExternalVibration)) {
1458 if (mCurrentExternalVibration == null) {
1459 // If we're not under external control right now, then cancel any normal
1460 // vibration that may be playing and ready the vibrator for external
1461 // control.
1462 doCancelVibrateLocked();
1463 setVibratorUnderExternalControl(true);
1464 }
1465 // At this point we either have an externally controlled vibration playing, or
1466 // no vibration playing. Since the interface defines that only one externally
1467 // controlled vibration can play at a time, by returning something other than
1468 // SCALE_MUTE from this function we can be assured that if we are currently
1469 // playing vibration, it will be muted in favor of the new vibration.
1470 //
1471 // Note that this doesn't support multiple concurrent external controls, as we
1472 // would need to mute the old one still if it came from a different controller.
1473 mCurrentExternalVibration = vib;
Alexey Kuzmin13381542019-06-05 17:23:43 +01001474 mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient();
1475 mCurrentExternalVibration.linkToDeath(mCurrentExternalDeathRecipient);
Alexey Kuzmind8b0f782019-06-05 17:20:26 +01001476 if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) {
1477 mPreviousExternalVibrations.removeFirst();
1478 }
1479 mPreviousExternalVibrations.addLast(vib);
Michael Wrightc390fbe2018-12-12 19:45:09 +00001480 if (DEBUG) {
1481 Slog.e(TAG, "Playing external vibration: " + vib);
1482 }
1483 }
1484 final int usage = vib.getAudioAttributes().getUsage();
1485 final int defaultIntensity;
1486 final int currentIntensity;
1487 if (isRingtone(usage)) {
1488 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity();
1489 currentIntensity = mRingIntensity;
1490 } else if (isNotification(usage)) {
1491 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
1492 currentIntensity = mNotificationIntensity;
1493 } else if (isHapticFeedback(usage)) {
1494 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
1495 currentIntensity = mHapticFeedbackIntensity;
Alexey Kuzmin082a59a2019-04-04 12:01:48 +01001496 } else if (isAlarm(usage)) {
1497 defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
1498 currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH;
Michael Wrightc390fbe2018-12-12 19:45:09 +00001499 } else {
1500 defaultIntensity = 0;
1501 currentIntensity = 0;
1502 }
1503 scaleLevel = currentIntensity - defaultIntensity;
1504 }
1505 if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) {
1506 return scaleLevel;
1507 } else {
1508 // Presumably we want to play this but something about our scaling has gone
1509 // wrong, so just play with no scaling.
1510 Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level "
1511 + scaleLevel + " for vibration " + vib);
1512 return SCALE_NONE;
1513 }
1514 }
1515
1516 @Override
1517 public void onExternalVibrationStop(ExternalVibration vib) {
1518 synchronized (mLock) {
1519 if (vib.equals(mCurrentExternalVibration)) {
Alexey Kuzmin13381542019-06-05 17:23:43 +01001520 mCurrentExternalVibration.unlinkToDeath(mCurrentExternalDeathRecipient);
1521 mCurrentExternalDeathRecipient = null;
Michael Wrightc390fbe2018-12-12 19:45:09 +00001522 mCurrentExternalVibration = null;
1523 setVibratorUnderExternalControl(false);
1524 if (DEBUG) {
1525 Slog.e(TAG, "Stopping external vibration" + vib);
1526 }
1527 }
1528 }
1529 }
Alexey Kuzmin13381542019-06-05 17:23:43 +01001530
1531 private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient {
1532 public void binderDied() {
1533 synchronized (mLock) {
1534 onExternalVibrationStop(mCurrentExternalVibration);
1535 }
1536 }
1537 }
Michael Wrightc390fbe2018-12-12 19:45:09 +00001538 }
1539
Felipe Lemea5281002017-02-10 15:13:48 -08001540 private final class VibratorShellCommand extends ShellCommand {
1541
Felipe Lemea5281002017-02-10 15:13:48 -08001542 private final IBinder mToken;
1543
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001544 private final class CommonOptions {
1545 public boolean force = false;
1546 public void check(String opt) {
1547 switch (opt) {
1548 case "-f":
1549 force = true;
1550 break;
1551 }
1552 }
1553 }
1554
Felipe Lemea5281002017-02-10 15:13:48 -08001555 private VibratorShellCommand(IBinder token) {
1556 mToken = token;
1557 }
1558
1559 @Override
1560 public int onCommand(String cmd) {
1561 if ("vibrate".equals(cmd)) {
1562 return runVibrate();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001563 } else if ("waveform".equals(cmd)) {
1564 return runWaveform();
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001565 } else if ("prebaked".equals(cmd)) {
1566 return runPrebaked();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001567 } else if ("cancel".equals(cmd)) {
1568 cancelVibrate(mToken);
1569 return 0;
Felipe Lemea5281002017-02-10 15:13:48 -08001570 }
1571 return handleDefaultCommands(cmd);
1572 }
1573
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001574 private boolean checkDoNotDisturb(CommonOptions opts) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001575 try {
1576 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1577 Settings.Global.ZEN_MODE);
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001578 if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001579 try (PrintWriter pw = getOutPrintWriter();) {
1580 pw.print("Ignoring because device is on DND mode ");
1581 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1582 zenMode));
1583 return true;
1584 }
1585 }
1586 } catch (SettingNotFoundException e) {
1587 // ignore
1588 }
1589
1590 return false;
1591 }
1592
Felipe Lemea5281002017-02-10 15:13:48 -08001593 private int runVibrate() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001594 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001595 try {
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001596 CommonOptions commonOptions = new CommonOptions();
1597
1598 String opt;
1599 while ((opt = getNextOption()) != null) {
1600 commonOptions.check(opt);
1601 }
1602
1603 if (checkDoNotDisturb(commonOptions)) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001604 return 0;
Felipe Leme5e2e6322017-07-14 17:25:59 -07001605 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001606
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001607 final long duration = Long.parseLong(getNextArgRequired());
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001608 String description = getNextArg();
1609 if (description == null) {
1610 description = "Shell command";
1611 }
Michael Wright71216972017-01-31 18:33:54 +00001612
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001613 VibrationEffect effect =
1614 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1615 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
Alexey Kuzmine1f06b82018-06-20 17:48:43 +01001616 "Shell Command", mToken);
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001617 return 0;
1618 } finally {
1619 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1620 }
Felipe Lemea5281002017-02-10 15:13:48 -08001621 }
1622
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001623 private int runWaveform() {
1624 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform");
1625 try {
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001626 String description = "Shell command";
1627 int repeat = -1;
1628 ArrayList<Integer> amplitudesList = null;
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001629 CommonOptions commonOptions = new CommonOptions();
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001630
1631 String opt;
1632 while ((opt = getNextOption()) != null) {
1633 switch (opt) {
1634 case "-d":
1635 description = getNextArgRequired();
1636 break;
1637 case "-r":
1638 repeat = Integer.parseInt(getNextArgRequired());
1639 break;
1640 case "-a":
1641 if (amplitudesList == null) {
1642 amplitudesList = new ArrayList<Integer>();
1643 }
1644 break;
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001645 default:
1646 commonOptions.check(opt);
1647 break;
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001648 }
1649 }
1650
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001651 if (checkDoNotDisturb(commonOptions)) {
1652 return 0;
1653 }
1654
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001655 ArrayList<Long> timingsList = new ArrayList<Long>();
1656
1657 String arg;
1658 while ((arg = getNextArg()) != null) {
1659 if (amplitudesList != null && amplitudesList.size() < timingsList.size()) {
1660 amplitudesList.add(Integer.parseInt(arg));
1661 } else {
1662 timingsList.add(Long.parseLong(arg));
1663 }
1664 }
1665
1666 VibrationEffect effect;
1667 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray();
1668 if (amplitudesList == null) {
1669 effect = VibrationEffect.createWaveform(timings, repeat);
1670 } else {
1671 int[] amplitudes =
1672 amplitudesList.stream().mapToInt(Integer::intValue).toArray();
1673 effect = VibrationEffect.createWaveform(timings, amplitudes, repeat);
1674 }
1675 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1676 "Shell Command", mToken);
1677 return 0;
1678 } finally {
1679 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1680 }
1681 }
1682
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001683 private int runPrebaked() {
1684 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
1685 try {
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001686 CommonOptions commonOptions = new CommonOptions();
1687
1688 String opt;
1689 while ((opt = getNextOption()) != null) {
1690 commonOptions.check(opt);
1691 }
1692
1693 if (checkDoNotDisturb(commonOptions)) {
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001694 return 0;
1695 }
1696
1697 final int id = Integer.parseInt(getNextArgRequired());
1698
1699 String description = getNextArg();
1700 if (description == null) {
1701 description = "Shell command";
1702 }
1703
1704 VibrationEffect effect =
1705 VibrationEffect.get(id, false);
1706 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1707 "Shell Command", mToken);
1708 return 0;
1709 } finally {
1710 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1711 }
1712 }
1713
Felipe Lemea5281002017-02-10 15:13:48 -08001714 @Override
1715 public void onHelp() {
1716 try (PrintWriter pw = getOutPrintWriter();) {
1717 pw.println("Vibrator commands:");
1718 pw.println(" help");
1719 pw.println(" Prints this help text.");
1720 pw.println("");
1721 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001722 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1723 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001724 pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ...");
1725 pw.println(" Vibrates for durations and amplitudes in list;");
1726 pw.println(" ignored when device is on DND (Do Not Disturb) mode.");
1727 pw.println(" If -r is provided, the waveform loops back to the specified");
1728 pw.println(" index (e.g. 0 loops from the beginning)");
1729 pw.println(" If -a is provided, the command accepts duration-amplitude pairs;");
1730 pw.println(" otherwise, it accepts durations only and alternates off/on");
1731 pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255.");
Harpreet "Eli" Sangha5ecc5362018-10-16 17:27:58 +09001732 pw.println(" prebaked effect-id [description]");
1733 pw.println(" Vibrates with prebaked effect; ignored when device is on DND ");
1734 pw.println(" (Do Not Disturb) mode.");
Harpreet "Eli" Sanghac5526dd2018-10-30 16:14:33 +09001735 pw.println(" cancel");
1736 pw.println(" Cancels any active vibration");
Harpreet "Eli" Sanghaf32459a2019-01-30 16:06:09 +09001737 pw.println("Common Options:");
1738 pw.println(" -f - Force. Ignore Do Not Disturb setting.");
Felipe Lemea5281002017-02-10 15:13:48 -08001739 pw.println("");
1740 }
1741 }
1742 }
1743
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744}