blob: 95e55182f8236234dfcf7e0d243ee35fd414995f [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborna06de0f2012-12-11 16:34:47 -080019import android.app.AppOpsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.content.pm.PackageManager;
Michael Wright71216972017-01-31 18:33:54 +000025import android.content.res.Resources;
Jeff Brown7f6c2312012-04-13 20:38:38 -070026import android.database.ContentObserver;
27import android.hardware.input.InputManager;
Michael Wrightf268bf52018-02-07 23:23:34 +000028import android.hardware.vibrator.V1_0.EffectStrength;
Michael Wright36d873f2018-01-08 15:54:05 +000029import android.icu.text.DateFormat;
Brad Ebinger2d1c3b32016-05-12 18:05:17 -070030import android.media.AudioManager;
Makoto Onuki2eccd022017-11-01 13:44:23 -070031import android.os.PowerManager.ServiceType;
jackqdyulei455e90a2017-02-09 15:29:16 -080032import android.os.PowerSaveState;
Dianne Hackborn91268cf2013-06-13 19:06:50 -070033import android.os.BatteryStats;
Joe Onorato95e4f702009-03-24 19:29:09 -070034import android.os.Handler;
Mike Lockwood3a322132009-11-24 00:30:52 -050035import android.os.IVibratorService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.os.PowerManager;
Dianne Hackborneb94fa72014-06-03 17:48:12 -070037import android.os.PowerManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Process;
39import android.os.RemoteException;
Felipe Lemea5281002017-02-10 15:13:48 -080040import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.os.IBinder;
42import android.os.Binder;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080043import android.os.ServiceManager;
Felipe Lemea5281002017-02-10 15:13:48 -080044import android.os.ShellCallback;
45import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.SystemClock;
Alexey Kuzmine59145a2018-02-10 15:19:03 +000047import android.os.Trace;
Jeff Brownd4935962012-09-25 13:27:20 -070048import android.os.UserHandle;
Jeff Brown7f6c2312012-04-13 20:38:38 -070049import android.os.Vibrator;
Michael Wright71216972017-01-31 18:33:54 +000050import android.os.VibrationEffect;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070051import android.os.WorkSource;
Jeff Brown7f6c2312012-04-13 20:38:38 -070052import android.provider.Settings;
53import android.provider.Settings.SettingNotFoundException;
Felipe Leme5e2e6322017-07-14 17:25:59 -070054import android.util.DebugUtils;
Joe Onorato8a9b2202010-02-26 18:56:32 -080055import android.util.Slog;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +000056import android.util.SparseArray;
Jeff Brown7f6c2312012-04-13 20:38:38 -070057import android.view.InputDevice;
John Spurlock7b414672014-07-18 13:02:39 -040058import android.media.AudioAttributes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +000060import com.android.internal.annotations.GuardedBy;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080061import com.android.internal.app.IAppOpsService;
62import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060063import com.android.internal.util.DumpUtils;
Dianne Hackborna06de0f2012-12-11 16:34:47 -080064
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -070065import java.io.FileDescriptor;
66import java.io.PrintWriter;
Jeff Brown7f6c2312012-04-13 20:38:38 -070067import java.util.ArrayList;
Patrick Scott18dd5f02009-07-02 11:31:12 -040068import java.util.LinkedList;
Michael Wright36d873f2018-01-08 15:54:05 +000069import java.util.Date;
Patrick Scott18dd5f02009-07-02 11:31:12 -040070
Jeff Brown7f6c2312012-04-13 20:38:38 -070071public class VibratorService extends IVibratorService.Stub
72 implements InputManager.InputDeviceListener {
Mike Lockwood3a322132009-11-24 00:30:52 -050073 private static final String TAG = "VibratorService";
Jeff Brown82379ba2014-07-25 19:03:28 -070074 private static final boolean DEBUG = false;
Jorim Jaggi18f18ae2015-09-10 15:48:21 -070075 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui";
Mike Lockwoodcc9a63d2009-11-10 07:50:28 -050076
Michael Wright36d873f2018-01-08 15:54:05 +000077 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
78
Michael Wright0dbb5162018-05-25 15:13:36 +010079 // Scale levels. Each level is defined as the delta between the current setting and the default
80 // intensity for that type of vibration (i.e. current - default).
81 private static final int SCALE_VERY_LOW = -2;
82 private static final int SCALE_LOW = -1;
83 private static final int SCALE_NONE = 0;
84 private static final int SCALE_HIGH = 1;
85 private static final int SCALE_VERY_HIGH = 2;
Michael Wright35a0c672018-01-24 00:32:53 +000086
Michael Wright0dbb5162018-05-25 15:13:36 +010087 // Gamma adjustments for scale levels.
88 private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
89 private static final float SCALE_LOW_GAMMA = 1.5f;
90 private static final float SCALE_NONE_GAMMA = 1.0f;
91 private static final float SCALE_HIGH_GAMMA = 0.5f;
92 private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
93
94 // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
95 // max amplitude.
96 private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
97 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
Michael Wright35a0c672018-01-24 00:32:53 +000098
99 // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
100 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
101
Michael Wright0dbb5162018-05-25 15:13:36 +0100102
103 // A mapping from the intensity adjustment to the scaling to apply, where the intensity
104 // adjustment is defined as the delta between the default intensity level and the user selected
105 // intensity level. It's important that we apply the scaling on the delta between the two so
106 // that the default intensity level applies no scaling to application provided effects.
107 private final SparseArray<ScaleLevel> mScaleLevels;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700108 private final LinkedList<VibrationInfo> mPreviousVibrations;
109 private final int mPreviousVibrationsLimit;
Tyler Freeman319a34a2017-05-04 17:23:35 -0700110 private final boolean mAllowPriorityVibrationsInLowPowerMode;
Michael Wright71216972017-01-31 18:33:54 +0000111 private final boolean mSupportsAmplitudeControl;
112 private final int mDefaultVibrationAmplitude;
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000113 private final SparseArray<VibrationEffect> mFallbackEffects;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700114 private final WorkSource mTmpWorkSource = new WorkSource();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700115 private final Handler mH = new Handler();
Michael Wright71216972017-01-31 18:33:54 +0000116 private final Object mLock = new Object();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700117
118 private final Context mContext;
119 private final PowerManager.WakeLock mWakeLock;
Svet Ganovf7b47252018-02-26 11:11:27 -0800120 private final AppOpsManager mAppOps;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800121 private final IBatteryStats mBatteryStatsService;
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700122 private PowerManagerInternal mPowerManagerInternal;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700123 private InputManager mIm;
Michael Wright35a0c672018-01-24 00:32:53 +0000124 private Vibrator mVibrator;
125 private SettingsObserver mSettingObserver;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700126
Michael Wright71216972017-01-31 18:33:54 +0000127 private volatile VibrateThread mThread;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700128
Michael Wright71216972017-01-31 18:33:54 +0000129 // mInputDeviceVibrators lock should be acquired after mLock, if both are
Jeff Brown7f6c2312012-04-13 20:38:38 -0700130 // to be acquired
131 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>();
132 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators
133 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators
134
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000135 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000136 private Vibration mCurrentVibration;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800137 private int mCurVibUid = -1;
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700138 private boolean mLowPowerMode;
Michael Wright35a0c672018-01-24 00:32:53 +0000139 private int mHapticFeedbackIntensity;
140 private int mNotificationIntensity;
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800141
Jeff Brown7f6c2312012-04-13 20:38:38 -0700142 native static boolean vibratorExists();
Vincent Beckere6904fb2012-08-10 14:17:33 +0200143 native static void vibratorInit();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700144 native static void vibratorOn(long milliseconds);
145 native static void vibratorOff();
Michael Wright71216972017-01-31 18:33:54 +0000146 native static boolean vibratorSupportsAmplitudeControl();
147 native static void vibratorSetAmplitude(int amplitude);
148 native static long vibratorPerformEffect(long effect, long strength);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400149
Patrick Scott18dd5f02009-07-02 11:31:12 -0400150 private class Vibration implements IBinder.DeathRecipient {
Michael Wright35a0c672018-01-24 00:32:53 +0000151 public final IBinder token;
Michael Wright36d873f2018-01-08 15:54:05 +0000152 // Start time in CLOCK_BOOTTIME base.
Michael Wright35a0c672018-01-24 00:32:53 +0000153 public final long startTime;
Michael Wright36d873f2018-01-08 15:54:05 +0000154 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate
Michael Wright35a0c672018-01-24 00:32:53 +0000155 // with other system events, any duration calculations should be done use startTime so as
Michael Wright36d873f2018-01-08 15:54:05 +0000156 // not to be affected by discontinuities created by RTC adjustments.
Michael Wright35a0c672018-01-24 00:32:53 +0000157 public final long startTimeDebug;
158 public final int usageHint;
159 public final int uid;
160 public final String opPkg;
161
162 // The actual effect to be played.
163 public VibrationEffect effect;
164 // The original effect that was requested. This is non-null only when the original effect
165 // differs from the effect that's being played. Typically these two things differ because
166 // the effect was scaled based on the users vibration intensity settings.
167 public VibrationEffect originalEffect;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400168
Michael Wright71216972017-01-31 18:33:54 +0000169 private Vibration(IBinder token, VibrationEffect effect,
170 int usageHint, int uid, String opPkg) {
Michael Wright35a0c672018-01-24 00:32:53 +0000171 this.token = token;
172 this.effect = effect;
173 this.startTime = SystemClock.elapsedRealtime();
174 this.startTimeDebug = System.currentTimeMillis();
175 this.usageHint = usageHint;
176 this.uid = uid;
177 this.opPkg = opPkg;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400178 }
179
180 public void binderDied() {
Michael Wright71216972017-01-31 18:33:54 +0000181 synchronized (mLock) {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400182 if (this == mCurrentVibration) {
183 doCancelVibrateLocked();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400184 }
185 }
186 }
187
Michael Wright35a0c672018-01-24 00:32:53 +0000188 public boolean hasTimeoutLongerThan(long millis) {
189 final long duration = effect.getDuration();
190 return duration >= 0 && duration > millis;
Patrick Scott18dd5f02009-07-02 11:31:12 -0400191 }
Jeff Brown969579b2014-05-20 19:29:29 -0700192
Michael Wright35a0c672018-01-24 00:32:53 +0000193 public boolean isHapticFeedback() {
194 if (effect instanceof VibrationEffect.Prebaked) {
195 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
196 switch (prebaked.getId()) {
197 case VibrationEffect.EFFECT_CLICK:
198 case VibrationEffect.EFFECT_DOUBLE_CLICK:
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000199 case VibrationEffect.EFFECT_HEAVY_CLICK:
Michael Wright35a0c672018-01-24 00:32:53 +0000200 case VibrationEffect.EFFECT_TICK:
Michael Wright0dbb5162018-05-25 15:13:36 +0100201 case VibrationEffect.EFFECT_POP:
202 case VibrationEffect.EFFECT_THUD:
Michael Wright35a0c672018-01-24 00:32:53 +0000203 return true;
204 default:
205 Slog.w(TAG, "Unknown prebaked vibration effect, "
206 + "assuming it isn't haptic feedback.");
207 return false;
208 }
Michael Wright71216972017-01-31 18:33:54 +0000209 }
Michael Wright35a0c672018-01-24 00:32:53 +0000210 final long duration = effect.getDuration();
211 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION;
212 }
213
214 public boolean isNotification() {
215 switch (usageHint) {
216 case AudioAttributes.USAGE_NOTIFICATION:
217 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
218 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
219 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
220 return true;
221 default:
222 return false;
223 }
224 }
225
226 public boolean isRingtone() {
227 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
228 }
229
230 public boolean isFromSystem() {
231 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg);
Jeff Brown969579b2014-05-20 19:29:29 -0700232 }
Michael Wright36d873f2018-01-08 15:54:05 +0000233
234 public VibrationInfo toInfo() {
Michael Wright35a0c672018-01-24 00:32:53 +0000235 return new VibrationInfo(
236 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg);
Michael Wright36d873f2018-01-08 15:54:05 +0000237 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400238 }
239
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700240 private static class VibrationInfo {
Michael Wright36d873f2018-01-08 15:54:05 +0000241 private final long mStartTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000242 private final VibrationEffect mEffect;
Michael Wright35a0c672018-01-24 00:32:53 +0000243 private final VibrationEffect mOriginalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000244 private final int mUsageHint;
245 private final int mUid;
246 private final String mOpPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700247
Michael Wright36d873f2018-01-08 15:54:05 +0000248 public VibrationInfo(long startTimeDebug, VibrationEffect effect,
Michael Wright35a0c672018-01-24 00:32:53 +0000249 VibrationEffect originalEffect, int usageHint, int uid, String opPkg) {
Michael Wright36d873f2018-01-08 15:54:05 +0000250 mStartTimeDebug = startTimeDebug;
Michael Wright71216972017-01-31 18:33:54 +0000251 mEffect = effect;
Michael Wright35a0c672018-01-24 00:32:53 +0000252 mOriginalEffect = originalEffect;
Michael Wright71216972017-01-31 18:33:54 +0000253 mUsageHint = usageHint;
254 mUid = uid;
255 mOpPkg = opPkg;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700256 }
257
258 @Override
259 public String toString() {
260 return new StringBuilder()
Michael Wright36d873f2018-01-08 15:54:05 +0000261 .append("startTime: ")
262 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug)))
Michael Wright71216972017-01-31 18:33:54 +0000263 .append(", effect: ")
264 .append(mEffect)
Michael Wright35a0c672018-01-24 00:32:53 +0000265 .append(", originalEffect: ")
266 .append(mOriginalEffect)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700267 .append(", usageHint: ")
Michael Wright71216972017-01-31 18:33:54 +0000268 .append(mUsageHint)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700269 .append(", uid: ")
Michael Wright71216972017-01-31 18:33:54 +0000270 .append(mUid)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700271 .append(", opPkg: ")
Michael Wright71216972017-01-31 18:33:54 +0000272 .append(mOpPkg)
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700273 .toString();
274 }
275 }
276
Michael Wright0dbb5162018-05-25 15:13:36 +0100277 private static final class ScaleLevel {
278 public final float gamma;
279 public final int maxAmplitude;
280
281 public ScaleLevel(float gamma) {
282 this(gamma, VibrationEffect.MAX_AMPLITUDE);
283 }
284
285 public ScaleLevel(float gamma, int maxAmplitude) {
286 this.gamma = gamma;
287 this.maxAmplitude = maxAmplitude;
288 }
289
290 @Override
291 public String toString() {
292 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
293 }
294 }
295
Mike Lockwood3a322132009-11-24 00:30:52 -0500296 VibratorService(Context context) {
Vincent Beckere6904fb2012-08-10 14:17:33 +0200297 vibratorInit();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 // Reset the hardware to a default state, in case this is a runtime
299 // restart instead of a fresh boot.
300 vibratorOff();
301
Michael Wright71216972017-01-31 18:33:54 +0000302 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 mContext = context;
Michael Wright71216972017-01-31 18:33:54 +0000305 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700306 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 mWakeLock.setReferenceCounted(true);
308
Svet Ganovf7b47252018-02-26 11:11:27 -0800309 mAppOps = mContext.getSystemService(AppOpsManager.class);
Dianne Hackborn91268cf2013-06-13 19:06:50 -0700310 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService(
311 BatteryStats.SERVICE_NAME));
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800312
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700313 mPreviousVibrationsLimit = mContext.getResources().getInteger(
314 com.android.internal.R.integer.config_previousVibrationsDumpLimit);
315
Michael Wright71216972017-01-31 18:33:54 +0000316 mDefaultVibrationAmplitude = mContext.getResources().getInteger(
317 com.android.internal.R.integer.config_defaultVibrationAmplitude);
318
Tyler Freeman319a34a2017-05-04 17:23:35 -0700319 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
320 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
321
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700322 mPreviousVibrations = new LinkedList<>();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 IntentFilter filter = new IntentFilter();
325 filter.addAction(Intent.ACTION_SCREEN_OFF);
326 context.registerReceiver(mIntentReceiver, filter);
Michael Wright71216972017-01-31 18:33:54 +0000327
Michael Wrightd39cbec2018-04-16 19:35:13 +0100328 VibrationEffect clickEffect = createEffectFromResource(
Michael Wright71216972017-01-31 18:33:54 +0000329 com.android.internal.R.array.config_virtualKeyVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000330 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform(
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000331 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100332 VibrationEffect heavyClickEffect = createEffectFromResource(
333 com.android.internal.R.array.config_longPressVibePattern);
334 VibrationEffect tickEffect = createEffectFromResource(
Michael Wright57d94d92017-05-31 14:44:45 +0100335 com.android.internal.R.array.config_clockTickVibePattern);
Michael Wright71216972017-01-31 18:33:54 +0000336
Michael Wright0dbb5162018-05-25 15:13:36 +0100337 mFallbackEffects = new SparseArray<>();
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +0000338 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
339 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
340 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
Michael Wrightd39cbec2018-04-16 19:35:13 +0100341 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
Michael Wright0dbb5162018-05-25 15:13:36 +0100342
343 mScaleLevels = new SparseArray<>();
344 mScaleLevels.put(SCALE_VERY_LOW,
345 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
346 mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
347 mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
348 mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
349 mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
Michael Wright57d94d92017-05-31 14:44:45 +0100350 }
351
Michael Wrightd39cbec2018-04-16 19:35:13 +0100352 private VibrationEffect createEffectFromResource(int resId) {
353 long[] timings = getLongIntArray(mContext.getResources(), resId);
354 return createEffectFromTimings(timings);
355 }
356
357 private static VibrationEffect createEffectFromTimings(long[] timings) {
Michael Wright57d94d92017-05-31 14:44:45 +0100358 if (timings == null || timings.length == 0) {
359 return null;
360 } else if (timings.length == 1) {
361 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE);
362 } else {
363 return VibrationEffect.createWaveform(timings, -1);
364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 }
366
Jeff Brown7f6c2312012-04-13 20:38:38 -0700367 public void systemReady() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000368 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady");
369 try {
370 mIm = mContext.getSystemService(InputManager.class);
371 mVibrator = mContext.getSystemService(Vibrator.class);
372 mSettingObserver = new SettingsObserver(mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700373
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000374 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
375 mPowerManagerInternal.registerLowPowerModeObserver(
376 new PowerManagerInternal.LowPowerModeListener() {
377 @Override
378 public int getServiceType() {
379 return ServiceType.VIBRATION;
380 }
jackqdyulei455e90a2017-02-09 15:29:16 -0800381
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000382 @Override
383 public void onLowPowerModeChanged(PowerSaveState result) {
384 updateVibrators();
385 }
386 });
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700387
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000388 mContext.getContentResolver().registerContentObserver(
389 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES),
390 true, mSettingObserver, UserHandle.USER_ALL);
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700391
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000392 mContext.getContentResolver().registerContentObserver(
393 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY),
394 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000395
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000396 mContext.getContentResolver().registerContentObserver(
397 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY),
398 true, mSettingObserver, UserHandle.USER_ALL);
Michael Wright35a0c672018-01-24 00:32:53 +0000399
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000400 mContext.registerReceiver(new BroadcastReceiver() {
401 @Override
402 public void onReceive(Context context, Intent intent) {
403 updateVibrators();
404 }
405 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
Jeff Brownd4935962012-09-25 13:27:20 -0700406
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000407 updateVibrators();
408 } finally {
409 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
410 }
Dianne Hackbornea9020e2010-11-04 11:39:12 -0700411 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700412
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700413 private final class SettingsObserver extends ContentObserver {
414 public SettingsObserver(Handler handler) {
415 super(handler);
416 }
417
418 @Override
419 public void onChange(boolean SelfChange) {
Michael Wright71216972017-01-31 18:33:54 +0000420 updateVibrators();
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700421 }
422 }
423
Jeff Brown82379ba2014-07-25 19:03:28 -0700424 @Override // Binder call
Jeff Brown7f6c2312012-04-13 20:38:38 -0700425 public boolean hasVibrator() {
426 return doVibratorExists();
427 }
428
Michael Wright71216972017-01-31 18:33:54 +0000429 @Override // Binder call
430 public boolean hasAmplitudeControl() {
431 synchronized (mInputDeviceVibrators) {
432 // Input device vibrators don't support amplitude controls yet, but are still used over
433 // the system vibrator when connected.
434 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty();
435 }
436 }
437
Dianne Hackbornf265ea92013-01-31 15:00:51 -0800438 private void verifyIncomingUid(int uid) {
439 if (uid == Binder.getCallingUid()) {
440 return;
441 }
442 if (Binder.getCallingPid() == Process.myPid()) {
443 return;
444 }
445 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
446 Binder.getCallingPid(), Binder.getCallingUid(), null);
447 }
448
Michael Wright71216972017-01-31 18:33:54 +0000449 /**
450 * Validate the incoming VibrationEffect.
451 *
452 * We can't throw exceptions here since we might be called from some system_server component,
453 * which would bring the whole system down.
454 *
455 * @return whether the VibrationEffect is valid
456 */
457 private static boolean verifyVibrationEffect(VibrationEffect effect) {
458 if (effect == null) {
459 // Effect must not be null.
460 Slog.wtf(TAG, "effect must not be null");
461 return false;
462 }
463 try {
464 effect.validate();
465 } catch (Exception e) {
466 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e);
467 return false;
468 }
469 return true;
470 }
471
472 private static long[] getLongIntArray(Resources r, int resid) {
473 int[] ar = r.getIntArray(resid);
474 if (ar == null) {
475 return null;
476 }
477 long[] out = new long[ar.length];
478 for (int i = 0; i < ar.length; i++) {
479 out[i] = ar[i];
480 }
481 return out;
482 }
483
Jeff Brown82379ba2014-07-25 19:03:28 -0700484 @Override // Binder call
Michael Wright71216972017-01-31 18:33:54 +0000485 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
John Spurlock1af30c72014-03-10 08:33:35 -0400486 IBinder token) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000487 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate");
488 try {
489 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)
490 != PackageManager.PERMISSION_GRANTED) {
491 throw new SecurityException("Requires VIBRATE permission");
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000492 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000493 if (token == null) {
494 Slog.e(TAG, "token must not be null");
495 return;
496 }
497 verifyIncomingUid(uid);
498 if (!verifyVibrationEffect(effect)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 return;
500 }
501
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000502 // If our current vibration is longer than the new vibration and is the same amplitude,
503 // then just let the current one finish.
504 synchronized (mLock) {
505 if (effect instanceof VibrationEffect.OneShot
506 && mCurrentVibration != null
507 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) {
508 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
509 VibrationEffect.OneShot currentOneShot =
510 (VibrationEffect.OneShot) mCurrentVibration.effect;
511 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())
512 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
513 if (DEBUG) {
514 Slog.d(TAG,
515 "Ignoring incoming vibration in favor of current vibration");
516 }
517 return;
518 }
519 }
520
521 // If the current vibration is repeating and the incoming one is non-repeating,
522 // then ignore the non-repeating vibration. This is so that we don't cancel
523 // vibrations that are meant to grab the attention of the user, like ringtones and
524 // alarms, in favor of one-shot vibrations that are likely quite short.
525 if (!isRepeatingVibration(effect)
526 && mCurrentVibration != null
527 && isRepeatingVibration(mCurrentVibration.effect)) {
528 if (DEBUG) {
529 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");
530 }
531 return;
532 }
533
534 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
535 linkVibration(vib);
536 long ident = Binder.clearCallingIdentity();
537 try {
538 doCancelVibrateLocked();
539 startVibrationLocked(vib);
540 addToPreviousVibrationsLocked(vib);
541 } finally {
542 Binder.restoreCallingIdentity(ident);
543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000545 } finally {
546 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 }
548 }
549
Michael Wright58c46312017-10-05 14:04:14 -0400550 private static boolean isRepeatingVibration(VibrationEffect effect) {
Michael Wright35a0c672018-01-24 00:32:53 +0000551 return effect.getDuration() == Long.MAX_VALUE;
Michael Wright58c46312017-10-05 14:04:14 -0400552 }
553
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700554 private void addToPreviousVibrationsLocked(Vibration vib) {
555 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
556 mPreviousVibrations.removeFirst();
557 }
Michael Wright36d873f2018-01-08 15:54:05 +0000558 mPreviousVibrations.addLast(vib.toInfo());
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -0700559 }
560
Jeff Brown82379ba2014-07-25 19:03:28 -0700561 @Override // Binder call
Patrick Scott18dd5f02009-07-02 11:31:12 -0400562 public void cancelVibrate(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 mContext.enforceCallingOrSelfPermission(
564 android.Manifest.permission.VIBRATE,
565 "cancelVibrate");
566
Michael Wright71216972017-01-31 18:33:54 +0000567 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +0000568 if (mCurrentVibration != null && mCurrentVibration.token == token) {
Michael Wright71216972017-01-31 18:33:54 +0000569 if (DEBUG) {
570 Slog.d(TAG, "Canceling vibration.");
571 }
572 long ident = Binder.clearCallingIdentity();
573 try {
Patrick Scott18dd5f02009-07-02 11:31:12 -0400574 doCancelVibrateLocked();
Michael Wright71216972017-01-31 18:33:54 +0000575 } finally {
576 Binder.restoreCallingIdentity(ident);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400577 }
578 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
Eric Olsenf42f15c2009-10-29 16:42:03 -0700581
Michael Wright71216972017-01-31 18:33:54 +0000582 private final Runnable mVibrationEndRunnable = new Runnable() {
Jeff Brown82379ba2014-07-25 19:03:28 -0700583 @Override
Patrick Scott18dd5f02009-07-02 11:31:12 -0400584 public void run() {
Michael Wright71216972017-01-31 18:33:54 +0000585 onVibrationFinished();
Patrick Scott18dd5f02009-07-02 11:31:12 -0400586 }
587 };
588
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000589 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400590 private void doCancelVibrateLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000591 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
592 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked");
593 try {
594 mH.removeCallbacks(mVibrationEndRunnable);
595 if (mThread != null) {
596 mThread.cancel();
597 mThread = null;
598 }
599 doVibratorOff();
600 reportFinishVibrationLocked();
601 } finally {
602 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Patrick Scott18dd5f02009-07-02 11:31:12 -0400603 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400604 }
605
Michael Wright71216972017-01-31 18:33:54 +0000606 // Callback for whenever the current vibration has finished played out
607 public void onVibrationFinished() {
608 if (DEBUG) {
609 Slog.e(TAG, "Vibration finished, cleaning up");
Patrick Scott18dd5f02009-07-02 11:31:12 -0400610 }
Michael Wright71216972017-01-31 18:33:54 +0000611 synchronized (mLock) {
612 // Make sure the vibration is really done. This also reports that the vibration is
613 // finished.
614 doCancelVibrateLocked();
615 }
Patrick Scott18dd5f02009-07-02 11:31:12 -0400616 }
617
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000618 @GuardedBy("mLock")
Patrick Scott18dd5f02009-07-02 11:31:12 -0400619 private void startVibrationLocked(final Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000620 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
621 try {
622 if (!isAllowedToVibrateLocked(vib)) {
623 return;
Michael Wright71216972017-01-31 18:33:54 +0000624 }
Michael Wright71216972017-01-31 18:33:54 +0000625
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000626 final int intensity = getCurrentIntensityLocked(vib);
627 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
628 return;
Michael Wright71216972017-01-31 18:33:54 +0000629 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000630
631 if (vib.isRingtone() && !shouldVibrateForRingtone()) {
632 if (DEBUG) {
633 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones");
634 }
635 return;
636 }
637
638 final int mode = getAppOpMode(vib);
639 if (mode != AppOpsManager.MODE_ALLOWED) {
640 if (mode == AppOpsManager.MODE_ERRORED) {
641 // We might be getting calls from within system_server, so we don't actually
642 // want to throw a SecurityException here.
643 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid);
644 }
645 return;
646 }
647 applyVibrationIntensityScalingLocked(vib, intensity);
648 startVibrationInnerLocked(vib);
649 } finally {
650 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +0000651 }
Michael Wright71216972017-01-31 18:33:54 +0000652 }
653
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000654 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000655 private void startVibrationInnerLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000656 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked");
657 try {
658 mCurrentVibration = vib;
659 if (vib.effect instanceof VibrationEffect.OneShot) {
660 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
661 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
662 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint);
663 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration());
664 } else if (vib.effect instanceof VibrationEffect.Waveform) {
665 // mThread better be null here. doCancelVibrate should always be
666 // called before startNextVibrationLocked or startVibrationLocked.
667 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
668 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
669 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint);
670 mThread.start();
671 } else if (vib.effect instanceof VibrationEffect.Prebaked) {
672 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0);
673 long timeout = doVibratorPrebakedEffectLocked(vib);
674 if (timeout > 0) {
675 mH.postDelayed(mVibrationEndRunnable, timeout);
676 }
677 } else {
678 Slog.e(TAG, "Unknown vibration type, ignoring");
Michael Wright71216972017-01-31 18:33:54 +0000679 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000680 } finally {
681 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683 }
684
Michael Wright35a0c672018-01-24 00:32:53 +0000685 private boolean isAllowedToVibrateLocked(Vibration vib) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700686 if (!mLowPowerMode) {
687 return true;
688 }
Michael Wright35a0c672018-01-24 00:32:53 +0000689
690 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700691 return true;
692 }
Tyler Freeman319a34a2017-05-04 17:23:35 -0700693
Michael Wright35a0c672018-01-24 00:32:53 +0000694 if (vib.usageHint == AudioAttributes.USAGE_ALARM ||
695 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY ||
696 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) {
Tyler Freeman319a34a2017-05-04 17:23:35 -0700697 return true;
698 }
699
700 return false;
701 }
702
Michael Wright35a0c672018-01-24 00:32:53 +0000703 private int getCurrentIntensityLocked(Vibration vib) {
704 if (vib.isNotification() || vib.isRingtone()){
705 return mNotificationIntensity;
706 } else if (vib.isHapticFeedback()) {
707 return mHapticFeedbackIntensity;
708 } else {
709 return Vibrator.VIBRATION_INTENSITY_MEDIUM;
710 }
711 }
712
713 /**
714 * Scale the vibration effect by the intensity as appropriate based its intent.
715 */
716 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) {
717 if (vib.effect instanceof VibrationEffect.Prebaked) {
718 // Prebaked effects are always just a direct translation from intensity to
719 // EffectStrength.
720 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect;
721 prebaked.setEffectStrength(intensityToEffectStrength(intensity));
722 return;
723 }
724
Michael Wright0dbb5162018-05-25 15:13:36 +0100725 final int defaultIntensity;
Michael Wright35a0c672018-01-24 00:32:53 +0000726 if (vib.isNotification() || vib.isRingtone()) {
Michael Wright0dbb5162018-05-25 15:13:36 +0100727 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
728 } else if (vib.isHapticFeedback()) {
729 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
Michael Wright35a0c672018-01-24 00:32:53 +0000730 } else {
Michael Wright0dbb5162018-05-25 15:13:36 +0100731 // If we don't know what kind of vibration we're playing then just skip scaling for
732 // now.
733 return;
734 }
735
736 final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
737 if (scale == null) {
738 // We should have scaling levels for all cases, so not being able to scale because of a
739 // missing level is unexpected.
740 Slog.e(TAG, "No configured scaling level!"
741 + " (current=" + intensity + ", default= " + defaultIntensity + ")");
742 return;
Michael Wright35a0c672018-01-24 00:32:53 +0000743 }
744
745 VibrationEffect scaledEffect = null;
746 if (vib.effect instanceof VibrationEffect.OneShot) {
747 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100748 oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100749 scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000750 } else if (vib.effect instanceof VibrationEffect.Waveform) {
751 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
Alexey Kuzmin59efe972018-04-24 12:58:13 +0100752 waveform = waveform.resolve(mDefaultVibrationAmplitude);
Michael Wright0dbb5162018-05-25 15:13:36 +0100753 scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
Michael Wright35a0c672018-01-24 00:32:53 +0000754 } else {
755 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
756 }
757
758 if (scaledEffect != null) {
759 vib.originalEffect = vib.effect;
760 vib.effect = scaledEffect;
761 }
762 }
763
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700764 private boolean shouldVibrateForRingtone() {
Michael Wright35a0c672018-01-24 00:32:53 +0000765 AudioManager audioManager = mContext.getSystemService(AudioManager.class);
Brad Ebingerdcbdc0d2016-06-23 17:42:30 -0700766 int ringerMode = audioManager.getRingerModeInternal();
Brad Ebinger2d1c3b32016-05-12 18:05:17 -0700767 // "Also vibrate for calls" Setting in Sound
768 if (Settings.System.getInt(
769 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) {
770 return ringerMode != AudioManager.RINGER_MODE_SILENT;
771 } else {
772 return ringerMode == AudioManager.RINGER_MODE_VIBRATE;
773 }
774 }
775
Michael Wright71216972017-01-31 18:33:54 +0000776 private int getAppOpMode(Vibration vib) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800777 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE,
778 vib.usageHint, vib.uid, vib.opPkg);
779 if (mode == AppOpsManager.MODE_ALLOWED) {
780 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg);
Michael Wright71216972017-01-31 18:33:54 +0000781 }
782 return mode;
783 }
784
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000785 @GuardedBy("mLock")
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800786 private void reportFinishVibrationLocked() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000787 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
788 try {
789 if (mCurrentVibration != null) {
Svet Ganovf7b47252018-02-26 11:11:27 -0800790 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid,
791 mCurrentVibration.opPkg);
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000792 unlinkVibration(mCurrentVibration);
793 mCurrentVibration = null;
794 }
795 } finally {
796 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Dianne Hackborna06de0f2012-12-11 16:34:47 -0800797 }
798 }
799
Michael Wright36d873f2018-01-08 15:54:05 +0000800 private void linkVibration(Vibration vib) {
801 // Only link against waveforms since they potentially don't have a finish if
802 // they're repeating. Let other effects just play out until they're done.
Michael Wright35a0c672018-01-24 00:32:53 +0000803 if (vib.effect instanceof VibrationEffect.Waveform) {
Michael Wright36d873f2018-01-08 15:54:05 +0000804 try {
Michael Wright35a0c672018-01-24 00:32:53 +0000805 vib.token.linkToDeath(vib, 0);
Michael Wright36d873f2018-01-08 15:54:05 +0000806 } catch (RemoteException e) {
807 return;
808 }
809 }
810 }
811
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200812 private void unlinkVibration(Vibration vib) {
Michael Wright35a0c672018-01-24 00:32:53 +0000813 if (vib.effect instanceof VibrationEffect.Waveform) {
814 vib.token.unlinkToDeath(vib, 0);
Mathias Jeppssonb23949b2010-09-28 14:45:23 +0200815 }
816 }
817
Michael Wright71216972017-01-31 18:33:54 +0000818 private void updateVibrators() {
819 synchronized (mLock) {
820 boolean devicesUpdated = updateInputDeviceVibratorsLocked();
821 boolean lowPowerModeUpdated = updateLowPowerModeLocked();
Michael Wright35a0c672018-01-24 00:32:53 +0000822 updateVibrationIntensityLocked();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700823
Michael Wright71216972017-01-31 18:33:54 +0000824 if (devicesUpdated || lowPowerModeUpdated) {
825 // If the state changes out from under us then just reset.
826 doCancelVibrateLocked();
827 }
828 }
829 }
Jeff Brown82065252012-04-16 13:19:05 -0700830
Michael Wright71216972017-01-31 18:33:54 +0000831 private boolean updateInputDeviceVibratorsLocked() {
832 boolean changed = false;
833 boolean vibrateInputDevices = false;
834 try {
835 vibrateInputDevices = Settings.System.getIntForUser(
836 mContext.getContentResolver(),
837 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0;
838 } catch (SettingNotFoundException snfe) {
839 }
840 if (vibrateInputDevices != mVibrateInputDevicesSetting) {
841 changed = true;
842 mVibrateInputDevicesSetting = vibrateInputDevices;
843 }
Ruchi Kandoi13b03af2014-05-07 20:10:32 -0700844
Michael Wright71216972017-01-31 18:33:54 +0000845 if (mVibrateInputDevicesSetting) {
846 if (!mInputDeviceListenerRegistered) {
847 mInputDeviceListenerRegistered = true;
848 mIm.registerInputDeviceListener(this, mH);
849 }
850 } else {
851 if (mInputDeviceListenerRegistered) {
852 mInputDeviceListenerRegistered = false;
853 mIm.unregisterInputDeviceListener(this);
854 }
855 }
Jeff Brown82065252012-04-16 13:19:05 -0700856
Michael Wright71216972017-01-31 18:33:54 +0000857 mInputDeviceVibrators.clear();
858 if (mVibrateInputDevicesSetting) {
859 int[] ids = mIm.getInputDeviceIds();
860 for (int i = 0; i < ids.length; i++) {
861 InputDevice device = mIm.getInputDevice(ids[i]);
862 Vibrator vibrator = device.getVibrator();
863 if (vibrator.hasVibrator()) {
864 mInputDeviceVibrators.add(vibrator);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700865 }
866 }
Michael Wright71216972017-01-31 18:33:54 +0000867 return true;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700868 }
Michael Wright71216972017-01-31 18:33:54 +0000869 return changed;
870 }
871
872 private boolean updateLowPowerModeLocked() {
873 boolean lowPowerMode = mPowerManagerInternal
874 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled;
875 if (lowPowerMode != mLowPowerMode) {
876 mLowPowerMode = lowPowerMode;
877 return true;
878 }
879 return false;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700880 }
881
Michael Wright35a0c672018-01-24 00:32:53 +0000882 private void updateVibrationIntensityLocked() {
883 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
884 Settings.System.HAPTIC_FEEDBACK_INTENSITY,
885 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT);
886 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(),
887 Settings.System.NOTIFICATION_VIBRATION_INTENSITY,
888 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT);
889 }
890
Jeff Brown7f6c2312012-04-13 20:38:38 -0700891 @Override
892 public void onInputDeviceAdded(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000893 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700894 }
895
896 @Override
897 public void onInputDeviceChanged(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000898 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700899 }
900
901 @Override
902 public void onInputDeviceRemoved(int deviceId) {
Michael Wright71216972017-01-31 18:33:54 +0000903 updateVibrators();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700904 }
905
906 private boolean doVibratorExists() {
Jeff Brown1064a502012-05-02 16:51:37 -0700907 // For now, we choose to ignore the presence of input devices that have vibrators
908 // when reporting whether the device has a vibrator. Applications often use this
909 // information to decide whether to enable certain features so they expect the
910 // result of hasVibrator() to be constant. For now, just report whether
911 // the device has a built-in vibrator.
912 //synchronized (mInputDeviceVibrators) {
913 // return !mInputDeviceVibrators.isEmpty() || vibratorExists();
914 //}
Dianne Hackbornc2293022013-02-06 23:14:49 -0800915 return vibratorExists();
Jeff Brown7f6c2312012-04-13 20:38:38 -0700916 }
917
Michael Wright71216972017-01-31 18:33:54 +0000918 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000919 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
920 try {
921 synchronized (mInputDeviceVibrators) {
922 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
923 amplitude = mDefaultVibrationAmplitude;
Jeff Brown7f6c2312012-04-13 20:38:38 -0700924 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000925 if (DEBUG) {
926 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" +
927 " with amplitude " + amplitude + ".");
928 }
929 noteVibratorOnLocked(uid, millis);
930 final int vibratorCount = mInputDeviceVibrators.size();
931 if (vibratorCount != 0) {
932 final AudioAttributes attributes =
933 new AudioAttributes.Builder().setUsage(usageHint).build();
934 for (int i = 0; i < vibratorCount; i++) {
935 mInputDeviceVibrators.get(i).vibrate(millis, attributes);
936 }
937 } else {
938 // Note: ordering is important here! Many haptic drivers will reset their
939 // amplitude when enabled, so we always have to enable frst, then set the
940 // amplitude.
941 vibratorOn(millis);
942 doVibratorSetAmplitude(amplitude);
943 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700944 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000945 } finally {
946 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700947 }
948 }
949
Michael Wright71216972017-01-31 18:33:54 +0000950 private void doVibratorSetAmplitude(int amplitude) {
951 if (mSupportsAmplitudeControl) {
952 vibratorSetAmplitude(amplitude);
953 }
954 }
955
Jeff Brown7f6c2312012-04-13 20:38:38 -0700956 private void doVibratorOff() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000957 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff");
958 try {
959 synchronized (mInputDeviceVibrators) {
960 if (DEBUG) {
961 Slog.d(TAG, "Turning vibrator off.");
Jeff Brown7f6c2312012-04-13 20:38:38 -0700962 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000963 noteVibratorOffLocked();
964 final int vibratorCount = mInputDeviceVibrators.size();
965 if (vibratorCount != 0) {
966 for (int i = 0; i < vibratorCount; i++) {
967 mInputDeviceVibrators.get(i).cancel();
968 }
969 } else {
970 vibratorOff();
971 }
Jeff Brown7f6c2312012-04-13 20:38:38 -0700972 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000973 } finally {
974 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Jeff Brown7f6c2312012-04-13 20:38:38 -0700975 }
976 }
977
Alexey Kuzmin7f38fb12018-02-07 13:51:28 +0000978 @GuardedBy("mLock")
Michael Wright71216972017-01-31 18:33:54 +0000979 private long doVibratorPrebakedEffectLocked(Vibration vib) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000980 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked");
981 try {
982 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
983 final boolean usingInputDeviceVibrators;
984 synchronized (mInputDeviceVibrators) {
985 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty();
Michael Wright35a0c672018-01-24 00:32:53 +0000986 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +0000987 // Input devices don't support prebaked effect, so skip trying it with them.
988 if (!usingInputDeviceVibrators) {
989 long timeout = vibratorPerformEffect(prebaked.getId(),
990 prebaked.getEffectStrength());
991 if (timeout > 0) {
992 noteVibratorOnLocked(vib.uid, timeout);
993 return timeout;
994 }
995 }
996 if (!prebaked.shouldFallback()) {
997 return 0;
998 }
999 VibrationEffect effect = getFallbackEffect(prebaked.getId());
1000 if (effect == null) {
1001 Slog.w(TAG, "Failed to play prebaked effect, no fallback");
1002 return 0;
1003 }
1004 Vibration fallbackVib =
1005 new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
1006 final int intensity = getCurrentIntensityLocked(fallbackVib);
1007 linkVibration(fallbackVib);
1008 applyVibrationIntensityScalingLocked(fallbackVib, intensity);
1009 startVibrationInnerLocked(fallbackVib);
Michael Wright35a0c672018-01-24 00:32:53 +00001010 return 0;
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001011 } finally {
1012 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright35a0c672018-01-24 00:32:53 +00001013 }
Michael Wright71216972017-01-31 18:33:54 +00001014 }
Eric Olsenf42f15c2009-10-29 16:42:03 -07001015
Michael Wright36d873f2018-01-08 15:54:05 +00001016 private VibrationEffect getFallbackEffect(int effectId) {
Alexey Kuzmin5a0a26f2018-03-20 18:25:51 +00001017 return mFallbackEffects.get(effectId);
Michael Wright36d873f2018-01-08 15:54:05 +00001018 }
1019
Michael Wright35a0c672018-01-24 00:32:53 +00001020 /**
1021 * Return the current desired effect strength.
1022 *
1023 * If the returned value is &lt; 0 then the vibration shouldn't be played at all.
1024 */
1025 private static int intensityToEffectStrength(int intensity) {
1026 switch (intensity) {
1027 case Vibrator.VIBRATION_INTENSITY_LOW:
1028 return EffectStrength.LIGHT;
1029 case Vibrator.VIBRATION_INTENSITY_MEDIUM:
1030 return EffectStrength.MEDIUM;
1031 case Vibrator.VIBRATION_INTENSITY_HIGH:
1032 return EffectStrength.STRONG;
1033 default:
1034 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity);
1035 return EffectStrength.STRONG;
1036 }
1037 }
1038
Michael Wright71216972017-01-31 18:33:54 +00001039 private void noteVibratorOnLocked(int uid, long millis) {
1040 try {
1041 mBatteryStatsService.noteVibratorOn(uid, millis);
1042 mCurVibUid = uid;
1043 } catch (RemoteException e) {
1044 }
1045 }
1046
1047 private void noteVibratorOffLocked() {
1048 if (mCurVibUid >= 0) {
1049 try {
1050 mBatteryStatsService.noteVibratorOff(mCurVibUid);
1051 } catch (RemoteException e) { }
1052 mCurVibUid = -1;
1053 }
1054 }
1055
1056 private class VibrateThread extends Thread {
1057 private final VibrationEffect.Waveform mWaveform;
1058 private final int mUid;
1059 private final int mUsageHint;
1060
1061 private boolean mForceStop;
1062
1063 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
1064 mWaveform = waveform;
1065 mUid = uid;
1066 mUsageHint = usageHint;
1067 mTmpWorkSource.set(uid);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001068 mWakeLock.setWorkSource(mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
1070
Michael Wright71216972017-01-31 18:33:54 +00001071 private long delayLocked(long duration) {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001072 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked");
1073 try {
1074 long durationRemaining = duration;
1075 if (duration > 0) {
1076 final long bedtime = duration + SystemClock.uptimeMillis();
1077 do {
1078 try {
1079 this.wait(durationRemaining);
1080 }
1081 catch (InterruptedException e) { }
1082 if (mForceStop) {
1083 break;
1084 }
1085 durationRemaining = bedtime - SystemClock.uptimeMillis();
1086 } while (durationRemaining > 0);
1087 return duration - durationRemaining;
1088 }
1089 return 0;
1090 } finally {
1091 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
1094
1095 public void run() {
1096 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
Michael Wright71216972017-01-31 18:33:54 +00001097 mWakeLock.acquire();
1098 try {
1099 boolean finished = playWaveform();
1100 if (finished) {
1101 onVibrationFinished();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001102 }
Michael Wright71216972017-01-31 18:33:54 +00001103 } finally {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 mWakeLock.release();
1105 }
Michael Wright71216972017-01-31 18:33:54 +00001106 }
1107
1108 /**
1109 * Play the waveform.
1110 *
1111 * @return true if it finished naturally, false otherwise (e.g. it was canceled).
1112 */
1113 public boolean playWaveform() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001114 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform");
1115 try {
1116 synchronized (this) {
1117 final long[] timings = mWaveform.getTimings();
1118 final int[] amplitudes = mWaveform.getAmplitudes();
1119 final int len = timings.length;
1120 final int repeat = mWaveform.getRepeatIndex();
Michael Wright71216972017-01-31 18:33:54 +00001121
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001122 int index = 0;
1123 long onDuration = 0;
1124 while (!mForceStop) {
1125 if (index < len) {
1126 final int amplitude = amplitudes[index];
1127 final long duration = timings[index++];
1128 if (duration <= 0) {
1129 continue;
Michael Wright71216972017-01-31 18:33:54 +00001130 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001131 if (amplitude != 0) {
1132 if (onDuration <= 0) {
1133 // Telling the vibrator to start multiple times usually causes
1134 // effects to feel "choppy" because the motor resets at every on
1135 // command. Instead we figure out how long our next "on" period
1136 // is going to be, tell the motor to stay on for the full
1137 // duration, and then wake up to change the amplitude at the
1138 // appropriate intervals.
1139 onDuration = getTotalOnDuration(timings, amplitudes, index - 1,
1140 repeat);
1141 doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
1142 } else {
1143 doVibratorSetAmplitude(amplitude);
1144 }
1145 }
Michael Wright71216972017-01-31 18:33:54 +00001146
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001147 long waitTime = delayLocked(duration);
1148 if (amplitude != 0) {
1149 onDuration -= waitTime;
1150 }
1151 } else if (repeat < 0) {
1152 break;
1153 } else {
1154 index = repeat;
Michael Wright71216972017-01-31 18:33:54 +00001155 }
Michael Wright71216972017-01-31 18:33:54 +00001156 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001157 return !mForceStop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001159 } finally {
1160 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
Michael Wright71216972017-01-31 18:33:54 +00001161 }
1162 }
1163
1164 public void cancel() {
1165 synchronized (this) {
1166 mThread.mForceStop = true;
1167 mThread.notify();
1168 }
1169 }
1170
1171 /**
1172 * Get the duration the vibrator will be on starting at startIndex until the next time it's
1173 * off.
1174 */
1175 private long getTotalOnDuration(
1176 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
1177 int i = startIndex;
1178 long timing = 0;
1179 while(amplitudes[i] != 0) {
1180 timing += timings[i++];
1181 if (i >= timings.length) {
1182 if (repeatIndex >= 0) {
1183 i = repeatIndex;
1184 } else {
1185 break;
1186 }
1187 }
1188 if (i == startIndex) {
1189 return 1000;
Patrick Scott18dd5f02009-07-02 11:31:12 -04001190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001191 }
Michael Wright71216972017-01-31 18:33:54 +00001192 return timing;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001193 }
Jeff Brown969579b2014-05-20 19:29:29 -07001194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
Jeff Brown969579b2014-05-20 19:29:29 -07001197 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 public void onReceive(Context context, Intent intent) {
1199 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Michael Wright71216972017-01-31 18:33:54 +00001200 synchronized (mLock) {
Jeff Brown969579b2014-05-20 19:29:29 -07001201 // When the system is entering a non-interactive state, we want
1202 // to cancel vibrations in case a misbehaving app has abandoned
1203 // them. However it may happen that the system is currently playing
1204 // haptic feedback as part of the transition. So we don't cancel
1205 // system vibrations.
1206 if (mCurrentVibration != null
Michael Wright35a0c672018-01-24 00:32:53 +00001207 && !(mCurrentVibration.isHapticFeedback()
1208 && mCurrentVibration.isFromSystem())) {
Jeff Brown969579b2014-05-20 19:29:29 -07001209 doCancelVibrateLocked();
Vairavan Srinivasan8a61f492011-05-13 10:47:20 -07001210 }
Patrick Scott18dd5f02009-07-02 11:31:12 -04001211 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001212 }
1213 }
1214 };
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001215
1216 @Override
1217 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001218 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001219
Michael Wright35a0c672018-01-24 00:32:53 +00001220 pw.println("Vibrator Service:");
Michael Wright71216972017-01-31 18:33:54 +00001221 synchronized (mLock) {
Michael Wright35a0c672018-01-24 00:32:53 +00001222 pw.print(" mCurrentVibration=");
1223 if (mCurrentVibration != null) {
1224 pw.println(mCurrentVibration.toInfo().toString());
1225 } else {
1226 pw.println("null");
1227 }
1228 pw.println(" mLowPowerMode=" + mLowPowerMode);
1229 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity);
1230 pw.println(" mNotificationIntensity=" + mNotificationIntensity);
1231 pw.println("");
1232 pw.println(" Previous vibrations:");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001233 for (VibrationInfo info : mPreviousVibrations) {
Michael Wright35a0c672018-01-24 00:32:53 +00001234 pw.print(" ");
Filip Gruszczynski3a8eb0f2015-06-25 18:35:00 -07001235 pw.println(info.toString());
1236 }
1237 }
1238 }
Felipe Lemea5281002017-02-10 15:13:48 -08001239
1240 @Override
1241 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1242 String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1243 throws RemoteException {
1244 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
1245 }
1246
1247 private final class VibratorShellCommand extends ShellCommand {
1248
1249 private static final long MAX_VIBRATION_MS = 200;
1250
1251 private final IBinder mToken;
1252
1253 private VibratorShellCommand(IBinder token) {
1254 mToken = token;
1255 }
1256
1257 @Override
1258 public int onCommand(String cmd) {
1259 if ("vibrate".equals(cmd)) {
1260 return runVibrate();
1261 }
1262 return handleDefaultCommands(cmd);
1263 }
1264
1265 private int runVibrate() {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001266 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001267 try {
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001268 try {
1269 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(),
1270 Settings.Global.ZEN_MODE);
1271 if (zenMode != Settings.Global.ZEN_MODE_OFF) {
1272 try (PrintWriter pw = getOutPrintWriter();) {
1273 pw.print("Ignoring because device is on DND mode ");
1274 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_",
1275 zenMode));
1276 return 0;
1277 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001278 }
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001279 } catch (SettingNotFoundException e) {
1280 // ignore
Felipe Leme5e2e6322017-07-14 17:25:59 -07001281 }
Felipe Leme5e2e6322017-07-14 17:25:59 -07001282
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001283 final long duration = Long.parseLong(getNextArgRequired());
1284 if (duration > MAX_VIBRATION_MS) {
1285 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS);
1286 }
1287 String description = getNextArg();
1288 if (description == null) {
1289 description = "Shell command";
1290 }
Michael Wright71216972017-01-31 18:33:54 +00001291
Alexey Kuzmine59145a2018-02-10 15:19:03 +00001292 VibrationEffect effect =
1293 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE);
1294 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN,
1295 mToken);
1296 return 0;
1297 } finally {
1298 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
1299 }
Felipe Lemea5281002017-02-10 15:13:48 -08001300 }
1301
1302 @Override
1303 public void onHelp() {
1304 try (PrintWriter pw = getOutPrintWriter();) {
1305 pw.println("Vibrator commands:");
1306 pw.println(" help");
1307 pw.println(" Prints this help text.");
1308 pw.println("");
1309 pw.println(" vibrate duration [description]");
Felipe Leme5e2e6322017-07-14 17:25:59 -07001310 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND ");
1311 pw.println(" (Do Not Disturb) mode.");
Felipe Lemea5281002017-02-10 15:13:48 -08001312 pw.println("");
1313 }
1314 }
1315 }
1316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317}