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.d(TAG, "Ignoring incoming vibration in favor of current vibration"); 377 } 378 return; 379 } 380 } 381 382 // If the current vibration is repeating and the incoming one is non-repeating, then ignore 383 // the non-repeating vibration. This is so that we don't cancel vibrations that are meant 384 // to grab the attention of the user, like ringtones and alarms, in favor of one-shot 385 // vibrations that are likely quite short. 386 if (!isRepeatingVibration(effect) 387 && mCurrentVibration != null && isRepeatingVibration(mCurrentVibration.mEffect)) { 388 if (DEBUG) { 389 Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration"); 390 } 391 return; 392 } 393 394 Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg); 395 396 // Only link against waveforms since they potentially don't have a finish if 397 // they're repeating. Let other effects just play out until they're done. 398 if (effect instanceof VibrationEffect.Waveform) { 399 try { 400 token.linkToDeath(vib, 0); 401 } catch (RemoteException e) { 402 return; 403 } 404 } 405 406 407 long ident = Binder.clearCallingIdentity(); 408 try { 409 synchronized (mLock) { 410 doCancelVibrateLocked(); 411 startVibrationLocked(vib); 412 addToPreviousVibrationsLocked(vib); 413 } 414 } finally { 415 Binder.restoreCallingIdentity(ident); 416 } 417 } 418 419 private static boolean isRepeatingVibration(VibrationEffect effect) { 420 if (effect instanceof VibrationEffect.Waveform) { 421 final VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) effect; 422 if (waveform.getRepeatIndex() >= 0) { 423 return true; 424 } 425 } 426 return false; 427 } 428 429 private void addToPreviousVibrationsLocked(Vibration vib) { 430 if (mPreviousVibrations.size() > mPreviousVibrationsLimit) { 431 mPreviousVibrations.removeFirst(); 432 } 433 mPreviousVibrations.addLast(new VibrationInfo( 434 vib.mStartTime, vib.mEffect, vib.mUsageHint, vib.mUid, vib.mOpPkg)); 435 } 436 437 @Override // Binder call 438 public void cancelVibrate(IBinder token) { 439 mContext.enforceCallingOrSelfPermission( 440 android.Manifest.permission.VIBRATE, 441 "cancelVibrate"); 442 443 synchronized (mLock) { 444 if (mCurrentVibration != null && mCurrentVibration.mToken == token) { 445 if (DEBUG) { 446 Slog.d(TAG, "Canceling vibration."); 447 } 448 long ident = Binder.clearCallingIdentity(); 449 try { 450 doCancelVibrateLocked(); 451 } finally { 452 Binder.restoreCallingIdentity(ident); 453 } 454 } 455 } 456 } 457 458 private final Runnable mVibrationEndRunnable = new Runnable() { 459 @Override 460 public void run() { 461 onVibrationFinished(); 462 } 463 }; 464 465 private void doCancelVibrateLocked() { 466 mH.removeCallbacks(mVibrationEndRunnable); 467 if (mThread != null) { 468 mThread.cancel(); 469 mThread = null; 470 } 471 doVibratorOff(); 472 reportFinishVibrationLocked(); 473 } 474 475 // Callback for whenever the current vibration has finished played out 476 public void onVibrationFinished() { 477 if (DEBUG) { 478 Slog.e(TAG, "Vibration finished, cleaning up"); 479 } 480 synchronized (mLock) { 481 // Make sure the vibration is really done. This also reports that the vibration is 482 // finished. 483 doCancelVibrateLocked(); 484 } 485 } 486 487 private void startVibrationLocked(final Vibration vib) { 488 if (!isAllowedToVibrate(vib)) { 489 if (DEBUG) { 490 Slog.e(TAG, "Vibrate ignored, low power mode"); 491 } 492 return; 493 } 494 495 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE && 496 !shouldVibrateForRingtone()) { 497 if (DEBUG) { 498 Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); 499 } 500 return; 501 } 502 503 final int mode = getAppOpMode(vib); 504 if (mode != AppOpsManager.MODE_ALLOWED) { 505 if (mode == AppOpsManager.MODE_ERRORED) { 506 // We might be getting calls from within system_server, so we don't actually want 507 // to throw a SecurityException here. 508 Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid); 509 } 510 return; 511 } 512 startVibrationInnerLocked(vib); 513 } 514 515 private void startVibrationInnerLocked(Vibration vib) { 516 mCurrentVibration = vib; 517 if (vib.mEffect instanceof VibrationEffect.OneShot) { 518 VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect; 519 doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint); 520 mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming()); 521 } else if (vib.mEffect instanceof VibrationEffect.Waveform) { 522 // mThread better be null here. doCancelVibrate should always be 523 // called before startNextVibrationLocked or startVibrationLocked. 524 VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect; 525 mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint); 526 mThread.start(); 527 } else if (vib.mEffect instanceof VibrationEffect.Prebaked) { 528 long timeout = doVibratorPrebakedEffectLocked(vib); 529 if (timeout > 0) { 530 mH.postDelayed(mVibrationEndRunnable, timeout); 531 } 532 } else { 533 Slog.e(TAG, "Unknown vibration type, ignoring"); 534 } 535 } 536 537 private boolean isAllowedToVibrate(Vibration vib) { 538 if (!mLowPowerMode) { 539 return true; 540 } 541 if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { 542 return true; 543 } 544 if (!mAllowPriorityVibrationsInLowPowerMode) { 545 return false; 546 } 547 if (vib.mUsageHint == AudioAttributes.USAGE_ALARM || 548 vib.mUsageHint == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY || 549 vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) { 550 551 return true; 552 } 553 554 return false; 555 } 556 557 private boolean shouldVibrateForRingtone() { 558 AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 559 int ringerMode = audioManager.getRingerModeInternal(); 560 // "Also vibrate for calls" Setting in Sound 561 if (Settings.System.getInt( 562 mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) != 0) { 563 return ringerMode != AudioManager.RINGER_MODE_SILENT; 564 } else { 565 return ringerMode == AudioManager.RINGER_MODE_VIBRATE; 566 } 567 } 568 569 private int getAppOpMode(Vibration vib) { 570 int mode; 571 try { 572 mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, 573 vib.mUsageHint, vib.mUid, vib.mOpPkg); 574 if (mode == AppOpsManager.MODE_ALLOWED) { 575 mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), 576 AppOpsManager.OP_VIBRATE, vib.mUid, vib.mOpPkg); 577 } 578 } catch (RemoteException e) { 579 Slog.e(TAG, "Failed to get appop mode for vibration!", e); 580 mode = AppOpsManager.MODE_IGNORED; 581 } 582 return mode; 583 } 584 585 private void reportFinishVibrationLocked() { 586 if (mCurrentVibration != null) { 587 try { 588 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), 589 AppOpsManager.OP_VIBRATE, mCurrentVibration.mUid, 590 mCurrentVibration.mOpPkg); 591 } catch (RemoteException e) { } 592 mCurrentVibration = null; 593 } 594 } 595 596 private void unlinkVibration(Vibration vib) { 597 if (vib.mEffect instanceof VibrationEffect.Waveform) { 598 vib.mToken.unlinkToDeath(vib, 0); 599 } 600 } 601 602 private void updateVibrators() { 603 synchronized (mLock) { 604 boolean devicesUpdated = updateInputDeviceVibratorsLocked(); 605 boolean lowPowerModeUpdated = updateLowPowerModeLocked(); 606 607 if (devicesUpdated || lowPowerModeUpdated) { 608 // If the state changes out from under us then just reset. 609 doCancelVibrateLocked(); 610 } 611 } 612 } 613 614 private boolean updateInputDeviceVibratorsLocked() { 615 boolean changed = false; 616 boolean vibrateInputDevices = false; 617 try { 618 vibrateInputDevices = Settings.System.getIntForUser( 619 mContext.getContentResolver(), 620 Settings.System.VIBRATE_INPUT_DEVICES, UserHandle.USER_CURRENT) > 0; 621 } catch (SettingNotFoundException snfe) { 622 } 623 if (vibrateInputDevices != mVibrateInputDevicesSetting) { 624 changed = true; 625 mVibrateInputDevicesSetting = vibrateInputDevices; 626 } 627 628 if (mVibrateInputDevicesSetting) { 629 if (!mInputDeviceListenerRegistered) { 630 mInputDeviceListenerRegistered = true; 631 mIm.registerInputDeviceListener(this, mH); 632 } 633 } else { 634 if (mInputDeviceListenerRegistered) { 635 mInputDeviceListenerRegistered = false; 636 mIm.unregisterInputDeviceListener(this); 637 } 638 } 639 640 mInputDeviceVibrators.clear(); 641 if (mVibrateInputDevicesSetting) { 642 int[] ids = mIm.getInputDeviceIds(); 643 for (int i = 0; i < ids.length; i++) { 644 InputDevice device = mIm.getInputDevice(ids[i]); 645 Vibrator vibrator = device.getVibrator(); 646 if (vibrator.hasVibrator()) { 647 mInputDeviceVibrators.add(vibrator); 648 } 649 } 650 return true; 651 } 652 return changed; 653 } 654 655 private boolean updateLowPowerModeLocked() { 656 boolean lowPowerMode = mPowerManagerInternal 657 .getLowPowerState(ServiceType.VIBRATION).batterySaverEnabled; 658 if (lowPowerMode != mLowPowerMode) { 659 mLowPowerMode = lowPowerMode; 660 return true; 661 } 662 return false; 663 } 664 665 @Override 666 public void onInputDeviceAdded(int deviceId) { 667 updateVibrators(); 668 } 669 670 @Override 671 public void onInputDeviceChanged(int deviceId) { 672 updateVibrators(); 673 } 674 675 @Override 676 public void onInputDeviceRemoved(int deviceId) { 677 updateVibrators(); 678 } 679 680 private boolean doVibratorExists() { 681 // For now, we choose to ignore the presence of input devices that have vibrators 682 // when reporting whether the device has a vibrator. Applications often use this 683 // information to decide whether to enable certain features so they expect the 684 // result of hasVibrator() to be constant. For now, just report whether 685 // the device has a built-in vibrator. 686 //synchronized (mInputDeviceVibrators) { 687 // return !mInputDeviceVibrators.isEmpty() || vibratorExists(); 688 //} 689 return vibratorExists(); 690 } 691 692 private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) { 693 synchronized (mInputDeviceVibrators) { 694 if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) { 695 amplitude = mDefaultVibrationAmplitude; 696 } 697 if (DEBUG) { 698 Slog.d(TAG, "Turning vibrator on for " + millis + " ms" + 699 " with amplitude " + amplitude + "."); 700 } 701 noteVibratorOnLocked(uid, millis); 702 final int vibratorCount = mInputDeviceVibrators.size(); 703 if (vibratorCount != 0) { 704 final AudioAttributes attributes = 705 new AudioAttributes.Builder().setUsage(usageHint).build(); 706 for (int i = 0; i < vibratorCount; i++) { 707 mInputDeviceVibrators.get(i).vibrate(millis, attributes); 708 } 709 } else { 710 // Note: ordering is important here! Many haptic drivers will reset their amplitude 711 // when enabled, so we always have to enable frst, then set the amplitude. 712 vibratorOn(millis); 713 doVibratorSetAmplitude(amplitude); 714 } 715 } 716 } 717 718 private void doVibratorSetAmplitude(int amplitude) { 719 if (mSupportsAmplitudeControl) { 720 vibratorSetAmplitude(amplitude); 721 } 722 } 723 724 private void doVibratorOff() { 725 synchronized (mInputDeviceVibrators) { 726 if (DEBUG) { 727 Slog.d(TAG, "Turning vibrator off."); 728 } 729 noteVibratorOffLocked(); 730 final int vibratorCount = mInputDeviceVibrators.size(); 731 if (vibratorCount != 0) { 732 for (int i = 0; i < vibratorCount; i++) { 733 mInputDeviceVibrators.get(i).cancel(); 734 } 735 } else { 736 vibratorOff(); 737 } 738 } 739 } 740 741 private long doVibratorPrebakedEffectLocked(Vibration vib) { 742 synchronized (mInputDeviceVibrators) { 743 VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.mEffect; 744 // Input devices don't support prebaked effect, so skip trying it with them. 745 final int vibratorCount = mInputDeviceVibrators.size(); 746 if (vibratorCount == 0) { 747 long timeout = vibratorPerformEffect(prebaked.getId(), EffectStrength.MEDIUM); 748 if (timeout > 0) { 749 noteVibratorOnLocked(vib.mUid, timeout); 750 return timeout; 751 } 752 } 753 if (!prebaked.shouldFallback()) { 754 return 0; 755 } 756 final int id = prebaked.getId(); 757 if (id < 0 || id >= mFallbackEffects.length || mFallbackEffects[id] == null) { 758 Slog.w(TAG, "Failed to play prebaked effect, no fallback"); 759 return 0; 760 } 761 VibrationEffect effect = mFallbackEffects[id]; 762 Vibration fallbackVib = 763 new Vibration(vib.mToken, effect, vib.mUsageHint, vib.mUid, vib.mOpPkg); 764 startVibrationInnerLocked(fallbackVib); 765 } 766 return 0; 767 } 768 769 private void noteVibratorOnLocked(int uid, long millis) { 770 try { 771 mBatteryStatsService.noteVibratorOn(uid, millis); 772 mCurVibUid = uid; 773 } catch (RemoteException e) { 774 } 775 } 776 777 private void noteVibratorOffLocked() { 778 if (mCurVibUid >= 0) { 779 try { 780 mBatteryStatsService.noteVibratorOff(mCurVibUid); 781 } catch (RemoteException e) { } 782 mCurVibUid = -1; 783 } 784 } 785 786 private class VibrateThread extends Thread { 787 private final VibrationEffect.Waveform mWaveform; 788 private final int mUid; 789 private final int mUsageHint; 790 791 private boolean mForceStop; 792 793 VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) { 794 mWaveform = waveform; 795 mUid = uid; 796 mUsageHint = usageHint; 797 mTmpWorkSource.set(uid); 798 mWakeLock.setWorkSource(mTmpWorkSource); 799 } 800 801 private long delayLocked(long duration) { 802 long durationRemaining = duration; 803 if (duration > 0) { 804 final long bedtime = duration + SystemClock.uptimeMillis(); 805 do { 806 try { 807 this.wait(durationRemaining); 808 } 809 catch (InterruptedException e) { } 810 if (mForceStop) { 811 break; 812 } 813 durationRemaining = bedtime - SystemClock.uptimeMillis(); 814 } while (durationRemaining > 0); 815 return duration - durationRemaining; 816 } 817 return 0; 818 } 819 820 public void run() { 821 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); 822 mWakeLock.acquire(); 823 try { 824 boolean finished = playWaveform(); 825 if (finished) { 826 onVibrationFinished(); 827 } 828 } finally { 829 mWakeLock.release(); 830 } 831 } 832 833 /** 834 * Play the waveform. 835 * 836 * @return true if it finished naturally, false otherwise (e.g. it was canceled). 837 */ 838 public boolean playWaveform() { 839 synchronized (this) { 840 final long[] timings = mWaveform.getTimings(); 841 final int[] amplitudes = mWaveform.getAmplitudes(); 842 final int len = timings.length; 843 final int repeat = mWaveform.getRepeatIndex(); 844 845 int index = 0; 846 long onDuration = 0; 847 while (!mForceStop) { 848 if (index < len) { 849 final int amplitude = amplitudes[index]; 850 final long duration = timings[index++]; 851 if (duration <= 0) { 852 continue; 853 } 854 if (amplitude != 0) { 855 if (onDuration <= 0) { 856 // Telling the vibrator to start multiple times usually causes 857 // effects to feel "choppy" because the motor resets at every on 858 // command. Instead we figure out how long our next "on" period is 859 // going to be, tell the motor to stay on for the full duration, 860 // and then wake up to change the amplitude at the appropriate 861 // intervals. 862 onDuration = 863 getTotalOnDuration(timings, amplitudes, index - 1, repeat); 864 doVibratorOn(onDuration, amplitude, mUid, mUsageHint); 865 } else { 866 doVibratorSetAmplitude(amplitude); 867 } 868 } 869 870 long waitTime = delayLocked(duration); 871 if (amplitude != 0) { 872 onDuration -= waitTime; 873 } 874 } else if (repeat < 0) { 875 break; 876 } else { 877 index = repeat; 878 } 879 } 880 return !mForceStop; 881 } 882 } 883 884 public void cancel() { 885 synchronized (this) { 886 mThread.mForceStop = true; 887 mThread.notify(); 888 } 889 } 890 891 /** 892 * Get the duration the vibrator will be on starting at startIndex until the next time it's 893 * off. 894 */ 895 private long getTotalOnDuration( 896 long[] timings, int[] amplitudes, int startIndex, int repeatIndex) { 897 int i = startIndex; 898 long timing = 0; 899 while(amplitudes[i] != 0) { 900 timing += timings[i++]; 901 if (i >= timings.length) { 902 if (repeatIndex >= 0) { 903 i = repeatIndex; 904 } else { 905 break; 906 } 907 } 908 if (i == startIndex) { 909 return 1000; 910 } 911 } 912 return timing; 913 } 914 } 915 916 BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { 917 @Override 918 public void onReceive(Context context, Intent intent) { 919 if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { 920 synchronized (mLock) { 921 // When the system is entering a non-interactive state, we want 922 // to cancel vibrations in case a misbehaving app has abandoned 923 // them. However it may happen that the system is currently playing 924 // haptic feedback as part of the transition. So we don't cancel 925 // system vibrations. 926 if (mCurrentVibration != null 927 && !mCurrentVibration.isSystemHapticFeedback()) { 928 doCancelVibrateLocked(); 929 } 930 } 931 } 932 } 933 }; 934 935 @Override 936 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 937 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 938 939 pw.println("Previous vibrations:"); 940 synchronized (mLock) { 941 for (VibrationInfo info : mPreviousVibrations) { 942 pw.print(" "); 943 pw.println(info.toString()); 944 } 945 } 946 } 947 948 @Override 949 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 950 String[] args, ShellCallback callback, ResultReceiver resultReceiver) 951 throws RemoteException { 952 new VibratorShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver); 953 } 954 955 private final class VibratorShellCommand extends ShellCommand { 956 957 private static final long MAX_VIBRATION_MS = 200; 958 959 private final IBinder mToken; 960 961 private VibratorShellCommand(IBinder token) { 962 mToken = token; 963 } 964 965 @Override 966 public int onCommand(String cmd) { 967 if ("vibrate".equals(cmd)) { 968 return runVibrate(); 969 } 970 return handleDefaultCommands(cmd); 971 } 972 973 private int runVibrate() { 974 try { 975 final int zenMode = Settings.Global.getInt(mContext.getContentResolver(), 976 Settings.Global.ZEN_MODE); 977 if (zenMode != Settings.Global.ZEN_MODE_OFF) { 978 try (PrintWriter pw = getOutPrintWriter();) { 979 pw.print("Ignoring because device is on DND mode "); 980 pw.println(DebugUtils.flagsToString(Settings.Global.class, "ZEN_MODE_", 981 zenMode)); 982 return 0; 983 } 984 } 985 } catch (SettingNotFoundException e) { 986 // ignore 987 } 988 989 final long duration = Long.parseLong(getNextArgRequired()); 990 if (duration > MAX_VIBRATION_MS) { 991 throw new IllegalArgumentException("maximum duration is " + MAX_VIBRATION_MS); 992 } 993 String description = getNextArg(); 994 if (description == null) { 995 description = "Shell command"; 996 } 997 998 VibrationEffect effect = 999 VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE); 1000 vibrate(Binder.getCallingUid(), description, effect, AudioAttributes.USAGE_UNKNOWN, 1001 mToken); 1002 return 0; 1003 } 1004 1005 @Override 1006 public void onHelp() { 1007 try (PrintWriter pw = getOutPrintWriter();) { 1008 pw.println("Vibrator commands:"); 1009 pw.println(" help"); 1010 pw.println(" Prints this help text."); 1011 pw.println(""); 1012 pw.println(" vibrate duration [description]"); 1013 pw.println(" Vibrates for duration milliseconds; ignored when device is on DND "); 1014 pw.println(" (Do Not Disturb) mode."); 1015 pw.println(""); 1016 } 1017 } 1018 } 1019 1020} 1021