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