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