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