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 159 static native boolean vibratorExists(); 160 static native void vibratorInit(); 161 static native void vibratorOn(long milliseconds); 162 static native void vibratorOff(); 163 static native boolean vibratorSupportsAmplitudeControl(); 164 static native void vibratorSetAmplitude(int amplitude); 165 static native long vibratorPerformEffect(long effect, long strength); 166 static native boolean vibratorSupportsExternalControl(); 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 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 220 public void binderDied() { 221 synchronized (mLock) { 222 if (this == mCurrentVibration) { 223 doCancelVibrateLocked(); 224 } 225 } 226 } 227 228 public boolean hasTimeoutLongerThan(long millis) { 229 final long duration = effect.getDuration(); 230 return duration >= 0 && duration > millis; 231 } 232 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 258 public boolean isNotification() { 259 return VibratorService.this.isNotification(usageHint); 260 } 261 262 public boolean isRingtone() { 263 return VibratorService.this.isRingtone(usageHint); 264 } 265 266 public boolean isAlarm() { 267 return VibratorService.this.isAlarm(usageHint); 268 } 269 270 public boolean isFromSystem() { 271 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg); 272 } 273 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 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 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 326 public ScaleLevel(float gamma) { 327 this(gamma, VibrationEffect.MAX_AMPLITUDE); 328 } 329 330 public ScaleLevel(float gamma, int maxAmplitude) { 331 this.gamma = gamma; 332 this.maxAmplitude = maxAmplitude; 333 } 334 335 @Override 336 public String toString() { 337 return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}"; 338 } 339 } 340 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 407 private VibrationEffect createEffectFromResource(int resId) { 408 long[] timings = getLongIntArray(mContext.getResources(), resId); 409 return createEffectFromTimings(timings); 410 } 411 412 private static VibrationEffect createEffectFromTimings(long[] timings) { 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 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 { 481 public SettingsObserver(Handler handler) { 482 super(handler); 483 } 484 485 @Override 486 public void onChange(boolean SelfChange) { 487 updateVibrators(); 488 } 489 } 490 491 @Override // Binder call 492 public boolean hasVibrator() { 493 return doVibratorExists(); 494 } 495 496 @Override // Binder call 497 public boolean hasAmplitudeControl() { 498 synchronized (mInputDeviceVibrators) { 499 // Input device vibrators don't support amplitude controls yet, but are still used over 500 // the system vibrator when connected. 501 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty(); 502 } 503 } 504 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 */ 524 private static boolean verifyVibrationEffect(VibrationEffect effect) { 525 if (effect == null) { 526 // Effect must not be null. 527 Slog.wtf(TAG, "effect must not be null"); 528 return false; 529 } 530 try { 531 effect.validate(); 532 } catch (Exception e) { 533 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e); 534 return false; 535 } 536 return true; 537 } 538 539 private static long[] getLongIntArray(Resources r, int resid) { 540 int[] ar = r.getIntArray(resid); 541 if (ar == null) { 542 return null; 543 } 544 long[] out = new long[ar.length]; 545 for (int i = 0; i < ar.length; i++) { 546 out[i] = ar[i]; 547 } 548 return out; 549 } 550 551 @Override // Binder call 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 635 private static boolean isRepeatingVibration(VibrationEffect effect) { 636 return effect.getDuration() == Long.MAX_VALUE; 637 } 638 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 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") 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 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") 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") 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 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 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 */ 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 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 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") 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 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 926 private void unlinkVibration(Vibration vib) { 927 if (vib.effect instanceof VibrationEffect.Waveform) { 928 vib.token.unlinkToDeath(vib, 0); 929 } 930 } 931 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 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 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 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 1009 public void onInputDeviceAdded(int deviceId) { 1010 updateVibrators(); 1011 } 1012 1013 @Override 1014 public void onInputDeviceChanged(int deviceId) { 1015 updateVibrators(); 1016 } 1017 1018 @Override 1019 public void onInputDeviceRemoved(int deviceId) { 1020 updateVibrators(); 1021 } 1022 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 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 1067 private void doVibratorSetAmplitude(int amplitude) { 1068 if (mSupportsAmplitudeControl) { 1069 vibratorSetAmplitude(amplitude); 1070 } 1071 } 1072 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") 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 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 */ 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 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 1168 private static boolean isRingtone(int usageHint) { 1169 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 1170 } 1171 1172 private static boolean isHapticFeedback(int usageHint) { 1173 return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; 1174 } 1175 1176 private static boolean isAlarm(int usageHint) { 1177 return usageHint == AudioAttributes.USAGE_ALARM; 1178 } 1179 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 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 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 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 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 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 */ 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 1321 public void cancel() { 1322 synchronized (this) { 1323 mThread.mForceStop = true; 1324 mThread.notify(); 1325 } 1326 } 1327 1328 /** 1329 * Get the duration the vibrator will be on starting at startIndex until the next time it's 1330 * off. 1331 */ 1332 private long getTotalOnDuration( 1333 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) { 1334 int i = startIndex; 1335 long timing = 0; 1336 while(amplitudes[i] != 0) { 1337 timing += timings[i++]; 1338 if (i >= timings.length) { 1339 if (repeatIndex >= 0) { 1340 i = repeatIndex; 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 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 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 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 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 { 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; 1546 public void check(String opt) { 1547 switch (opt) { 1548 case "-f": 1549 force = true; 1550 break; 1551 } 1552 } 1553 } 1554 1555 private VibratorShellCommand(IBinder token) { 1556 mToken = token; 1557 } 1558 1559 @Override 1560 public int onCommand(String cmd) { 1561 if ("vibrate".equals(cmd)) { 1562 return runVibrate(); 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 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 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 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 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 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