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