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