Loading services/core/Android.bp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ java_library_static { "android.hardware.power-V1.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.tv.cec-V1.0-java", "app-compat-annotations", "app-compat-annotations", "vintf-vibrator-java", ], ], required: [ required: [ Loading @@ -50,7 +51,6 @@ java_library_static { "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.oemlock-V1.0-java", "android.hardware.oemlock-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.vibrator-V1.4-java", "android.hardware.configstore-V1.0-java", "android.hardware.configstore-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hidl.manager-V1.2-java", "android.hidl.manager-V1.2-java", Loading services/core/java/com/android/server/VibratorService.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -28,8 +28,8 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.Resources; import android.database.ContentObserver; import android.database.ContentObserver; import android.hardware.input.InputManager; import android.hardware.input.InputManager; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_4.Capabilities; import android.icu.text.DateFormat; import android.icu.text.DateFormat; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManager; Loading Loading @@ -1153,7 +1153,7 @@ public class VibratorService extends IVibratorService.Stub long duration = vibratorPerformEffect(prebaked.getId(), long duration = vibratorPerformEffect(prebaked.getId(), prebaked.getEffectStrength(), vib); prebaked.getEffectStrength(), vib); long timeout = duration; long timeout = duration; if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) { if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) { timeout *= ASYNC_TIMEOUT_MULTIPLIER; timeout *= ASYNC_TIMEOUT_MULTIPLIER; } } if (timeout > 0) { if (timeout > 0) { Loading services/core/jni/Android.bp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -130,7 +130,6 @@ cc_defaults { "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", "android.hardware.vibrator@1.3", "android.hardware.vibrator@1.4", "android.hardware.vr@1.0", "android.hardware.vr@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", "android.frameworks.sensorservice@1.0", Loading services/core/jni/com_android_server_VibratorService.cpp +235 −238 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,7 @@ #define LOG_TAG "VibratorService" #define LOG_TAG "VibratorService" #include <android/hardware/vibrator/1.4/IVibrator.h> #include <android/hardware/vibrator/1.3/IVibrator.h> #include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> #include <android/hardware/vibrator/IVibrator.h> #include <binder/IServiceManager.h> #include <binder/IServiceManager.h> Loading @@ -43,102 +43,19 @@ namespace V1_0 = android::hardware::vibrator::V1_0; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_3 = android::hardware::vibrator::V1_3; namespace V1_3 = android::hardware::vibrator::V1_3; namespace V1_4 = android::hardware::vibrator::V1_4; namespace aidl = android::hardware::vibrator; namespace aidl = android::hardware::vibrator; namespace android { namespace android { static jmethodID sMethodIdOnComplete; static jmethodID sMethodIdOnComplete; // TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove // shim class VibratorShim : public V1_4::IVibrator { public: VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {} Return<V1_0::Status> on(uint32_t timeoutMs) override { return on_1_4(timeoutMs, nullptr); } Return<V1_0::Status> off() override { return toHidlStatus(mVib->off()); } Return<bool> supportsAmplitudeControl() override { int32_t cap = 0; if (!mVib->getCapabilities(&cap).isOk()) return false; if (mUnderExternalControl) { return (cap & aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0; } else { return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; } } Return<V1_0::Status> setAmplitude(uint8_t amplitude) override { return toHidlStatus(mVib->setAmplitude(amplitude)); } Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_1_1_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength, perform_1_2_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<bool> supportsExternalControl() override { int32_t cap = 0; if (!mVib->getCapabilities(&cap).isOk()) return false; return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; } Return<V1_0::Status> setExternalControl(bool enabled) override { Return<V1_0::Status> status = toHidlStatus(mVib->setExternalControl(enabled)); if (status.isOk() && status == V1_0::Status::OK) { mUnderExternalControl = enabled; } return status; } Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength, perform_1_3_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<uint32_t> getCapabilities() override { static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) == static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK)); static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) == static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK)); int32_t cap; if (!mVib->getCapabilities(&cap).isOk()) return 0; return (cap & (aidl::IVibrator::CAP_ON_CALLBACK | aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0; } Return<V1_0::Status> on_1_4(uint32_t timeoutMs, const sp<V1_4::IVibratorCallback>& callback) override { sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; return toHidlStatus(mVib->on(timeoutMs, cb)); } Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength, const sp<V1_4::IVibratorCallback>& callback, perform_1_4_cb _hidl_cb) override { static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == static_cast<uint8_t>(aidl::EffectStrength::STRONG)); static_cast<uint8_t>(aidl::EffectStrength::STRONG)); static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == static_cast<uint8_t>(aidl::Effect::CLICK)); static_cast<uint8_t>(aidl::Effect::CLICK)); static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == Loading @@ -160,49 +77,7 @@ class VibratorShim : public V1_4::IVibrator { static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; class VibratorCallback { int timeoutMs = 0; Return<V1_0::Status> status = toHidlStatus( mVib->perform(static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs)); if (status.isOk()) { _hidl_cb(status, timeoutMs); return android::hardware::Status::ok(); } else { return android::hardware::details::StatusOf<V1_0::Status, void>(status); } } private: sp<aidl::IVibrator> mVib; bool mUnderExternalControl = false; Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) { switch(status.exceptionCode()) { using android::hardware::Status; case Status::EX_NONE: return V1_0::Status::OK; case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE; case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION; case Status::EX_TRANSACTION_FAILED: { return Status::fromStatusT(status.transactionError()); } } return V1_0::Status::UNKNOWN_ERROR; } class CallbackShim : public aidl::BnVibratorCallback { public: CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {} binder::Status onComplete() { mCb->onComplete(); return binder::Status::ok(); // oneway, local call } private: sp<V1_4::IVibratorCallback> mCb; }; }; class VibratorCallback : public V1_4::IVibratorCallback { public: public: VibratorCallback(JNIEnv *env, jobject vibration) : VibratorCallback(JNIEnv *env, jobject vibration) : mVibration(MakeGlobalRefOrDie(env, vibration)) {} mVibration(MakeGlobalRefOrDie(env, vibration)) {} Loading @@ -212,47 +87,92 @@ class VibratorCallback : public V1_4::IVibratorCallback { env->DeleteGlobalRef(mVibration); env->DeleteGlobalRef(mVibration); } } Return<void> onComplete() override { void onComplete() { auto env = AndroidRuntime::getJNIEnv(); auto env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(mVibration, sMethodIdOnComplete); env->CallVoidMethod(mVibration, sMethodIdOnComplete); return Void(); } } private: private: jobject mVibration; jobject mVibration; }; }; class AidlVibratorCallback : public aidl::BnVibratorCallback { public: AidlVibratorCallback(JNIEnv *env, jobject vibration) : mCb(env, vibration) {} binder::Status onComplete() override { mCb.onComplete(); return binder::Status::ok(); // oneway, local call } private: VibratorCallback mCb; }; static constexpr int NUM_TRIES = 2; static constexpr int NUM_TRIES = 2; template<class R> inline R NoneStatus() { using ::android::hardware::Status; return Status::fromExceptionCode(Status::EX_NONE); } template<> inline binder::Status NoneStatus() { using binder::Status; return Status::fromExceptionCode(Status::EX_NONE); } // Creates a Return<R> with STATUS::EX_NULL_POINTER. // Creates a Return<R> with STATUS::EX_NULL_POINTER. template<class R> template<class R> inline Return<R> NullptrStatus() { inline R NullptrStatus() { using ::android::hardware::Status; using ::android::hardware::Status; return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; return Status::fromExceptionCode(Status::EX_NULL_POINTER); } template<> inline binder::Status NullptrStatus() { using binder::Status; return Status::fromExceptionCode(Status::EX_NULL_POINTER); } template <typename I> sp<I> getService() { return I::getService(); } template <> sp<aidl::IVibrator> getService() { return waitForVintfService<aidl::IVibrator>(); } template <typename I> sp<I> tryGetService() { return I::tryGetService(); } template <> sp<aidl::IVibrator> tryGetService() { return checkVintfService<aidl::IVibrator>(); } } template <typename I> template <typename I> class HalWrapper { class HalWrapper { public: public: static std::unique_ptr<HalWrapper> Create() { static std::unique_ptr<HalWrapper> Create() { sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>(); if (aidlVib) { return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib))); } // Assume that if getService returns a nullptr, HAL is not available on the // Assume that if getService returns a nullptr, HAL is not available on the // device. // device. auto hal = I::getService(); auto hal = getService<I>(); return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; } } // Helper used to transparently deal with the vibrator HAL becoming unavailable. // Helper used to transparently deal with the vibrator HAL becoming unavailable. template<class R, class... Args0, class... Args1> template<class R, class... Args0, class... Args1> Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) { R call(R (I::* fn)(Args0...), Args1&&... args1) { // Return<R> doesn't have a default constructor, so make a Return<R> with // Return<R> doesn't have a default constructor, so make a Return<R> with // STATUS::EX_NONE. // STATUS::EX_NONE. using ::android::hardware::Status; R ret{NoneStatus<R>()}; Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)}; // Note that ret is guaranteed to be changed after this loop. // Note that ret is guaranteed to be changed after this loop. for (int i = 0; i < NUM_TRIES; ++i) { for (int i = 0; i < NUM_TRIES; ++i) { Loading @@ -266,12 +186,7 @@ class HalWrapper { ALOGE("Failed to issue command to vibrator HAL. Retrying."); ALOGE("Failed to issue command to vibrator HAL. Retrying."); // Restoring connection to the HAL. // Restoring connection to the HAL. sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>(); mHal = tryGetService<I>(); if (aidlVib) { mHal = new VibratorShim(aidlVib); } else { mHal = I::tryGetService(); } } } return ret; return ret; } } Loading @@ -290,7 +205,7 @@ static auto getHal() { } } template<class R, class I, class... Args0, class... Args1> template<class R, class I, class... Args0, class... Args1> Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) { R halCall(R (I::* fn)(Args0...), Args1&&... args1) { auto hal = getHal<I>(); auto hal = getHal<I>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); } } Loading @@ -307,35 +222,80 @@ bool isValidEffect(jlong effect) { static void vibratorInit(JNIEnv *env, jclass clazz) static void vibratorInit(JNIEnv *env, jclass clazz) { { if (auto hal = getHal<aidl::IVibrator>()) { // IBinder::pingBinder isn't accessible as a pointer function // but getCapabilities can serve the same purpose int32_t cap; hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); } else { halCall(&V1_0::IVibrator::ping).isOk(); halCall(&V1_0::IVibrator::ping).isOk(); } } } static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) { { return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE; bool ok; if (auto hal = getHal<aidl::IVibrator>()) { // IBinder::pingBinder isn't accessible as a pointer function // but getCapabilities can serve the same purpose int32_t cap; ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); } else { ok = halCall(&V1_0::IVibrator::ping).isOk(); } return ok ? JNI_TRUE : JNI_FALSE; } } static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) { { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr); if (!status.isOk()) { ALOGE("vibratorOn command failed: %s", status.toString8().string()); } } else { Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); if (retStatus != Status::OK) { if (retStatus != Status::OK) { ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); } } } } } static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) { { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::off); if (!status.isOk()) { ALOGE("vibratorOff command failed: %s", status.toString8().string()); } } else { Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); if (retStatus != Status::OK) { if (retStatus != Status::OK) { ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); } } } } } static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return false; } return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; } else { return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); } } } static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude); if (!status.isOk()) { ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string()); } } else { Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) .withDefault(Status::UNKNOWN_ERROR); .withDefault(Status::UNKNOWN_ERROR); if (status != Status::OK) { if (status != Status::OK) { Loading @@ -343,12 +303,27 @@ static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { static_cast<uint32_t>(status)); static_cast<uint32_t>(status)); } } } } } static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return false; } return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; } else { return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); } } } static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled); if (!status.isOk()) { ALOGE("Failed to set vibrator external control: %s", status.toString8().string()); } } else { Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) .withDefault(Status::UNKNOWN_ERROR); .withDefault(Status::UNKNOWN_ERROR); if (status != Status::OK) { if (status != Status::OK) { Loading @@ -356,9 +331,26 @@ static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { static_cast<uint32_t>(status)); static_cast<uint32_t>(status)); } } } } } static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, jobject vibration) { jobject vibration) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t lengthMs; sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration); aidl::Effect effectType(static_cast<aidl::Effect>(strength)); aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength)); auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs); if (!status.isOk()) { if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string()); } return -1; } return lengthMs; } else { Status status; Status status; uint32_t lengthMs; uint32_t lengthMs; auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { Loading @@ -368,11 +360,7 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre EffectStrength effectStrength(static_cast<EffectStrength>(strength)); EffectStrength effectStrength(static_cast<EffectStrength>(strength)); Return<void> ret; Return<void> ret; if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) { if (isValidEffect<V1_0::Effect>(effect)) { sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration); ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect), effectStrength, effectCallback, callback); } else if (isValidEffect<V1_0::Effect>(effect)) { ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), effectStrength, callback); effectStrength, callback); } else if (isValidEffect<Effect_1_1>(effect)) { } else if (isValidEffect<Effect_1_1>(effect)) { Loading Loading @@ -405,12 +393,21 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre ", error=%" PRIu32 ").", static_cast<int64_t>(effect), ", error=%" PRIu32 ").", static_cast<int64_t>(effect), static_cast<int32_t>(strength), static_cast<uint32_t>(status)); static_cast<int32_t>(strength), static_cast<uint32_t>(status)); } } } return -1; return -1; } } static jlong vibratorGetCapabilities(JNIEnv*, jclass) { static jlong vibratorGetCapabilities(JNIEnv*, jclass) { return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0); if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return 0; } return cap; } return 0; } } static const JNINativeMethod method_table[] = { static const JNINativeMethod method_table[] = { Loading Loading
services/core/Android.bp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ java_library_static { "android.hardware.power-V1.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.tv.cec-V1.0-java", "app-compat-annotations", "app-compat-annotations", "vintf-vibrator-java", ], ], required: [ required: [ Loading @@ -50,7 +51,6 @@ java_library_static { "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.biometrics.fingerprint-V2.1-java", "android.hardware.oemlock-V1.0-java", "android.hardware.oemlock-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.tetheroffload.control-V1.0-java", "android.hardware.vibrator-V1.4-java", "android.hardware.configstore-V1.0-java", "android.hardware.configstore-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hardware.contexthub-V1.0-java", "android.hidl.manager-V1.2-java", "android.hidl.manager-V1.2-java", Loading
services/core/java/com/android/server/VibratorService.java +2 −2 Original line number Original line Diff line number Diff line Loading @@ -28,8 +28,8 @@ import android.content.pm.PackageManager; import android.content.res.Resources; import android.content.res.Resources; import android.database.ContentObserver; import android.database.ContentObserver; import android.hardware.input.InputManager; import android.hardware.input.InputManager; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_0.EffectStrength; import android.hardware.vibrator.V1_4.Capabilities; import android.icu.text.DateFormat; import android.icu.text.DateFormat; import android.media.AudioAttributes; import android.media.AudioAttributes; import android.media.AudioManager; import android.media.AudioManager; Loading Loading @@ -1153,7 +1153,7 @@ public class VibratorService extends IVibratorService.Stub long duration = vibratorPerformEffect(prebaked.getId(), long duration = vibratorPerformEffect(prebaked.getId(), prebaked.getEffectStrength(), vib); prebaked.getEffectStrength(), vib); long timeout = duration; long timeout = duration; if ((mCapabilities & Capabilities.PERFORM_COMPLETION_CALLBACK) != 0) { if ((mCapabilities & IVibrator.CAP_PERFORM_CALLBACK) != 0) { timeout *= ASYNC_TIMEOUT_MULTIPLIER; timeout *= ASYNC_TIMEOUT_MULTIPLIER; } } if (timeout > 0) { if (timeout > 0) { Loading
services/core/jni/Android.bp +0 −1 Original line number Original line Diff line number Diff line Loading @@ -130,7 +130,6 @@ cc_defaults { "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.2", "android.hardware.vibrator@1.3", "android.hardware.vibrator@1.3", "android.hardware.vibrator@1.4", "android.hardware.vr@1.0", "android.hardware.vr@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.schedulerservice@1.0", "android.frameworks.sensorservice@1.0", "android.frameworks.sensorservice@1.0", Loading
services/core/jni/com_android_server_VibratorService.cpp +235 −238 Original line number Original line Diff line number Diff line Loading @@ -16,7 +16,7 @@ #define LOG_TAG "VibratorService" #define LOG_TAG "VibratorService" #include <android/hardware/vibrator/1.4/IVibrator.h> #include <android/hardware/vibrator/1.3/IVibrator.h> #include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/BnVibratorCallback.h> #include <android/hardware/vibrator/IVibrator.h> #include <android/hardware/vibrator/IVibrator.h> #include <binder/IServiceManager.h> #include <binder/IServiceManager.h> Loading @@ -43,102 +43,19 @@ namespace V1_0 = android::hardware::vibrator::V1_0; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_1 = android::hardware::vibrator::V1_1; namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_2 = android::hardware::vibrator::V1_2; namespace V1_3 = android::hardware::vibrator::V1_3; namespace V1_3 = android::hardware::vibrator::V1_3; namespace V1_4 = android::hardware::vibrator::V1_4; namespace aidl = android::hardware::vibrator; namespace aidl = android::hardware::vibrator; namespace android { namespace android { static jmethodID sMethodIdOnComplete; static jmethodID sMethodIdOnComplete; // TODO(b/141828236): remove HIDL 1.4 and re-write all of this code to remove // shim class VibratorShim : public V1_4::IVibrator { public: VibratorShim(const sp<aidl::IVibrator>& vib) : mVib(vib) {} Return<V1_0::Status> on(uint32_t timeoutMs) override { return on_1_4(timeoutMs, nullptr); } Return<V1_0::Status> off() override { return toHidlStatus(mVib->off()); } Return<bool> supportsAmplitudeControl() override { int32_t cap = 0; if (!mVib->getCapabilities(&cap).isOk()) return false; if (mUnderExternalControl) { return (cap & aidl::IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL) > 0; } else { return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; } } Return<V1_0::Status> setAmplitude(uint8_t amplitude) override { return toHidlStatus(mVib->setAmplitude(amplitude)); } Return<void> perform(V1_0::Effect effect, V1_0::EffectStrength strength, perform_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<void> perform_1_1(V1_1::Effect_1_1 effect, V1_0::EffectStrength strength, perform_1_1_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<void> perform_1_2(V1_2::Effect effect, V1_0::EffectStrength strength, perform_1_2_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<bool> supportsExternalControl() override { int32_t cap = 0; if (!mVib->getCapabilities(&cap).isOk()) return false; return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; } Return<V1_0::Status> setExternalControl(bool enabled) override { Return<V1_0::Status> status = toHidlStatus(mVib->setExternalControl(enabled)); if (status.isOk() && status == V1_0::Status::OK) { mUnderExternalControl = enabled; } return status; } Return<void> perform_1_3(V1_3::Effect effect, V1_0::EffectStrength strength, perform_1_3_cb _hidl_cb) override { return perform_1_4(static_cast<V1_3::Effect>(effect), strength, nullptr, _hidl_cb); } Return<uint32_t> getCapabilities() override { static_assert(static_cast<int32_t>(V1_4::Capabilities::ON_COMPLETION_CALLBACK) == static_cast<int32_t>(aidl::IVibrator::CAP_ON_CALLBACK)); static_assert(static_cast<int32_t>(V1_4::Capabilities::PERFORM_COMPLETION_CALLBACK) == static_cast<int32_t>(aidl::IVibrator::CAP_PERFORM_CALLBACK)); int32_t cap; if (!mVib->getCapabilities(&cap).isOk()) return 0; return (cap & (aidl::IVibrator::CAP_ON_CALLBACK | aidl::IVibrator::CAP_PERFORM_CALLBACK)) > 0; } Return<V1_0::Status> on_1_4(uint32_t timeoutMs, const sp<V1_4::IVibratorCallback>& callback) override { sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; return toHidlStatus(mVib->on(timeoutMs, cb)); } Return<void> perform_1_4(V1_3::Effect effect, V1_0::EffectStrength strength, const sp<V1_4::IVibratorCallback>& callback, perform_1_4_cb _hidl_cb) override { static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::LIGHT) == static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); static_cast<uint8_t>(aidl::EffectStrength::LIGHT)); static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::MEDIUM) == static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); static_cast<uint8_t>(aidl::EffectStrength::MEDIUM)); static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == static_assert(static_cast<uint8_t>(V1_0::EffectStrength::STRONG) == static_cast<uint8_t>(aidl::EffectStrength::STRONG)); static_cast<uint8_t>(aidl::EffectStrength::STRONG)); static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::CLICK) == static_cast<uint8_t>(aidl::Effect::CLICK)); static_cast<uint8_t>(aidl::Effect::CLICK)); static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::DOUBLE_CLICK) == Loading @@ -160,49 +77,7 @@ class VibratorShim : public V1_4::IVibrator { static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_assert(static_cast<uint8_t>(V1_3::Effect::TEXTURE_TICK) == static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); static_cast<uint8_t>(aidl::Effect::TEXTURE_TICK)); sp<aidl::IVibratorCallback> cb = callback ? new CallbackShim(callback) : nullptr; class VibratorCallback { int timeoutMs = 0; Return<V1_0::Status> status = toHidlStatus( mVib->perform(static_cast<aidl::Effect>(effect), static_cast<aidl::EffectStrength>(strength), cb, &timeoutMs)); if (status.isOk()) { _hidl_cb(status, timeoutMs); return android::hardware::Status::ok(); } else { return android::hardware::details::StatusOf<V1_0::Status, void>(status); } } private: sp<aidl::IVibrator> mVib; bool mUnderExternalControl = false; Return<V1_0::Status> toHidlStatus(const android::binder::Status& status) { switch(status.exceptionCode()) { using android::hardware::Status; case Status::EX_NONE: return V1_0::Status::OK; case Status::EX_ILLEGAL_ARGUMENT: return V1_0::Status::BAD_VALUE; case Status::EX_UNSUPPORTED_OPERATION: return V1_0::Status::UNSUPPORTED_OPERATION; case Status::EX_TRANSACTION_FAILED: { return Status::fromStatusT(status.transactionError()); } } return V1_0::Status::UNKNOWN_ERROR; } class CallbackShim : public aidl::BnVibratorCallback { public: CallbackShim(const sp<V1_4::IVibratorCallback>& cb) : mCb(cb) {} binder::Status onComplete() { mCb->onComplete(); return binder::Status::ok(); // oneway, local call } private: sp<V1_4::IVibratorCallback> mCb; }; }; class VibratorCallback : public V1_4::IVibratorCallback { public: public: VibratorCallback(JNIEnv *env, jobject vibration) : VibratorCallback(JNIEnv *env, jobject vibration) : mVibration(MakeGlobalRefOrDie(env, vibration)) {} mVibration(MakeGlobalRefOrDie(env, vibration)) {} Loading @@ -212,47 +87,92 @@ class VibratorCallback : public V1_4::IVibratorCallback { env->DeleteGlobalRef(mVibration); env->DeleteGlobalRef(mVibration); } } Return<void> onComplete() override { void onComplete() { auto env = AndroidRuntime::getJNIEnv(); auto env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(mVibration, sMethodIdOnComplete); env->CallVoidMethod(mVibration, sMethodIdOnComplete); return Void(); } } private: private: jobject mVibration; jobject mVibration; }; }; class AidlVibratorCallback : public aidl::BnVibratorCallback { public: AidlVibratorCallback(JNIEnv *env, jobject vibration) : mCb(env, vibration) {} binder::Status onComplete() override { mCb.onComplete(); return binder::Status::ok(); // oneway, local call } private: VibratorCallback mCb; }; static constexpr int NUM_TRIES = 2; static constexpr int NUM_TRIES = 2; template<class R> inline R NoneStatus() { using ::android::hardware::Status; return Status::fromExceptionCode(Status::EX_NONE); } template<> inline binder::Status NoneStatus() { using binder::Status; return Status::fromExceptionCode(Status::EX_NONE); } // Creates a Return<R> with STATUS::EX_NULL_POINTER. // Creates a Return<R> with STATUS::EX_NULL_POINTER. template<class R> template<class R> inline Return<R> NullptrStatus() { inline R NullptrStatus() { using ::android::hardware::Status; using ::android::hardware::Status; return Return<R>{Status::fromExceptionCode(Status::EX_NULL_POINTER)}; return Status::fromExceptionCode(Status::EX_NULL_POINTER); } template<> inline binder::Status NullptrStatus() { using binder::Status; return Status::fromExceptionCode(Status::EX_NULL_POINTER); } template <typename I> sp<I> getService() { return I::getService(); } template <> sp<aidl::IVibrator> getService() { return waitForVintfService<aidl::IVibrator>(); } template <typename I> sp<I> tryGetService() { return I::tryGetService(); } template <> sp<aidl::IVibrator> tryGetService() { return checkVintfService<aidl::IVibrator>(); } } template <typename I> template <typename I> class HalWrapper { class HalWrapper { public: public: static std::unique_ptr<HalWrapper> Create() { static std::unique_ptr<HalWrapper> Create() { sp<aidl::IVibrator> aidlVib = waitForVintfService<aidl::IVibrator>(); if (aidlVib) { return std::unique_ptr<HalWrapper>(new HalWrapper(new VibratorShim(aidlVib))); } // Assume that if getService returns a nullptr, HAL is not available on the // Assume that if getService returns a nullptr, HAL is not available on the // device. // device. auto hal = I::getService(); auto hal = getService<I>(); return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; return hal ? std::unique_ptr<HalWrapper>(new HalWrapper(std::move(hal))) : nullptr; } } // Helper used to transparently deal with the vibrator HAL becoming unavailable. // Helper used to transparently deal with the vibrator HAL becoming unavailable. template<class R, class... Args0, class... Args1> template<class R, class... Args0, class... Args1> Return<R> call(Return<R> (I::* fn)(Args0...), Args1&&... args1) { R call(R (I::* fn)(Args0...), Args1&&... args1) { // Return<R> doesn't have a default constructor, so make a Return<R> with // Return<R> doesn't have a default constructor, so make a Return<R> with // STATUS::EX_NONE. // STATUS::EX_NONE. using ::android::hardware::Status; R ret{NoneStatus<R>()}; Return<R> ret{Status::fromExceptionCode(Status::EX_NONE)}; // Note that ret is guaranteed to be changed after this loop. // Note that ret is guaranteed to be changed after this loop. for (int i = 0; i < NUM_TRIES; ++i) { for (int i = 0; i < NUM_TRIES; ++i) { Loading @@ -266,12 +186,7 @@ class HalWrapper { ALOGE("Failed to issue command to vibrator HAL. Retrying."); ALOGE("Failed to issue command to vibrator HAL. Retrying."); // Restoring connection to the HAL. // Restoring connection to the HAL. sp<aidl::IVibrator> aidlVib = checkVintfService<aidl::IVibrator>(); mHal = tryGetService<I>(); if (aidlVib) { mHal = new VibratorShim(aidlVib); } else { mHal = I::tryGetService(); } } } return ret; return ret; } } Loading @@ -290,7 +205,7 @@ static auto getHal() { } } template<class R, class I, class... Args0, class... Args1> template<class R, class I, class... Args0, class... Args1> Return<R> halCall(Return<R> (I::* fn)(Args0...), Args1&&... args1) { R halCall(R (I::* fn)(Args0...), Args1&&... args1) { auto hal = getHal<I>(); auto hal = getHal<I>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); return hal ? hal->call(fn, std::forward<Args1>(args1)...) : NullptrStatus<R>(); } } Loading @@ -307,35 +222,80 @@ bool isValidEffect(jlong effect) { static void vibratorInit(JNIEnv *env, jclass clazz) static void vibratorInit(JNIEnv *env, jclass clazz) { { if (auto hal = getHal<aidl::IVibrator>()) { // IBinder::pingBinder isn't accessible as a pointer function // but getCapabilities can serve the same purpose int32_t cap; hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); } else { halCall(&V1_0::IVibrator::ping).isOk(); halCall(&V1_0::IVibrator::ping).isOk(); } } } static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) static jboolean vibratorExists(JNIEnv* /* env */, jclass /* clazz */) { { return halCall(&V1_0::IVibrator::ping).isOk() ? JNI_TRUE : JNI_FALSE; bool ok; if (auto hal = getHal<aidl::IVibrator>()) { // IBinder::pingBinder isn't accessible as a pointer function // but getCapabilities can serve the same purpose int32_t cap; ok = hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk(); } else { ok = halCall(&V1_0::IVibrator::ping).isOk(); } return ok ? JNI_TRUE : JNI_FALSE; } } static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) static void vibratorOn(JNIEnv* /* env */, jclass /* clazz */, jlong timeout_ms) { { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::on, timeout_ms, nullptr); if (!status.isOk()) { ALOGE("vibratorOn command failed: %s", status.toString8().string()); } } else { Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR); if (retStatus != Status::OK) { if (retStatus != Status::OK) { ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); } } } } } static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) static void vibratorOff(JNIEnv* /* env */, jclass /* clazz */) { { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::off); if (!status.isOk()) { ALOGE("vibratorOff command failed: %s", status.toString8().string()); } } else { Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR); if (retStatus != Status::OK) { if (retStatus != Status::OK) { ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus)); } } } } } static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { static jlong vibratorSupportsAmplitudeControl(JNIEnv*, jclass) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return false; } return (cap & aidl::IVibrator::CAP_AMPLITUDE_CONTROL) > 0; } else { return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); return halCall(&V1_0::IVibrator::supportsAmplitudeControl).withDefault(false); } } } static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::IVibrator::setAmplitude, amplitude); if (!status.isOk()) { ALOGE("Failed to set vibrator amplitude: %s", status.toString8().string()); } } else { Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) Status status = halCall(&V1_0::IVibrator::setAmplitude, static_cast<uint32_t>(amplitude)) .withDefault(Status::UNKNOWN_ERROR); .withDefault(Status::UNKNOWN_ERROR); if (status != Status::OK) { if (status != Status::OK) { Loading @@ -343,12 +303,27 @@ static void vibratorSetAmplitude(JNIEnv*, jclass, jint amplitude) { static_cast<uint32_t>(status)); static_cast<uint32_t>(status)); } } } } } static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { static jboolean vibratorSupportsExternalControl(JNIEnv*, jclass) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return false; } return (cap & aidl::IVibrator::CAP_EXTERNAL_CONTROL) > 0; } else { return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); return halCall(&V1_3::IVibrator::supportsExternalControl).withDefault(false); } } } static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { if (auto hal = getHal<aidl::IVibrator>()) { auto status = hal->call(&aidl::IVibrator::IVibrator::setExternalControl, enabled); if (!status.isOk()) { ALOGE("Failed to set vibrator external control: %s", status.toString8().string()); } } else { Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) Status status = halCall(&V1_3::IVibrator::setExternalControl, static_cast<uint32_t>(enabled)) .withDefault(Status::UNKNOWN_ERROR); .withDefault(Status::UNKNOWN_ERROR); if (status != Status::OK) { if (status != Status::OK) { Loading @@ -356,9 +331,26 @@ static void vibratorSetExternalControl(JNIEnv*, jclass, jboolean enabled) { static_cast<uint32_t>(status)); static_cast<uint32_t>(status)); } } } } } static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong strength, jobject vibration) { jobject vibration) { if (auto hal = getHal<aidl::IVibrator>()) { int32_t lengthMs; sp<AidlVibratorCallback> effectCallback = new AidlVibratorCallback(env, vibration); aidl::Effect effectType(static_cast<aidl::Effect>(strength)); aidl::EffectStrength effectStrength(static_cast<aidl::EffectStrength>(strength)); auto status = hal->call(&aidl::IVibrator::perform, effectType, effectStrength, effectCallback, &lengthMs); if (!status.isOk()) { if (status.exceptionCode() != binder::Status::EX_UNSUPPORTED_OPERATION) { ALOGE("Failed to perform haptic effect: effect=%" PRId64 ", strength=%" PRId32 ": %s", static_cast<int64_t>(effect), static_cast<int32_t>(strength), status.toString8().string()); } return -1; } return lengthMs; } else { Status status; Status status; uint32_t lengthMs; uint32_t lengthMs; auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { auto callback = [&status, &lengthMs](Status retStatus, uint32_t retLengthMs) { Loading @@ -368,11 +360,7 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre EffectStrength effectStrength(static_cast<EffectStrength>(strength)); EffectStrength effectStrength(static_cast<EffectStrength>(strength)); Return<void> ret; Return<void> ret; if (auto hal = getHal<V1_4::IVibrator>(); hal && isValidEffect<V1_3::Effect>(effect)) { if (isValidEffect<V1_0::Effect>(effect)) { sp<VibratorCallback> effectCallback = new VibratorCallback(env, vibration); ret = hal->call(&V1_4::IVibrator::perform_1_4, static_cast<V1_3::Effect>(effect), effectStrength, effectCallback, callback); } else if (isValidEffect<V1_0::Effect>(effect)) { ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), ret = halCall(&V1_0::IVibrator::perform, static_cast<V1_0::Effect>(effect), effectStrength, callback); effectStrength, callback); } else if (isValidEffect<Effect_1_1>(effect)) { } else if (isValidEffect<Effect_1_1>(effect)) { Loading Loading @@ -405,12 +393,21 @@ static jlong vibratorPerformEffect(JNIEnv* env, jclass, jlong effect, jlong stre ", error=%" PRIu32 ").", static_cast<int64_t>(effect), ", error=%" PRIu32 ").", static_cast<int64_t>(effect), static_cast<int32_t>(strength), static_cast<uint32_t>(status)); static_cast<int32_t>(strength), static_cast<uint32_t>(status)); } } } return -1; return -1; } } static jlong vibratorGetCapabilities(JNIEnv*, jclass) { static jlong vibratorGetCapabilities(JNIEnv*, jclass) { return halCall(&V1_4::IVibrator::getCapabilities).withDefault(0); if (auto hal = getHal<aidl::IVibrator>()) { int32_t cap = 0; if (!hal->call(&aidl::IVibrator::getCapabilities, &cap).isOk()) { return 0; } return cap; } return 0; } } static const JNINativeMethod method_table[] = { static const JNINativeMethod method_table[] = { Loading