1 /* 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 17 package com.android.server; 18 19 import android.annotation.Nullable; 20 import android.app.ActivityManager; 21 import android.app.AppOpsManager; 22 import android.app.IUidObserver; 23 import android.content.BroadcastReceiver; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager; 28 import android.content.res.Resources; 29 import android.database.ContentObserver; 30 import android.hardware.input.InputManager; 31 import android.hardware.vibrator.IVibrator; 32 import android.hardware.vibrator.V1_0.EffectStrength; 33 import android.icu.text.DateFormat; 34 import android.media.AudioAttributes; 35 import android.media.AudioManager; 36 import android.os.BatteryStats; 37 import android.os.Binder; 38 import android.os.ExternalVibration; 39 import android.os.Handler; 40 import android.os.IBinder; 41 import android.os.IExternalVibratorService; 42 import android.os.IVibratorService; 43 import android.os.PowerManager; 44 import android.os.PowerManager.ServiceType; 45 import android.os.PowerManagerInternal; 46 import android.os.PowerSaveState; 47 import android.os.Process; 48 import android.os.RemoteException; 49 import android.os.ResultReceiver; 50 import android.os.ServiceManager; 51 import android.os.ShellCallback; 52 import android.os.ShellCommand; 53 import android.os.SystemClock; 54 import android.os.Trace; 55 import android.os.UserHandle; 56 import android.os.VibrationEffect; 57 import android.os.Vibrator; 58 import android.os.WorkSource; 59 import android.provider.DeviceConfig; 60 import android.provider.Settings; 61 import android.provider.Settings.SettingNotFoundException; 62 import android.util.DebugUtils; 63 import android.util.Slog; 64 import android.util.SparseArray; 65 import android.util.StatsLog; 66 import android.view.InputDevice; 67 68 import com.android.internal.annotations.GuardedBy; 69 import com.android.internal.app.IBatteryStats; 70 import com.android.internal.util.DumpUtils; 71 72 import java.io.FileDescriptor; 73 import java.io.PrintWriter; 74 import java.util.ArrayList; 75 import java.util.Date; 76 import java.util.LinkedList; 77 78 public class VibratorService extends IVibratorService.Stub 79 implements InputManager.InputDeviceListener { 80 private static final String TAG = "VibratorService"; 81 private static final boolean DEBUG = false; 82 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui"; 83 private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service"; 84 private static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled"; 85 86 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 }; 87 88 // Scale levels. Each level, except MUTE, is defined as the delta between the current setting 89 // and the default intensity for that type of vibration (i.e. current - default). 90 private static final int SCALE_MUTE = IExternalVibratorService.SCALE_MUTE; // -100 91 private static final int SCALE_VERY_LOW = IExternalVibratorService.SCALE_VERY_LOW; // -2 92 private static final int SCALE_LOW = IExternalVibratorService.SCALE_LOW; // -1 93 private static final int SCALE_NONE = IExternalVibratorService.SCALE_NONE; // 0 94 private static final int SCALE_HIGH = IExternalVibratorService.SCALE_HIGH; // 1 95 private static final int SCALE_VERY_HIGH = IExternalVibratorService.SCALE_VERY_HIGH; // 2 96 97 // Gamma adjustments for scale levels. 98 private static final float SCALE_VERY_LOW_GAMMA = 2.0f; 99 private static final float SCALE_LOW_GAMMA = 1.5f; 100 private static final float SCALE_NONE_GAMMA = 1.0f; 101 private static final float SCALE_HIGH_GAMMA = 0.5f; 102 private static final float SCALE_VERY_HIGH_GAMMA = 0.25f; 103 104 // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default 105 // max amplitude. 106 private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255 107 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255 108 109 // If a vibration is playing for longer than 5s, it's probably not haptic feedback. 110 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; 111 112 // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration. 113 private static final long ASYNC_TIMEOUT_MULTIPLIER = 2; 114 115 116 // A mapping from the intensity adjustment to the scaling to apply, where the intensity 117 // adjustment is defined as the delta between the default intensity level and the user selected 118 // intensity level. It's important that we apply the scaling on the delta between the two so 119 // that the default intensity level applies no scaling to application provided effects. 120 private final SparseArray<ScaleLevel> mScaleLevels; 121 private final LinkedList<VibrationInfo> mPreviousRingVibrations; 122 private final LinkedList<VibrationInfo> mPreviousNotificationVibrations; 123 private final LinkedList<VibrationInfo> mPreviousAlarmVibrations; 124 private final LinkedList<ExternalVibration> mPreviousExternalVibrations; 125 private final LinkedList<VibrationInfo> mPreviousVibrations; 126 private final int mPreviousVibrationsLimit; 127 private final boolean mAllowPriorityVibrationsInLowPowerMode; 128 private final boolean mSupportsAmplitudeControl; 129 private final boolean mSupportsExternalControl; 130 private final long mCapabilities; 131 private final int mDefaultVibrationAmplitude; 132 private final SparseArray<VibrationEffect> mFallbackEffects; 133 private final SparseArray<Integer> mProcStatesCache = new SparseArray(); 134 private final WorkSource mTmpWorkSource = new WorkSource(); 135 private final Handler mH = new Handler(); 136 private final Object mLock = new Object(); 137 138 private final Context mContext; 139 private final PowerManager.WakeLock mWakeLock; 140 private final AppOpsManager mAppOps; 141 private final IBatteryStats mBatteryStatsService; 142 private PowerManagerInternal mPowerManagerInternal; 143 private InputManager mIm; 144 private Vibrator mVibrator; 145 private SettingsObserver mSettingObserver; 146 147 private volatile VibrateThread mThread; 148 149 // mInputDeviceVibrators lock should be acquired after mLock, if both are 150 // to be acquired 151 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>(); 152 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators 153 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators 154 155 @GuardedBy("mLock") 156 private Vibration mCurrentVibration; 157 private int mCurVibUid = -1; 158 private ExternalVibration mCurrentExternalVibration; 159 private boolean mVibratorUnderExternalControl; 160 private boolean mLowPowerMode; 161 private int mHapticFeedbackIntensity; 162 private int mNotificationIntensity; 163 private int mRingIntensity; 164 private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); 165 vibratorExists()166 static native boolean vibratorExists(); vibratorInit()167 static native void vibratorInit(); vibratorOn(long milliseconds)168 static native void vibratorOn(long milliseconds); vibratorOff()169 static native void vibratorOff(); vibratorSupportsAmplitudeControl()170 static native boolean vibratorSupportsAmplitudeControl(); vibratorSetAmplitude(int amplitude)171 static native void vibratorSetAmplitude(int amplitude); vibratorPerformEffect(long effect, long strength, Vibration vibration)172 static native long vibratorPerformEffect(long effect, long strength, Vibration vibration); vibratorSupportsExternalControl()173 static native boolean vibratorSupportsExternalControl(); vibratorSetExternalControl(boolean enabled)174 static native void vibratorSetExternalControl(boolean enabled); vibratorGetCapabilities()175 static native long vibratorGetCapabilities(); vibratorAlwaysOnEnable(long id, long effect, long strength)176 static native void vibratorAlwaysOnEnable(long id, long effect, long strength); vibratorAlwaysOnDisable(long id)177 static native void vibratorAlwaysOnDisable(long id); 178 179 private final IUidObserver mUidObserver = new IUidObserver.Stub() { 180 @Override public void onUidStateChanged(int uid, int procState, long procStateSeq) { 181 mProcStatesCache.put(uid, procState); 182 } 183 184 @Override public void onUidGone(int uid, boolean disabled) { 185 mProcStatesCache.delete(uid); 186 } 187 188 @Override public void onUidActive(int uid) { 189 } 190 191 @Override public void onUidIdle(int uid, boolean disabled) { 192 } 193 194 @Override public void onUidCachedChanged(int uid, boolean cached) { 195 } 196 }; 197 198 private class Vibration implements IBinder.DeathRecipient { 199 public final IBinder token; 200 // Start time in CLOCK_BOOTTIME base. 201 public final long startTime; 202 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate 203 // with other system events, any duration calculations should be done use startTime so as 204 // not to be affected by discontinuities created by RTC adjustments. 205 public final long startTimeDebug; 206 public final AudioAttributes attrs; 207 public final int uid; 208 public final String opPkg; 209 public final String reason; 210 211 // The actual effect to be played. 212 public VibrationEffect effect; 213 // The original effect that was requested. This is non-null only when the original effect 214 // differs from the effect that's being played. Typically these two things differ because 215 // the effect was scaled based on the users vibration intensity settings. 216 public VibrationEffect originalEffect; 217 Vibration(IBinder token, VibrationEffect effect, AudioAttributes attrs, int uid, String opPkg, String reason)218 private Vibration(IBinder token, VibrationEffect effect, 219 AudioAttributes attrs, int uid, String opPkg, String reason) { 220 this.token = token; 221 this.effect = effect; 222 this.startTime = SystemClock.elapsedRealtime(); 223 this.startTimeDebug = System.currentTimeMillis(); 224 this.attrs = attrs; 225 this.uid = uid; 226 this.opPkg = opPkg; 227 this.reason = reason; 228 } 229 binderDied()230 public void binderDied() { 231 synchronized (mLock) { 232 if (this == mCurrentVibration) { 233 doCancelVibrateLocked(); 234 } 235 } 236 } 237 onComplete()238 private void onComplete() { 239 synchronized (mLock) { 240 if (this == mCurrentVibration) { 241 doCancelVibrateLocked(); 242 } 243 } 244 } 245 hasTimeoutLongerThan(long millis)246 public boolean hasTimeoutLongerThan(long millis) { 247 final long duration = effect.getDuration(); 248 return duration >= 0 && duration > millis; 249 } 250 isHapticFeedback()251 public boolean isHapticFeedback() { 252 if (VibratorService.this.isHapticFeedback(attrs.getUsage())) { 253 return true; 254 } 255 if (effect instanceof VibrationEffect.Prebaked) { 256 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; 257 switch (prebaked.getId()) { 258 case VibrationEffect.EFFECT_CLICK: 259 case VibrationEffect.EFFECT_DOUBLE_CLICK: 260 case VibrationEffect.EFFECT_HEAVY_CLICK: 261 case VibrationEffect.EFFECT_TEXTURE_TICK: 262 case VibrationEffect.EFFECT_TICK: 263 case VibrationEffect.EFFECT_POP: 264 case VibrationEffect.EFFECT_THUD: 265 return true; 266 default: 267 Slog.w(TAG, "Unknown prebaked vibration effect, " 268 + "assuming it isn't haptic feedback."); 269 return false; 270 } 271 } 272 final long duration = effect.getDuration(); 273 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION; 274 } 275 isNotification()276 public boolean isNotification() { 277 return VibratorService.this.isNotification(attrs.getUsage()); 278 } 279 isRingtone()280 public boolean isRingtone() { 281 return VibratorService.this.isRingtone(attrs.getUsage()); 282 } 283 isAlarm()284 public boolean isAlarm() { 285 return VibratorService.this.isAlarm(attrs.getUsage()); 286 } 287 isFromSystem()288 public boolean isFromSystem() { 289 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg); 290 } 291 toInfo()292 public VibrationInfo toInfo() { 293 return new VibrationInfo( 294 startTimeDebug, effect, originalEffect, attrs, uid, opPkg, reason); 295 } 296 } 297 298 private static class VibrationInfo { 299 private final long mStartTimeDebug; 300 private final VibrationEffect mEffect; 301 private final VibrationEffect mOriginalEffect; 302 private final AudioAttributes mAttrs; 303 private final int mUid; 304 private final String mOpPkg; 305 private final String mReason; 306 VibrationInfo(long startTimeDebug, VibrationEffect effect, VibrationEffect originalEffect, AudioAttributes attrs, int uid, String opPkg, String reason)307 public VibrationInfo(long startTimeDebug, VibrationEffect effect, 308 VibrationEffect originalEffect, AudioAttributes attrs, int uid, 309 String opPkg, String reason) { 310 mStartTimeDebug = startTimeDebug; 311 mEffect = effect; 312 mOriginalEffect = originalEffect; 313 mAttrs = attrs; 314 mUid = uid; 315 mOpPkg = opPkg; 316 mReason = reason; 317 } 318 319 @Override toString()320 public String toString() { 321 return new StringBuilder() 322 .append("startTime: ") 323 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug))) 324 .append(", effect: ") 325 .append(mEffect) 326 .append(", originalEffect: ") 327 .append(mOriginalEffect) 328 .append(", attrs: ") 329 .append(mAttrs) 330 .append(", uid: ") 331 .append(mUid) 332 .append(", opPkg: ") 333 .append(mOpPkg) 334 .append(", reason: ") 335 .append(mReason) 336 .toString(); 337 } 338 } 339 340 private static final class ScaleLevel { 341 public final float gamma; 342 public final int maxAmplitude; 343 ScaleLevel(float gamma)344 public ScaleLevel(float gamma) { 345 this(gamma, VibrationEffect.MAX_AMPLITUDE); 346 } 347 ScaleLevel(float gamma, int maxAmplitude)348 public ScaleLevel(float gamma, int maxAmplitude) { 349 this.gamma = gamma; 350 this.maxAmplitude = maxAmplitude; 351 } 352 353 @Override toString()354 public String toString() { 355 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}"; 356 } 357 } 358 VibratorService(Context context)359 VibratorService(Context context) { 360 vibratorInit(); 361 // Reset the hardware to a default state, in case this is a runtime 362 // restart instead of a fresh boot. 363 vibratorOff(); 364 365 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl(); 366 mSupportsExternalControl = vibratorSupportsExternalControl(); 367 mCapabilities = vibratorGetCapabilities(); 368 369 mContext = context; 370 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 371 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); 372 mWakeLock.setReferenceCounted(true); 373 374 mAppOps = mContext.getSystemService(AppOpsManager.class); 375 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( 376 BatteryStats.SERVICE_NAME)); 377 378 mPreviousVibrationsLimit = mContext.getResources().getInteger( 379 com.android.internal.R.integer.config_previousVibrationsDumpLimit); 380 381 mDefaultVibrationAmplitude = mContext.getResources().getInteger( 382 com.android.internal.R.integer.config_defaultVibrationAmplitude); 383 384 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean( 385 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode); 386 387 mPreviousRingVibrations = new LinkedList<>(); 388 mPreviousNotificationVibrations = new LinkedList<>(); 389 mPreviousAlarmVibrations = new LinkedList<>(); 390 mPreviousVibrations = new LinkedList<>(); 391 mPreviousExternalVibrations = new LinkedList<>(); 392 393 IntentFilter filter = new IntentFilter(); 394 filter.addAction(Intent.ACTION_SCREEN_OFF); 395 context.registerReceiver(mIntentReceiver, filter); 396 397 VibrationEffect clickEffect = createEffectFromResource( 398 com.android.internal.R.array.config_virtualKeyVibePattern); 399 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform( 400 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/); 401 VibrationEffect heavyClickEffect = createEffectFromResource( 402 com.android.internal.R.array.config_longPressVibePattern); 403 VibrationEffect tickEffect = createEffectFromResource( 404 com.android.internal.R.array.config_clockTickVibePattern); 405 406 mFallbackEffects = new SparseArray<>(); 407 mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect); 408 mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect); 409 mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect); 410 mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect); 411 412 mFallbackEffects.put(VibrationEffect.EFFECT_TEXTURE_TICK, 413 VibrationEffect.get(VibrationEffect.EFFECT_TICK, false)); 414 415 mScaleLevels = new SparseArray<>(); 416 mScaleLevels.put(SCALE_VERY_LOW, 417 new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE)); 418 mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE)); 419 mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA)); 420 mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA)); 421 mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA)); 422 423 ServiceManager.addService(EXTERNAL_VIBRATOR_SERVICE, new ExternalVibratorService()); 424 } 425 createEffectFromResource(int resId)426 private VibrationEffect createEffectFromResource(int resId) { 427 long[] timings = getLongIntArray(mContext.getResources(), resId); 428 return createEffectFromTimings(timings); 429 } 430 createEffectFromTimings(long[] timings)431 private static VibrationEffect createEffectFromTimings(long[] timings) { 432 if (timings == null || timings.length == 0) { 433 return null; 434 } else if (timings.length == 1) { 435 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE); 436 } else { 437 return VibrationEffect.createWaveform(timings, -1); 438 } 439 } 440 systemReady()441 public void systemReady() { 442 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady"); 443 try { 444 mIm = mContext.getSystemService(InputManager.class); 445 mVibrator = mContext.getSystemService(Vibrator.class); 446 mSettingObserver = new SettingsObserver(mH); 447 448 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); 449 mPowerManagerInternal.registerLowPowerModeObserver( 450 new PowerManagerInternal.LowPowerModeListener() { 451 @Override 452 public int getServiceType() { 453 return ServiceType.VIBRATION; 454 } 455 456 @Override 457 public void onLowPowerModeChanged(PowerSaveState result) { 458 updateVibrators(); 459 } 460 }); 461 462 mContext.getContentResolver().registerContentObserver( 463 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), 464 true, mSettingObserver, UserHandle.USER_ALL); 465 466 mContext.getContentResolver().registerContentObserver( 467 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY), 468 true, mSettingObserver, UserHandle.USER_ALL); 469 470 mContext.getContentResolver().registerContentObserver( 471 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY), 472 true, mSettingObserver, UserHandle.USER_ALL); 473 474 mContext.getContentResolver().registerContentObserver( 475 Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY), 476 true, mSettingObserver, UserHandle.USER_ALL); 477 478 mContext.getContentResolver().registerContentObserver( 479 Settings.Global.getUriFor(Settings.Global.ZEN_MODE), 480 true, mSettingObserver, UserHandle.USER_ALL); 481 482 mContext.registerReceiver(new BroadcastReceiver() { 483 @Override 484 public void onReceive(Context context, Intent intent) { 485 updateVibrators(); 486 } 487 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH); 488 489 try { 490 ActivityManager.getService().registerUidObserver(mUidObserver, 491 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE, 492 ActivityManager.PROCESS_STATE_UNKNOWN, null); 493 } catch (RemoteException e) { 494 // ignored; both services live in system_server 495 } 496 497 updateVibrators(); 498 } finally { 499 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 500 } 501 } 502 503 private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)504 public SettingsObserver(Handler handler) { 505 super(handler); 506 } 507 508 @Override onChange(boolean SelfChange)509 public void onChange(boolean SelfChange) { 510 updateVibrators(); 511 } 512 } 513 514 @Override // Binder call hasVibrator()515 public boolean hasVibrator() { 516 return doVibratorExists(); 517 } 518 519 @Override // Binder call hasAmplitudeControl()520 public boolean hasAmplitudeControl() { 521 synchronized (mInputDeviceVibrators) { 522 // Input device vibrators don't support amplitude controls yet, but are still used over 523 // the system vibrator when connected. 524 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty(); 525 } 526 } 527 528 @Override // Binder call setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, AudioAttributes attrs)529 public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, 530 AudioAttributes attrs) { 531 if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { 532 throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); 533 } 534 if ((mCapabilities & IVibrator.CAP_ALWAYS_ON_CONTROL) == 0) { 535 Slog.e(TAG, "Always-on effects not supported."); 536 return false; 537 } 538 if (effect == null) { 539 synchronized (mLock) { 540 mAlwaysOnEffects.delete(alwaysOnId); 541 vibratorAlwaysOnDisable(alwaysOnId); 542 } 543 } else { 544 if (!verifyVibrationEffect(effect)) { 545 return false; 546 } 547 if (!(effect instanceof VibrationEffect.Prebaked)) { 548 Slog.e(TAG, "Only prebaked effects supported for always-on."); 549 return false; 550 } 551 attrs = fixupVibrationAttributes(attrs); 552 synchronized (mLock) { 553 Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); 554 mAlwaysOnEffects.put(alwaysOnId, vib); 555 updateAlwaysOnLocked(alwaysOnId, vib); 556 } 557 } 558 return true; 559 } 560 verifyIncomingUid(int uid)561 private void verifyIncomingUid(int uid) { 562 if (uid == Binder.getCallingUid()) { 563 return; 564 } 565 if (Binder.getCallingPid() == Process.myPid()) { 566 return; 567 } 568 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 569 Binder.getCallingPid(), Binder.getCallingUid(), null); 570 } 571 572 /** 573 * Validate the incoming VibrationEffect. 574 * 575 * We can't throw exceptions here since we might be called from some system_server component, 576 * which would bring the whole system down. 577 * 578 * @return whether the VibrationEffect is valid 579 */ verifyVibrationEffect(VibrationEffect effect)580 private static boolean verifyVibrationEffect(VibrationEffect effect) { 581 if (effect == null) { 582 // Effect must not be null. 583 Slog.wtf(TAG, "effect must not be null"); 584 return false; 585 } 586 try { 587 effect.validate(); 588 } catch (Exception e) { 589 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e); 590 return false; 591 } 592 return true; 593 } 594 fixupVibrationAttributes(AudioAttributes attrs)595 private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) { 596 if (attrs == null) { 597 attrs = new AudioAttributes.Builder() 598 .setUsage(AudioAttributes.USAGE_UNKNOWN) 599 .build(); 600 } 601 if (shouldBypassDnd(attrs)) { 602 if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 603 || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) 604 || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { 605 final int flags = attrs.getAllFlags() 606 & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; 607 attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); 608 } 609 } 610 611 return attrs; 612 } 613 getLongIntArray(Resources r, int resid)614 private static long[] getLongIntArray(Resources r, int resid) { 615 int[] ar = r.getIntArray(resid); 616 if (ar == null) { 617 return null; 618 } 619 long[] out = new long[ar.length]; 620 for (int i = 0; i < ar.length; i++) { 621 out[i] = ar[i]; 622 } 623 return out; 624 } 625 626 @Override // Binder call vibrate(int uid, String opPkg, VibrationEffect effect, @Nullable AudioAttributes attrs, String reason, IBinder token)627 public void vibrate(int uid, String opPkg, VibrationEffect effect, 628 @Nullable AudioAttributes attrs, String reason, IBinder token) { 629 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason); 630 try { 631 if (!hasPermission(android.Manifest.permission.VIBRATE)) { 632 throw new SecurityException("Requires VIBRATE permission"); 633 } 634 if (token == null) { 635 Slog.e(TAG, "token must not be null"); 636 return; 637 } 638 verifyIncomingUid(uid); 639 if (!verifyVibrationEffect(effect)) { 640 return; 641 } 642 643 attrs = fixupVibrationAttributes(attrs); 644 645 // If our current vibration is longer than the new vibration and is the same amplitude, 646 // then just let the current one finish. 647 synchronized (mLock) { 648 if (effect instanceof VibrationEffect.OneShot 649 && mCurrentVibration != null 650 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) { 651 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect; 652 VibrationEffect.OneShot currentOneShot = 653 (VibrationEffect.OneShot) mCurrentVibration.effect; 654 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration()) 655 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) { 656 if (DEBUG) { 657 Slog.d(TAG, 658 "Ignoring incoming vibration in favor of current vibration"); 659 } 660 return; 661 } 662 } 663 664 665 // If something has external control of the vibrator, assume that it's more 666 // important for now. 667 if (mCurrentExternalVibration != null) { 668 if (DEBUG) { 669 Slog.d(TAG, "Ignoring incoming vibration for current external vibration"); 670 } 671 return; 672 } 673 674 // If the current vibration is repeating and the incoming one is non-repeating, 675 // then ignore the non-repeating vibration. This is so that we don't cancel 676 // vibrations that are meant to grab the attention of the user, like ringtones and 677 // alarms, in favor of one-shot vibrations that are likely quite short. 678 if (!isRepeatingVibration(effect) 679 && mCurrentVibration != null 680 && isRepeatingVibration(mCurrentVibration.effect)) { 681 if (DEBUG) { 682 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); 683 } 684 return; 685 } 686 687 Vibration vib = new Vibration(token, effect, attrs, uid, opPkg, reason); 688 if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) 689 > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND 690 && !vib.isNotification() && !vib.isRingtone() && !vib.isAlarm()) { 691 Slog.e(TAG, "Ignoring incoming vibration as process with" 692 + " uid= " + uid + " is background," 693 + " attrs= " + vib.attrs); 694 return; 695 } 696 linkVibration(vib); 697 long ident = Binder.clearCallingIdentity(); 698 try { 699 doCancelVibrateLocked(); 700 startVibrationLocked(vib); 701 addToPreviousVibrationsLocked(vib); 702 } finally { 703 Binder.restoreCallingIdentity(ident); 704 } 705 } 706 } finally { 707 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 708 } 709 } 710 hasPermission(String permission)711 private boolean hasPermission(String permission) { 712 return mContext.checkCallingOrSelfPermission(permission) 713 == PackageManager.PERMISSION_GRANTED; 714 } 715 isRepeatingVibration(VibrationEffect effect)716 private static boolean isRepeatingVibration(VibrationEffect effect) { 717 return effect.getDuration() == Long.MAX_VALUE; 718 } 719 addToPreviousVibrationsLocked(Vibration vib)720 private void addToPreviousVibrationsLocked(Vibration vib) { 721 final LinkedList<VibrationInfo> previousVibrations; 722 if (vib.isRingtone()) { 723 previousVibrations = mPreviousRingVibrations; 724 } else if (vib.isNotification()) { 725 previousVibrations = mPreviousNotificationVibrations; 726 } else if (vib.isAlarm()) { 727 previousVibrations = mPreviousAlarmVibrations; 728 } else { 729 previousVibrations = mPreviousVibrations; 730 } 731 732 if (previousVibrations.size() > mPreviousVibrationsLimit) { 733 previousVibrations.removeFirst(); 734 } 735 previousVibrations.addLast(vib.toInfo()); 736 } 737 738 @Override // Binder call cancelVibrate(IBinder token)739 public void cancelVibrate(IBinder token) { 740 mContext.enforceCallingOrSelfPermission( 741 android.Manifest.permission.VIBRATE, 742 "cancelVibrate"); 743 744 synchronized (mLock) { 745 if (mCurrentVibration != null && mCurrentVibration.token == token) { 746 if (DEBUG) { 747 Slog.d(TAG, "Canceling vibration."); 748 } 749 long ident = Binder.clearCallingIdentity(); 750 try { 751 doCancelVibrateLocked(); 752 } finally { 753 Binder.restoreCallingIdentity(ident); 754 } 755 } 756 } 757 } 758 759 private final Runnable mVibrationEndRunnable = new Runnable() { 760 @Override 761 public void run() { 762 onVibrationFinished(); 763 } 764 }; 765 766 @GuardedBy("mLock") doCancelVibrateLocked()767 private void doCancelVibrateLocked() { 768 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 769 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked"); 770 try { 771 mH.removeCallbacks(mVibrationEndRunnable); 772 if (mThread != null) { 773 mThread.cancel(); 774 mThread = null; 775 } 776 if (mCurrentExternalVibration != null) { 777 mCurrentExternalVibration.mute(); 778 mCurrentExternalVibration = null; 779 setVibratorUnderExternalControl(false); 780 } 781 doVibratorOff(); 782 reportFinishVibrationLocked(); 783 } finally { 784 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 785 } 786 } 787 788 // Callback for whenever the current vibration has finished played out onVibrationFinished()789 public void onVibrationFinished() { 790 if (DEBUG) { 791 Slog.e(TAG, "Vibration finished, cleaning up"); 792 } 793 synchronized (mLock) { 794 // Make sure the vibration is really done. This also reports that the vibration is 795 // finished. 796 doCancelVibrateLocked(); 797 } 798 } 799 800 @GuardedBy("mLock") startVibrationLocked(final Vibration vib)801 private void startVibrationLocked(final Vibration vib) { 802 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); 803 try { 804 final int intensity = getCurrentIntensityLocked(vib); 805 if (!shouldVibrate(vib, intensity)) { 806 return; 807 } 808 applyVibrationIntensityScalingLocked(vib, intensity); 809 startVibrationInnerLocked(vib); 810 } finally { 811 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 812 } 813 } 814 815 @GuardedBy("mLock") startVibrationInnerLocked(Vibration vib)816 private void startVibrationInnerLocked(Vibration vib) { 817 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked"); 818 try { 819 mCurrentVibration = vib; 820 if (vib.effect instanceof VibrationEffect.OneShot) { 821 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 822 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; 823 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.attrs); 824 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration()); 825 } else if (vib.effect instanceof VibrationEffect.Waveform) { 826 // mThread better be null here. doCancelVibrate should always be 827 // called before startNextVibrationLocked or startVibrationLocked. 828 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 829 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; 830 mThread = new VibrateThread(waveform, vib.uid, vib.attrs); 831 mThread.start(); 832 } else if (vib.effect instanceof VibrationEffect.Prebaked) { 833 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 834 long timeout = doVibratorPrebakedEffectLocked(vib); 835 if (timeout > 0) { 836 mH.postDelayed(mVibrationEndRunnable, timeout); 837 } 838 } else { 839 Slog.e(TAG, "Unknown vibration type, ignoring"); 840 } 841 } finally { 842 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 843 } 844 } 845 isAllowedToVibrateLocked(Vibration vib)846 private boolean isAllowedToVibrateLocked(Vibration vib) { 847 if (!mLowPowerMode) { 848 return true; 849 } 850 851 if (vib.attrs.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { 852 return true; 853 } 854 855 if (vib.attrs.getUsage() == AudioAttributes.USAGE_ALARM 856 || vib.attrs.getUsage() == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY 857 || vib.attrs.getUsage() 858 == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) { 859 return true; 860 } 861 862 return false; 863 } 864 getCurrentIntensityLocked(Vibration vib)865 private int getCurrentIntensityLocked(Vibration vib) { 866 if (vib.isRingtone()) { 867 return mRingIntensity; 868 } else if (vib.isNotification()) { 869 return mNotificationIntensity; 870 } else if (vib.isHapticFeedback()) { 871 return mHapticFeedbackIntensity; 872 } else if (vib.isAlarm()) { 873 return Vibrator.VIBRATION_INTENSITY_HIGH; 874 } else { 875 return Vibrator.VIBRATION_INTENSITY_MEDIUM; 876 } 877 } 878 879 /** 880 * Scale the vibration effect by the intensity as appropriate based its intent. 881 */ applyVibrationIntensityScalingLocked(Vibration vib, int intensity)882 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) { 883 if (vib.effect instanceof VibrationEffect.Prebaked) { 884 // Prebaked effects are always just a direct translation from intensity to 885 // EffectStrength. 886 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect; 887 prebaked.setEffectStrength(intensityToEffectStrength(intensity)); 888 return; 889 } 890 891 final int defaultIntensity; 892 if (vib.isRingtone()) { 893 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity(); 894 } else if (vib.isNotification()) { 895 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity(); 896 } else if (vib.isHapticFeedback()) { 897 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity(); 898 } else if (vib.isAlarm()) { 899 defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH; 900 } else { 901 // If we don't know what kind of vibration we're playing then just skip scaling for 902 // now. 903 return; 904 } 905 906 final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity); 907 if (scale == null) { 908 // We should have scaling levels for all cases, so not being able to scale because of a 909 // missing level is unexpected. 910 Slog.e(TAG, "No configured scaling level!" 911 + " (current=" + intensity + ", default= " + defaultIntensity + ")"); 912 return; 913 } 914 915 VibrationEffect scaledEffect = null; 916 if (vib.effect instanceof VibrationEffect.OneShot) { 917 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; 918 oneShot = oneShot.resolve(mDefaultVibrationAmplitude); 919 scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude); 920 } else if (vib.effect instanceof VibrationEffect.Waveform) { 921 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; 922 waveform = waveform.resolve(mDefaultVibrationAmplitude); 923 scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude); 924 } else { 925 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type"); 926 } 927 928 if (scaledEffect != null) { 929 vib.originalEffect = vib.effect; 930 vib.effect = scaledEffect; 931 } 932 } 933 shouldVibrateForRingtone()934 private boolean shouldVibrateForRingtone() { 935 AudioManager audioManager = mContext.getSystemService(AudioManager.class); 936 int ringerMode = audioManager.getRingerModeInternal(); 937 // "Also vibrate for calls" Setting in Sound 938 if (Settings.System.getInt( 939 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) { 940 return ringerMode != AudioManager.RINGER_MODE_SILENT; 941 } else if (Settings.Global.getInt( 942 mContext.getContentResolver(), Settings.Global.APPLY_RAMPING_RINGER, 0) != 0 943 && DeviceConfig.getBoolean( 944 DeviceConfig.NAMESPACE_TELEPHONY, RAMPING_RINGER_ENABLED, false)) { 945 return ringerMode != AudioManager.RINGER_MODE_SILENT; 946 } else { 947 return ringerMode == AudioManager.RINGER_MODE_VIBRATE; 948 } 949 } 950 shouldBypassDnd(AudioAttributes attrs)951 private static boolean shouldBypassDnd(AudioAttributes attrs) { 952 return (attrs.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0; 953 } 954 getAppOpMode(Vibration vib)955 private int getAppOpMode(Vibration vib) { 956 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, 957 vib.attrs.getUsage(), vib.uid, vib.opPkg); 958 if (mode == AppOpsManager.MODE_ALLOWED) { 959 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); 960 } 961 962 if (mode == AppOpsManager.MODE_IGNORED && shouldBypassDnd(vib.attrs)) { 963 // If we're just ignoring the vibration op then this is set by DND and we should ignore 964 // if we're asked to bypass. AppOps won't be able to record this operation, so make 965 // sure we at least note it in the logs for debugging. 966 Slog.d(TAG, "Bypassing DND for vibration: " + vib); 967 mode = AppOpsManager.MODE_ALLOWED; 968 } 969 return mode; 970 } 971 shouldVibrate(Vibration vib, int intensity)972 private boolean shouldVibrate(Vibration vib, int intensity) { 973 if (!isAllowedToVibrateLocked(vib)) { 974 return false; 975 } 976 977 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { 978 return false; 979 } 980 981 if (vib.isRingtone() && !shouldVibrateForRingtone()) { 982 if (DEBUG) { 983 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); 984 } 985 return false; 986 } 987 988 final int mode = getAppOpMode(vib); 989 if (mode != AppOpsManager.MODE_ALLOWED) { 990 if (mode == AppOpsManager.MODE_ERRORED) { 991 // We might be getting calls from within system_server, so we don't actually 992 // want to throw a SecurityException here. 993 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); 994 } 995 return false; 996 } 997 998 return true; 999 } 1000 1001 @GuardedBy("mLock") reportFinishVibrationLocked()1002 private void reportFinishVibrationLocked() { 1003 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); 1004 try { 1005 if (mCurrentVibration != null) { 1006 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, 1007 mCurrentVibration.opPkg); 1008 unlinkVibration(mCurrentVibration); 1009 mCurrentVibration = null; 1010 } 1011 } finally { 1012 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1013 } 1014 } 1015 linkVibration(Vibration vib)1016 private void linkVibration(Vibration vib) { 1017 // Only link against waveforms since they potentially don't have a finish if 1018 // they're repeating. Let other effects just play out until they're done. 1019 if (vib.effect instanceof VibrationEffect.Waveform) { 1020 try { 1021 vib.token.linkToDeath(vib, 0); 1022 } catch (RemoteException e) { 1023 return; 1024 } 1025 } 1026 } 1027 unlinkVibration(Vibration vib)1028 private void unlinkVibration(Vibration vib) { 1029 if (vib.effect instanceof VibrationEffect.Waveform) { 1030 vib.token.unlinkToDeath(vib, 0); 1031 } 1032 } 1033 updateVibrators()1034 private void updateVibrators() { 1035 synchronized (mLock) { 1036 boolean devicesUpdated = updateInputDeviceVibratorsLocked(); 1037 boolean lowPowerModeUpdated = updateLowPowerModeLocked(); 1038 updateVibrationIntensityLocked(); 1039 1040 if (devicesUpdated || lowPowerModeUpdated) { 1041 // If the state changes out from under us then just reset. 1042 doCancelVibrateLocked(); 1043 } 1044 1045 updateAlwaysOnLocked(); 1046 } 1047 } 1048 updateInputDeviceVibratorsLocked()1049 private boolean updateInputDeviceVibratorsLocked() { 1050 boolean changed = false; 1051 boolean vibrateInputDevices = false; 1052 try { 1053 vibrateInputDevices = Settings.System.getIntForUser( 1054 mContext.getContentResolver(), 1055 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 1056 } catch (SettingNotFoundException snfe) { 1057 } 1058 if (vibrateInputDevices != mVibrateInputDevicesSetting) { 1059 changed = true; 1060 mVibrateInputDevicesSetting = vibrateInputDevices; 1061 } 1062 1063 if (mVibrateInputDevicesSetting) { 1064 if (!mInputDeviceListenerRegistered) { 1065 mInputDeviceListenerRegistered = true; 1066 mIm.registerInputDeviceListener(this, mH); 1067 } 1068 } else { 1069 if (mInputDeviceListenerRegistered) { 1070 mInputDeviceListenerRegistered = false; 1071 mIm.unregisterInputDeviceListener(this); 1072 } 1073 } 1074 1075 mInputDeviceVibrators.clear(); 1076 if (mVibrateInputDevicesSetting) { 1077 int[] ids = mIm.getInputDeviceIds(); 1078 for (int i = 0; i < ids.length; i++) { 1079 InputDevice device = mIm.getInputDevice(ids[i]); 1080 Vibrator vibrator = device.getVibrator(); 1081 if (vibrator.hasVibrator()) { 1082 mInputDeviceVibrators.add(vibrator); 1083 } 1084 } 1085 return true; 1086 } 1087 return changed; 1088 } 1089 updateLowPowerModeLocked()1090 private boolean updateLowPowerModeLocked() { 1091 boolean lowPowerMode = mPowerManagerInternal 1092 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled; 1093 if (lowPowerMode != mLowPowerMode) { 1094 mLowPowerMode = lowPowerMode; 1095 return true; 1096 } 1097 return false; 1098 } 1099 updateVibrationIntensityLocked()1100 private void updateVibrationIntensityLocked() { 1101 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), 1102 Settings.System.HAPTIC_FEEDBACK_INTENSITY, 1103 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT); 1104 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), 1105 Settings.System.NOTIFICATION_VIBRATION_INTENSITY, 1106 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT); 1107 mRingIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), 1108 Settings.System.RING_VIBRATION_INTENSITY, 1109 mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); 1110 } 1111 updateAlwaysOnLocked(int id, Vibration vib)1112 private void updateAlwaysOnLocked(int id, Vibration vib) { 1113 final int intensity = getCurrentIntensityLocked(vib); 1114 if (!shouldVibrate(vib, intensity)) { 1115 vibratorAlwaysOnDisable(id); 1116 } else { 1117 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; 1118 final int strength = intensityToEffectStrength(intensity); 1119 vibratorAlwaysOnEnable(id, prebaked.getId(), strength); 1120 } 1121 } 1122 updateAlwaysOnLocked()1123 private void updateAlwaysOnLocked() { 1124 for (int i = 0; i < mAlwaysOnEffects.size(); i++) { 1125 int id = mAlwaysOnEffects.keyAt(i); 1126 Vibration vib = mAlwaysOnEffects.valueAt(i); 1127 updateAlwaysOnLocked(id, vib); 1128 } 1129 } 1130 1131 @Override onInputDeviceAdded(int deviceId)1132 public void onInputDeviceAdded(int deviceId) { 1133 updateVibrators(); 1134 } 1135 1136 @Override onInputDeviceChanged(int deviceId)1137 public void onInputDeviceChanged(int deviceId) { 1138 updateVibrators(); 1139 } 1140 1141 @Override onInputDeviceRemoved(int deviceId)1142 public void onInputDeviceRemoved(int deviceId) { 1143 updateVibrators(); 1144 } 1145 doVibratorExists()1146 private boolean doVibratorExists() { 1147 // For now, we choose to ignore the presence of input devices that have vibrators 1148 // when reporting whether the device has a vibrator. Applications often use this 1149 // information to decide whether to enable certain features so they expect the 1150 // result of hasVibrator() to be constant. For now, just report whether 1151 // the device has a built-in vibrator. 1152 //synchronized (mInputDeviceVibrators) { 1153 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 1154 //} 1155 return vibratorExists(); 1156 } 1157 doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs)1158 private void doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs) { 1159 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); 1160 try { 1161 synchronized (mInputDeviceVibrators) { 1162 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) { 1163 amplitude = mDefaultVibrationAmplitude; 1164 } 1165 if (DEBUG) { 1166 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" + 1167 " with amplitude " + amplitude + "."); 1168 } 1169 noteVibratorOnLocked(uid, millis); 1170 final int vibratorCount = mInputDeviceVibrators.size(); 1171 if (vibratorCount != 0) { 1172 for (int i = 0; i < vibratorCount; i++) { 1173 mInputDeviceVibrators.get(i).vibrate(millis, attrs); 1174 } 1175 } else { 1176 // Note: ordering is important here! Many haptic drivers will reset their 1177 // amplitude when enabled, so we always have to enable frst, then set the 1178 // amplitude. 1179 vibratorOn(millis); 1180 doVibratorSetAmplitude(amplitude); 1181 } 1182 } 1183 } finally { 1184 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1185 } 1186 } 1187 doVibratorSetAmplitude(int amplitude)1188 private void doVibratorSetAmplitude(int amplitude) { 1189 if (mSupportsAmplitudeControl) { 1190 vibratorSetAmplitude(amplitude); 1191 } 1192 } 1193 doVibratorOff()1194 private void doVibratorOff() { 1195 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff"); 1196 try { 1197 synchronized (mInputDeviceVibrators) { 1198 if (DEBUG) { 1199 Slog.d(TAG, "Turning vibrator off."); 1200 } 1201 noteVibratorOffLocked(); 1202 final int vibratorCount = mInputDeviceVibrators.size(); 1203 if (vibratorCount != 0) { 1204 for (int i = 0; i < vibratorCount; i++) { 1205 mInputDeviceVibrators.get(i).cancel(); 1206 } 1207 } else { 1208 vibratorOff(); 1209 } 1210 } 1211 } finally { 1212 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1213 } 1214 } 1215 1216 @GuardedBy("mLock") doVibratorPrebakedEffectLocked(Vibration vib)1217 private long doVibratorPrebakedEffectLocked(Vibration vib) { 1218 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked"); 1219 try { 1220 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; 1221 final boolean usingInputDeviceVibrators; 1222 synchronized (mInputDeviceVibrators) { 1223 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty(); 1224 } 1225 // Input devices don't support prebaked effect, so skip trying it with them. 1226 if (!usingInputDeviceVibrators) { 1227 long duration = vibratorPerformEffect(prebaked.getId(), 1228 prebaked.getEffectStrength(), vib); 1229 long timeout = duration; 1230 if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) { 1231 timeout *= ASYNC_TIMEOUT_MULTIPLIER; 1232 } 1233 if (timeout > 0) { 1234 noteVibratorOnLocked(vib.uid, duration); 1235 return timeout; 1236 } 1237 } 1238 if (!prebaked.shouldFallback()) { 1239 return 0; 1240 } 1241 VibrationEffect effect = getFallbackEffect(prebaked.getId()); 1242 if (effect == null) { 1243 Slog.w(TAG, "Failed to play prebaked effect, no fallback"); 1244 return 0; 1245 } 1246 Vibration fallbackVib = new Vibration(vib.token, effect, vib.attrs, vib.uid, 1247 vib.opPkg, vib.reason + " (fallback)"); 1248 final int intensity = getCurrentIntensityLocked(fallbackVib); 1249 linkVibration(fallbackVib); 1250 applyVibrationIntensityScalingLocked(fallbackVib, intensity); 1251 startVibrationInnerLocked(fallbackVib); 1252 return 0; 1253 } finally { 1254 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1255 } 1256 } 1257 getFallbackEffect(int effectId)1258 private VibrationEffect getFallbackEffect(int effectId) { 1259 return mFallbackEffects.get(effectId); 1260 } 1261 1262 /** 1263 * Return the current desired effect strength. 1264 * 1265 * If the returned value is < 0 then the vibration shouldn't be played at all. 1266 */ intensityToEffectStrength(int intensity)1267 private static int intensityToEffectStrength(int intensity) { 1268 switch (intensity) { 1269 case Vibrator.VIBRATION_INTENSITY_LOW: 1270 return EffectStrength.LIGHT; 1271 case Vibrator.VIBRATION_INTENSITY_MEDIUM: 1272 return EffectStrength.MEDIUM; 1273 case Vibrator.VIBRATION_INTENSITY_HIGH: 1274 return EffectStrength.STRONG; 1275 default: 1276 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity); 1277 return EffectStrength.STRONG; 1278 } 1279 } 1280 isNotification(int usageHint)1281 private static boolean isNotification(int usageHint) { 1282 switch (usageHint) { 1283 case AudioAttributes.USAGE_NOTIFICATION: 1284 case AudioAttributes.USAGE_NOTIFICATION_EVENT: 1285 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 1286 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 1287 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 1288 return true; 1289 default: 1290 return false; 1291 } 1292 } 1293 isRingtone(int usageHint)1294 private static boolean isRingtone(int usageHint) { 1295 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 1296 } 1297 isHapticFeedback(int usageHint)1298 private static boolean isHapticFeedback(int usageHint) { 1299 return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; 1300 } 1301 isAlarm(int usageHint)1302 private static boolean isAlarm(int usageHint) { 1303 return usageHint == AudioAttributes.USAGE_ALARM; 1304 } 1305 noteVibratorOnLocked(int uid, long millis)1306 private void noteVibratorOnLocked(int uid, long millis) { 1307 try { 1308 mBatteryStatsService.noteVibratorOn(uid, millis); 1309 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, uid, null, 1310 StatsLog.VIBRATOR_STATE_CHANGED__STATE__ON, millis); 1311 mCurVibUid = uid; 1312 } catch (RemoteException e) { 1313 } 1314 } 1315 noteVibratorOffLocked()1316 private void noteVibratorOffLocked() { 1317 if (mCurVibUid >= 0) { 1318 try { 1319 mBatteryStatsService.noteVibratorOff(mCurVibUid); 1320 StatsLog.write_non_chained(StatsLog.VIBRATOR_STATE_CHANGED, mCurVibUid, null, 1321 StatsLog.VIBRATOR_STATE_CHANGED__STATE__OFF, 0); 1322 } catch (RemoteException e) { } 1323 mCurVibUid = -1; 1324 } 1325 } 1326 setVibratorUnderExternalControl(boolean externalControl)1327 private void setVibratorUnderExternalControl(boolean externalControl) { 1328 if (DEBUG) { 1329 if (externalControl) { 1330 Slog.d(TAG, "Vibrator going under external control."); 1331 } else { 1332 Slog.d(TAG, "Taking back control of vibrator."); 1333 } 1334 } 1335 mVibratorUnderExternalControl = externalControl; 1336 vibratorSetExternalControl(externalControl); 1337 } 1338 1339 private class VibrateThread extends Thread { 1340 private final VibrationEffect.Waveform mWaveform; 1341 private final int mUid; 1342 private final AudioAttributes mAttrs; 1343 1344 private boolean mForceStop; 1345 VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs)1346 VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs) { 1347 mWaveform = waveform; 1348 mUid = uid; 1349 mAttrs = attrs; 1350 mTmpWorkSource.set(uid); 1351 mWakeLock.setWorkSource(mTmpWorkSource); 1352 } 1353 delayLocked(long duration)1354 private long delayLocked(long duration) { 1355 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked"); 1356 try { 1357 long durationRemaining = duration; 1358 if (duration > 0) { 1359 final long bedtime = duration + SystemClock.uptimeMillis(); 1360 do { 1361 try { 1362 this.wait(durationRemaining); 1363 } 1364 catch (InterruptedException e) { } 1365 if (mForceStop) { 1366 break; 1367 } 1368 durationRemaining = bedtime - SystemClock.uptimeMillis(); 1369 } while (durationRemaining > 0); 1370 return duration - durationRemaining; 1371 } 1372 return 0; 1373 } finally { 1374 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1375 } 1376 } 1377 run()1378 public void run() { 1379 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 1380 mWakeLock.acquire(); 1381 try { 1382 boolean finished = playWaveform(); 1383 if (finished) { 1384 onVibrationFinished(); 1385 } 1386 } finally { 1387 mWakeLock.release(); 1388 } 1389 } 1390 1391 /** 1392 * Play the waveform. 1393 * 1394 * @return true if it finished naturally, false otherwise (e.g. it was canceled). 1395 */ playWaveform()1396 public boolean playWaveform() { 1397 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform"); 1398 try { 1399 synchronized (this) { 1400 final long[] timings = mWaveform.getTimings(); 1401 final int[] amplitudes = mWaveform.getAmplitudes(); 1402 final int len = timings.length; 1403 final int repeat = mWaveform.getRepeatIndex(); 1404 1405 int index = 0; 1406 long onDuration = 0; 1407 while (!mForceStop) { 1408 if (index < len) { 1409 final int amplitude = amplitudes[index]; 1410 final long duration = timings[index++]; 1411 if (duration <= 0) { 1412 continue; 1413 } 1414 if (amplitude != 0) { 1415 if (onDuration <= 0) { 1416 // Telling the vibrator to start multiple times usually causes 1417 // effects to feel "choppy" because the motor resets at every on 1418 // command. Instead we figure out how long our next "on" period 1419 // is going to be, tell the motor to stay on for the full 1420 // duration, and then wake up to change the amplitude at the 1421 // appropriate intervals. 1422 onDuration = getTotalOnDuration(timings, amplitudes, index - 1, 1423 repeat); 1424 doVibratorOn(onDuration, amplitude, mUid, mAttrs); 1425 } else { 1426 doVibratorSetAmplitude(amplitude); 1427 } 1428 } 1429 1430 long waitTime = delayLocked(duration); 1431 if (amplitude != 0) { 1432 onDuration -= waitTime; 1433 } 1434 } else if (repeat < 0) { 1435 break; 1436 } else { 1437 index = repeat; 1438 } 1439 } 1440 return !mForceStop; 1441 } 1442 } finally { 1443 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1444 } 1445 } 1446 cancel()1447 public void cancel() { 1448 synchronized (this) { 1449 mThread.mForceStop = true; 1450 mThread.notify(); 1451 } 1452 } 1453 1454 /** 1455 * Get the duration the vibrator will be on starting at startIndex until the next time it's 1456 * off. 1457 */ getTotalOnDuration( long[] timings, int[] amplitudes, int startIndex, int repeatIndex)1458 private long getTotalOnDuration( 1459 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) { 1460 int i = startIndex; 1461 long timing = 0; 1462 while(amplitudes[i] != 0) { 1463 timing += timings[i++]; 1464 if (i >= timings.length) { 1465 if (repeatIndex >= 0) { 1466 i = repeatIndex; 1467 // prevent infinite loop 1468 repeatIndex = -1; 1469 } else { 1470 break; 1471 } 1472 } 1473 if (i == startIndex) { 1474 return 1000; 1475 } 1476 } 1477 return timing; 1478 } 1479 } 1480 1481 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1482 @Override 1483 public void onReceive(Context context, Intent intent) { 1484 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 1485 synchronized (mLock) { 1486 // When the system is entering a non-interactive state, we want 1487 // to cancel vibrations in case a misbehaving app has abandoned 1488 // them. However it may happen that the system is currently playing 1489 // haptic feedback as part of the transition. So we don't cancel 1490 // system vibrations. 1491 if (mCurrentVibration != null 1492 && !(mCurrentVibration.isHapticFeedback() 1493 && mCurrentVibration.isFromSystem())) { 1494 doCancelVibrateLocked(); 1495 } 1496 } 1497 } 1498 } 1499 }; 1500 1501 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)1502 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1503 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1504 1505 pw.println("Vibrator Service:"); 1506 synchronized (mLock) { 1507 pw.print(" mCurrentVibration="); 1508 if (mCurrentVibration != null) { 1509 pw.println(mCurrentVibration.toInfo().toString()); 1510 } else { 1511 pw.println("null"); 1512 } 1513 pw.print(" mCurrentExternalVibration="); 1514 if (mCurrentExternalVibration != null) { 1515 pw.println(mCurrentExternalVibration.toString()); 1516 } else { 1517 pw.println("null"); 1518 } 1519 pw.println(" mVibratorUnderExternalControl=" + mVibratorUnderExternalControl); 1520 pw.println(" mLowPowerMode=" + mLowPowerMode); 1521 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity); 1522 pw.println(" mNotificationIntensity=" + mNotificationIntensity); 1523 pw.println(" mRingIntensity=" + mRingIntensity); 1524 pw.println(""); 1525 pw.println(" Previous ring vibrations:"); 1526 for (VibrationInfo info : mPreviousRingVibrations) { 1527 pw.print(" "); 1528 pw.println(info.toString()); 1529 } 1530 1531 pw.println(" Previous notification vibrations:"); 1532 for (VibrationInfo info : mPreviousNotificationVibrations) { 1533 pw.print(" "); 1534 pw.println(info.toString()); 1535 } 1536 1537 pw.println(" Previous alarm vibrations:"); 1538 for (VibrationInfo info : mPreviousAlarmVibrations) { 1539 pw.print(" "); 1540 pw.println(info.toString()); 1541 } 1542 1543 pw.println(" Previous vibrations:"); 1544 for (VibrationInfo info : mPreviousVibrations) { 1545 pw.print(" "); 1546 pw.println(info.toString()); 1547 } 1548 1549 pw.println(" Previous external vibrations:"); 1550 for (ExternalVibration vib : mPreviousExternalVibrations) { 1551 pw.print(" "); 1552 pw.println(vib.toString()); 1553 } 1554 } 1555 } 1556 1557 @Override onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1558 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1559 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 1560 throws RemoteException { 1561 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); 1562 } 1563 1564 final class ExternalVibratorService extends IExternalVibratorService.Stub { 1565 ExternalVibrationDeathRecipient mCurrentExternalDeathRecipient; 1566 1567 @Override onExternalVibrationStart(ExternalVibration vib)1568 public int onExternalVibrationStart(ExternalVibration vib) { 1569 if (!mSupportsExternalControl) { 1570 return SCALE_MUTE; 1571 } 1572 if (ActivityManager.checkComponentPermission(android.Manifest.permission.VIBRATE, 1573 vib.getUid(), -1 /*owningUid*/, true /*exported*/) 1574 != PackageManager.PERMISSION_GRANTED) { 1575 Slog.w(TAG, "pkg=" + vib.getPackage() + ", uid=" + vib.getUid() 1576 + " tried to play externally controlled vibration" 1577 + " without VIBRATE permission, ignoring."); 1578 return SCALE_MUTE; 1579 } 1580 1581 final int scaleLevel; 1582 synchronized (mLock) { 1583 if (!vib.equals(mCurrentExternalVibration)) { 1584 if (mCurrentExternalVibration == null) { 1585 // If we're not under external control right now, then cancel any normal 1586 // vibration that may be playing and ready the vibrator for external 1587 // control. 1588 doCancelVibrateLocked(); 1589 setVibratorUnderExternalControl(true); 1590 } 1591 // At this point we either have an externally controlled vibration playing, or 1592 // no vibration playing. Since the interface defines that only one externally 1593 // controlled vibration can play at a time, by returning something other than 1594 // SCALE_MUTE from this function we can be assured that if we are currently 1595 // playing vibration, it will be muted in favor of the new vibration. 1596 // 1597 // Note that this doesn't support multiple concurrent external controls, as we 1598 // would need to mute the old one still if it came from a different controller. 1599 mCurrentExternalVibration = vib; 1600 mCurrentExternalDeathRecipient = new ExternalVibrationDeathRecipient(); 1601 mCurrentExternalVibration.linkToDeath(mCurrentExternalDeathRecipient); 1602 if (mPreviousExternalVibrations.size() > mPreviousVibrationsLimit) { 1603 mPreviousExternalVibrations.removeFirst(); 1604 } 1605 mPreviousExternalVibrations.addLast(vib); 1606 if (DEBUG) { 1607 Slog.e(TAG, "Playing external vibration: " + vib); 1608 } 1609 } 1610 final int usage = vib.getAudioAttributes().getUsage(); 1611 final int defaultIntensity; 1612 final int currentIntensity; 1613 if (isRingtone(usage)) { 1614 defaultIntensity = mVibrator.getDefaultRingVibrationIntensity(); 1615 currentIntensity = mRingIntensity; 1616 } else if (isNotification(usage)) { 1617 defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity(); 1618 currentIntensity = mNotificationIntensity; 1619 } else if (isHapticFeedback(usage)) { 1620 defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity(); 1621 currentIntensity = mHapticFeedbackIntensity; 1622 } else if (isAlarm(usage)) { 1623 defaultIntensity = Vibrator.VIBRATION_INTENSITY_HIGH; 1624 currentIntensity = Vibrator.VIBRATION_INTENSITY_HIGH; 1625 } else { 1626 defaultIntensity = 0; 1627 currentIntensity = 0; 1628 } 1629 scaleLevel = currentIntensity - defaultIntensity; 1630 } 1631 if (scaleLevel >= SCALE_VERY_LOW && scaleLevel <= SCALE_VERY_HIGH) { 1632 return scaleLevel; 1633 } else { 1634 // Presumably we want to play this but something about our scaling has gone 1635 // wrong, so just play with no scaling. 1636 Slog.w(TAG, "Error in scaling calculations, ended up with invalid scale level " 1637 + scaleLevel + " for vibration " + vib); 1638 return SCALE_NONE; 1639 } 1640 } 1641 1642 @Override onExternalVibrationStop(ExternalVibration vib)1643 public void onExternalVibrationStop(ExternalVibration vib) { 1644 synchronized (mLock) { 1645 if (vib.equals(mCurrentExternalVibration)) { 1646 mCurrentExternalVibration.unlinkToDeath(mCurrentExternalDeathRecipient); 1647 mCurrentExternalDeathRecipient = null; 1648 mCurrentExternalVibration = null; 1649 setVibratorUnderExternalControl(false); 1650 if (DEBUG) { 1651 Slog.e(TAG, "Stopping external vibration" + vib); 1652 } 1653 } 1654 } 1655 } 1656 1657 private class ExternalVibrationDeathRecipient implements IBinder.DeathRecipient { binderDied()1658 public void binderDied() { 1659 synchronized (mLock) { 1660 onExternalVibrationStop(mCurrentExternalVibration); 1661 } 1662 } 1663 } 1664 } 1665 1666 private final class VibratorShellCommand extends ShellCommand { 1667 1668 private final IBinder mToken; 1669 1670 private final class CommonOptions { 1671 public boolean force = false; check(String opt)1672 public void check(String opt) { 1673 switch (opt) { 1674 case "-f": 1675 force = true; 1676 break; 1677 } 1678 } 1679 } 1680 VibratorShellCommand(IBinder token)1681 private VibratorShellCommand(IBinder token) { 1682 mToken = token; 1683 } 1684 1685 @Override onCommand(String cmd)1686 public int onCommand(String cmd) { 1687 if ("vibrate".equals(cmd)) { 1688 return runVibrate(); 1689 } else if ("waveform".equals(cmd)) { 1690 return runWaveform(); 1691 } else if ("prebaked".equals(cmd)) { 1692 return runPrebaked(); 1693 } else if ("cancel".equals(cmd)) { 1694 cancelVibrate(mToken); 1695 return 0; 1696 } 1697 return handleDefaultCommands(cmd); 1698 } 1699 checkDoNotDisturb(CommonOptions opts)1700 private boolean checkDoNotDisturb(CommonOptions opts) { 1701 try { 1702 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(), 1703 Settings.Global.ZEN_MODE); 1704 if (zenMode != Settings.Global.ZEN_MODE_OFF && !opts.force) { 1705 try (PrintWriter pw = getOutPrintWriter();) { 1706 pw.print("Ignoring because device is on DND mode "); 1707 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_", 1708 zenMode)); 1709 return true; 1710 } 1711 } 1712 } catch (SettingNotFoundException e) { 1713 // ignore 1714 } 1715 1716 return false; 1717 } 1718 runVibrate()1719 private int runVibrate() { 1720 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate"); 1721 try { 1722 CommonOptions commonOptions = new CommonOptions(); 1723 1724 String opt; 1725 while ((opt = getNextOption()) != null) { 1726 commonOptions.check(opt); 1727 } 1728 1729 if (checkDoNotDisturb(commonOptions)) { 1730 return 0; 1731 } 1732 1733 final long duration = Long.parseLong(getNextArgRequired()); 1734 String description = getNextArg(); 1735 if (description == null) { 1736 description = "Shell command"; 1737 } 1738 1739 VibrationEffect effect = 1740 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE); 1741 AudioAttributes attrs = createAudioAttributes(commonOptions); 1742 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", 1743 mToken); 1744 return 0; 1745 } finally { 1746 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1747 } 1748 } 1749 runWaveform()1750 private int runWaveform() { 1751 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runWaveform"); 1752 try { 1753 String description = "Shell command"; 1754 int repeat = -1; 1755 ArrayList<Integer> amplitudesList = null; 1756 CommonOptions commonOptions = new CommonOptions(); 1757 1758 String opt; 1759 while ((opt = getNextOption()) != null) { 1760 switch (opt) { 1761 case "-d": 1762 description = getNextArgRequired(); 1763 break; 1764 case "-r": 1765 repeat = Integer.parseInt(getNextArgRequired()); 1766 break; 1767 case "-a": 1768 if (amplitudesList == null) { 1769 amplitudesList = new ArrayList<Integer>(); 1770 } 1771 break; 1772 default: 1773 commonOptions.check(opt); 1774 break; 1775 } 1776 } 1777 1778 if (checkDoNotDisturb(commonOptions)) { 1779 return 0; 1780 } 1781 1782 ArrayList<Long> timingsList = new ArrayList<Long>(); 1783 1784 String arg; 1785 while ((arg = getNextArg()) != null) { 1786 if (amplitudesList != null && amplitudesList.size() < timingsList.size()) { 1787 amplitudesList.add(Integer.parseInt(arg)); 1788 } else { 1789 timingsList.add(Long.parseLong(arg)); 1790 } 1791 } 1792 1793 VibrationEffect effect; 1794 long[] timings = timingsList.stream().mapToLong(Long::longValue).toArray(); 1795 if (amplitudesList == null) { 1796 effect = VibrationEffect.createWaveform(timings, repeat); 1797 } else { 1798 int[] amplitudes = 1799 amplitudesList.stream().mapToInt(Integer::intValue).toArray(); 1800 effect = VibrationEffect.createWaveform(timings, amplitudes, repeat); 1801 } 1802 AudioAttributes attrs = createAudioAttributes(commonOptions); 1803 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", 1804 mToken); 1805 return 0; 1806 } finally { 1807 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1808 } 1809 } 1810 runPrebaked()1811 private int runPrebaked() { 1812 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked"); 1813 try { 1814 CommonOptions commonOptions = new CommonOptions(); 1815 1816 String opt; 1817 while ((opt = getNextOption()) != null) { 1818 commonOptions.check(opt); 1819 } 1820 1821 if (checkDoNotDisturb(commonOptions)) { 1822 return 0; 1823 } 1824 1825 final int id = Integer.parseInt(getNextArgRequired()); 1826 1827 String description = getNextArg(); 1828 if (description == null) { 1829 description = "Shell command"; 1830 } 1831 1832 VibrationEffect effect = 1833 VibrationEffect.get(id, false); 1834 AudioAttributes attrs = createAudioAttributes(commonOptions); 1835 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", 1836 mToken); 1837 return 0; 1838 } finally { 1839 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1840 } 1841 } 1842 createAudioAttributes(CommonOptions commonOptions)1843 private AudioAttributes createAudioAttributes(CommonOptions commonOptions) { 1844 final int flags = commonOptions.force 1845 ? AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY 1846 : 0; 1847 return new AudioAttributes.Builder() 1848 .setUsage(AudioAttributes.USAGE_UNKNOWN) 1849 .setFlags(flags) 1850 .build(); 1851 } 1852 1853 @Override onHelp()1854 public void onHelp() { 1855 try (PrintWriter pw = getOutPrintWriter();) { 1856 pw.println("Vibrator commands:"); 1857 pw.println(" help"); 1858 pw.println(" Prints this help text."); 1859 pw.println(""); 1860 pw.println(" vibrate duration [description]"); 1861 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND "); 1862 pw.println(" (Do Not Disturb) mode."); 1863 pw.println(" waveform [-d description] [-r index] [-a] duration [amplitude] ..."); 1864 pw.println(" Vibrates for durations and amplitudes in list;"); 1865 pw.println(" ignored when device is on DND (Do Not Disturb) mode."); 1866 pw.println(" If -r is provided, the waveform loops back to the specified"); 1867 pw.println(" index (e.g. 0 loops from the beginning)"); 1868 pw.println(" If -a is provided, the command accepts duration-amplitude pairs;"); 1869 pw.println(" otherwise, it accepts durations only and alternates off/on"); 1870 pw.println(" Duration is in milliseconds; amplitude is a scale of 1-255."); 1871 pw.println(" prebaked effect-id [description]"); 1872 pw.println(" Vibrates with prebaked effect; ignored when device is on DND "); 1873 pw.println(" (Do Not Disturb) mode."); 1874 pw.println(" cancel"); 1875 pw.println(" Cancels any active vibration"); 1876 pw.println("Common Options:"); 1877 pw.println(" -f - Force. Ignore Do Not Disturb setting."); 1878 pw.println(""); 1879 } 1880 } 1881 } 1882 1883 } 1884