| /* |
| * Copyright (C) 2019 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. |
| */ |
| |
| #include "Vibrator.h" |
| |
| #include <android-base/logging.h> |
| #include <thread> |
| |
| namespace aidl { |
| namespace android { |
| namespace hardware { |
| namespace vibrator { |
| |
| #ifdef VIBRATOR_SUPPORTS_EFFECTS |
| Vibrator::Vibrator() { |
| if (exists(kVibratorStrength)) { |
| mVibratorStrengthSupported = true; |
| mVibratorStrengthMax = getNode(kVibratorStrengthMax, 9); |
| } |
| } |
| #endif |
| |
| ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) { |
| LOG(VERBOSE) << "Vibrator reporting capabilities"; |
| *_aidl_return = IVibrator::CAP_ON_CALLBACK; |
| |
| #ifdef VIBRATOR_SUPPORTS_EFFECTS |
| *_aidl_return |= IVibrator::CAP_PERFORM_CALLBACK; |
| #endif |
| |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| ndk::ScopedAStatus Vibrator::off() { |
| LOG(VERBOSE) << "Vibrator off"; |
| return setNode(kVibratorActivate, 0); |
| } |
| |
| ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs, |
| const std::shared_ptr<IVibratorCallback>& callback) { |
| ndk::ScopedAStatus status; |
| |
| LOG(VERBOSE) << "Vibrator on for timeoutMs: " << timeoutMs; |
| |
| status = activate(timeoutMs); |
| if (!status.isOk()) |
| return status; |
| |
| if (callback != nullptr) { |
| std::thread([=] { |
| LOG(VERBOSE) << "Starting on on another thread"; |
| usleep(timeoutMs * 1000); |
| LOG(VERBOSE) << "Notifying on complete"; |
| if (!callback->onComplete().isOk()) { |
| LOG(ERROR) << "Failed to call onComplete"; |
| } |
| }).detach(); |
| } |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| #ifdef VIBRATOR_SUPPORTS_EFFECTS |
| ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength, |
| const std::shared_ptr<IVibratorCallback>& callback, |
| int32_t* _aidl_return) { |
| ndk::ScopedAStatus status; |
| int32_t timeoutMs; |
| |
| if (vibEffects.find(effect) == vibEffects.end()) |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| |
| if (vibStrengths.find(strength) == vibStrengths.end()) |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| |
| if (mVibratorStrengthSupported) { |
| // Vibration strength is relative to the max strength reported by the kernel. |
| int vib_strength = static_cast<int>(mVibratorStrengthMax * vibStrengths[strength] / 10.0 + 0.5); |
| status = setNode(kVibratorStrength, vib_strength); |
| if (!status.isOk()) |
| return status; |
| } |
| |
| timeoutMs = vibEffects[effect]; |
| |
| status = activate(timeoutMs); |
| if (!status.isOk()) |
| return status; |
| |
| if (callback != nullptr) { |
| std::thread([=] { |
| LOG(INFO) << "Starting perform on another thread"; |
| usleep(timeoutMs * 1000); |
| LOG(INFO) << "Notifying perform complete"; |
| callback->onComplete(); |
| }).detach(); |
| } |
| |
| *_aidl_return = timeoutMs; |
| return ndk::ScopedAStatus::ok(); |
| #else |
| ndk::ScopedAStatus Vibrator::perform(Effect /* effect */, EffectStrength /* strength */, |
| const std::shared_ptr<IVibratorCallback>& /* callback */, |
| int32_t* /* _aidl_return */) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| #endif |
| } |
| |
| #ifdef VIBRATOR_SUPPORTS_EFFECTS |
| ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) { |
| for (auto const& pair : vibEffects) |
| _aidl_return->push_back(pair.first); |
| #else |
| ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* /* _aidl_return */) { |
| #endif |
| return ndk::ScopedAStatus::ok(); |
| } |
| |
| ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* maxDelayMs __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* maxSize __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getSupportedPrimitives(std::vector<CompositePrimitive>* supported __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive primitive __unused, |
| int32_t* durationMs __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& composite __unused, |
| const std::shared_ptr<IVibratorCallback>& callback __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t id __unused, Effect effect __unused, EffectStrength strength __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t id __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getResonantFrequency(float *resonantFreqHz __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getQFactor(float *qFactor __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getFrequencyResolution(float *freqResolutionHz __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float *freqMinimumHz __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float> *_aidl_return __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t *durationMs __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t *maxSize __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking> *supported __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle> &composite __unused, |
| const std::shared_ptr<IVibratorCallback> &callback __unused) { |
| return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); |
| } |
| |
| } // namespace vibrator |
| } // namespace hardware |
| } // namespace android |
| } // namespace aidl |