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