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