VibratorService.java revision f7b4725375dfb5f6b65433f1679c44501c2478e3
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 17package com.android.server; 18 19import android.app.AppOpsManager; 20import android.content.BroadcastReceiver; 21import android.content.Context; 22import android.content.Intent; 23import android.content.IntentFilter; 24import android.content.pm.PackageManager; 25import android.content.res.Resources; 26import android.database.ContentObserver; 27import android.hardware.input.InputManager; 28import android.hardware.vibrator.V1_0.EffectStrength; 29import android.icu.text.DateFormat; 30import android.media.AudioManager; 31import android.os.PowerManager.ServiceType; 32import android.os.PowerSaveState; 33import android.os.BatteryStats; 34import android.os.Handler; 35import android.os.IVibratorService; 36import android.os.PowerManager; 37import android.os.PowerManagerInternal; 38import android.os.Process; 39import android.os.RemoteException; 40import android.os.ResultReceiver; 41import android.os.IBinder; 42import android.os.Binder; 43import android.os.ServiceManager; 44import android.os.ShellCallback; 45import android.os.ShellCommand; 46import android.os.SystemClock; 47import android.os.Trace; 48import android.os.UserHandle; 49import android.os.Vibrator; 50import android.os.VibrationEffect; 51import android.os.WorkSource; 52import android.provider.Settings; 53import android.provider.Settings.SettingNotFoundException; 54import android.util.DebugUtils; 55import android.util.Slog; 56import android.view.InputDevice; 57import android.media.AudioAttributes; 58 59import com.android.internal.annotations.GuardedBy; 60import com.android.internal.app.IAppOpsService; 61import com.android.internal.app.IBatteryStats; 62import com.android.internal.util.DumpUtils; 63 64import java.io.FileDescriptor; 65import java.io.PrintWriter; 66import java.util.ArrayList; 67import java.util.LinkedList; 68import java.util.Date; 69 70public class VibratorService extends IVibratorService.Stub 71 implements InputManager.InputDeviceListener { 72 private static final String TAG = "VibratorService"; 73 private static final boolean DEBUG = false; 74 private static final String SYSTEM_UI_PACKAGE = "com.android.systemui"; 75 76 private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 }; 77 78 private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f; 79 private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f; 80 private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f; 81 private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f; 82 83 private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255 84 private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255 85 86 // If a vibration is playing for longer than 5s, it's probably not haptic feedback. 87 private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; 88 89 private final LinkedList<VibrationInfo> mPreviousVibrations; 90 private final int mPreviousVibrationsLimit; 91 private final boolean mAllowPriorityVibrationsInLowPowerMode; 92 private final boolean mSupportsAmplitudeControl; 93 private final int mDefaultVibrationAmplitude; 94 private final VibrationEffect[] mFallbackEffects; 95 private final WorkSource mTmpWorkSource = new WorkSource(); 96 private final Handler mH = new Handler(); 97 private final Object mLock = new Object(); 98 99 private final Context mContext; 100 private final PowerManager.WakeLock mWakeLock; 101 private final AppOpsManager mAppOps; 102 private final IBatteryStats mBatteryStatsService; 103 private PowerManagerInternal mPowerManagerInternal; 104 private InputManager mIm; 105 private Vibrator mVibrator; 106 private SettingsObserver mSettingObserver; 107 108 private volatile VibrateThread mThread; 109 110 // mInputDeviceVibrators lock should be acquired after mLock, if both are 111 // to be acquired 112 private final ArrayList<Vibrator> mInputDeviceVibrators = new ArrayList<Vibrator>(); 113 private boolean mVibrateInputDevicesSetting; // guarded by mInputDeviceVibrators 114 private boolean mInputDeviceListenerRegistered; // guarded by mInputDeviceVibrators 115 116 @GuardedBy("mLock") 117 private Vibration mCurrentVibration; 118 private int mCurVibUid = -1; 119 private boolean mLowPowerMode; 120 private int mHapticFeedbackIntensity; 121 private int mNotificationIntensity; 122 123 native static boolean vibratorExists(); 124 native static void vibratorInit(); 125 native static void vibratorOn(long milliseconds); 126 native static void vibratorOff(); 127 native static boolean vibratorSupportsAmplitudeControl(); 128 native static void vibratorSetAmplitude(int amplitude); 129 native static long vibratorPerformEffect(long effect, long strength); 130 131 private class Vibration implements IBinder.DeathRecipient { 132 public final IBinder token; 133 // Start time in CLOCK_BOOTTIME base. 134 public final long startTime; 135 // Start time in unix epoch time. Only to be used for debugging purposes and to correlate 136 // with other system events, any duration calculations should be done use startTime so as 137 // not to be affected by discontinuities created by RTC adjustments. 138 public final long startTimeDebug; 139 public final int usageHint; 140 public final int uid; 141 public final String opPkg; 142 143 // The actual effect to be played. 144 public VibrationEffect effect; 145 // The original effect that was requested. This is non-null only when the original effect 146 // differs from the effect that's being played. Typically these two things differ because 147 // the effect was scaled based on the users vibration intensity settings. 148 public VibrationEffect originalEffect; 149 150 private Vibration(IBinder token, VibrationEffect effect, 151 int usageHint, int uid, String opPkg) { 152 this.token = token; 153 this.effect = effect; 154 this.startTime = SystemClock.elapsedRealtime(); 155 this.startTimeDebug = System.currentTimeMillis(); 156 this.usageHint = usageHint; 157 this.uid = uid; 158 this.opPkg = opPkg; 159 } 160 161 public void binderDied() { 162 synchronized (mLock) { 163 if (this == mCurrentVibration) { 164 doCancelVibrateLocked(); 165 } 166 } 167 } 168 169 public boolean hasTimeoutLongerThan(long millis) { 170 final long duration = effect.getDuration(); 171 return duration >= 0 && duration > millis; 172 } 173 174 public boolean isHapticFeedback() { 175 if (effect instanceof VibrationEffect.Prebaked) { 176 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; 177 switch (prebaked.getId()) { 178 case VibrationEffect.EFFECT_CLICK: 179 case VibrationEffect.EFFECT_DOUBLE_CLICK: 180 case VibrationEffect.EFFECT_TICK: 181 return true; 182 default: 183 Slog.w(TAG, "Unknown prebaked vibration effect, " 184 + "assuming it isn't haptic feedback."); 185 return false; 186 } 187 } 188 final long duration = effect.getDuration(); 189 return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION; 190 } 191 192 public boolean isNotification() { 193 switch (usageHint) { 194 case AudioAttributes.USAGE_NOTIFICATION: 195 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: 196 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: 197 case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: 198 return true; 199 default: 200 return false; 201 } 202 } 203 204 public boolean isRingtone() { 205 return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE; 206 } 207 208 public boolean isFromSystem() { 209 return uid == Process.SYSTEM_UID || uid == 0 || SYSTEM_UI_PACKAGE.equals(opPkg); 210 } 211 212 public VibrationInfo toInfo() { 213 return new VibrationInfo( 214 startTimeDebug, effect, originalEffect, usageHint, uid, opPkg); 215 } 216 } 217 218 private static class VibrationInfo { 219 private final long mStartTimeDebug; 220 private final VibrationEffect mEffect; 221 private final VibrationEffect mOriginalEffect; 222 private final int mUsageHint; 223 private final int mUid; 224 private final String mOpPkg; 225 226 public VibrationInfo(long startTimeDebug, VibrationEffect effect, 227 VibrationEffect originalEffect, int usageHint, int uid, String opPkg) { 228 mStartTimeDebug = startTimeDebug; 229 mEffect = effect; 230 mOriginalEffect = originalEffect; 231 mUsageHint = usageHint; 232 mUid = uid; 233 mOpPkg = opPkg; 234 } 235 236 @Override 237 public String toString() { 238 return new StringBuilder() 239 .append("startTime: ") 240 .append(DateFormat.getDateTimeInstance().format(new Date(mStartTimeDebug))) 241 .append(", effect: ") 242 .append(mEffect) 243 .append(", originalEffect: ") 244 .append(mOriginalEffect) 245 .append(", usageHint: ") 246 .append(mUsageHint) 247 .append(", uid: ") 248 .append(mUid) 249 .append(", opPkg: ") 250 .append(mOpPkg) 251 .toString(); 252 } 253 } 254 255 VibratorService(Context context) { 256 vibratorInit(); 257 // Reset the hardware to a default state, in case this is a runtime 258 // restart instead of a fresh boot. 259 vibratorOff(); 260 261 mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl(); 262 263 mContext = context; 264 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 265 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); 266 mWakeLock.setReferenceCounted(true); 267 268 mAppOps = mContext.getSystemService(AppOpsManager.class); 269 mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( 270 BatteryStats.SERVICE_NAME)); 271 272 mPreviousVibrationsLimit = mContext.getResources().getInteger( 273 com.android.internal.R.integer.config_previousVibrationsDumpLimit); 274 275 mDefaultVibrationAmplitude = mContext.getResources().getInteger( 276 com.android.internal.R.integer.config_defaultVibrationAmplitude); 277 278 mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean( 279 com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode); 280 281 mPreviousVibrations = new LinkedList<>(); 282 283 IntentFilter filter = new IntentFilter(); 284 filter.addAction(Intent.ACTION_SCREEN_OFF); 285 context.registerReceiver(mIntentReceiver, filter); 286 287 long[] clickEffectTimings = getLongIntArray(context.getResources(), 288 com.android.internal.R.array.config_virtualKeyVibePattern); 289 VibrationEffect clickEffect = createEffect(clickEffectTimings); 290 VibrationEffect doubleClickEffect = VibrationEffect.createWaveform( 291 DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS, -1 /*repeatIndex*/); 292 long[] tickEffectTimings = getLongIntArray(context.getResources(), 293 com.android.internal.R.array.config_clockTickVibePattern); 294 VibrationEffect tickEffect = createEffect(tickEffectTimings); 295 296 mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect, tickEffect }; 297 } 298 299 private static VibrationEffect createEffect(long[] timings) { 300 if (timings == null || timings.length == 0) { 301 return null; 302 } else if (timings.length == 1) { 303 return VibrationEffect.createOneShot(timings[0], VibrationEffect.DEFAULT_AMPLITUDE); 304 } else { 305 return VibrationEffect.createWaveform(timings, -1); 306 } 307 } 308 309 public void systemReady() { 310 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "VibratorService#systemReady"); 311 try { 312 mIm = mContext.getSystemService(InputManager.class); 313 mVibrator = mContext.getSystemService(Vibrator.class); 314 mSettingObserver = new SettingsObserver(mH); 315 316 mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); 317 mPowerManagerInternal.registerLowPowerModeObserver( 318 new PowerManagerInternal.LowPowerModeListener() { 319 @Override 320 public int getServiceType() { 321 return ServiceType.VIBRATION; 322 } 323 324 @Override 325 public void onLowPowerModeChanged(PowerSaveState result) { 326 updateVibrators(); 327 } 328 }); 329 330 mContext.getContentResolver().registerContentObserver( 331 Settings.System.getUriFor(Settings.System.VIBRATE_INPUT_DEVICES), 332 true, mSettingObserver, UserHandle.USER_ALL); 333 334 mContext.getContentResolver().registerContentObserver( 335 Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_INTENSITY), 336 true, mSettingObserver, UserHandle.USER_ALL); 337 338 mContext.getContentResolver().registerContentObserver( 339 Settings.System.getUriFor(Settings.System.NOTIFICATION_VIBRATION_INTENSITY), 340 true, mSettingObserver, UserHandle.USER_ALL); 341 342 mContext.registerReceiver(new BroadcastReceiver() { 343 @Override 344 public void onReceive(Context context, Intent intent) { 345 updateVibrators(); 346 } 347 }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH); 348 349 updateVibrators(); 350 } finally { 351 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 352 } 353 } 354 355 private final class SettingsObserver extends ContentObserver { 356 public SettingsObserver(Handler handler) { 357 super(handler); 358 } 359 360 @Override 361 public void onChange(boolean SelfChange) { 362 updateVibrators(); 363 } 364 } 365 366 @Override // Binder call 367 public boolean hasVibrator() { 368 return doVibratorExists(); 369 } 370 371 @Override // Binder call 372 public boolean hasAmplitudeControl() { 373 synchronized (mInputDeviceVibrators) { 374 // Input device vibrators don't support amplitude controls yet, but are still used over 375 // the system vibrator when connected. 376 return mSupportsAmplitudeControl && mInputDeviceVibrators.isEmpty(); 377 } 378 } 379 380 private void verifyIncomingUid(int uid) { 381 if (uid == Binder.getCallingUid()) { 382 return; 383 } 384 if (Binder.getCallingPid() == Process.myPid()) { 385 return; 386 } 387 mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS, 388 Binder.getCallingPid(), Binder.getCallingUid(), null); 389 } 390 391 /** 392 * Validate the incoming VibrationEffect. 393 * 394 * We can't throw exceptions here since we might be called from some system_server component, 395 * which would bring the whole system down. 396 * 397 * @return whether the VibrationEffect is valid 398 */ 399 private static boolean verifyVibrationEffect(VibrationEffect effect) { 400 if (effect == null) { 401 // Effect must not be null. 402 Slog.wtf(TAG, "effect must not be null"); 403 return false; 404 } 405 try { 406 effect.validate(); 407 } catch (Exception e) { 408 Slog.wtf(TAG, "Encountered issue when verifying VibrationEffect.", e); 409 return false; 410 } 411 return true; 412 } 413 414 private static long[] getLongIntArray(Resources r, int resid) { 415 int[] ar = r.getIntArray(resid); 416 if (ar == null) { 417 return null; 418 } 419 long[] out = new long[ar.length]; 420 for (int i = 0; i < ar.length; i++) { 421 out[i] = ar[i]; 422 } 423 return out; 424 } 425 426 @Override // Binder call 427 public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint, 428 IBinder token) { 429 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate"); 430 try { 431 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) 432 != PackageManager.PERMISSION_GRANTED) { 433 throw new SecurityException("Requires VIBRATE permission"); 434 } 435 if (token == null) { 436 Slog.e(TAG, "token must not be null"); 437 return; 438 } 439 verifyIncomingUid(uid); 440 if (!verifyVibrationEffect(effect)) { 441 return; 442 } 443 444 // If our current vibration is longer than the new vibration and is the same amplitude, 445 // then just let the current one finish. 446 synchronized (mLock) { 447 if (effect instanceof VibrationEffect.OneShot 448 && mCurrentVibration != null 449 && mCurrentVibration.effect instanceof VibrationEffect.OneShot) { 450 VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect; 451 VibrationEffect.OneShot currentOneShot = 452 (VibrationEffect.OneShot) mCurrentVibration.effect; 453 if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration()) 454 && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) { 455 if (DEBUG) { 456 Slog.d(TAG, 457 "Ignoring incoming vibration in favor of current vibration"); 458 } 459 return; 460 } 461 } 462 463 // If the current vibration is repeating and the incoming one is non-repeating, 464 // then ignore the non-repeating vibration. This is so that we don't cancel 465 // vibrations that are meant to grab the attention of the user, like ringtones and 466 // alarms, in favor of one-shot vibrations that are likely quite short. 467 if (!isRepeatingVibration(effect) 468 && mCurrentVibration != null 469 && isRepeatingVibration(mCurrentVibration.effect)) { 470 if (DEBUG) { 471 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); 472 } 473 return; 474 } 475 476 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg); 477 linkVibration(vib); 478 long ident = Binder.clearCallingIdentity(); 479 try { 480 doCancelVibrateLocked(); 481 startVibrationLocked(vib); 482 addToPreviousVibrationsLocked(vib); 483 } finally { 484 Binder.restoreCallingIdentity(ident); 485 } 486 } 487 } finally { 488 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 489 } 490 } 491 492 private static boolean isRepeatingVibration(VibrationEffect effect) { 493 return effect.getDuration() == Long.MAX_VALUE; 494 } 495 496 private void addToPreviousVibrationsLocked(Vibration vib) { 497 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) { 498 mPreviousVibrations.removeFirst(); 499 } 500 mPreviousVibrations.addLast(vib.toInfo()); 501 } 502 503 @Override // Binder call 504 public void cancelVibrate(IBinder token) { 505 mContext.enforceCallingOrSelfPermission( 506 android.Manifest.permission.VIBRATE, 507 "cancelVibrate"); 508 509 synchronized (mLock) { 510 if (mCurrentVibration != null && mCurrentVibration.token == token) { 511 if (DEBUG) { 512 Slog.d(TAG, "Canceling vibration."); 513 } 514 long ident = Binder.clearCallingIdentity(); 515 try { 516 doCancelVibrateLocked(); 517 } finally { 518 Binder.restoreCallingIdentity(ident); 519 } 520 } 521 } 522 } 523 524 private final Runnable mVibrationEndRunnable = new Runnable() { 525 @Override 526 public void run() { 527 onVibrationFinished(); 528 } 529 }; 530 531 @GuardedBy("mLock") 532 private void doCancelVibrateLocked() { 533 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 534 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doCancelVibrateLocked"); 535 try { 536 mH.removeCallbacks(mVibrationEndRunnable); 537 if (mThread != null) { 538 mThread.cancel(); 539 mThread = null; 540 } 541 doVibratorOff(); 542 reportFinishVibrationLocked(); 543 } finally { 544 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 545 } 546 } 547 548 // Callback for whenever the current vibration has finished played out 549 public void onVibrationFinished() { 550 if (DEBUG) { 551 Slog.e(TAG, "Vibration finished, cleaning up"); 552 } 553 synchronized (mLock) { 554 // Make sure the vibration is really done. This also reports that the vibration is 555 // finished. 556 doCancelVibrateLocked(); 557 } 558 } 559 560 @GuardedBy("mLock") 561 private void startVibrationLocked(final Vibration vib) { 562 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); 563 try { 564 if (!isAllowedToVibrateLocked(vib)) { 565 return; 566 } 567 568 final int intensity = getCurrentIntensityLocked(vib); 569 if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { 570 return; 571 } 572 573 if (vib.isRingtone() && !shouldVibrateForRingtone()) { 574 if (DEBUG) { 575 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); 576 } 577 return; 578 } 579 580 final int mode = getAppOpMode(vib); 581 if (mode != AppOpsManager.MODE_ALLOWED) { 582 if (mode == AppOpsManager.MODE_ERRORED) { 583 // We might be getting calls from within system_server, so we don't actually 584 // want to throw a SecurityException here. 585 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); 586 } 587 return; 588 } 589 applyVibrationIntensityScalingLocked(vib, intensity); 590 startVibrationInnerLocked(vib); 591 } finally { 592 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 593 } 594 } 595 596 @GuardedBy("mLock") 597 private void startVibrationInnerLocked(Vibration vib) { 598 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationInnerLocked"); 599 try { 600 mCurrentVibration = vib; 601 if (vib.effect instanceof VibrationEffect.OneShot) { 602 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 603 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; 604 doVibratorOn(oneShot.getDuration(), oneShot.getAmplitude(), vib.uid, vib.usageHint); 605 mH.postDelayed(mVibrationEndRunnable, oneShot.getDuration()); 606 } else if (vib.effect instanceof VibrationEffect.Waveform) { 607 // mThread better be null here. doCancelVibrate should always be 608 // called before startNextVibrationLocked or startVibrationLocked. 609 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 610 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; 611 mThread = new VibrateThread(waveform, vib.uid, vib.usageHint); 612 mThread.start(); 613 } else if (vib.effect instanceof VibrationEffect.Prebaked) { 614 Trace.asyncTraceBegin(Trace.TRACE_TAG_VIBRATOR, "vibration", 0); 615 long timeout = doVibratorPrebakedEffectLocked(vib); 616 if (timeout > 0) { 617 mH.postDelayed(mVibrationEndRunnable, timeout); 618 } 619 } else { 620 Slog.e(TAG, "Unknown vibration type, ignoring"); 621 } 622 } finally { 623 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 624 } 625 } 626 627 private boolean isAllowedToVibrateLocked(Vibration vib) { 628 if (!mLowPowerMode) { 629 return true; 630 } 631 632 if (vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { 633 return true; 634 } 635 636 if (vib.usageHint == AudioAttributes.USAGE_ALARM || 637 vib.usageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY || 638 vib.usageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) { 639 return true; 640 } 641 642 return false; 643 } 644 645 private int getCurrentIntensityLocked(Vibration vib) { 646 if (vib.isNotification() || vib.isRingtone()){ 647 return mNotificationIntensity; 648 } else if (vib.isHapticFeedback()) { 649 return mHapticFeedbackIntensity; 650 } else { 651 return Vibrator.VIBRATION_INTENSITY_MEDIUM; 652 } 653 } 654 655 /** 656 * Scale the vibration effect by the intensity as appropriate based its intent. 657 */ 658 private void applyVibrationIntensityScalingLocked(Vibration vib, int intensity) { 659 if (vib.effect instanceof VibrationEffect.Prebaked) { 660 // Prebaked effects are always just a direct translation from intensity to 661 // EffectStrength. 662 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked)vib.effect; 663 prebaked.setEffectStrength(intensityToEffectStrength(intensity)); 664 return; 665 } 666 667 final float gamma; 668 final int maxAmplitude; 669 if (vib.isNotification() || vib.isRingtone()) { 670 if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) { 671 gamma = GAMMA_SCALE_FACTOR_MINIMUM; 672 maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY; 673 } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) { 674 gamma = GAMMA_SCALE_FACTOR_LOW; 675 maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY; 676 } else { 677 gamma = GAMMA_SCALE_FACTOR_NONE; 678 maxAmplitude = VibrationEffect.MAX_AMPLITUDE; 679 } 680 } else { 681 if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) { 682 gamma = GAMMA_SCALE_FACTOR_LOW; 683 maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY; 684 } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) { 685 gamma = GAMMA_SCALE_FACTOR_HIGH; 686 maxAmplitude = VibrationEffect.MAX_AMPLITUDE; 687 } else { 688 gamma = GAMMA_SCALE_FACTOR_NONE; 689 maxAmplitude = VibrationEffect.MAX_AMPLITUDE; 690 } 691 } 692 693 VibrationEffect scaledEffect = null; 694 if (vib.effect instanceof VibrationEffect.OneShot) { 695 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect; 696 scaledEffect = oneShot.scale(gamma, maxAmplitude); 697 } else if (vib.effect instanceof VibrationEffect.Waveform) { 698 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect; 699 scaledEffect = waveform.scale(gamma, maxAmplitude); 700 } else { 701 Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type"); 702 } 703 704 if (scaledEffect != null) { 705 vib.originalEffect = vib.effect; 706 vib.effect = scaledEffect; 707 } 708 } 709 710 private boolean shouldVibrateForRingtone() { 711 AudioManager audioManager = mContext.getSystemService(AudioManager.class); 712 int ringerMode = audioManager.getRingerModeInternal(); 713 // "Also vibrate for calls" Setting in Sound 714 if (Settings.System.getInt( 715 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) { 716 return ringerMode != AudioManager.RINGER_MODE_SILENT; 717 } else { 718 return ringerMode == AudioManager.RINGER_MODE_VIBRATE; 719 } 720 } 721 722 private int getAppOpMode(Vibration vib) { 723 int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, 724 vib.usageHint, vib.uid, vib.opPkg); 725 if (mode == AppOpsManager.MODE_ALLOWED) { 726 mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); 727 } 728 return mode; 729 } 730 731 @GuardedBy("mLock") 732 private void reportFinishVibrationLocked() { 733 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); 734 try { 735 if (mCurrentVibration != null) { 736 mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, 737 mCurrentVibration.opPkg); 738 unlinkVibration(mCurrentVibration); 739 mCurrentVibration = null; 740 } 741 } finally { 742 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 743 } 744 } 745 746 private void linkVibration(Vibration vib) { 747 // Only link against waveforms since they potentially don't have a finish if 748 // they're repeating. Let other effects just play out until they're done. 749 if (vib.effect instanceof VibrationEffect.Waveform) { 750 try { 751 vib.token.linkToDeath(vib, 0); 752 } catch (RemoteException e) { 753 return; 754 } 755 } 756 } 757 758 private void unlinkVibration(Vibration vib) { 759 if (vib.effect instanceof VibrationEffect.Waveform) { 760 vib.token.unlinkToDeath(vib, 0); 761 } 762 } 763 764 private void updateVibrators() { 765 synchronized (mLock) { 766 boolean devicesUpdated = updateInputDeviceVibratorsLocked(); 767 boolean lowPowerModeUpdated = updateLowPowerModeLocked(); 768 updateVibrationIntensityLocked(); 769 770 if (devicesUpdated || lowPowerModeUpdated) { 771 // If the state changes out from under us then just reset. 772 doCancelVibrateLocked(); 773 } 774 } 775 } 776 777 private boolean updateInputDeviceVibratorsLocked() { 778 boolean changed = false; 779 boolean vibrateInputDevices = false; 780 try { 781 vibrateInputDevices = Settings.System.getIntForUser( 782 mContext.getContentResolver(), 783 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 784 } catch (SettingNotFoundException snfe) { 785 } 786 if (vibrateInputDevices != mVibrateInputDevicesSetting) { 787 changed = true; 788 mVibrateInputDevicesSetting = vibrateInputDevices; 789 } 790 791 if (mVibrateInputDevicesSetting) { 792 if (!mInputDeviceListenerRegistered) { 793 mInputDeviceListenerRegistered = true; 794 mIm.registerInputDeviceListener(this, mH); 795 } 796 } else { 797 if (mInputDeviceListenerRegistered) { 798 mInputDeviceListenerRegistered = false; 799 mIm.unregisterInputDeviceListener(this); 800 } 801 } 802 803 mInputDeviceVibrators.clear(); 804 if (mVibrateInputDevicesSetting) { 805 int[] ids = mIm.getInputDeviceIds(); 806 for (int i = 0; i < ids.length; i++) { 807 InputDevice device = mIm.getInputDevice(ids[i]); 808 Vibrator vibrator = device.getVibrator(); 809 if (vibrator.hasVibrator()) { 810 mInputDeviceVibrators.add(vibrator); 811 } 812 } 813 return true; 814 } 815 return changed; 816 } 817 818 private boolean updateLowPowerModeLocked() { 819 boolean lowPowerMode = mPowerManagerInternal 820 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled; 821 if (lowPowerMode != mLowPowerMode) { 822 mLowPowerMode = lowPowerMode; 823 return true; 824 } 825 return false; 826 } 827 828 private void updateVibrationIntensityLocked() { 829 mHapticFeedbackIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), 830 Settings.System.HAPTIC_FEEDBACK_INTENSITY, 831 mVibrator.getDefaultHapticFeedbackIntensity(), UserHandle.USER_CURRENT); 832 mNotificationIntensity = Settings.System.getIntForUser(mContext.getContentResolver(), 833 Settings.System.NOTIFICATION_VIBRATION_INTENSITY, 834 mVibrator.getDefaultNotificationVibrationIntensity(), UserHandle.USER_CURRENT); 835 } 836 837 @Override 838 public void onInputDeviceAdded(int deviceId) { 839 updateVibrators(); 840 } 841 842 @Override 843 public void onInputDeviceChanged(int deviceId) { 844 updateVibrators(); 845 } 846 847 @Override 848 public void onInputDeviceRemoved(int deviceId) { 849 updateVibrators(); 850 } 851 852 private boolean doVibratorExists() { 853 // For now, we choose to ignore the presence of input devices that have vibrators 854 // when reporting whether the device has a vibrator. Applications often use this 855 // information to decide whether to enable certain features so they expect the 856 // result of hasVibrator() to be constant. For now, just report whether 857 // the device has a built-in vibrator. 858 //synchronized (mInputDeviceVibrators) { 859 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 860 //} 861 return vibratorExists(); 862 } 863 864 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) { 865 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); 866 try { 867 synchronized (mInputDeviceVibrators) { 868 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) { 869 amplitude = mDefaultVibrationAmplitude; 870 } 871 if (DEBUG) { 872 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" + 873 " with amplitude " + amplitude + "."); 874 } 875 noteVibratorOnLocked(uid, millis); 876 final int vibratorCount = mInputDeviceVibrators.size(); 877 if (vibratorCount != 0) { 878 final AudioAttributes attributes = 879 new AudioAttributes.Builder().setUsage(usageHint).build(); 880 for (int i = 0; i < vibratorCount; i++) { 881 mInputDeviceVibrators.get(i).vibrate(millis, attributes); 882 } 883 } else { 884 // Note: ordering is important here! Many haptic drivers will reset their 885 // amplitude when enabled, so we always have to enable frst, then set the 886 // amplitude. 887 vibratorOn(millis); 888 doVibratorSetAmplitude(amplitude); 889 } 890 } 891 } finally { 892 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 893 } 894 } 895 896 private void doVibratorSetAmplitude(int amplitude) { 897 if (mSupportsAmplitudeControl) { 898 vibratorSetAmplitude(amplitude); 899 } 900 } 901 902 private void doVibratorOff() { 903 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOff"); 904 try { 905 synchronized (mInputDeviceVibrators) { 906 if (DEBUG) { 907 Slog.d(TAG, "Turning vibrator off."); 908 } 909 noteVibratorOffLocked(); 910 final int vibratorCount = mInputDeviceVibrators.size(); 911 if (vibratorCount != 0) { 912 for (int i = 0; i < vibratorCount; i++) { 913 mInputDeviceVibrators.get(i).cancel(); 914 } 915 } else { 916 vibratorOff(); 917 } 918 } 919 } finally { 920 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 921 } 922 } 923 924 @GuardedBy("mLock") 925 private long doVibratorPrebakedEffectLocked(Vibration vib) { 926 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorPrebakedEffectLocked"); 927 try { 928 final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; 929 final boolean usingInputDeviceVibrators; 930 synchronized (mInputDeviceVibrators) { 931 usingInputDeviceVibrators = !mInputDeviceVibrators.isEmpty(); 932 } 933 // Input devices don't support prebaked effect, so skip trying it with them. 934 if (!usingInputDeviceVibrators) { 935 long timeout = vibratorPerformEffect(prebaked.getId(), 936 prebaked.getEffectStrength()); 937 if (timeout > 0) { 938 noteVibratorOnLocked(vib.uid, timeout); 939 return timeout; 940 } 941 } 942 if (!prebaked.shouldFallback()) { 943 return 0; 944 } 945 VibrationEffect effect = getFallbackEffect(prebaked.getId()); 946 if (effect == null) { 947 Slog.w(TAG, "Failed to play prebaked effect, no fallback"); 948 return 0; 949 } 950 Vibration fallbackVib = 951 new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg); 952 final int intensity = getCurrentIntensityLocked(fallbackVib); 953 linkVibration(fallbackVib); 954 applyVibrationIntensityScalingLocked(fallbackVib, intensity); 955 startVibrationInnerLocked(fallbackVib); 956 return 0; 957 } finally { 958 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 959 } 960 } 961 962 private VibrationEffect getFallbackEffect(int effectId) { 963 if (effectId < 0 || effectId >= mFallbackEffects.length) { 964 return null; 965 } 966 return mFallbackEffects[effectId]; 967 } 968 969 /** 970 * Return the current desired effect strength. 971 * 972 * If the returned value is < 0 then the vibration shouldn't be played at all. 973 */ 974 private static int intensityToEffectStrength(int intensity) { 975 switch (intensity) { 976 case Vibrator.VIBRATION_INTENSITY_LOW: 977 return EffectStrength.LIGHT; 978 case Vibrator.VIBRATION_INTENSITY_MEDIUM: 979 return EffectStrength.MEDIUM; 980 case Vibrator.VIBRATION_INTENSITY_HIGH: 981 return EffectStrength.STRONG; 982 default: 983 Slog.w(TAG, "Got unexpected vibration intensity: " + intensity); 984 return EffectStrength.STRONG; 985 } 986 } 987 988 private void noteVibratorOnLocked(int uid, long millis) { 989 try { 990 mBatteryStatsService.noteVibratorOn(uid, millis); 991 mCurVibUid = uid; 992 } catch (RemoteException e) { 993 } 994 } 995 996 private void noteVibratorOffLocked() { 997 if (mCurVibUid >= 0) { 998 try { 999 mBatteryStatsService.noteVibratorOff(mCurVibUid); 1000 } catch (RemoteException e) { } 1001 mCurVibUid = -1; 1002 } 1003 } 1004 1005 private class VibrateThread extends Thread { 1006 private final VibrationEffect.Waveform mWaveform; 1007 private final int mUid; 1008 private final int mUsageHint; 1009 1010 private boolean mForceStop; 1011 1012 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) { 1013 mWaveform = waveform; 1014 mUid = uid; 1015 mUsageHint = usageHint; 1016 mTmpWorkSource.set(uid); 1017 mWakeLock.setWorkSource(mTmpWorkSource); 1018 } 1019 1020 private long delayLocked(long duration) { 1021 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "delayLocked"); 1022 try { 1023 long durationRemaining = duration; 1024 if (duration > 0) { 1025 final long bedtime = duration + SystemClock.uptimeMillis(); 1026 do { 1027 try { 1028 this.wait(durationRemaining); 1029 } 1030 catch (InterruptedException e) { } 1031 if (mForceStop) { 1032 break; 1033 } 1034 durationRemaining = bedtime - SystemClock.uptimeMillis(); 1035 } while (durationRemaining > 0); 1036 return duration - durationRemaining; 1037 } 1038 return 0; 1039 } finally { 1040 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1041 } 1042 } 1043 1044 public void run() { 1045 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 1046 mWakeLock.acquire(); 1047 try { 1048 boolean finished = playWaveform(); 1049 if (finished) { 1050 onVibrationFinished(); 1051 } 1052 } finally { 1053 mWakeLock.release(); 1054 } 1055 } 1056 1057 /** 1058 * Play the waveform. 1059 * 1060 * @return true if it finished naturally, false otherwise (e.g. it was canceled). 1061 */ 1062 public boolean playWaveform() { 1063 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "playWaveform"); 1064 try { 1065 synchronized (this) { 1066 final long[] timings = mWaveform.getTimings(); 1067 final int[] amplitudes = mWaveform.getAmplitudes(); 1068 final int len = timings.length; 1069 final int repeat = mWaveform.getRepeatIndex(); 1070 1071 int index = 0; 1072 long onDuration = 0; 1073 while (!mForceStop) { 1074 if (index < len) { 1075 final int amplitude = amplitudes[index]; 1076 final long duration = timings[index++]; 1077 if (duration <= 0) { 1078 continue; 1079 } 1080 if (amplitude != 0) { 1081 if (onDuration <= 0) { 1082 // Telling the vibrator to start multiple times usually causes 1083 // effects to feel "choppy" because the motor resets at every on 1084 // command. Instead we figure out how long our next "on" period 1085 // is going to be, tell the motor to stay on for the full 1086 // duration, and then wake up to change the amplitude at the 1087 // appropriate intervals. 1088 onDuration = getTotalOnDuration(timings, amplitudes, index - 1, 1089 repeat); 1090 doVibratorOn(onDuration, amplitude, mUid, mUsageHint); 1091 } else { 1092 doVibratorSetAmplitude(amplitude); 1093 } 1094 } 1095 1096 long waitTime = delayLocked(duration); 1097 if (amplitude != 0) { 1098 onDuration -= waitTime; 1099 } 1100 } else if (repeat < 0) { 1101 break; 1102 } else { 1103 index = repeat; 1104 } 1105 } 1106 return !mForceStop; 1107 } 1108 } finally { 1109 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1110 } 1111 } 1112 1113 public void cancel() { 1114 synchronized (this) { 1115 mThread.mForceStop = true; 1116 mThread.notify(); 1117 } 1118 } 1119 1120 /** 1121 * Get the duration the vibrator will be on starting at startIndex until the next time it's 1122 * off. 1123 */ 1124 private long getTotalOnDuration( 1125 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) { 1126 int i = startIndex; 1127 long timing = 0; 1128 while(amplitudes[i] != 0) { 1129 timing += timings[i++]; 1130 if (i >= timings.length) { 1131 if (repeatIndex >= 0) { 1132 i = repeatIndex; 1133 } else { 1134 break; 1135 } 1136 } 1137 if (i == startIndex) { 1138 return 1000; 1139 } 1140 } 1141 return timing; 1142 } 1143 } 1144 1145 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 1146 @Override 1147 public void onReceive(Context context, Intent intent) { 1148 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 1149 synchronized (mLock) { 1150 // When the system is entering a non-interactive state, we want 1151 // to cancel vibrations in case a misbehaving app has abandoned 1152 // them. However it may happen that the system is currently playing 1153 // haptic feedback as part of the transition. So we don't cancel 1154 // system vibrations. 1155 if (mCurrentVibration != null 1156 && !(mCurrentVibration.isHapticFeedback() 1157 && mCurrentVibration.isFromSystem())) { 1158 doCancelVibrateLocked(); 1159 } 1160 } 1161 } 1162 } 1163 }; 1164 1165 @Override 1166 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1167 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1168 1169 pw.println("Vibrator Service:"); 1170 synchronized (mLock) { 1171 pw.print(" mCurrentVibration="); 1172 if (mCurrentVibration != null) { 1173 pw.println(mCurrentVibration.toInfo().toString()); 1174 } else { 1175 pw.println("null"); 1176 } 1177 pw.println(" mLowPowerMode=" + mLowPowerMode); 1178 pw.println(" mHapticFeedbackIntensity=" + mHapticFeedbackIntensity); 1179 pw.println(" mNotificationIntensity=" + mNotificationIntensity); 1180 pw.println(""); 1181 pw.println(" Previous vibrations:"); 1182 for (VibrationInfo info : mPreviousVibrations) { 1183 pw.print(" "); 1184 pw.println(info.toString()); 1185 } 1186 } 1187 } 1188 1189 @Override 1190 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 1191 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 1192 throws RemoteException { 1193 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); 1194 } 1195 1196 private final class VibratorShellCommand extends ShellCommand { 1197 1198 private static final long MAX_VIBRATION_MS = 200; 1199 1200 private final IBinder mToken; 1201 1202 private VibratorShellCommand(IBinder token) { 1203 mToken = token; 1204 } 1205 1206 @Override 1207 public int onCommand(String cmd) { 1208 if ("vibrate".equals(cmd)) { 1209 return runVibrate(); 1210 } 1211 return handleDefaultCommands(cmd); 1212 } 1213 1214 private int runVibrate() { 1215 Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runVibrate"); 1216 try { 1217 try { 1218 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(), 1219 Settings.Global.ZEN_MODE); 1220 if (zenMode != Settings.Global.ZEN_MODE_OFF) { 1221 try (PrintWriter pw = getOutPrintWriter();) { 1222 pw.print("Ignoring because device is on DND mode "); 1223 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_", 1224 zenMode)); 1225 return 0; 1226 } 1227 } 1228 } catch (SettingNotFoundException e) { 1229 // ignore 1230 } 1231 1232 final long duration = Long.parseLong(getNextArgRequired()); 1233 if (duration > MAX_VIBRATION_MS) { 1234 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS); 1235 } 1236 String description = getNextArg(); 1237 if (description == null) { 1238 description = "Shell command"; 1239 } 1240 1241 VibrationEffect effect = 1242 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE); 1243 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN, 1244 mToken); 1245 return 0; 1246 } finally { 1247 Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR); 1248 } 1249 } 1250 1251 @Override 1252 public void onHelp() { 1253 try (PrintWriter pw = getOutPrintWriter();) { 1254 pw.println("Vibrator commands:"); 1255 pw.println(" help"); 1256 pw.println(" Prints this help text."); 1257 pw.println(""); 1258 pw.println(" vibrate duration [description]"); 1259 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND "); 1260 pw.println(" (Do Not Disturb) mode."); 1261 pw.println(""); 1262 } 1263 } 1264 } 1265 1266} 1267