xref: /aosp_15_r20/hardware/interfaces/vibrator/aidl/default/VibratorManager.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "vibrator-impl/VibratorManager.h"
18 #include "vibrator-impl/VibrationSession.h"
19 
20 #include <aidl/android/hardware/vibrator/BnVibratorCallback.h>
21 
22 #include <android-base/logging.h>
23 #include <thread>
24 
25 namespace aidl {
26 namespace android {
27 namespace hardware {
28 namespace vibrator {
29 
30 static constexpr int32_t kDefaultVibratorId = 1;
31 
32 class VibratorCallback : public BnVibratorCallback {
33   public:
VibratorCallback(const std::function<void ()> & callback)34     VibratorCallback(const std::function<void()>& callback) : mCallback(callback) {}
onComplete()35     ndk::ScopedAStatus onComplete() override {
36         mCallback();
37         return ndk::ScopedAStatus::ok();
38     }
39 
40   private:
41     std::function<void()> mCallback;
42 };
43 
getCapabilities(int32_t * _aidl_return)44 ndk::ScopedAStatus VibratorManager::getCapabilities(int32_t* _aidl_return) {
45     LOG(VERBOSE) << "Vibrator manager reporting capabilities";
46     std::lock_guard lock(mMutex);
47     if (mCapabilities == 0) {
48         int32_t version;
49         if (!getInterfaceVersion(&version).isOk()) {
50             return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_STATE));
51         }
52         mCapabilities = IVibratorManager::CAP_SYNC | IVibratorManager::CAP_PREPARE_ON |
53                         IVibratorManager::CAP_PREPARE_PERFORM |
54                         IVibratorManager::CAP_PREPARE_COMPOSE |
55                         IVibratorManager::CAP_MIXED_TRIGGER_ON |
56                         IVibratorManager::CAP_MIXED_TRIGGER_PERFORM |
57                         IVibratorManager::CAP_MIXED_TRIGGER_COMPOSE |
58                         IVibratorManager::CAP_TRIGGER_CALLBACK;
59 
60         if (version >= 3) {
61             mCapabilities |= IVibratorManager::CAP_START_SESSIONS;
62         }
63     }
64 
65     *_aidl_return = mCapabilities;
66     return ndk::ScopedAStatus::ok();
67 }
68 
getVibratorIds(std::vector<int32_t> * _aidl_return)69 ndk::ScopedAStatus VibratorManager::getVibratorIds(std::vector<int32_t>* _aidl_return) {
70     LOG(VERBOSE) << "Vibrator manager getting vibrator ids";
71     *_aidl_return = {kDefaultVibratorId};
72     return ndk::ScopedAStatus::ok();
73 }
74 
getVibrator(int32_t vibratorId,std::shared_ptr<IVibrator> * _aidl_return)75 ndk::ScopedAStatus VibratorManager::getVibrator(int32_t vibratorId,
76                                                 std::shared_ptr<IVibrator>* _aidl_return) {
77     LOG(VERBOSE) << "Vibrator manager getting vibrator " << vibratorId;
78     if (vibratorId == kDefaultVibratorId) {
79         *_aidl_return = mDefaultVibrator;
80         return ndk::ScopedAStatus::ok();
81     } else {
82         *_aidl_return = nullptr;
83         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
84     }
85 }
86 
prepareSynced(const std::vector<int32_t> & vibratorIds)87 ndk::ScopedAStatus VibratorManager::prepareSynced(const std::vector<int32_t>& vibratorIds) {
88     LOG(VERBOSE) << "Vibrator Manager prepare synced";
89     if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
90         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
91     }
92     std::lock_guard lock(mMutex);
93     if (mIsPreparing) {
94         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
95     }
96     mIsPreparing = true;
97     return ndk::ScopedAStatus::ok();
98 }
99 
triggerSynced(const std::shared_ptr<IVibratorCallback> & callback)100 ndk::ScopedAStatus VibratorManager::triggerSynced(
101         const std::shared_ptr<IVibratorCallback>& callback) {
102     LOG(VERBOSE) << "Vibrator Manager trigger synced";
103     std::lock_guard lock(mMutex);
104     if (!mIsPreparing) {
105         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
106     }
107     std::thread([callback] {
108         if (callback != nullptr) {
109             LOG(VERBOSE) << "Notifying perform complete";
110             callback->onComplete();
111         }
112     }).detach();
113     mIsPreparing = false;
114     return ndk::ScopedAStatus::ok();
115 }
116 
cancelSynced()117 ndk::ScopedAStatus VibratorManager::cancelSynced() {
118     LOG(VERBOSE) << "Vibrator Manager cancel synced";
119     std::lock_guard lock(mMutex);
120     mIsPreparing = false;
121     return ndk::ScopedAStatus::ok();
122 }
123 
startSession(const std::vector<int32_t> & vibratorIds,const VibrationSessionConfig &,const std::shared_ptr<IVibratorCallback> & callback,std::shared_ptr<IVibrationSession> * _aidl_return)124 ndk::ScopedAStatus VibratorManager::startSession(const std::vector<int32_t>& vibratorIds,
125                                                  const VibrationSessionConfig&,
126                                                  const std::shared_ptr<IVibratorCallback>& callback,
127                                                  std::shared_ptr<IVibrationSession>* _aidl_return) {
128     LOG(VERBOSE) << "Vibrator Manager start session";
129     *_aidl_return = nullptr;
130     int32_t capabilities = 0;
131     if (!getCapabilities(&capabilities).isOk()) {
132         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
133     }
134     if ((capabilities & IVibratorManager::CAP_START_SESSIONS) == 0) {
135         return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
136     }
137     if (vibratorIds.size() != 1 || vibratorIds[0] != kDefaultVibratorId) {
138         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
139     }
140     std::lock_guard lock(mMutex);
141     if (mIsPreparing || mSession) {
142         return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
143     }
144     mSessionCallback = callback;
145     mSession = ndk::SharedRefBase::make<VibrationSession>(this->ref<VibratorManager>());
146     *_aidl_return = static_cast<std::shared_ptr<IVibrationSession>>(mSession);
147     return ndk::ScopedAStatus::ok();
148 }
149 
clearSessions()150 ndk::ScopedAStatus VibratorManager::clearSessions() {
151     LOG(VERBOSE) << "Vibrator Manager clear sessions";
152     abortSession();
153     return ndk::ScopedAStatus::ok();
154 }
155 
abortSession()156 void VibratorManager::abortSession() {
157     std::shared_ptr<IVibrationSession> session;
158     {
159         std::lock_guard lock(mMutex);
160         session = mSession;
161     }
162     if (session) {
163         mDefaultVibrator->off();
164         clearSession(session);
165     }
166 }
167 
closeSession(int32_t delayMs)168 void VibratorManager::closeSession(int32_t delayMs) {
169     std::shared_ptr<IVibrationSession> session;
170     {
171         std::lock_guard lock(mMutex);
172         if (mIsClosingSession) {
173             // Already closing session, ignore this.
174             return;
175         }
176         session = mSession;
177         mIsClosingSession = true;
178     }
179     if (session) {
180         auto callback = ndk::SharedRefBase::make<VibratorCallback>(
181                 [session, delayMs, sharedThis = this->ref<VibratorManager>()] {
182                     LOG(VERBOSE) << "Closing session after vibrator became idle";
183                     usleep(delayMs * 1000);
184 
185                     if (sharedThis) {
186                         sharedThis->clearSession(session);
187                     }
188                 });
189         mDefaultVibrator->setGlobalVibrationCallback(callback);
190     }
191 }
192 
clearSession(const std::shared_ptr<IVibrationSession> & session)193 void VibratorManager::clearSession(const std::shared_ptr<IVibrationSession>& session) {
194     std::lock_guard lock(mMutex);
195     if (mSession != session) {
196         // Probably a delayed call from an old session that was already cleared, ignore it.
197         return;
198     }
199     std::shared_ptr<IVibratorCallback> callback = mSessionCallback;
200     mSession = nullptr;
201     mSessionCallback = nullptr;  // make sure any delayed call will not trigger this again.
202     mIsClosingSession = false;
203     if (callback) {
204         std::thread([callback] {
205             LOG(VERBOSE) << "Notifying session complete";
206             if (!callback->onComplete().isOk()) {
207                 LOG(ERROR) << "Failed to call onComplete";
208             }
209         }).detach();
210     }
211 }
212 
213 }  // namespace vibrator
214 }  // namespace hardware
215 }  // namespace android
216 }  // namespace aidl
217