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