blob: f5e6c45c75b87aa1218637e4039a70607861bb86 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "VibratorController"
#include <android/hardware/vibrator/1.3/IVibrator.h>
#include <android/hardware/vibrator/IVibrator.h>
#include <nativehelper/JNIHelp.h>
#include "android_runtime/AndroidRuntime.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include <utils/Log.h>
#include <utils/misc.h>
#include <vibratorservice/VibratorHalController.h>
#include "com_android_server_vibrator_VibratorManagerService.h"
namespace V1_0 = android::hardware::vibrator::V1_0;
namespace V1_3 = android::hardware::vibrator::V1_3;
namespace aidl = android::hardware::vibrator;
namespace android {
static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnComplete;
static jclass sFrequencyProfileClass;
static jmethodID sFrequencyProfileCtor;
static struct {
jmethodID setCapabilities;
jmethodID setSupportedEffects;
jmethodID setSupportedBraking;
jmethodID setPwlePrimitiveDurationMax;
jmethodID setPwleSizeMax;
jmethodID setSupportedPrimitive;
jmethodID setPrimitiveDelayMax;
jmethodID setCompositionSizeMax;
jmethodID setQFactor;
jmethodID setFrequencyProfile;
} sVibratorInfoBuilderClassInfo;
static struct {
jfieldID id;
jfieldID scale;
jfieldID delay;
} sPrimitiveClassInfo;
static struct {
jfieldID startAmplitude;
jfieldID endAmplitude;
jfieldID startFrequencyHz;
jfieldID endFrequencyHz;
jfieldID duration;
} sRampClassInfo;
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) ==
static_cast<uint8_t>(aidl::EffectStrength::LIGHT));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) ==
static_cast<uint8_t>(aidl::EffectStrength::MEDIUM));
static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) ==
static_cast<uint8_t>(aidl::EffectStrength::STRONG));
static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) ==
static_cast<uint8_t>(aidl::Effect::CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) ==
static_cast<uint8_t>(aidl::Effect::DOUBLE_CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::TICK) == static_cast<uint8_t>(aidl::Effect::TICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::THUD) == static_cast<uint8_t>(aidl::Effect::THUD));
static_assert(static_cast<uint8_t>(V1_3::Effect::POP) == static_cast<uint8_t>(aidl::Effect::POP));
static_assert(static_cast<uint8_t>(V1_3::Effect::HEAVY_CLICK) ==
static_cast<uint8_t>(aidl::Effect::HEAVY_CLICK));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_1) ==
static_cast<uint8_t>(aidl::Effect::RINGTONE_1));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_2) ==
static_cast<uint8_t>(aidl::Effect::RINGTONE_2));
static_assert(static_cast<uint8_t>(V1_3::Effect::RINGTONE_15) ==
static_cast<uint8_t>(aidl::Effect::RINGTONE_15));
static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) ==
static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK));
static std::shared_ptr<vibrator::HalController> findVibrator(int32_t vibratorId) {
vibrator::ManagerHalController* manager =
android_server_vibrator_VibratorManagerService_getManager();
if (manager == nullptr) {
return nullptr;
}
auto result = manager->getVibrator(vibratorId);
return result.isOk() ? std::move(result.value()) : nullptr;
}
class VibratorControllerWrapper {
public:
VibratorControllerWrapper(JNIEnv* env, int32_t vibratorId, jobject callbackListener)
: mHal(findVibrator(vibratorId)),
mVibratorId(vibratorId),
mCallbackListener(env->NewGlobalRef(callbackListener)) {
LOG_ALWAYS_FATAL_IF(mHal == nullptr,
"Failed to connect to vibrator HAL, or vibratorId is invalid");
LOG_ALWAYS_FATAL_IF(mCallbackListener == nullptr,
"Unable to create global reference to vibration callback handler");
}
~VibratorControllerWrapper() {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
jniEnv->DeleteGlobalRef(mCallbackListener);
}
int32_t getVibratorId() const { return mVibratorId; }
vibrator::Info getVibratorInfo() { return mHal->getInfo(); }
void initHal() { mHal->init(); }
template <typename T>
vibrator::HalResult<T> halCall(const vibrator::HalFunction<vibrator::HalResult<T>>& fn,
const char* functionName) {
return mHal->doWithRetry(fn, functionName);
}
std::function<void()> createCallback(jlong vibrationId) {
return [vibrationId, this]() {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
jniEnv->CallVoidMethod(mCallbackListener, sMethodIdOnComplete, mVibratorId,
vibrationId);
};
}
private:
const std::shared_ptr<vibrator::HalController> mHal;
const int32_t mVibratorId;
const jobject mCallbackListener;
};
static aidl::BrakingPwle brakingPwle(aidl::Braking braking, int32_t duration) {
aidl::BrakingPwle pwle;
pwle.braking = braking;
pwle.duration = duration;
return pwle;
}
static aidl::ActivePwle activePwleFromJavaPrimitive(JNIEnv* env, jobject ramp) {
aidl::ActivePwle pwle;
pwle.startAmplitude =
static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.startAmplitude));
pwle.endAmplitude = static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.endAmplitude));
pwle.startFrequency =
static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.startFrequencyHz));
pwle.endFrequency = static_cast<float>(env->GetFloatField(ramp, sRampClassInfo.endFrequencyHz));
pwle.duration = static_cast<int32_t>(env->GetIntField(ramp, sRampClassInfo.duration));
return pwle;
}
/* Return true if braking is not NONE and the active PWLE starts and ends with zero amplitude. */
static bool shouldBeReplacedWithBraking(aidl::ActivePwle activePwle, aidl::Braking braking) {
return (braking != aidl::Braking::NONE) && (activePwle.startAmplitude == 0) &&
(activePwle.endAmplitude == 0);
}
/* Return true if braking is not NONE and the active PWLE only ends with zero amplitude. */
static bool shouldAddLastBraking(aidl::ActivePwle lastActivePwle, aidl::Braking braking) {
return (braking != aidl::Braking::NONE) && (lastActivePwle.startAmplitude > 0) &&
(lastActivePwle.endAmplitude == 0);
}
static aidl::CompositeEffect effectFromJavaPrimitive(JNIEnv* env, jobject primitive) {
aidl::CompositeEffect effect;
effect.primitive = static_cast<aidl::CompositePrimitive>(
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 destroyNativeWrapper(void* ptr) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper) {
delete wrapper;
}
}
static jlong vibratorNativeInit(JNIEnv* env, jclass /* clazz */, jint vibratorId,
jobject callbackListener) {
std::unique_ptr<VibratorControllerWrapper> wrapper =
std::make_unique<VibratorControllerWrapper>(env, vibratorId, callbackListener);
wrapper->initHal();
return reinterpret_cast<jlong>(wrapper.release());
}
static jlong vibratorGetNativeFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
return static_cast<jlong>(reinterpret_cast<uintptr_t>(&destroyNativeWrapper));
}
static jboolean vibratorIsAvailable(JNIEnv* env, jclass /* clazz */, jlong ptr) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorIsAvailable failed because native wrapper was not initialized");
return JNI_FALSE;
}
auto pingFn = [](vibrator::HalWrapper* hal) { return hal->ping(); };
return wrapper->halCall<void>(pingFn, "ping").isOk() ? JNI_TRUE : JNI_FALSE;
}
static jlong vibratorOn(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong timeoutMs,
jlong vibrationId) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorOn failed because native wrapper was not initialized");
return -1;
}
auto callback = wrapper->createCallback(vibrationId);
auto onFn = [timeoutMs, &callback](vibrator::HalWrapper* hal) {
return hal->on(std::chrono::milliseconds(timeoutMs), callback);
};
auto result = wrapper->halCall<void>(onFn, "on");
return result.isOk() ? timeoutMs : (result.isUnsupported() ? 0 : -1);
}
static void vibratorOff(JNIEnv* env, jclass /* clazz */, jlong ptr) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorOff failed because native wrapper was not initialized");
return;
}
auto offFn = [](vibrator::HalWrapper* hal) { return hal->off(); };
wrapper->halCall<void>(offFn, "off");
}
static void vibratorSetAmplitude(JNIEnv* env, jclass /* clazz */, jlong ptr, jfloat amplitude) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorSetAmplitude failed because native wrapper was not initialized");
return;
}
auto setAmplitudeFn = [amplitude](vibrator::HalWrapper* hal) {
return hal->setAmplitude(static_cast<float>(amplitude));
};
wrapper->halCall<void>(setAmplitudeFn, "setAmplitude");
}
static void vibratorSetExternalControl(JNIEnv* env, jclass /* clazz */, jlong ptr,
jboolean enabled) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorSetExternalControl failed because native wrapper was not initialized");
return;
}
auto setExternalControlFn = [enabled](vibrator::HalWrapper* hal) {
return hal->setExternalControl(enabled);
};
wrapper->halCall<void>(setExternalControlFn, "setExternalControl");
}
static jlong vibratorPerformEffect(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong effect,
jlong strength, jlong vibrationId) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorPerformEffect failed because native wrapper was not initialized");
return -1;
}
aidl::Effect effectType = static_cast<aidl::Effect>(effect);
aidl::EffectStrength effectStrength = static_cast<aidl::EffectStrength>(strength);
auto callback = wrapper->createCallback(vibrationId);
auto performEffectFn = [effectType, effectStrength, &callback](vibrator::HalWrapper* hal) {
return hal->performEffect(effectType, effectStrength, callback);
};
auto result = wrapper->halCall<std::chrono::milliseconds>(performEffectFn, "performEffect");
return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1);
}
static jlong vibratorPerformComposedEffect(JNIEnv* env, jclass /* clazz */, jlong ptr,
jobjectArray composition, jlong vibrationId) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorPerformComposedEffect failed because native wrapper was not initialized");
return -1;
}
size_t size = env->GetArrayLength(composition);
std::vector<aidl::CompositeEffect> effects;
for (size_t i = 0; i < size; i++) {
jobject element = env->GetObjectArrayElement(composition, i);
effects.push_back(effectFromJavaPrimitive(env, element));
}
auto callback = wrapper->createCallback(vibrationId);
auto performComposedEffectFn = [&effects, &callback](vibrator::HalWrapper* hal) {
return hal->performComposedEffect(effects, callback);
};
auto result = wrapper->halCall<std::chrono::milliseconds>(performComposedEffectFn,
"performComposedEffect");
return result.isOk() ? result.value().count() : (result.isUnsupported() ? 0 : -1);
}
static jlong vibratorPerformPwleEffect(JNIEnv* env, jclass /* clazz */, jlong ptr,
jobjectArray waveform, jint brakingId, jlong vibrationId) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorPerformPwleEffect failed because native wrapper was not initialized");
return -1;
}
aidl::Braking braking = static_cast<aidl::Braking>(brakingId);
size_t size = env->GetArrayLength(waveform);
std::vector<aidl::PrimitivePwle> primitives;
std::chrono::milliseconds totalDuration(0);
for (size_t i = 0; i < size; i++) {
jobject element = env->GetObjectArrayElement(waveform, i);
aidl::ActivePwle activePwle = activePwleFromJavaPrimitive(env, element);
if ((i > 0) && shouldBeReplacedWithBraking(activePwle, braking)) {
primitives.push_back(brakingPwle(braking, activePwle.duration));
} else {
primitives.push_back(activePwle);
}
totalDuration += std::chrono::milliseconds(activePwle.duration);
if ((i == (size - 1)) && shouldAddLastBraking(activePwle, braking)) {
primitives.push_back(brakingPwle(braking, 0 /* duration */));
}
}
auto callback = wrapper->createCallback(vibrationId);
auto performPwleEffectFn = [&primitives, &callback](vibrator::HalWrapper* hal) {
return hal->performPwleEffect(primitives, callback);
};
auto result = wrapper->halCall<void>(performPwleEffectFn, "performPwleEffect");
return result.isOk() ? totalDuration.count() : (result.isUnsupported() ? 0 : -1);
}
static void vibratorAlwaysOnEnable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id,
jlong effect, jlong strength) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorAlwaysOnEnable failed because native wrapper was not initialized");
return;
}
auto alwaysOnEnableFn = [id, effect, strength](vibrator::HalWrapper* hal) {
return hal->alwaysOnEnable(static_cast<int32_t>(id), static_cast<aidl::Effect>(effect),
static_cast<aidl::EffectStrength>(strength));
};
wrapper->halCall<void>(alwaysOnEnableFn, "alwaysOnEnable");
}
static void vibratorAlwaysOnDisable(JNIEnv* env, jclass /* clazz */, jlong ptr, jlong id) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorAlwaysOnDisable failed because native wrapper was not initialized");
return;
}
auto alwaysOnDisableFn = [id](vibrator::HalWrapper* hal) {
return hal->alwaysOnDisable(static_cast<int32_t>(id));
};
wrapper->halCall<void>(alwaysOnDisableFn, "alwaysOnDisable");
}
static jboolean vibratorGetInfo(JNIEnv* env, jclass /* clazz */, jlong ptr,
jobject vibratorInfoBuilder) {
VibratorControllerWrapper* wrapper = reinterpret_cast<VibratorControllerWrapper*>(ptr);
if (wrapper == nullptr) {
ALOGE("vibratorGetInfo failed because native wrapper was not initialized");
return JNI_FALSE;
}
vibrator::Info info = wrapper->getVibratorInfo();
if (info.capabilities.isOk()) {
env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setCapabilities,
static_cast<jlong>(info.capabilities.value()));
}
if (info.supportedEffects.isOk()) {
std::vector<aidl::Effect> effects = info.supportedEffects.value();
jintArray supportedEffects = env->NewIntArray(effects.size());
env->SetIntArrayRegion(supportedEffects, 0, effects.size(),
reinterpret_cast<jint*>(effects.data()));
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setSupportedEffects, supportedEffects);
}
if (info.supportedBraking.isOk()) {
std::vector<aidl::Braking> braking = info.supportedBraking.value();
jintArray supportedBraking = env->NewIntArray(braking.size());
env->SetIntArrayRegion(supportedBraking, 0, braking.size(),
reinterpret_cast<jint*>(braking.data()));
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setSupportedBraking, supportedBraking);
}
if (info.pwlePrimitiveDurationMax.isOk()) {
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax,
static_cast<jint>(info.pwlePrimitiveDurationMax.value().count()));
}
if (info.pwleSizeMax.isOk()) {
// Use (pwleMaxSize - 1) to account for a possible extra braking segment added by the
// vibratorPerformPwleEffect method.
env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setPwleSizeMax,
static_cast<jint>(info.pwleSizeMax.value() - 1));
}
if (info.supportedPrimitives.isOk()) {
auto durations = info.primitiveDurations.valueOr({});
for (auto& primitive : info.supportedPrimitives.value()) {
auto primitiveIdx = static_cast<size_t>(primitive);
auto duration = durations.size() > primitiveIdx ? durations[primitiveIdx].count() : 0;
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setSupportedPrimitive,
static_cast<jint>(primitive), static_cast<jint>(duration));
}
}
if (info.primitiveDelayMax.isOk()) {
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax,
static_cast<jint>(info.primitiveDelayMax.value().count()));
}
if (info.compositionSizeMax.isOk()) {
env->CallObjectMethod(vibratorInfoBuilder,
sVibratorInfoBuilderClassInfo.setCompositionSizeMax,
static_cast<jint>(info.compositionSizeMax.value()));
}
if (info.qFactor.isOk()) {
env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setQFactor,
static_cast<jfloat>(info.qFactor.value()));
}
jfloat minFrequency = static_cast<jfloat>(info.minFrequency.valueOr(NAN));
jfloat resonantFrequency = static_cast<jfloat>(info.resonantFrequency.valueOr(NAN));
jfloat frequencyResolution = static_cast<jfloat>(info.frequencyResolution.valueOr(NAN));
jfloatArray maxAmplitudes = nullptr;
if (info.maxAmplitudes.isOk()) {
std::vector<float> amplitudes = info.maxAmplitudes.value();
maxAmplitudes = env->NewFloatArray(amplitudes.size());
env->SetFloatArrayRegion(maxAmplitudes, 0, amplitudes.size(),
reinterpret_cast<jfloat*>(amplitudes.data()));
}
jobject frequencyProfile =
env->NewObject(sFrequencyProfileClass, sFrequencyProfileCtor, resonantFrequency,
minFrequency, frequencyResolution, maxAmplitudes);
env->CallObjectMethod(vibratorInfoBuilder, sVibratorInfoBuilderClassInfo.setFrequencyProfile,
frequencyProfile);
return info.isFailedLogged("vibratorGetInfo") ? JNI_FALSE : JNI_TRUE;
}
static const JNINativeMethod method_table[] = {
{"nativeInit",
"(ILcom/android/server/vibrator/VibratorController$OnVibrationCompleteListener;)J",
(void*)vibratorNativeInit},
{"getNativeFinalizer", "()J", (void*)vibratorGetNativeFinalizer},
{"isAvailable", "(J)Z", (void*)vibratorIsAvailable},
{"on", "(JJJ)J", (void*)vibratorOn},
{"off", "(J)V", (void*)vibratorOff},
{"setAmplitude", "(JF)V", (void*)vibratorSetAmplitude},
{"performEffect", "(JJJJ)J", (void*)vibratorPerformEffect},
{"performComposedEffect", "(J[Landroid/os/vibrator/PrimitiveSegment;J)J",
(void*)vibratorPerformComposedEffect},
{"performPwleEffect", "(J[Landroid/os/vibrator/RampSegment;IJ)J",
(void*)vibratorPerformPwleEffect},
{"setExternalControl", "(JZ)V", (void*)vibratorSetExternalControl},
{"alwaysOnEnable", "(JJJJ)V", (void*)vibratorAlwaysOnEnable},
{"alwaysOnDisable", "(JJ)V", (void*)vibratorAlwaysOnDisable},
{"getInfo", "(JLandroid/os/VibratorInfo$Builder;)Z", (void*)vibratorGetInfo},
};
int register_android_server_vibrator_VibratorController(JavaVM* jvm, JNIEnv* env) {
sJvm = jvm;
auto listenerClassName =
"com/android/server/vibrator/VibratorController$OnVibrationCompleteListener";
jclass listenerClass = FindClassOrDie(env, listenerClassName);
sMethodIdOnComplete = GetMethodIDOrDie(env, listenerClass, "onComplete", "(IJ)V");
jclass primitiveClass = FindClassOrDie(env, "android/os/vibrator/PrimitiveSegment");
sPrimitiveClassInfo.id = GetFieldIDOrDie(env, primitiveClass, "mPrimitiveId", "I");
sPrimitiveClassInfo.scale = GetFieldIDOrDie(env, primitiveClass, "mScale", "F");
sPrimitiveClassInfo.delay = GetFieldIDOrDie(env, primitiveClass, "mDelay", "I");
jclass rampClass = FindClassOrDie(env, "android/os/vibrator/RampSegment");
sRampClassInfo.startAmplitude = GetFieldIDOrDie(env, rampClass, "mStartAmplitude", "F");
sRampClassInfo.endAmplitude = GetFieldIDOrDie(env, rampClass, "mEndAmplitude", "F");
sRampClassInfo.startFrequencyHz = GetFieldIDOrDie(env, rampClass, "mStartFrequencyHz", "F");
sRampClassInfo.endFrequencyHz = GetFieldIDOrDie(env, rampClass, "mEndFrequencyHz", "F");
sRampClassInfo.duration = GetFieldIDOrDie(env, rampClass, "mDuration", "I");
jclass frequencyProfileClass = FindClassOrDie(env, "android/os/VibratorInfo$FrequencyProfile");
sFrequencyProfileClass = static_cast<jclass>(env->NewGlobalRef(frequencyProfileClass));
sFrequencyProfileCtor = GetMethodIDOrDie(env, sFrequencyProfileClass, "<init>", "(FFF[F)V");
jclass vibratorInfoBuilderClass = FindClassOrDie(env, "android/os/VibratorInfo$Builder");
sVibratorInfoBuilderClassInfo.setCapabilities =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCapabilities",
"(J)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setSupportedEffects =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedEffects",
"([I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setSupportedBraking =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedBraking",
"([I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setPwlePrimitiveDurationMax =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwlePrimitiveDurationMax",
"(I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setPwleSizeMax =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPwleSizeMax",
"(I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setSupportedPrimitive =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setSupportedPrimitive",
"(II)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setPrimitiveDelayMax =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setPrimitiveDelayMax",
"(I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setCompositionSizeMax =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setCompositionSizeMax",
"(I)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setQFactor =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setQFactor",
"(F)Landroid/os/VibratorInfo$Builder;");
sVibratorInfoBuilderClassInfo.setFrequencyProfile =
GetMethodIDOrDie(env, vibratorInfoBuilderClass, "setFrequencyProfile",
"(Landroid/os/VibratorInfo$FrequencyProfile;)"
"Landroid/os/VibratorInfo$Builder;");
return jniRegisterNativeMethods(env,
"com/android/server/vibrator/VibratorController$NativeWrapper",
method_table, NELEM(method_table));
}
}; // namespace android