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 MAX_N_PRINTABLE_ITEMS { 5 };
40 constexpr size_t SINGLE_KEY_PRESSED { 1 };
41 }
42 
~Handler()43 KeyGestureManager::Handler::~Handler()
44 {
45     ResetTimer();
46 }
47 
ResetTimer()48 void KeyGestureManager::Handler::ResetTimer()
49 {
50     if (timerId_ >= 0) {
51         TimerMgr->RemoveTimer(timerId_);
52         timerId_ = INVALID_ENTITY_ID;
53     }
54 }
55 
Trigger(std::shared_ptr<KeyEvent> keyEvent)56 void KeyGestureManager::Handler::Trigger(std::shared_ptr<KeyEvent> keyEvent)
57 {
58     MMI_HILOGI("[Handler] Handler will run after %{public}dms", GetLongPressTime());
59     keyEvent_ = KeyEvent::Clone(keyEvent);
60     timerId_ = TimerMgr->AddTimer(GetLongPressTime(), REPEAT_ONCE,
61         [this]() {
62             CHKPV(keyEvent_);
63             Run(keyEvent_);
64             keyEvent_ = nullptr;
65             timerId_ = INVALID_ENTITY_ID;
66         });
67     if (timerId_ < 0) {
68         MMI_HILOGI("[Handler] AddTimer fail");
69     }
70 }
71 
Run(std::shared_ptr<KeyEvent> keyEvent) const72 void KeyGestureManager::Handler::Run(std::shared_ptr<KeyEvent> keyEvent) const
73 {
74     if (callback_ != nullptr) {
75         callback_(keyEvent);
76     }
77 }
78 
RunPending()79 void KeyGestureManager::Handler::RunPending()
80 {
81     if (keyEvent_ != nullptr) {
82         Run(keyEvent_);
83         keyEvent_ = nullptr;
84     }
85 }
86 
IsWorking()87 bool KeyGestureManager::KeyGesture::IsWorking()
88 {
89     return true;
90 }
91 
AddHandler(int32_t pid, int32_t longPressTime, std::function<void(std::shared_ptr<KeyEvent>)> callback)92 int32_t KeyGestureManager::KeyGesture::AddHandler(int32_t pid, int32_t longPressTime,
93     std::function<void(std::shared_ptr<KeyEvent>)> callback)
94 {
95     static int32_t baseId { 0 };
96 
97     longPressTime = std::max(longPressTime, COMBINATION_KEY_TIMEOUT);
98     return handlers_.emplace_back(++baseId, pid, longPressTime, callback).GetId();
99 }
100 
RemoveHandler(int32_t id)101 bool KeyGestureManager::KeyGesture::RemoveHandler(int32_t id)
102 {
103     for (auto iter = handlers_.begin(); iter != handlers_.end(); ++iter) {
104         if (iter->GetId() == id) {
105             iter->ResetTimer();
106             handlers_.erase(iter);
107             MMI_HILOGI("Handler(%{public}d) of key gesture was removed", iter->GetId());
108             return true;
109         }
110     }
111     return false;
112 }
113 
Reset()114 void KeyGestureManager::KeyGesture::Reset()
115 {
116     MarkActive(false);
117     ResetTimers();
118 }
119 
ResetTimers()120 void KeyGestureManager::KeyGesture::ResetTimers()
121 {
122     for (auto &handler : handlers_) {
123         handler.ResetTimer();
124     }
125 }
126 
GetForegroundPids() const127 std::set<int32_t> KeyGestureManager::KeyGesture::GetForegroundPids() const
128 {
129     std::set<int32_t> pids;
130     std::vector<AppExecFwk::AppStateData> appStates = APP_OBSERVER_MGR->GetForegroundAppData();
131     std::for_each(appStates.cbegin(), appStates.cend(), [&pids](auto &appState) {
132         pids.insert(appState.pid);
133     });
134 
135     std::ostringstream sPids;
136     size_t nItems = 0;
137 
138     if (auto iter = pids.cbegin(); iter != pids.cend()) {
139         sPids << *iter;
140         ++nItems;
141 
142         for (++iter; iter != pids.cend(); ++iter) {
143             if (nItems > MAX_N_PRINTABLE_ITEMS) {
144                 sPids << ",...";
145                 break;
146             }
147             sPids << "," << *iter;
148             ++nItems;
149         }
150     }
151     MMI_HILOGI("Foreground pids: {%{public}zu}[%{public}s]", pids.size(), sPids.str().c_str());
152     return pids;
153 }
154 
HaveForegroundHandler(const std::set<int32_t> &foregroundApps) const155 bool KeyGestureManager::KeyGesture::HaveForegroundHandler(const std::set<int32_t> &foregroundApps) const
156 {
157     return std::any_of(handlers_.cbegin(), handlers_.cend(), [&foregroundApps](const auto &handler) {
158         return (foregroundApps.find(handler.GetPid()) != foregroundApps.cend());
159     });
160 }
161 
TriggerHandlers(std::shared_ptr<KeyEvent> keyEvent)162 void KeyGestureManager::KeyGesture::TriggerHandlers(std::shared_ptr<KeyEvent> keyEvent)
163 {
164     std::set<int32_t> foregroundPids = GetForegroundPids();
165     bool haveForeground = HaveForegroundHandler(foregroundPids);
166     ShowHandlers(std::string("TriggerHandlers"), foregroundPids);
167 
168     for (auto &handler : handlers_) {
169         if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
170             handler.Trigger(keyEvent);
171         }
172     }
173 }
174 
RunHandler(int32_t handlerId, std::shared_ptr<KeyEvent> keyEvent)175 void KeyGestureManager::KeyGesture::RunHandler(int32_t handlerId, std::shared_ptr<KeyEvent> keyEvent)
176 {
177     for (auto &handler : handlers_) {
178         if (handler.GetId() == handlerId) {
179             handler.ResetTimer();
180             handler.Run(keyEvent);
181             break;
182         }
183     }
184 }
185 
NotifyHandlers(std::shared_ptr<KeyEvent> keyEvent)186 void KeyGestureManager::KeyGesture::NotifyHandlers(std::shared_ptr<KeyEvent> keyEvent)
187 {
188     std::set<int32_t> foregroundPids = GetForegroundPids();
189     bool haveForeground = HaveForegroundHandler(foregroundPids);
190     ShowHandlers(std::string("NotifyHandlers"), foregroundPids);
191 
192     for (auto &handler : handlers_) {
193         if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
194             handler.Run(keyEvent);
195         }
196     }
197 }
198 
ShowHandlers( const std::string &prefix, const std::set<int32_t> &foregroundPids) const199 void KeyGestureManager::KeyGesture::ShowHandlers(
200     const std::string &prefix, const std::set<int32_t> &foregroundPids) const
201 {
202     std::ostringstream output;
203     size_t nHandlers = 0;
204 
205     for (const auto &handler : handlers_) {
206         if (nHandlers > MAX_N_PRINTABLE_ITEMS) {
207             output << "...";
208             break;
209         }
210         ++nHandlers;
211         output << "[" << handler.GetId() << "," << handler.GetPid()
212             << (foregroundPids.find(handler.GetPid()) != foregroundPids.cend() ? ",F]" : ",B]");
213     }
214     MMI_HILOGI("[KeyGesture] %{public}s {%{public}zu}%{public}s",
215         prefix.c_str(), handlers_.size(), output.str().c_str());
216 }
217 
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const218 bool KeyGestureManager::LongPressSingleKey::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
219 {
220     std::set<int32_t> keys = keyOption->GetPreKeys();
221     return (keys.empty() &&
222             (keyOption->GetFinalKey() == keyCode_) &&
223             keyOption->IsFinalKeyDown() &&
224             (keyOption->GetFinalKeyDownDuration() < COMBINATION_KEY_TIMEOUT));
225 }
226 
Intercept(std::shared_ptr<KeyEvent> keyEvent)227 bool KeyGestureManager::LongPressSingleKey::Intercept(std::shared_ptr<KeyEvent> keyEvent)
228 {
229     if ((keyEvent->GetKeyCode() == keyCode_) && (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN)) {
230         if (IsActive()) {
231             int64_t now = GetSysClockTime();
232             if (now >= (firstDownTime_ + MS2US(COMBINATION_KEY_TIMEOUT))) {
233                 NotifyHandlers(keyEvent);
234             }
235         } else {
236             firstDownTime_ = GetSysClockTime();
237             MarkActive(true);
238             TriggerHandlers(keyEvent);
239         }
240         return true;
241     }
242     if (IsActive()) {
243         Reset();
244         RunPendingHandlers();
245     }
246     return false;
247 }
248 
Dump(std::ostringstream &output) const249 void KeyGestureManager::LongPressSingleKey::Dump(std::ostringstream &output) const
250 {
251     output << "[" << keyCode_ << "] --> {";
252     if (auto iter = handlers_.begin(); iter != handlers_.end()) {
253         output << iter->GetLongPressTime();
254         for (++iter; iter != handlers_.end(); ++iter) {
255             output << "," << iter->GetLongPressTime();
256         }
257     }
258     output << "}";
259 }
260 
RunPendingHandlers()261 void KeyGestureManager::LongPressSingleKey::RunPendingHandlers()
262 {
263     std::set<int32_t> foregroundPids = GetForegroundPids();
264     bool haveForeground = HaveForegroundHandler(foregroundPids);
265     ShowHandlers(std::string("RunPendingHandlers"), foregroundPids);
266 
267     for (auto &handler : handlers_) {
268         if (!haveForeground || (foregroundPids.find(handler.GetPid()) != foregroundPids.end())) {
269             handler.RunPending();
270         }
271     }
272 }
273 
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const274 bool KeyGestureManager::LongPressCombinationKey::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
275 {
276     std::set<int32_t> keys = keyOption->GetPreKeys();
277     keys.insert(keyOption->GetFinalKey());
278     return (keys_ == keys);
279 }
280 
Intercept(std::shared_ptr<KeyEvent> keyEvent)281 bool KeyGestureManager::LongPressCombinationKey::Intercept(std::shared_ptr<KeyEvent> keyEvent)
282 {
283     if ((keys_.find(keyEvent->GetKeyCode()) != keys_.end()) &&
284         (keyEvent->GetKeyAction() == KeyEvent::KEY_ACTION_DOWN)) {
285         if (IsActive()) {
286             std::ostringstream output;
287             Dump(output);
288             if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
289                 MMI_HILOGI("[LongPressCombinationKey] %{public}s is active now", output.str().c_str());
290             } else {
291                 MMI_HILOGI("[LongPressCombinationKey] %s is active now", output.str().c_str());
292             }
293             return true;
294         }
295         if (!IsWorking()) {
296             std::ostringstream output;
297             Dump(output);
298             if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
299                 MMI_HILOGI("[LongPressCombinationKey] Switch off %{public}s", output.str().c_str());
300             } else {
301                 MMI_HILOGI("[LongPressCombinationKey] Switch off %s", output.str().c_str());
302             }
303             return false;
304         }
305         if (handlers_.empty()) {
306             std::ostringstream output;
307             Dump(output);
308             if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
309                 MMI_HILOGI("[LongPressCombinationKey] No handler for %{public}s", output.str().c_str());
310             } else {
311                 MMI_HILOGI("[LongPressCombinationKey] No handler for %s", output.str().c_str());
312             }
313             return false;
314         }
315         if (RecognizeGesture(keyEvent)) {
316             TriggerAll(keyEvent);
317             return true;
318         }
319     }
320     if (IsActive()) {
321         Reset();
322     }
323     return false;
324 }
325 
Dump(std::ostringstream &output) const326 void KeyGestureManager::LongPressCombinationKey::Dump(std::ostringstream &output) const
327 {
328     output << "[";
329     if (auto keyIter = keys_.begin(); keyIter != keys_.end()) {
330         output << *keyIter;
331         for (++keyIter; keyIter != keys_.end(); ++keyIter) {
332             output << "," << *keyIter;
333         }
334     }
335     output << "] --> {";
336     if (auto iter = handlers_.begin(); iter != handlers_.end()) {
337         output << "(ID:" << iter->GetId() << ",T:" << iter->GetLongPressTime() << ")";
338         for (++iter; iter != handlers_.end(); ++iter) {
339             output << ",(ID:" << iter->GetId() << ",T:" << iter->GetLongPressTime() << ")";
340         }
341     }
342     output << "}";
343 }
344 
RecognizeGesture(std::shared_ptr<KeyEvent> keyEvent)345 bool KeyGestureManager::LongPressCombinationKey::RecognizeGesture(std::shared_ptr<KeyEvent> keyEvent)
346 {
347     if (keyEvent->GetPressedKeys().size() == SINGLE_KEY_PRESSED) {
348         firstDownTime_ = GetSysClockTime();
349     }
350     int64_t now = GetSysClockTime();
351     return std::all_of(keys_.cbegin(), keys_.cend(), [this, keyEvent, now](auto keyCode) {
352         auto itemOpt = keyEvent->GetKeyItem(keyCode);
353         return (itemOpt && itemOpt->IsPressed() &&
354                 (now < (firstDownTime_ + MS2US(COMBINATION_KEY_TIMEOUT))));
355     });
356 }
357 
TriggerAll(std::shared_ptr<KeyEvent> keyEvent)358 void KeyGestureManager::LongPressCombinationKey::TriggerAll(std::shared_ptr<KeyEvent> keyEvent)
359 {
360     MarkActive(true);
361     std::ostringstream output;
362     Dump(output);
363     if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
364         MMI_HILOGI("[LongPressCombinationKey] trigger %{public}s", output.str().c_str());
365     } else {
366         MMI_HILOGI("[LongPressCombinationKey] trigger %s", output.str().c_str());
367     }
368     OnTriggerAll(keyEvent);
369     TriggerHandlers(keyEvent);
370 }
371 
PullUpAccessibility()372 KeyGestureManager::PullUpAccessibility::PullUpAccessibility()
373     : LongPressCombinationKey(std::set({ KeyEvent::KEYCODE_VOLUME_DOWN, KeyEvent::KEYCODE_VOLUME_UP }))
374 {}
375 
IsWorking()376 bool KeyGestureManager::PullUpAccessibility::IsWorking()
377 {
378     if ((DISPLAY_MONITOR->GetScreenStatus() == EventFwk::CommonEventSupport::COMMON_EVENT_SCREEN_OFF)) {
379         return false;
380     }
381     if (DISPLAY_MONITOR->GetScreenLocked()) {
382         return ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutEnabledOnScreenLocked();
383     } else {
384         return ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutEnabled();
385     }
386 }
387 
AddHandler(int32_t pid, int32_t longPressTime, std::function<void(std::shared_ptr<KeyEvent>)> callback)388 int32_t KeyGestureManager::PullUpAccessibility::AddHandler(int32_t pid,
389     int32_t longPressTime, std::function<void(std::shared_ptr<KeyEvent>)> callback)
390 {
391     return KeyGesture::AddHandler(pid, ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout(), callback);
392 }
393 
OnTriggerAll(std::shared_ptr<KeyEvent> keyEvent)394 void KeyGestureManager::PullUpAccessibility::OnTriggerAll(std::shared_ptr<KeyEvent> keyEvent)
395 {
396     MMI_HILOGI("[PullUpAccessibility] Current AccShortcutTimeout setting: %{public}dms",
397         ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout());
398     for (auto &handler : handlers_) {
399         handler.SetLongPressTime(ACCOUNT_MGR->GetCurrentAccountSetting().GetAccShortcutTimeout());
400     }
401 }
402 
KeyGestureManager()403 KeyGestureManager::KeyGestureManager()
404 {
405     keyGestures_.push_back(std::make_unique<PullUpAccessibility>());
406     keyGestures_.push_back(std::make_unique<LongPressSingleKey>(KeyEvent::KEYCODE_VOLUME_DOWN));
407     keyGestures_.push_back(std::make_unique<LongPressSingleKey>(KeyEvent::KEYCODE_VOLUME_UP));
408 }
409 
ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const410 bool KeyGestureManager::ShouldIntercept(std::shared_ptr<KeyOption> keyOption) const
411 {
412     CALL_INFO_TRACE;
413     CHKPF(keyOption);
414     return std::any_of(keyGestures_.cbegin(), keyGestures_.cend(),
415         [keyOption](const auto &keyGesture) {
416             return keyGesture->ShouldIntercept(keyOption);
417         });
418 }
419 
420 int32_t KeyGestureManager::AddKeyGesture(int32_t pid, std::shared_ptr<KeyOption> keyOption,
421     std::function<void(std::shared_ptr<KeyEvent>)> callback)
422 {
423     CHKPR(keyOption, INVALID_ENTITY_ID);
424     for (auto &keyGesture : keyGestures_) {
425         if (keyGesture->ShouldIntercept(keyOption)) {
426             auto downDuration = std::max(keyOption->GetFinalKeyDownDuration(), COMBINATION_KEY_TIMEOUT);
427             return keyGesture->AddHandler(pid, downDuration, callback);
428         }
429     }
430     return INVALID_ENTITY_ID;
431 }
432 
433 void KeyGestureManager::RemoveKeyGesture(int32_t id)
434 {
435     for (auto &keyGesture : keyGestures_) {
436         if (keyGesture->RemoveHandler(id)) {
437             break;
438         }
439     }
440 }
441 
442 bool KeyGestureManager::Intercept(std::shared_ptr<KeyEvent> keyEvent)
443 {
444     CALL_INFO_TRACE;
445     CHKPF(keyEvent);
446     for (auto iter = keyGestures_.begin(); iter != keyGestures_.end(); ++iter) {
447         if ((*iter)->Intercept(keyEvent)) {
448             std::ostringstream output;
449             (*iter)->Dump(output);
450             if (EventLogHelper::IsBetaVersion() && !keyEvent->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
451                 MMI_HILOGI("Intercepted by %{public}s", output.str().c_str());
452             } else {
453                 MMI_HILOGI("Intercepted by %s", output.str().c_str());
454             }
455             for (++iter; iter != keyGestures_.end(); ++iter) {
456                 (*iter)->Reset();
457             }
458             return true;
459         }
460     }
461     return false;
462 }
463 
464 void KeyGestureManager::ResetAll()
465 {
466     for (auto &keyGesture : keyGestures_) {
467         keyGesture->Reset();
468     }
469 }
470 
471 void KeyGestureManager::Dump() const
472 {
473     for (const auto &keyGesture : keyGestures_) {
474         std::ostringstream output;
475         keyGesture->Dump(output);
476         MMI_HILOGI("%s", output.str().c_str());
477     }
478 }
479 } // namespace MMI
480 } // namespace OHOS
481