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