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