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