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