1 /* 2 * Copyright (C) 2020 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.vibrator; 18 19 import static android.os.Trace.TRACE_TAG_VIBRATOR; 20 21 import android.annotation.Nullable; 22 import android.hardware.vibrator.IVibrator; 23 import android.os.Binder; 24 import android.os.IVibratorStateListener; 25 import android.os.Parcel; 26 import android.os.RemoteCallbackList; 27 import android.os.RemoteException; 28 import android.os.Trace; 29 import android.os.VibrationEffect; 30 import android.os.VibratorInfo; 31 import android.os.vibrator.PrebakedSegment; 32 import android.os.vibrator.PrimitiveSegment; 33 import android.os.vibrator.PwlePoint; 34 import android.os.vibrator.RampSegment; 35 import android.util.IndentingPrintWriter; 36 import android.util.Slog; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.annotations.VisibleForTesting; 40 41 import libcore.util.NativeAllocationRegistry; 42 43 /** Controls a single vibrator. */ 44 final class VibratorController { 45 private static final String TAG = "VibratorController"; 46 47 private final Object mLock = new Object(); 48 49 @GuardedBy("mLock") 50 private final NativeWrapper mNativeWrapper; 51 52 // Vibrator state listeners that support concurrent updates and broadcasts, but should lock 53 // while broadcasting to guarantee delivery order. 54 private final RemoteCallbackList<IVibratorStateListener> mVibratorStateListeners = 55 new RemoteCallbackList<>(); 56 57 // Vibrator state variables that are updated from synchronized blocks but can be read anytime 58 // for a snippet of the current known vibrator state/info. 59 private volatile VibratorInfo mVibratorInfo; 60 private volatile boolean mVibratorInfoLoadSuccessful; 61 private volatile VibratorState mCurrentState; 62 private volatile float mCurrentAmplitude; 63 64 /** 65 * Listener for vibration completion callbacks from native. 66 * 67 * <p>Only the latest active native call to {@link VibratorController#on} will ever trigger this 68 * completion callback, to avoid race conditions during a vibration playback. If a new call to 69 * {@link #on} or {@link #off} happens before a previous callback was triggered then the 70 * previous callback will be disabled, even if the new command fails. 71 */ 72 public interface OnVibrationCompleteListener { 73 74 /** Callback triggered when an active vibration command is complete. */ onComplete(int vibratorId, long vibrationId, long stepId)75 void onComplete(int vibratorId, long vibrationId, long stepId); 76 } 77 78 /** Representation of the vibrator state based on the interactions through this controller. */ 79 private enum VibratorState { 80 IDLE, VIBRATING, UNDER_EXTERNAL_CONTROL 81 } 82 VibratorController(int vibratorId, OnVibrationCompleteListener listener)83 VibratorController(int vibratorId, OnVibrationCompleteListener listener) { 84 this(vibratorId, listener, new NativeWrapper()); 85 } 86 87 @VisibleForTesting VibratorController(int vibratorId, OnVibrationCompleteListener listener, NativeWrapper nativeWrapper)88 VibratorController(int vibratorId, OnVibrationCompleteListener listener, 89 NativeWrapper nativeWrapper) { 90 mNativeWrapper = nativeWrapper; 91 mNativeWrapper.init(vibratorId, listener); 92 VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId); 93 mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder); 94 mVibratorInfo = vibratorInfoBuilder.build(); 95 mCurrentState = VibratorState.IDLE; 96 97 if (!mVibratorInfoLoadSuccessful) { 98 Slog.e(TAG, 99 "Vibrator controller initialization failed to load some HAL info for vibrator " 100 + vibratorId); 101 } 102 } 103 104 /** Register state listener for this vibrator. */ registerVibratorStateListener(IVibratorStateListener listener)105 public boolean registerVibratorStateListener(IVibratorStateListener listener) { 106 final long token = Binder.clearCallingIdentity(); 107 try { 108 // Register the listener and send the first state atomically, to avoid potentially 109 // out of order broadcasts in between. 110 synchronized (mLock) { 111 if (!mVibratorStateListeners.register(listener)) { 112 return false; 113 } 114 // Notify its callback after new client registered. 115 notifyStateListener(listener, isVibrating(mCurrentState)); 116 } 117 return true; 118 } finally { 119 Binder.restoreCallingIdentity(token); 120 } 121 } 122 123 /** Remove registered state listener for this vibrator. */ unregisterVibratorStateListener(IVibratorStateListener listener)124 public boolean unregisterVibratorStateListener(IVibratorStateListener listener) { 125 final long token = Binder.clearCallingIdentity(); 126 try { 127 return mVibratorStateListeners.unregister(listener); 128 } finally { 129 Binder.restoreCallingIdentity(token); 130 } 131 } 132 133 /** Reruns the query to the vibrator to load the {@link VibratorInfo}, if not yet successful. */ reloadVibratorInfoIfNeeded()134 public void reloadVibratorInfoIfNeeded() { 135 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#reloadVibratorInfoIfNeeded"); 136 try { 137 // Early check outside lock, for quick return. 138 if (mVibratorInfoLoadSuccessful) { 139 return; 140 } 141 synchronized (mLock) { 142 if (mVibratorInfoLoadSuccessful) { 143 return; 144 } 145 int vibratorId = mVibratorInfo.getId(); 146 VibratorInfo.Builder vibratorInfoBuilder = new VibratorInfo.Builder(vibratorId); 147 mVibratorInfoLoadSuccessful = mNativeWrapper.getInfo(vibratorInfoBuilder); 148 mVibratorInfo = vibratorInfoBuilder.build(); 149 if (!mVibratorInfoLoadSuccessful) { 150 Slog.e(TAG, "Failed retry of HAL getInfo for vibrator " + vibratorId); 151 } 152 } 153 } finally { 154 Trace.traceEnd(TRACE_TAG_VIBRATOR); 155 } 156 } 157 158 /** Checks if the {@link VibratorInfo} was loaded from the vibrator hardware successfully. */ isVibratorInfoLoadSuccessful()159 boolean isVibratorInfoLoadSuccessful() { 160 return mVibratorInfoLoadSuccessful; 161 } 162 163 /** Return the {@link VibratorInfo} representing the vibrator controlled by this instance. */ getVibratorInfo()164 public VibratorInfo getVibratorInfo() { 165 return mVibratorInfo; 166 } 167 168 /** 169 * Return {@code true} is this vibrator is currently vibrating, false otherwise. 170 * 171 * <p>This state is controlled by calls to {@link #on} and {@link #off} methods, and is 172 * automatically notified to any registered {@link IVibratorStateListener} on change. 173 */ isVibrating()174 public boolean isVibrating() { 175 return isVibrating(mCurrentState); 176 } 177 178 /** 179 * Returns the current amplitude the device is vibrating. 180 * 181 * <p>This value is set to 1 by the method {@link #on(long, long)}, and can be updated via 182 * {@link #setAmplitude(float)} if called while the device is vibrating. 183 * 184 * <p>If the device is vibrating via any other {@link #on} method then the current amplitude is 185 * unknown and this will return -1. 186 * 187 * <p>If {@link #isVibrating()} is false then this will be zero. 188 */ getCurrentAmplitude()189 public float getCurrentAmplitude() { 190 return mCurrentAmplitude; 191 } 192 193 /** 194 * Check against this vibrator capabilities. 195 * 196 * @param capability one of IVibrator.CAP_* 197 * @return true if this vibrator has this capability, false otherwise 198 */ hasCapability(long capability)199 public boolean hasCapability(long capability) { 200 return mVibratorInfo.hasCapability(capability); 201 } 202 203 /** Return {@code true} if the underlying vibrator is currently available, false otherwise. */ isAvailable()204 public boolean isAvailable() { 205 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#isAvailable"); 206 try { 207 synchronized (mLock) { 208 return mNativeWrapper.isAvailable(); 209 } 210 } finally { 211 Trace.traceEnd(TRACE_TAG_VIBRATOR); 212 } 213 } 214 215 /** 216 * Set the vibrator control to be external or not, based on given flag. 217 * 218 * <p>This will affect the state of {@link #isVibrating()}. 219 */ setExternalControl(boolean externalControl)220 public void setExternalControl(boolean externalControl) { 221 Trace.traceBegin(TRACE_TAG_VIBRATOR, 222 externalControl ? "VibratorController#enableExternalControl" 223 : "VibratorController#disableExternalControl"); 224 try { 225 if (!mVibratorInfo.hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) { 226 return; 227 } 228 VibratorState newState = 229 externalControl ? VibratorState.UNDER_EXTERNAL_CONTROL : VibratorState.IDLE; 230 synchronized (mLock) { 231 mNativeWrapper.setExternalControl(externalControl); 232 updateStateAndNotifyListenersLocked(newState); 233 } 234 } finally { 235 Trace.traceEnd(TRACE_TAG_VIBRATOR); 236 } 237 } 238 239 /** 240 * Update the predefined vibration effect saved with given id. This will remove the saved effect 241 * if given {@code effect} is {@code null}. 242 */ updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked)243 public void updateAlwaysOn(int id, @Nullable PrebakedSegment prebaked) { 244 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#updateAlwaysOn"); 245 try { 246 if (!mVibratorInfo.hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) { 247 return; 248 } 249 synchronized (mLock) { 250 if (prebaked == null) { 251 mNativeWrapper.alwaysOnDisable(id); 252 } else { 253 mNativeWrapper.alwaysOnEnable(id, prebaked.getEffectId(), 254 prebaked.getEffectStrength()); 255 } 256 } 257 } finally { 258 Trace.traceEnd(TRACE_TAG_VIBRATOR); 259 } 260 } 261 262 /** Set the vibration amplitude. This will NOT affect the state of {@link #isVibrating()}. */ setAmplitude(float amplitude)263 public void setAmplitude(float amplitude) { 264 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#setAmplitude"); 265 try { 266 synchronized (mLock) { 267 if (mVibratorInfo.hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) { 268 mNativeWrapper.setAmplitude(amplitude); 269 } 270 if (mCurrentState == VibratorState.VIBRATING) { 271 mCurrentAmplitude = amplitude; 272 } 273 } 274 } finally { 275 Trace.traceEnd(TRACE_TAG_VIBRATOR); 276 } 277 } 278 279 /** 280 * Turn on the vibrator for {@code milliseconds} time, using {@code vibrationId} for completion 281 * callback to {@link OnVibrationCompleteListener}. 282 * 283 * <p>This will affect the state of {@link #isVibrating()}. 284 * 285 * @return The positive duration of the vibration started, if successful, zero if the vibrator 286 * do not support the input or a negative number if the operation failed. 287 */ on(long milliseconds, long vibrationId, long stepId)288 public long on(long milliseconds, long vibrationId, long stepId) { 289 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on"); 290 try { 291 synchronized (mLock) { 292 long duration = mNativeWrapper.on(milliseconds, vibrationId, stepId); 293 if (duration > 0) { 294 mCurrentAmplitude = -1; 295 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 296 } 297 return duration; 298 } 299 } finally { 300 Trace.traceEnd(TRACE_TAG_VIBRATOR); 301 } 302 } 303 304 /** 305 * Plays vendor vibration effect, using {@code vibrationId} for completion callback to 306 * {@link OnVibrationCompleteListener}. 307 * 308 * <p>This will affect the state of {@link #isVibrating()}. 309 * 310 * @return The positive duration of the vibration started, if successful, zero if the vibrator 311 * do not support the input or a negative number if the operation failed. 312 */ on(VibrationEffect.VendorEffect vendorEffect, long vibrationId, long stepId)313 public long on(VibrationEffect.VendorEffect vendorEffect, long vibrationId, long stepId) { 314 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (vendor)"); 315 synchronized (mLock) { 316 Parcel vendorData = Parcel.obtain(); 317 try { 318 vendorEffect.getVendorData().writeToParcel(vendorData, /* flags= */ 0); 319 vendorData.setDataPosition(0); 320 long duration = mNativeWrapper.performVendorEffect(vendorData, 321 vendorEffect.getEffectStrength(), vendorEffect.getScale(), 322 vendorEffect.getAdaptiveScale(), vibrationId, stepId); 323 if (duration > 0) { 324 mCurrentAmplitude = -1; 325 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 326 } 327 return duration; 328 } finally { 329 vendorData.recycle(); 330 Trace.traceEnd(TRACE_TAG_VIBRATOR); 331 } 332 } 333 } 334 335 /** 336 * Plays predefined vibration effect, using {@code vibrationId} for completion callback to 337 * {@link OnVibrationCompleteListener}. 338 * 339 * <p>This will affect the state of {@link #isVibrating()}. 340 * 341 * @return The positive duration of the vibration started, if successful, zero if the vibrator 342 * do not support the input or a negative number if the operation failed. 343 */ on(PrebakedSegment prebaked, long vibrationId, long stepId)344 public long on(PrebakedSegment prebaked, long vibrationId, long stepId) { 345 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (Prebaked)"); 346 try { 347 synchronized (mLock) { 348 long duration = mNativeWrapper.perform(prebaked.getEffectId(), 349 prebaked.getEffectStrength(), vibrationId, stepId); 350 if (duration > 0) { 351 mCurrentAmplitude = -1; 352 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 353 } 354 return duration; 355 } 356 } finally { 357 Trace.traceEnd(TRACE_TAG_VIBRATOR); 358 } 359 } 360 361 /** 362 * Plays a composition of vibration primitives, using {@code vibrationId} for completion 363 * callback to {@link OnVibrationCompleteListener}. 364 * 365 * <p>This will affect the state of {@link #isVibrating()}. 366 * 367 * @return The positive duration of the vibration started, if successful, zero if the vibrator 368 * do not support the input or a negative number if the operation failed. 369 */ on(PrimitiveSegment[] primitives, long vibrationId, long stepId)370 public long on(PrimitiveSegment[] primitives, long vibrationId, long stepId) { 371 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (Primitive)"); 372 try { 373 if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) { 374 return 0; 375 } 376 synchronized (mLock) { 377 long duration = mNativeWrapper.compose(primitives, vibrationId, stepId); 378 if (duration > 0) { 379 mCurrentAmplitude = -1; 380 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 381 } 382 return duration; 383 } 384 } finally { 385 Trace.traceEnd(TRACE_TAG_VIBRATOR); 386 } 387 } 388 389 /** 390 * Plays a composition of pwle primitives, using {@code vibrationId} for completion callback 391 * to {@link OnVibrationCompleteListener}. 392 * 393 * <p>This will affect the state of {@link #isVibrating()}. 394 * 395 * @return The duration of the effect playing, or 0 if unsupported. 396 */ on(RampSegment[] primitives, long vibrationId, long stepId)397 public long on(RampSegment[] primitives, long vibrationId, long stepId) { 398 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE)"); 399 try { 400 if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS)) { 401 return 0; 402 } 403 synchronized (mLock) { 404 int braking = mVibratorInfo.getDefaultBraking(); 405 long duration = mNativeWrapper.composePwle( 406 primitives, braking, vibrationId, stepId); 407 if (duration > 0) { 408 mCurrentAmplitude = -1; 409 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 410 } 411 return duration; 412 } 413 } finally { 414 Trace.traceEnd(TRACE_TAG_VIBRATOR); 415 } 416 } 417 418 /** 419 * Plays a composition of pwle v2 points, using {@code vibrationId} for completion callback 420 * to {@link OnVibrationCompleteListener}. 421 * 422 * <p>This will affect the state of {@link #isVibrating()}. 423 * 424 * @return The duration of the effect playing, or 0 if unsupported. 425 */ on(PwlePoint[] pwlePoints, long vibrationId, long stepId)426 public long on(PwlePoint[] pwlePoints, long vibrationId, long stepId) { 427 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#on (PWLE v2)"); 428 try { 429 if (!mVibratorInfo.hasCapability(IVibrator.CAP_COMPOSE_PWLE_EFFECTS_V2)) { 430 return 0; 431 } 432 synchronized (mLock) { 433 long duration = mNativeWrapper.composePwleV2(pwlePoints, vibrationId, stepId); 434 if (duration > 0) { 435 mCurrentAmplitude = -1; 436 updateStateAndNotifyListenersLocked(VibratorState.VIBRATING); 437 } 438 return duration; 439 } 440 } finally { 441 Trace.traceEnd(TRACE_TAG_VIBRATOR); 442 } 443 } 444 445 /** 446 * Turns off the vibrator and disables completion callback to any pending vibration. 447 * 448 * <p>This will affect the state of {@link #isVibrating()}. 449 */ off()450 public void off() { 451 Trace.traceBegin(TRACE_TAG_VIBRATOR, "VibratorController#off"); 452 try { 453 synchronized (mLock) { 454 mNativeWrapper.off(); 455 mCurrentAmplitude = 0; 456 updateStateAndNotifyListenersLocked(VibratorState.IDLE); 457 } 458 } finally { 459 Trace.traceEnd(TRACE_TAG_VIBRATOR); 460 } 461 } 462 463 /** 464 * Resets the vibrator hardware to a default state. 465 * This turns the vibrator off, which will affect the state of {@link #isVibrating()}. 466 */ reset()467 public void reset() { 468 setExternalControl(false); 469 off(); 470 } 471 472 @Override toString()473 public String toString() { 474 return "VibratorController{" 475 + "mVibratorInfo=" + mVibratorInfo 476 + ", mVibratorInfoLoadSuccessful=" + mVibratorInfoLoadSuccessful 477 + ", mCurrentState=" + mCurrentState.name() 478 + ", mCurrentAmplitude=" + mCurrentAmplitude 479 + ", mVibratorStateListeners count=" 480 + mVibratorStateListeners.getRegisteredCallbackCount() 481 + '}'; 482 } 483 dump(IndentingPrintWriter pw)484 void dump(IndentingPrintWriter pw) { 485 pw.println("Vibrator (id=" + mVibratorInfo.getId() + "):"); 486 pw.increaseIndent(); 487 pw.println("currentState = " + mCurrentState.name()); 488 pw.println("currentAmplitude = " + mCurrentAmplitude); 489 pw.println("vibratorInfoLoadSuccessful = " + mVibratorInfoLoadSuccessful); 490 pw.println("vibratorStateListener size = " 491 + mVibratorStateListeners.getRegisteredCallbackCount()); 492 mVibratorInfo.dump(pw); 493 pw.decreaseIndent(); 494 } 495 496 /** 497 * Updates current vibrator state and notify listeners if {@link #isVibrating()} result changed. 498 */ 499 @GuardedBy("mLock") updateStateAndNotifyListenersLocked(VibratorState state)500 private void updateStateAndNotifyListenersLocked(VibratorState state) { 501 boolean previousIsVibrating = isVibrating(mCurrentState); 502 final boolean newIsVibrating = isVibrating(state); 503 mCurrentState = state; 504 if (previousIsVibrating != newIsVibrating) { 505 // The broadcast method is safe w.r.t. register/unregister listener methods, but lock 506 // is required here to guarantee delivery order. 507 mVibratorStateListeners.broadcast( 508 listener -> notifyStateListener(listener, newIsVibrating)); 509 } 510 } 511 notifyStateListener(IVibratorStateListener listener, boolean isVibrating)512 private void notifyStateListener(IVibratorStateListener listener, boolean isVibrating) { 513 try { 514 listener.onVibrating(isVibrating); 515 } catch (RemoteException | RuntimeException e) { 516 Slog.e(TAG, "Vibrator state listener failed to call", e); 517 } 518 } 519 520 /** Returns true only if given state is not {@link VibratorState#IDLE}. */ isVibrating(VibratorState state)521 private static boolean isVibrating(VibratorState state) { 522 return state != VibratorState.IDLE; 523 } 524 525 /** Wrapper around the static-native methods of {@link VibratorController} for tests. */ 526 @VisibleForTesting 527 public static class NativeWrapper { 528 /** 529 * Initializes the native part of this controller, creating a global reference to given 530 * {@link OnVibrationCompleteListener} and returns a newly allocated native pointer. This 531 * wrapper is responsible for deleting this pointer by calling the method pointed 532 * by {@link #getNativeFinalizer()}. 533 * 534 * <p><b>Note:</b> Make sure the given implementation of {@link OnVibrationCompleteListener} 535 * do not hold any strong reference to the instance responsible for deleting the returned 536 * pointer, to avoid creating a cyclic GC root reference. 537 */ nativeInit(int vibratorId, OnVibrationCompleteListener listener)538 private static native long nativeInit(int vibratorId, OnVibrationCompleteListener listener); 539 540 /** 541 * Returns pointer to native function responsible for cleaning up the native pointer 542 * allocated and returned by {@link #nativeInit(int, OnVibrationCompleteListener)}. 543 */ getNativeFinalizer()544 private static native long getNativeFinalizer(); 545 isAvailable(long nativePtr)546 private static native boolean isAvailable(long nativePtr); 547 on(long nativePtr, long milliseconds, long vibrationId, long stepId)548 private static native long on(long nativePtr, long milliseconds, long vibrationId, 549 long stepId); 550 off(long nativePtr)551 private static native void off(long nativePtr); 552 setAmplitude(long nativePtr, float amplitude)553 private static native void setAmplitude(long nativePtr, float amplitude); 554 performEffect(long nativePtr, long effect, long strength, long vibrationId, long stepId)555 private static native long performEffect(long nativePtr, long effect, long strength, 556 long vibrationId, long stepId); 557 performVendorEffect(long nativePtr, Parcel vendorData, long strength, float scale, float adaptiveScale, long vibrationId, long stepId)558 private static native long performVendorEffect(long nativePtr, Parcel vendorData, 559 long strength, float scale, float adaptiveScale, long vibrationId, long stepId); 560 performComposedEffect(long nativePtr, PrimitiveSegment[] effect, long vibrationId, long stepId)561 private static native long performComposedEffect(long nativePtr, PrimitiveSegment[] effect, 562 long vibrationId, long stepId); 563 performPwleEffect(long nativePtr, RampSegment[] effect, int braking, long vibrationId, long stepId)564 private static native long performPwleEffect(long nativePtr, RampSegment[] effect, 565 int braking, long vibrationId, long stepId); 566 performPwleV2Effect(long nativePtr, PwlePoint[] effect, long vibrationId, long stepId)567 private static native long performPwleV2Effect(long nativePtr, PwlePoint[] effect, 568 long vibrationId, long stepId); 569 setExternalControl(long nativePtr, boolean enabled)570 private static native void setExternalControl(long nativePtr, boolean enabled); 571 alwaysOnEnable(long nativePtr, long id, long effect, long strength)572 private static native void alwaysOnEnable(long nativePtr, long id, long effect, 573 long strength); 574 alwaysOnDisable(long nativePtr, long id)575 private static native void alwaysOnDisable(long nativePtr, long id); 576 getInfo(long nativePtr, VibratorInfo.Builder infoBuilder)577 private static native boolean getInfo(long nativePtr, VibratorInfo.Builder infoBuilder); 578 579 private long mNativePtr = 0; 580 581 /** Initializes native controller and allocation registry to destroy native instances. */ init(int vibratorId, OnVibrationCompleteListener listener)582 public void init(int vibratorId, OnVibrationCompleteListener listener) { 583 mNativePtr = nativeInit(vibratorId, listener); 584 long finalizerPtr = getNativeFinalizer(); 585 586 if (finalizerPtr != 0) { 587 NativeAllocationRegistry registry = 588 NativeAllocationRegistry.createMalloced( 589 VibratorController.class.getClassLoader(), finalizerPtr); 590 registry.registerNativeAllocation(this, mNativePtr); 591 } 592 } 593 594 /** Check if the vibrator is currently available. */ isAvailable()595 public boolean isAvailable() { 596 return isAvailable(mNativePtr); 597 } 598 599 /** Turns vibrator on for given time. */ on(long milliseconds, long vibrationId, long stepId)600 public long on(long milliseconds, long vibrationId, long stepId) { 601 return on(mNativePtr, milliseconds, vibrationId, stepId); 602 } 603 604 /** Turns vibrator off. */ off()605 public void off() { 606 off(mNativePtr); 607 } 608 609 /** Sets the amplitude for the vibrator to run. */ setAmplitude(float amplitude)610 public void setAmplitude(float amplitude) { 611 setAmplitude(mNativePtr, amplitude); 612 } 613 614 /** Turns vibrator on to perform one of the supported effects. */ perform(long effect, long strength, long vibrationId, long stepId)615 public long perform(long effect, long strength, long vibrationId, long stepId) { 616 return performEffect(mNativePtr, effect, strength, vibrationId, stepId); 617 } 618 619 /** Turns vibrator on to perform a vendor-specific effect. */ performVendorEffect(Parcel vendorData, long strength, float scale, float adaptiveScale, long vibrationId, long stepId)620 public long performVendorEffect(Parcel vendorData, long strength, float scale, 621 float adaptiveScale, long vibrationId, long stepId) { 622 return performVendorEffect(mNativePtr, vendorData, strength, scale, adaptiveScale, 623 vibrationId, stepId); 624 } 625 626 /** Turns vibrator on to perform effect composed of give primitives effect. */ compose(PrimitiveSegment[] primitives, long vibrationId, long stepId)627 public long compose(PrimitiveSegment[] primitives, long vibrationId, long stepId) { 628 return performComposedEffect(mNativePtr, primitives, vibrationId, stepId); 629 } 630 631 /** Turns vibrator on to perform PWLE effect composed of given primitives. */ composePwle(RampSegment[] primitives, int braking, long vibrationId, long stepId)632 public long composePwle(RampSegment[] primitives, int braking, long vibrationId, 633 long stepId) { 634 return performPwleEffect(mNativePtr, primitives, braking, vibrationId, stepId); 635 } 636 637 /** Turns vibrator on to perform PWLE effect composed of given points. */ composePwleV2(PwlePoint[] pwlePoints, long vibrationId, long stepId)638 public long composePwleV2(PwlePoint[] pwlePoints, long vibrationId, long stepId) { 639 return performPwleV2Effect(mNativePtr, pwlePoints, vibrationId, stepId); 640 } 641 642 /** Enabled the device vibrator to be controlled by another service. */ setExternalControl(boolean enabled)643 public void setExternalControl(boolean enabled) { 644 setExternalControl(mNativePtr, enabled); 645 } 646 647 /** Enable always-on vibration with given id and effect. */ alwaysOnEnable(long id, long effect, long strength)648 public void alwaysOnEnable(long id, long effect, long strength) { 649 alwaysOnEnable(mNativePtr, id, effect, strength); 650 } 651 652 /** Disable always-on vibration for given id. */ alwaysOnDisable(long id)653 public void alwaysOnDisable(long id) { 654 alwaysOnDisable(mNativePtr, id); 655 } 656 657 /** 658 * Loads device vibrator metadata and returns true if all metadata was loaded successfully. 659 */ getInfo(VibratorInfo.Builder infoBuilder)660 public boolean getInfo(VibratorInfo.Builder infoBuilder) { 661 return getInfo(mNativePtr, infoBuilder); 662 } 663 } 664 } 665