Use vibration id as callback reference in VibratorService
Instead of creating a new global reference for each Vibration jobject
for native callback we are now only keeping a local copy of a jlong
vibrationId to be passed back to a method from VibrationService.
The single global reference to VibrationService is created in
vibratorInit and used in all callbacks.
Fix: 163901838
Fix: 165045639
Fix: 164290392
Bug: 153418251
Test: atest FrameworksServicesTests:VibratorServiceTest
atest CorePerfTests:ViewPerfTest
atest CorePerfTests:VibratorPerfTest
Change-Id: I91791d0a8c524f09167bf6256faa751b957f3056
This commit is contained in:
@@ -85,6 +85,7 @@ import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class VibratorService extends IVibratorService.Stub
|
||||
implements InputManager.InputDeviceListener {
|
||||
@@ -114,6 +115,9 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private static final VibrationAttributes DEFAULT_ATTRIBUTES =
|
||||
new VibrationAttributes.Builder().build();
|
||||
|
||||
// Used to generate globally unique vibration ids.
|
||||
private final AtomicInteger mNextVibrationId = new AtomicInteger(1); // 0 = no callback
|
||||
|
||||
// A mapping from the intensity adjustment to the scaling to apply, where the intensity
|
||||
// adjustment is defined as the delta between the default intensity level and the user selected
|
||||
// intensity level. It's important that we apply the scaling on the delta between the two so
|
||||
@@ -171,34 +175,34 @@ public class VibratorService extends IVibratorService.Stub
|
||||
private int mRingIntensity;
|
||||
private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
|
||||
|
||||
static native long vibratorInit();
|
||||
static native long vibratorInit(OnCompleteListener listener);
|
||||
|
||||
static native long vibratorGetFinalizer();
|
||||
|
||||
static native boolean vibratorExists(long controllerPtr);
|
||||
static native boolean vibratorExists(long nativeServicePtr);
|
||||
|
||||
static native void vibratorOn(long controllerPtr, long milliseconds, Vibration vibration);
|
||||
static native void vibratorOn(long nativeServicePtr, long milliseconds, long vibrationId);
|
||||
|
||||
static native void vibratorOff(long controllerPtr);
|
||||
static native void vibratorOff(long nativeServicePtr);
|
||||
|
||||
static native void vibratorSetAmplitude(long controllerPtr, int amplitude);
|
||||
static native void vibratorSetAmplitude(long nativeServicePtr, int amplitude);
|
||||
|
||||
static native int[] vibratorGetSupportedEffects(long controllerPtr);
|
||||
static native int[] vibratorGetSupportedEffects(long nativeServicePtr);
|
||||
|
||||
static native int[] vibratorGetSupportedPrimitives(long controllerPtr);
|
||||
static native int[] vibratorGetSupportedPrimitives(long nativeServicePtr);
|
||||
|
||||
static native long vibratorPerformEffect(
|
||||
long controllerPtr, long effect, long strength, Vibration vibration);
|
||||
long nativeServicePtr, long effect, long strength, long vibrationId);
|
||||
|
||||
static native void vibratorPerformComposedEffect(long controllerPtr,
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration);
|
||||
static native void vibratorPerformComposedEffect(long nativeServicePtr,
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId);
|
||||
|
||||
static native void vibratorSetExternalControl(long controllerPtr, boolean enabled);
|
||||
static native void vibratorSetExternalControl(long nativeServicePtr, boolean enabled);
|
||||
|
||||
static native long vibratorGetCapabilities(long controllerPtr);
|
||||
static native void vibratorAlwaysOnEnable(long controllerPtr, long id, long effect,
|
||||
static native long vibratorGetCapabilities(long nativeServicePtr);
|
||||
static native void vibratorAlwaysOnEnable(long nativeServicePtr, long id, long effect,
|
||||
long strength);
|
||||
static native void vibratorAlwaysOnDisable(long controllerPtr, long id);
|
||||
static native void vibratorAlwaysOnDisable(long nativeServicePtr, long id);
|
||||
|
||||
private final IUidObserver mUidObserver = new IUidObserver.Stub() {
|
||||
@Override public void onUidStateChanged(int uid, int procState, long procStateSeq,
|
||||
@@ -220,12 +224,19 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
};
|
||||
|
||||
/** Listener for vibration completion callbacks from native. */
|
||||
public interface OnCompleteListener {
|
||||
|
||||
/** Callback triggered when vibration is complete, identified by {@link Vibration#id}. */
|
||||
void onComplete(long vibrationId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holder for a vibration to be played. This class can be shared with native methods for
|
||||
* hardware callback support.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public final class Vibration implements IBinder.DeathRecipient {
|
||||
private final class Vibration implements IBinder.DeathRecipient {
|
||||
|
||||
public final IBinder token;
|
||||
// Start time in CLOCK_BOOTTIME base.
|
||||
public final long startTime;
|
||||
@@ -234,6 +245,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
// not to be affected by discontinuities created by RTC adjustments.
|
||||
public final long startTimeDebug;
|
||||
public final VibrationAttributes attrs;
|
||||
public final long id;
|
||||
public final int uid;
|
||||
public final String opPkg;
|
||||
public final String reason;
|
||||
@@ -248,6 +260,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
VibrationAttributes attrs, int uid, String opPkg, String reason) {
|
||||
this.token = token;
|
||||
this.effect = effect;
|
||||
this.id = mNextVibrationId.getAndIncrement();
|
||||
this.startTime = SystemClock.elapsedRealtime();
|
||||
this.startTimeDebug = System.currentTimeMillis();
|
||||
this.attrs = attrs;
|
||||
@@ -268,19 +281,6 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback for when vibration is complete, to be called by native. */
|
||||
@VisibleForTesting
|
||||
public void onComplete() {
|
||||
synchronized (mLock) {
|
||||
if (this == mCurrentVibration) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibration finished by callback, cleaning up");
|
||||
}
|
||||
doCancelVibrateLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasTimeoutLongerThan(long millis) {
|
||||
final long duration = effect.getDuration();
|
||||
return duration >= 0 && duration > millis;
|
||||
@@ -385,14 +385,14 @@ public class VibratorService extends IVibratorService.Stub
|
||||
mNativeWrapper = injector.getNativeWrapper();
|
||||
mH = injector.createHandler(Looper.myLooper());
|
||||
|
||||
long controllerPtr = mNativeWrapper.vibratorInit();
|
||||
long nativeServicePtr = mNativeWrapper.vibratorInit(this::onVibrationComplete);
|
||||
long finalizerPtr = mNativeWrapper.vibratorGetFinalizer();
|
||||
|
||||
if (finalizerPtr != 0) {
|
||||
NativeAllocationRegistry registry =
|
||||
NativeAllocationRegistry.createMalloced(
|
||||
VibratorService.class.getClassLoader(), finalizerPtr);
|
||||
registry.registerNativeAllocation(this, controllerPtr);
|
||||
registry.registerNativeAllocation(this, nativeServicePtr);
|
||||
}
|
||||
|
||||
// Reset the hardware to a default state, in case this is a runtime
|
||||
@@ -549,6 +549,19 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/** Callback for when vibration is complete, to be called by native. */
|
||||
@VisibleForTesting
|
||||
public void onVibrationComplete(long vibrationId) {
|
||||
synchronized (mLock) {
|
||||
if (mCurrentVibration != null && mCurrentVibration.id == vibrationId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Vibration finished by callback, cleaning up");
|
||||
}
|
||||
doCancelVibrateLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Binder call
|
||||
public boolean hasVibrator() {
|
||||
return doVibratorExists();
|
||||
@@ -1266,18 +1279,18 @@ public class VibratorService extends IVibratorService.Stub
|
||||
return mNativeWrapper.vibratorExists();
|
||||
}
|
||||
|
||||
/** Vibrates with native callback trigger for {@link Vibration#onComplete()}. */
|
||||
/** Vibrates with native callback trigger for {@link #onVibrationComplete(long)}. */
|
||||
private void doVibratorOn(long millis, int amplitude, Vibration vib) {
|
||||
doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib);
|
||||
doVibratorOn(millis, amplitude, vib.uid, vib.attrs, vib.id);
|
||||
}
|
||||
|
||||
/** Vibrates without native callback. */
|
||||
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) {
|
||||
doVibratorOn(millis, amplitude, uid, attrs, /* vib= */ null);
|
||||
doVibratorOn(millis, amplitude, uid, attrs, /* vibrationId= */ 0);
|
||||
}
|
||||
|
||||
private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs,
|
||||
@Nullable Vibration vib) {
|
||||
long vibrationId) {
|
||||
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn");
|
||||
try {
|
||||
synchronized (mInputDeviceVibrators) {
|
||||
@@ -1299,7 +1312,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
// Note: ordering is important here! Many haptic drivers will reset their
|
||||
// amplitude when enabled, so we always have to enable first, then set the
|
||||
// amplitude.
|
||||
mNativeWrapper.vibratorOn(millis, vib);
|
||||
mNativeWrapper.vibratorOn(millis, vibrationId);
|
||||
doVibratorSetAmplitude(amplitude);
|
||||
}
|
||||
}
|
||||
@@ -1348,7 +1361,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
// Input devices don't support prebaked effect, so skip trying it with them.
|
||||
if (!usingInputDeviceVibrators) {
|
||||
long duration = mNativeWrapper.vibratorPerformEffect(
|
||||
prebaked.getId(), prebaked.getEffectStrength(), vib);
|
||||
prebaked.getId(), prebaked.getEffectStrength(), vib.id);
|
||||
if (duration > 0) {
|
||||
noteVibratorOnLocked(vib.uid, duration);
|
||||
return;
|
||||
@@ -1395,7 +1408,7 @@ public class VibratorService extends IVibratorService.Stub
|
||||
|
||||
PrimitiveEffect[] primitiveEffects =
|
||||
composed.getPrimitiveEffects().toArray(new PrimitiveEffect[0]);
|
||||
mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib);
|
||||
mNativeWrapper.vibratorPerformComposedEffect(primitiveEffects, vib.id);
|
||||
|
||||
// Composed effects don't actually give us an estimated duration, so we just guess here.
|
||||
noteVibratorOnLocked(vib.uid, 10 * primitiveEffects.length);
|
||||
@@ -1726,20 +1739,20 @@ public class VibratorService extends IVibratorService.Stub
|
||||
@VisibleForTesting
|
||||
public static class NativeWrapper {
|
||||
|
||||
private long mNativeControllerPtr = 0;
|
||||
private long mNativeServicePtr = 0;
|
||||
|
||||
/** Checks if vibrator exists on device. */
|
||||
public boolean vibratorExists() {
|
||||
return VibratorService.vibratorExists(mNativeControllerPtr);
|
||||
return VibratorService.vibratorExists(mNativeServicePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns native pointer to newly created controller and initializes connection to vibrator
|
||||
* HAL service.
|
||||
*/
|
||||
public long vibratorInit() {
|
||||
mNativeControllerPtr = VibratorService.vibratorInit();
|
||||
return mNativeControllerPtr;
|
||||
public long vibratorInit(OnCompleteListener listener) {
|
||||
mNativeServicePtr = VibratorService.vibratorInit(listener);
|
||||
return mNativeServicePtr;
|
||||
}
|
||||
|
||||
/** Returns pointer to native finalizer function to be called by GC. */
|
||||
@@ -1748,60 +1761,61 @@ public class VibratorService extends IVibratorService.Stub
|
||||
}
|
||||
|
||||
/** Turns vibrator on for given time. */
|
||||
public void vibratorOn(long milliseconds, @Nullable Vibration vibration) {
|
||||
VibratorService.vibratorOn(mNativeControllerPtr, milliseconds, vibration);
|
||||
public void vibratorOn(long milliseconds, long vibrationId) {
|
||||
VibratorService.vibratorOn(mNativeServicePtr, milliseconds, vibrationId);
|
||||
}
|
||||
|
||||
/** Turns vibrator off. */
|
||||
public void vibratorOff() {
|
||||
VibratorService.vibratorOff(mNativeControllerPtr);
|
||||
VibratorService.vibratorOff(mNativeServicePtr);
|
||||
}
|
||||
|
||||
/** Sets the amplitude for the vibrator to run. */
|
||||
public void vibratorSetAmplitude(int amplitude) {
|
||||
VibratorService.vibratorSetAmplitude(mNativeControllerPtr, amplitude);
|
||||
VibratorService.vibratorSetAmplitude(mNativeServicePtr, amplitude);
|
||||
}
|
||||
|
||||
/** Returns all predefined effects supported by the device vibrator. */
|
||||
public int[] vibratorGetSupportedEffects() {
|
||||
return VibratorService.vibratorGetSupportedEffects(mNativeControllerPtr);
|
||||
return VibratorService.vibratorGetSupportedEffects(mNativeServicePtr);
|
||||
}
|
||||
|
||||
/** Returns all compose primitives supported by the device vibrator. */
|
||||
public int[] vibratorGetSupportedPrimitives() {
|
||||
return VibratorService.vibratorGetSupportedPrimitives(mNativeControllerPtr);
|
||||
return VibratorService.vibratorGetSupportedPrimitives(mNativeServicePtr);
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported effects. */
|
||||
public long vibratorPerformEffect(long effect, long strength, Vibration vibration) {
|
||||
public long vibratorPerformEffect(long effect, long strength, long vibrationId) {
|
||||
return VibratorService.vibratorPerformEffect(
|
||||
mNativeControllerPtr, effect, strength, vibration);
|
||||
mNativeServicePtr, effect, strength, vibrationId);
|
||||
}
|
||||
|
||||
/** Turns vibrator on to perform one of the supported composed effects. */
|
||||
public void vibratorPerformComposedEffect(
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, Vibration vibration) {
|
||||
VibratorService.vibratorPerformComposedEffect(mNativeControllerPtr, effect, vibration);
|
||||
VibrationEffect.Composition.PrimitiveEffect[] effect, long vibrationId) {
|
||||
VibratorService.vibratorPerformComposedEffect(mNativeServicePtr, effect,
|
||||
vibrationId);
|
||||
}
|
||||
|
||||
/** Enabled the device vibrator to be controlled by another service. */
|
||||
public void vibratorSetExternalControl(boolean enabled) {
|
||||
VibratorService.vibratorSetExternalControl(mNativeControllerPtr, enabled);
|
||||
VibratorService.vibratorSetExternalControl(mNativeServicePtr, enabled);
|
||||
}
|
||||
|
||||
/** Returns all capabilities of the device vibrator. */
|
||||
public long vibratorGetCapabilities() {
|
||||
return VibratorService.vibratorGetCapabilities(mNativeControllerPtr);
|
||||
return VibratorService.vibratorGetCapabilities(mNativeServicePtr);
|
||||
}
|
||||
|
||||
/** Enable always-on vibration with given id and effect. */
|
||||
public void vibratorAlwaysOnEnable(long id, long effect, long strength) {
|
||||
VibratorService.vibratorAlwaysOnEnable(mNativeControllerPtr, id, effect, strength);
|
||||
VibratorService.vibratorAlwaysOnEnable(mNativeServicePtr, id, effect, strength);
|
||||
}
|
||||
|
||||
/** Disable always-on vibration for given id. */
|
||||
public void vibratorAlwaysOnDisable(long id) {
|
||||
VibratorService.vibratorAlwaysOnDisable(mNativeControllerPtr, id);
|
||||
VibratorService.vibratorAlwaysOnDisable(mNativeServicePtr, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,14 +40,12 @@ namespace aidl = android::hardware::vibrator;
|
||||
namespace android {
|
||||
|
||||
static JavaVM* sJvm = nullptr;
|
||||
|
||||
static jmethodID sMethodIdOnComplete;
|
||||
|
||||
static struct {
|
||||
jfieldID id;
|
||||
jfieldID scale;
|
||||
jfieldID delay;
|
||||
} gPrimitiveClassInfo;
|
||||
} sPrimitiveClassInfo;
|
||||
|
||||
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
|
||||
static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
|
||||
@@ -77,100 +75,117 @@ static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
|
||||
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
|
||||
static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
|
||||
|
||||
static inline void callVibrationOnComplete(jobject vibration) {
|
||||
if (vibration == nullptr) {
|
||||
return;
|
||||
class NativeVibratorService {
|
||||
public:
|
||||
NativeVibratorService(JNIEnv* env, jobject callbackListener)
|
||||
: mController(std::make_unique<vibrator::HalController>()),
|
||||
mCallbackListener(env->NewGlobalRef(callbackListener)) {
|
||||
LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
|
||||
"Unable to create global reference to vibration callback handler");
|
||||
}
|
||||
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
|
||||
jniEnv->CallVoidMethod(vibration, sMethodIdOnComplete);
|
||||
jniEnv->DeleteGlobalRef(vibration);
|
||||
}
|
||||
|
||||
~NativeVibratorService() {
|
||||
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
|
||||
jniEnv->DeleteGlobalRef(mCallbackListener);
|
||||
}
|
||||
|
||||
vibrator::HalController* controller() const { return mController.get(); }
|
||||
|
||||
std::function<void()> createCallback(jlong vibrationId) {
|
||||
return [vibrationId, this]() {
|
||||
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
|
||||
jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, vibrationId);
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
const std::unique_ptr<vibrator::HalController> mController;
|
||||
const jobject mCallbackListener;
|
||||
};
|
||||
|
||||
static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
|
||||
aidl::CompositeEffect effect;
|
||||
effect.primitive = static_cast<aidl::CompositePrimitive>(
|
||||
env->GetIntField(primitive, gPrimitiveClassInfo.id));
|
||||
effect.scale = static_cast<float>(env->GetFloatField(primitive, gPrimitiveClassInfo.scale));
|
||||
effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, gPrimitiveClassInfo.delay));
|
||||
env->GetIntField(primitive, sPrimitiveClassInfo.id));
|
||||
effect.scale = static_cast<float>(env->GetFloatField(primitive, sPrimitiveClassInfo.scale));
|
||||
effect.delayMs = static_cast<int32_t>(env->GetIntField(primitive, sPrimitiveClassInfo.delay));
|
||||
return effect;
|
||||
}
|
||||
|
||||
static void destroyVibratorController(void* rawVibratorController) {
|
||||
vibrator::HalController* vibratorController =
|
||||
reinterpret_cast<vibrator::HalController*>(rawVibratorController);
|
||||
if (vibratorController) {
|
||||
delete vibratorController;
|
||||
static void destroyNativeService(void* servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service) {
|
||||
delete service;
|
||||
}
|
||||
}
|
||||
|
||||
static jlong vibratorInit(JNIEnv* /* env */, jclass /* clazz */) {
|
||||
std::unique_ptr<vibrator::HalController> controller =
|
||||
std::make_unique<vibrator::HalController>();
|
||||
controller->init();
|
||||
return reinterpret_cast<jlong>(controller.release());
|
||||
static jlong vibratorInit(JNIEnv* env, jclass /* clazz */, jobject callbackListener) {
|
||||
std::unique_ptr<NativeVibratorService> service =
|
||||
std::make_unique<NativeVibratorService>(env, callbackListener);
|
||||
service->controller()->init();
|
||||
return reinterpret_cast<jlong>(service.release());
|
||||
}
|
||||
|
||||
static jlong vibratorGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyVibratorController));
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeService));
|
||||
}
|
||||
|
||||
static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorExists failed because controller was not initialized");
|
||||
static jboolean vibratorExists(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorExists failed because native service was not initialized");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
return controller->ping().isOk() ? JNI_TRUE : JNI_FALSE;
|
||||
return service->controller()->ping().isOk() ? JNI_TRUE : JNI_FALSE;
|
||||
}
|
||||
|
||||
static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong timeoutMs,
|
||||
jobject vibration) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorOn failed because controller was not initialized");
|
||||
static void vibratorOn(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong timeoutMs,
|
||||
jlong vibrationId) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorOn failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
|
||||
auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
|
||||
controller->on(std::chrono::milliseconds(timeoutMs), callback);
|
||||
auto callback = service->createCallback(vibrationId);
|
||||
service->controller()->on(std::chrono::milliseconds(timeoutMs), callback);
|
||||
}
|
||||
|
||||
static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorOff failed because controller was not initialized");
|
||||
static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorOff failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
controller->off();
|
||||
service->controller()->off();
|
||||
}
|
||||
|
||||
static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
|
||||
static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
|
||||
jint amplitude) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorSetAmplitude failed because controller was not initialized");
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorSetAmplitude failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
controller->setAmplitude(static_cast<int32_t>(amplitude));
|
||||
service->controller()->setAmplitude(static_cast<int32_t>(amplitude));
|
||||
}
|
||||
|
||||
static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
|
||||
static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
|
||||
jboolean enabled) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorSetExternalControl failed because controller was not initialized");
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorSetExternalControl failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
controller->setExternalControl(enabled);
|
||||
service->controller()->setExternalControl(enabled);
|
||||
}
|
||||
|
||||
static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorGetSupportedEffects failed because controller was not initialized");
|
||||
static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorGetSupportedEffects failed because native service was not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
auto result = controller->getSupportedEffects();
|
||||
auto result = service->controller()->getSupportedEffects();
|
||||
if (!result.isOk()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -181,14 +196,13 @@ static jintArray vibratorGetSupportedEffects(JNIEnv* env, jclass /* clazz */, jl
|
||||
return effects;
|
||||
}
|
||||
|
||||
static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */,
|
||||
jlong controllerPtr) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorGetSupportedPrimitives failed because controller was not initialized");
|
||||
static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorGetSupportedPrimitives failed because native service was not initialized");
|
||||
return nullptr;
|
||||
}
|
||||
auto result = controller->getSupportedPrimitives();
|
||||
auto result = service->controller()->getSupportedPrimitives();
|
||||
if (!result.isOk()) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -199,26 +213,25 @@ static jintArray vibratorGetSupportedPrimitives(JNIEnv* env, jclass /* clazz */,
|
||||
return primitives;
|
||||
}
|
||||
|
||||
static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
|
||||
jlong effect, jlong strength, jobject vibration) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorPerformEffect failed because controller was not initialized");
|
||||
static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong effect,
|
||||
jlong strength, jlong vibrationId) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorPerformEffect failed because native service was not initialized");
|
||||
return -1;
|
||||
}
|
||||
aidl::Effect effectType = static_cast<aidl::Effect>(effect);
|
||||
aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
|
||||
jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
|
||||
auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
|
||||
auto result = controller->performEffect(effectType, effectStrength, callback);
|
||||
auto callback = service->createCallback(vibrationId);
|
||||
auto result = service->controller()->performEffect(effectType, effectStrength, callback);
|
||||
return result.isOk() ? result.value().count() : -1;
|
||||
}
|
||||
|
||||
static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
|
||||
jobjectArray composition, jobject vibration) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorPerformComposedEffect failed because controller was not initialized");
|
||||
static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong servicePtr,
|
||||
jobjectArray composition, jlong vibrationId) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorPerformComposedEffect failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
size_t size = env->GetArrayLength(composition);
|
||||
@@ -227,54 +240,52 @@ static void vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong
|
||||
jobject element = env->GetObjectArrayElement(composition, i);
|
||||
effects.push_back(effectFromJavaPrimitive(env, element));
|
||||
}
|
||||
jobject vibrationRef = vibration == nullptr ? vibration : MakeGlobalRefOrDie(env, vibration);
|
||||
auto callback = [vibrationRef]() { callVibrationOnComplete(vibrationRef); };
|
||||
controller->performComposedEffect(effects, callback);
|
||||
auto callback = service->createCallback(vibrationId);
|
||||
service->controller()->performComposedEffect(effects, callback);
|
||||
}
|
||||
|
||||
static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong controllerPtr) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorGetCapabilities failed because controller was not initialized");
|
||||
static jlong vibratorGetCapabilities(JNIEnv* env, jclass /* clazz */, jlong servicePtr) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorGetCapabilities failed because native service was not initialized");
|
||||
return 0;
|
||||
}
|
||||
auto result = controller->getCapabilities();
|
||||
auto result = service->controller()->getCapabilities();
|
||||
return result.isOk() ? static_cast<jlong>(result.value()) : 0;
|
||||
}
|
||||
|
||||
static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr, jlong id,
|
||||
static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id,
|
||||
jlong effect, jlong strength) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorAlwaysOnEnable failed because controller was not initialized");
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorAlwaysOnEnable failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
controller->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
|
||||
static_cast<aidl::EffectStrength>(strength));
|
||||
service->controller()->alwaysOnEnable(static_cast<int32_t>(id),
|
||||
static_cast<aidl::Effect>(effect),
|
||||
static_cast<aidl::EffectStrength>(strength));
|
||||
}
|
||||
|
||||
static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong controllerPtr,
|
||||
jlong id) {
|
||||
vibrator::HalController* controller = reinterpret_cast<vibrator::HalController*>(controllerPtr);
|
||||
if (controller == nullptr) {
|
||||
ALOGE("vibratorAlwaysOnDisable failed because controller was not initialized");
|
||||
static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong servicePtr, jlong id) {
|
||||
NativeVibratorService* service = reinterpret_cast<NativeVibratorService*>(servicePtr);
|
||||
if (service == nullptr) {
|
||||
ALOGE("vibratorAlwaysOnDisable failed because native service was not initialized");
|
||||
return;
|
||||
}
|
||||
controller->alwaysOnDisable(static_cast<int32_t>(id));
|
||||
service->controller()->alwaysOnDisable(static_cast<int32_t>(id));
|
||||
}
|
||||
|
||||
static const JNINativeMethod method_table[] = {
|
||||
{"vibratorInit", "()J", (void*)vibratorInit},
|
||||
{"vibratorInit", "(Lcom/android/server/VibratorService$OnCompleteListener;)J",
|
||||
(void*)vibratorInit},
|
||||
{"vibratorGetFinalizer", "()J", (void*)vibratorGetFinalizer},
|
||||
{"vibratorExists", "(J)Z", (void*)vibratorExists},
|
||||
{"vibratorOn", "(JJLcom/android/server/VibratorService$Vibration;)V", (void*)vibratorOn},
|
||||
{"vibratorOn", "(JJJ)V", (void*)vibratorOn},
|
||||
{"vibratorOff", "(J)V", (void*)vibratorOff},
|
||||
{"vibratorSetAmplitude", "(JI)V", (void*)vibratorSetAmplitude},
|
||||
{"vibratorPerformEffect", "(JJJLcom/android/server/VibratorService$Vibration;)J",
|
||||
(void*)vibratorPerformEffect},
|
||||
{"vibratorPerformEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
|
||||
{"vibratorPerformComposedEffect",
|
||||
"(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;Lcom/android/server/"
|
||||
"VibratorService$Vibration;)V",
|
||||
"(J[Landroid/os/VibrationEffect$Composition$PrimitiveEffect;J)V",
|
||||
(void*)vibratorPerformComposedEffect},
|
||||
{"vibratorGetSupportedEffects", "(J)[I", (void*)vibratorGetSupportedEffects},
|
||||
{"vibratorGetSupportedPrimitives", "(J)[I", (void*)vibratorGetSupportedPrimitives},
|
||||
@@ -284,18 +295,17 @@ static const JNINativeMethod method_table[] = {
|
||||
{"vibratorAlwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
|
||||
};
|
||||
|
||||
int register_android_server_VibratorService(JavaVM* vm, JNIEnv* env) {
|
||||
sJvm = vm;
|
||||
sMethodIdOnComplete =
|
||||
GetMethodIDOrDie(env,
|
||||
FindClassOrDie(env, "com/android/server/VibratorService$Vibration"),
|
||||
"onComplete", "()V");
|
||||
int register_android_server_VibratorService(JavaVM* jvm, JNIEnv* env) {
|
||||
sJvm = jvm;
|
||||
jclass listenerClass =
|
||||
FindClassOrDie(env, "com/android/server/VibratorService$OnCompleteListener");
|
||||
sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(J)V");
|
||||
|
||||
jclass primitiveClass =
|
||||
FindClassOrDie(env, "android/os/VibrationEffect$Composition$PrimitiveEffect");
|
||||
gPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
|
||||
gPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
|
||||
gPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
|
||||
sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "id", "I");
|
||||
sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "scale", "F");
|
||||
sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "delay", "I");
|
||||
|
||||
return jniRegisterNativeMethods(env, "com/android/server/VibratorService", method_table,
|
||||
NELEM(method_table));
|
||||
|
||||
@@ -20,12 +20,13 @@ import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.AdditionalMatchers.gt;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.ArgumentMatchers.intThat;
|
||||
import static org.mockito.ArgumentMatchers.isNull;
|
||||
import static org.mockito.ArgumentMatchers.notNull;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -167,7 +168,7 @@ public class VibratorServiceTest {
|
||||
@Test
|
||||
public void createService_initializesNativeService() {
|
||||
createService();
|
||||
verify(mNativeWrapperMock).vibratorInit();
|
||||
verify(mNativeWrapperMock).vibratorInit(notNull());
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@@ -294,7 +295,7 @@ public class VibratorServiceTest {
|
||||
assertTrue(service.isVibrating());
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
|
||||
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(128));
|
||||
}
|
||||
|
||||
@@ -307,7 +308,7 @@ public class VibratorServiceTest {
|
||||
assertTrue(service.isVibrating());
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L), any(VibratorService.Vibration.class));
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(100L), gt(0L));
|
||||
verify(mNativeWrapperMock, never()).vibratorSetAmplitude(anyInt());
|
||||
}
|
||||
|
||||
@@ -321,10 +322,8 @@ public class VibratorServiceTest {
|
||||
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
|
||||
any(VibratorService.Vibration.class));
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), gt(0L));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -343,7 +342,7 @@ public class VibratorServiceTest {
|
||||
|
||||
verify(mNativeWrapperMock).vibratorOff();
|
||||
verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
primitivesCaptor.capture(), any(VibratorService.Vibration.class));
|
||||
primitivesCaptor.capture(), gt(0L));
|
||||
|
||||
// Check all primitive effect fields are passed down to the HAL.
|
||||
assertEquals(1, primitivesCaptor.getValue().length);
|
||||
@@ -368,7 +367,7 @@ public class VibratorServiceTest {
|
||||
|
||||
// Wait for VibrateThread to turn vibrator ON with total timing and no callback.
|
||||
Thread.sleep(5);
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(30L), isNull());
|
||||
verify(mNativeWrapperMock).vibratorOn(eq(30L), eq(0L));
|
||||
|
||||
// First amplitude set right away.
|
||||
verify(mNativeWrapperMock).vibratorSetAmplitude(eq(100));
|
||||
@@ -384,11 +383,11 @@ public class VibratorServiceTest {
|
||||
|
||||
@Test
|
||||
public void vibrate_withOneShotAndNativeCallbackTriggered_finishesVibration() {
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
|
||||
VibratorService service = createService();
|
||||
doAnswer(invocation -> {
|
||||
service.onVibrationComplete(invocation.getArgument(1));
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE));
|
||||
@@ -396,7 +395,7 @@ public class VibratorServiceTest {
|
||||
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(100L),
|
||||
any(VibratorService.Vibration.class));
|
||||
gt(0L));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@@ -404,12 +403,11 @@ public class VibratorServiceTest {
|
||||
public void vibrate_withPrebakedAndNativeCallbackTriggered_finishesVibration() {
|
||||
when(mNativeWrapperMock.vibratorGetSupportedEffects())
|
||||
.thenReturn(new int[]{VibrationEffect.EFFECT_CLICK});
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(2)).onComplete();
|
||||
return 10_000L; // 10s
|
||||
}).when(mNativeWrapperMock).vibratorPerformEffect(
|
||||
anyLong(), anyLong(), any(VibratorService.Vibration.class));
|
||||
VibratorService service = createService();
|
||||
doAnswer(invocation -> {
|
||||
service.onVibrationComplete(invocation.getArgument(2));
|
||||
return 10_000L; // 10s
|
||||
}).when(mNativeWrapperMock).vibratorPerformEffect(anyLong(), anyLong(), anyLong());
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
vibrate(service, VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK));
|
||||
@@ -419,7 +417,7 @@ public class VibratorServiceTest {
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG),
|
||||
any(VibratorService.Vibration.class));
|
||||
gt(0L));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@@ -436,20 +434,19 @@ public class VibratorServiceTest {
|
||||
Thread.sleep(15);
|
||||
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), isNull());
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), isNull());
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(3L), eq(0L));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOn(eq(2L), eq(0L));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_withComposedAndNativeCallbackTriggered_finishesVibration() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(), any(VibratorService.Vibration.class));
|
||||
VibratorService service = createService();
|
||||
doAnswer(invocation -> {
|
||||
service.onVibrationComplete(invocation.getArgument(1));
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorPerformComposedEffect(any(), anyLong());
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
@@ -460,32 +457,7 @@ public class VibratorServiceTest {
|
||||
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(VibrationEffect.Composition.PrimitiveEffect[].class),
|
||||
any(VibratorService.Vibration.class));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void vibrate_whenBinderDies_cancelsVibration() {
|
||||
mockVibratorCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).binderDied();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(), any(VibratorService.Vibration.class));
|
||||
VibratorService service = createService();
|
||||
Mockito.clearInvocations(mNativeWrapperMock);
|
||||
|
||||
VibrationEffect effect = VibrationEffect.startComposition()
|
||||
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1f, 10)
|
||||
.compose();
|
||||
vibrate(service, effect);
|
||||
|
||||
InOrder inOrderVerifier = inOrder(mNativeWrapperMock);
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorPerformComposedEffect(
|
||||
any(VibrationEffect.Composition.PrimitiveEffect[].class),
|
||||
any(VibratorService.Vibration.class));
|
||||
any(VibrationEffect.Composition.PrimitiveEffect[].class), gt(0L));
|
||||
inOrderVerifier.verify(mNativeWrapperMock).vibratorOff();
|
||||
}
|
||||
|
||||
@@ -513,12 +485,11 @@ public class VibratorServiceTest {
|
||||
|
||||
@Test
|
||||
public void registerVibratorStateListener_callbacksAreTriggered() throws Exception {
|
||||
doAnswer(invocation -> {
|
||||
((VibratorService.Vibration) invocation.getArgument(1)).onComplete();
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorOn(anyLong(), any(VibratorService.Vibration.class));
|
||||
VibratorService service = createService();
|
||||
|
||||
doAnswer(invocation -> {
|
||||
service.onVibrationComplete(invocation.getArgument(1));
|
||||
return null;
|
||||
}).when(mNativeWrapperMock).vibratorOn(anyLong(), anyLong());
|
||||
service.registerVibratorStateListener(mVibratorStateListenerMock);
|
||||
verify(mVibratorStateListenerMock).onVibrating(false);
|
||||
Mockito.clearInvocations(mVibratorStateListenerMock);
|
||||
@@ -569,15 +540,15 @@ public class VibratorServiceTest {
|
||||
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), any());
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_STRONG), anyLong());
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_TICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), any());
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_MEDIUM), anyLong());
|
||||
verify(mNativeWrapperMock).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_DOUBLE_CLICK),
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), any());
|
||||
eq((long) VibrationEffect.EFFECT_STRENGTH_LIGHT), anyLong());
|
||||
verify(mNativeWrapperMock, never()).vibratorPerformEffect(
|
||||
eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), any());
|
||||
eq((long) VibrationEffect.EFFECT_HEAVY_CLICK), anyLong(), anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -644,7 +615,7 @@ public class VibratorServiceTest {
|
||||
|
||||
// Ringtone vibration is off, so only the other 3 are propagated to native.
|
||||
verify(mNativeWrapperMock, times(3)).vibratorPerformComposedEffect(
|
||||
primitivesCaptor.capture(), any());
|
||||
primitivesCaptor.capture(), anyLong());
|
||||
|
||||
List<VibrationEffect.Composition.PrimitiveEffect[]> values =
|
||||
primitivesCaptor.getAllValues();
|
||||
|
||||
Reference in New Issue
Block a user