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