1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "key_gesture_manager.h"
17
18 #include <algorithm>
19
20 #include "account_manager.h"
21 #include "app_state_observer.h"
22 #include "define_multimodal.h"
23 #include "display_event_monitor.h"
24 #include "event_log_helper.h"
25 #include "timer_manager.h"
26 #include "util.h"
27
28 #undef MMI_LOG_DOMAIN
29 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
30 #undef MMI_LOG_TAG
31 #define MMI_LOG_TAG "KeyGestureManager"
32
33 namespace OHOS {
34 namespace MMI {
35 namespace {
36 constexpr int32_t COMBINATION_KEY_TIMEOUT { 150 };
37 constexpr int32_t INVALID_ENTITY_ID { -1 };
38 constexpr int32_t REPEAT_ONCE { 1 };
39 constexpr size_t SINGLE_KEY_PRESSED { 1 };
40 }
41
~Handler()42 KeyGestureManager::Handler::~Handler()
43 {
44 ResetTimer();
45 }
46
ResetTimer()47 void KeyGestureManager::Handler::ResetTimer()
48 {
49 if (timerId_ >= 0) {
50 TimerMgr->RemoveTimer(timerId_);
51 timerId_ = INVALID_ENTITY_ID;
52 }
53 }
54
Trigger(std::shared_ptr<KeyEvent> keyEvent)55 void KeyGestureManager::Handler::Trigger(std::shared_ptr<KeyEvent> keyEvent)
56 {
57 MMI_HILOGI("[Handler] Handler will run after %{public}dms", GetLongPressTime());
58 keyEvent_ = KeyEvent::Clone(keyEvent);
59 timerId_ = TimerMgr->AddTimer(GetLongPressTime(), REPEAT_ONCE,
60 [this]() {
61 CHKPV(keyEvent_);
62 Run(keyEvent_);
63 keyEvent_ = nullptr;
64 timerId_ = INVALID_ENTITY_ID;
65 });
66 if (timerId_ < 0) {
67 MMI_HILOGI("[Handler] AddTimer fail");
68 }
69 }
70
Run(std::shared_ptr<KeyEvent> keyEvent) const71 void KeyGestureManager::Handler::Run(std::shared_ptr<KeyEvent> keyEvent) const
72 {
73 if (callback_ != nullptr) {
74 callback_(keyEvent);
75 }
76 }
77
RunPending()78 void KeyGestureManager::Handler::RunPending()
79 {
80 if (keyEvent_ != nullptr) {
81 Run(keyEvent_);
82 keyEvent_ = nullptr;
83 }
84 }
85
IsWorking()86 bool KeyGestureManager::KeyGesture::IsWorking()
87 {
88 return true;
89 }
90
AddHandler(int32_t pid,int32_t longPressTime,std::function<void (std::shared_ptr<KeyEvent>)> callback)91 int32_t KeyGestureManager::KeyGesture::AddHandler(int32_t pid, int32_t longPressTime,
92 std::function<void(std::shared_ptr<KeyEvent>)> callback)
93 {
94 static int32_t baseId { 0 };
95
96 longPressTime = std::max(longPressTime, COMBINATION_KEY_TIMEOUT);
97 return handlers_.emplace_back(++baseId, pid, longPressTime, callback).GetId();
98 }
99
RemoveHandler(int32_t id)100 bool KeyGestureManager::KeyGesture::RemoveHandler(int32_t id)
101 {
102 for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) {
103 if (iter->GetId() == id) {
104 iter->ResetTimer();
105 handlers_.erase(iter);
106 MMI_HILOGI("Handler(%{public}d) of key gesture was removed", iter->GetId());
107 return true;
108 }
109 }
110 return false;
111 }
112
Reset()113 void KeyGestureManager::KeyGesture::Reset()
114 {
115 MarkActive(false);
116 ResetTimers();
117 }
118
ResetTimers()119 void KeyGestureManager::KeyGesture::ResetTimers()
120 {
121 for (auto &handler : handlers_) {
122 handler.ResetTimer();
123 }
124 }
125
GetForegroundPids() const126 std::set<int32_t> KeyGestureManager::KeyGesture::GetForegroundPids() const
127 {
128 std::set<int32_t> pids;
129 std::vector<AppExecFwk::AppStateData> appStates = APP_OBSERVER_MGR->GetForegroundAppData();
130 std::for_each(appStates.cbegin(), appStates.cend(), [&pids](auto &appState) {
131 pids.insert(appState.pid);
132 });
133 return pids;
134 }
135
HaveForegroundHandler(const std::set<int32_t> & foregroundApps) const136 bool KeyGestureManager::KeyGesture::HaveForegroundHandler(const std::set<int32_t> &foregroundApps) const
137 {
138 return std::any_of(handlers_.cbegin(), handlers_.cend(), [&foregroundApps](const auto &handler) {
139 return (foregroundApps.find(handler.GetPid()) != foregroundApps.cend());
140 });
141 }
142
TriggerHandlers(std::shared_ptr<KeyEvent> keyEvent)143 void KeyGestureManager::KeyGesture::TriggerHandlers(std::shared_ptr<KeyEvent> keyEvent)
144 {
145 std::set<int32_t> foregroundPids = GetForegroundPids();
146 bool haveForeground = HaveForegroundHandler(foregroundPids);
147
148 for (auto &handler : handlers_) {
149 if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
150 handler.Trigger(keyEvent);
151 }
152 }
153 }
154
RunHandler(int32_t handlerId,std::shared_ptr<KeyEvent> keyEvent)155 void KeyGestureManager::KeyGesture::RunHandler(int32_t handlerId, std::shared_ptr<KeyEvent> keyEvent)
156 {
157 for (auto &handler : handlers_) {
158 if (handler.GetId() == handlerId) {
159 handler.ResetTimer();
160 handler.Run(keyEvent);
161 break;
162 }
163 }
164 }
165
NotifyHandlers(std::shared_ptr<KeyEvent> keyEvent)166 void KeyGestureManager::KeyGesture::NotifyHandlers(std::shared_ptr<KeyEvent> keyEvent)
167 {
168 std::set<int32_t> foregroundPids = GetForegroundPids();
169 bool haveForeground = HaveForegroundHandler(foregroundPids);
170
171 for (auto &handler : handlers_) {
172 if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
173 handler.Run(keyEvent);
174 }
175 }
176 }
177
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const178 bool KeyGestureManager::LongPressSingleKey::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
179 {
180 std::set<int32_t> keys = keyOption->GetPreKeys();
181 return (keys.empty() &&
182 (keyOption->GetFinalKey() == keyCode_) &&
183 keyOption->IsFinalKeyDown() &&
184 (keyOption->GetFinalKeyDownDuration() < COMBINATION_KEY_TIMEOUT));
185 }
186
Intercept(std::shared_ptr<KeyEvent> keyEvent)187 bool KeyGestureManager::LongPressSingleKey::Intercept(std::shared_ptr<KeyEvent> keyEvent)
188 {
189 if ((keyEvent->GetKeyCode() == keyCode_) && (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN)) {
190 if (IsActive()) {
191 int64_t now = GetSysClockTime();
192 if (now >= (firstDownTime_ + MS2US(COMBINATION_KEY_TIMEOUT))) {
193 NotifyHandlers(keyEvent);
194 }
195 } else {
196 firstDownTime_ = GetSysClockTime();
197 MarkActive(true);
198 TriggerHandlers(keyEvent);
199 }
200 return true;
201 }
202 if (IsActive()) {
203 Reset();
204 RunPendingHandlers();
205 }
206 return false;
207 }
208
Dump(std::ostringstream & output) const209 void KeyGestureManager::LongPressSingleKey::Dump(std::ostringstream &output) const
210 {
211 output << "[" << keyCode_ << "] --> {";
212 if (auto iter = handlers_.begin(); iter != handlers_.end()) {
213 output << iter->GetLongPressTime();
214 for (++iter; iter != handlers_.end(); ++iter) {
215 output << "," << iter->GetLongPressTime();
216 }
217 }
218 output << "}";
219 }
220
RunPendingHandlers()221 void KeyGestureManager::LongPressSingleKey::RunPendingHandlers()
222 {
223 std::set<int32_t> foregroundPids = GetForegroundPids();
224 bool haveForeground = HaveForegroundHandler(foregroundPids);
225
226 for (auto &handler : handlers_) {
227 if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
228 handler.RunPending();
229 }
230 }
231 }
232
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const233 bool KeyGestureManager::LongPressCombinationKey::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
234 {
235 std::set<int32_t> keys = keyOption->GetPreKeys();
236 keys.insert(keyOption->GetFinalKey());
237 return (keys_ == keys);
238 }
239
Intercept(std::shared_ptr<KeyEvent> keyEvent)240 bool KeyGestureManager::LongPressCombinationKey::Intercept(std::shared_ptr<KeyEvent> keyEvent)
241 {
242 if ((keys_.find(keyEvent->GetKeyCode()) != keys_.end()) &&
243 (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN)) {
244 if (IsActive()) {
245 std::ostringstream output;
246 output << "[LongPressCombinationKey] ";
247 Dump(output);
248 if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
249 MMI_HILOGI("%s is active now", output.str().c_str());
250 } else {
251 MMI_HILOGI("%s is active now", output.str().c_str());
252 }
253 return true;
254 }
255 if (!IsWorking()) {
256 std::ostringstream output;
257 output << "[LongPressCombinationKey] Switch off ";
258 Dump(output);
259 if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
260 MMI_HILOGI("%s switch off", output.str().c_str());
261 } else {
262 MMI_HILOGI("%s switch off", output.str().c_str());
263 }
264 return false;
265 }
266 if (handlers_.empty()) {
267 std::ostringstream output;
268 output << "[LongPressCombinationKey] No handler for ";
269 Dump(output);
270 if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
271 MMI_HILOGI("No handler for %s", output.str().c_str());
272 } else {
273 MMI_HILOGI("No handler for %s", output.str().c_str());
274 }
275 return false;
276 }
277 if (RecognizeGesture(keyEvent)) {
278 TriggerAll(keyEvent);
279 return true;
280 }
281 }
282 if (IsActive()) {
283 Reset();
284 }
285 return false;
286 }
287
Dump(std::ostringstream & output) const288 void KeyGestureManager::LongPressCombinationKey::Dump(std::ostringstream &output) const
289 {
290 output << "[";
291 if (auto keyIter = keys_.begin(); keyIter != keys_.end()) {
292 output << *keyIter;
293 for (++keyIter; keyIter != keys_.end(); ++keyIter) {
294 output << "," << *keyIter;
295 }
296 }
297 output << "] --> {";
298 if (auto iter = handlers_.begin(); iter != handlers_.end()) {
299 output << "(ID:" << iter->GetId() << ",T:" << iter->GetLongPressTime() << ")";
300 for (++iter; iter != handlers_.end(); ++iter) {
301 output << ",(ID:" << iter->GetId() << ",T:" << iter->GetLongPressTime() << ")";
302 }
303 }
304 output << "}";
305 }
306
RecognizeGesture(std::shared_ptr<KeyEvent> keyEvent)307 bool KeyGestureManager::LongPressCombinationKey::RecognizeGesture(std::shared_ptr<KeyEvent> keyEvent)
308 {
309 if (keyEvent->GetPressedKeys().size() == SINGLE_KEY_PRESSED) {
310 firstDownTime_ = GetSysClockTime();
311 }
312 int64_t now = GetSysClockTime();
313 return std::all_of(keys_.cbegin(), keys_.cend(), [this, keyEvent, now](auto keyCode) {
314 auto itemOpt = keyEvent->GetKeyItem(keyCode);
315 return (itemOpt && itemOpt->IsPressed() &&
316 (now < (firstDownTime_ + MS2US(COMBINATION_KEY_TIMEOUT))));
317 });
318 }
319
TriggerAll(std::shared_ptr<KeyEvent> keyEvent)320 void KeyGestureManager::LongPressCombinationKey::TriggerAll(std::shared_ptr<KeyEvent> keyEvent)
321 {
322 MarkActive(true);
323 std::ostringstream output;
324 output << "[LongPressCombinationKey] trigger ";
325 Dump(output);
326 if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
327 MMI_HILOGI("%s trigger", output.str().c_str());
328 } else {
329 MMI_HILOGI("%s trigger", output.str().c_str());
330 }
331 OnTriggerAll(keyEvent);
332 TriggerHandlers(keyEvent);
333 }
334
PullUpAccessibility()335 KeyGestureManager::PullUpAccessibility::PullUpAccessibility()
336 : LongPressCombinationKey(std::set({ KeyEvent::KEYCODE_VOLUME_DOWN, KeyEvent::KEYCODE_VOLUME_UP }))
337 {}
338
IsWorking()339 bool KeyGestureManager::PullUpAccessibility::IsWorking()
340 {
341 if ((DISPLAY_MONITOR->GetScreenStatus() == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_OFF)) {
342 return false;
343 }
344 if (DISPLAY_MONITOR->GetScreenLocked()) {
345 return ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutEnabledOnScreenLocked();
346 } else {
347 return ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutEnabled();
348 }
349 }
350
AddHandler(int32_t pid,int32_t longPressTime,std::function<void (std::shared_ptr<KeyEvent>)> callback)351 int32_t KeyGestureManager::PullUpAccessibility::AddHandler(int32_t pid,
352 int32_t longPressTime, std::function<void(std::shared_ptr<KeyEvent>)> callback)
353 {
354 return KeyGesture::AddHandler(pid, ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout(), callback);
355 }
356
OnTriggerAll(std::shared_ptr<KeyEvent> keyEvent)357 void KeyGestureManager::PullUpAccessibility::OnTriggerAll(std::shared_ptr<KeyEvent> keyEvent)
358 {
359 MMI_HILOGI("[PullUpAccessibility] Current AccShortcutTimeout setting: %{public}dms",
360 ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout());
361 for (auto &handler : handlers_) {
362 handler.SetLongPressTime(ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout());
363 }
364 }
365
KeyGestureManager()366 KeyGestureManager::KeyGestureManager()
367 {
368 keyGestures_.push_back(std::make_unique<PullUpAccessibility>());
369 keyGestures_.push_back(std::make_unique<LongPressSingleKey>(KeyEvent::KEYCODE_VOLUME_DOWN));
370 keyGestures_.push_back(std::make_unique<LongPressSingleKey>(KeyEvent::KEYCODE_VOLUME_UP));
371 }
372
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const373 bool KeyGestureManager::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
374 {
375 CALL_INFO_TRACE;
376 CHKPF(keyOption);
377 return std::any_of(keyGestures_.cbegin(), keyGestures_.cend(),
378 [keyOption](const auto &keyGesture) {
379 return keyGesture->ShouldIntercept(keyOption);
380 });
381 }
382
AddKeyGesture(int32_t pid,std::shared_ptr<KeyOption> keyOption,std::function<void (std::shared_ptr<KeyEvent>)> callback)383 int32_t KeyGestureManager::AddKeyGesture(int32_t pid, std::shared_ptr<KeyOption> keyOption,
384 std::function<void(std::shared_ptr<KeyEvent>)> callback)
385 {
386 CHKPR(keyOption, INVALID_ENTITY_ID);
387 for (auto &keyGesture : keyGestures_) {
388 if (keyGesture->ShouldIntercept(keyOption)) {
389 auto downDuration = std::max(keyOption->GetFinalKeyDownDuration(), COMBINATION_KEY_TIMEOUT);
390 return keyGesture->AddHandler(pid, downDuration, callback);
391 }
392 }
393 return INVALID_ENTITY_ID;
394 }
395
RemoveKeyGesture(int32_t id)396 void KeyGestureManager::RemoveKeyGesture(int32_t id)
397 {
398 for (auto &keyGesture : keyGestures_) {
399 if (keyGesture->RemoveHandler(id)) {
400 break;
401 }
402 }
403 }
404
Intercept(std::shared_ptr<KeyEvent> keyEvent)405 bool KeyGestureManager::Intercept(std::shared_ptr<KeyEvent> keyEvent)
406 {
407 CALL_INFO_TRACE;
408 CHKPF(keyEvent);
409 for (auto iter = keyGestures_.begin(); iter != keyGestures_.end(); ++iter) {
410 if ((*iter)->Intercept(keyEvent)) {
411 std::ostringstream output;
412 (*iter)->Dump(output);
413 if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
414 MMI_HILOGI("Intercepted by %s", output.str().c_str());
415 } else {
416 MMI_HILOGI("Intercepted by %s", output.str().c_str());
417 }
418 for (++iter; iter != keyGestures_.end(); ++iter) {
419 (*iter)->Reset();
420 }
421 return true;
422 }
423 }
424 return false;
425 }
426
ResetAll()427 void KeyGestureManager::ResetAll()
428 {
429 for (auto &keyGesture : keyGestures_) {
430 keyGesture->Reset();
431 }
432 }
433
Dump() const434 void KeyGestureManager::Dump() const
435 {
436 for (const auto &keyGesture : keyGestures_) {
437 std::ostringstream output;
438 keyGesture->Dump(output);
439 MMI_HILOGI("%s", output.str().c_str());
440 }
441 }
442 } // namespace MMI
443 } // namespace OHOS
444