• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "intention_event_manager.h"
17 
18 #ifdef IMF_ENABLE
19 #include <input_method_controller.h>
20 #endif // IMF_ENABLE
21 #include "session_helper.h"
22 #include "session_manager/include/scene_session_manager.h"
23 #include "window_manager_hilog.h"
24 #include <hitrace_meter.h>
25 #include "parameters.h"
26 #include "xcollie/xcollie.h"
27 
28 namespace OHOS {
29 namespace Rosen {
30 namespace {
31 constexpr HiviewDFX::HiLogLabel LABEL = { LOG_CORE, HILOG_DOMAIN_WINDOW, "IntentionEventManager" };
32 constexpr int32_t TRANSPARENT_FINGER_ID = 10000;
33 constexpr int32_t DELAY_TIME = 15;
34 constexpr unsigned int FREQUENT_CLICK_TIME_LIMIT = 3;
35 constexpr int FREQUENT_CLICK_COUNT_LIMIT = 8;
36 static const bool IS_BETA = OHOS::system::GetParameter("const.logsystem.versiontype", "").find("beta") !=
37     std::string::npos;
38 
LogPointInfo(const std::shared_ptr<MMI::PointerEvent> & pointerEvent)39 void LogPointInfo(const std::shared_ptr<MMI::PointerEvent>& pointerEvent)
40 {
41     if (pointerEvent == nullptr) {
42         return;
43     }
44 
45     uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetTargetWindowId());
46     TLOGD(WmsLogTag::WMS_EVENT, "point source:%{public}d", pointerEvent->GetSourceType());
47     auto actionId = pointerEvent->GetPointerId();
48     int32_t action = pointerEvent->GetPointerAction();
49     if (action == MMI::PointerEvent::POINTER_ACTION_MOVE) {
50         return;
51     }
52 
53     MMI::PointerEvent::PointerItem item;
54     if (pointerEvent->GetPointerItem(actionId, item)) {
55         TLOGD(WmsLogTag::WMS_EVENT, "action point info:windowid:%{public}d,id:%{public}d,displayx:%{private}d,"
56             "displayy:%{private}d,windowx:%{private}d,windowy:%{private}d,action:%{public}d pressure:"
57             "%{public}f,tiltx:%{public}f,tiltY:%{public}f",
58             windowId, actionId, item.GetDisplayX(), item.GetDisplayY(), item.GetWindowX(), item.GetWindowY(),
59             pointerEvent->GetPointerAction(), item.GetPressure(), item.GetTiltX(), item.GetTiltY());
60     }
61     auto ids = pointerEvent->GetPointerIds();
62     for (auto&& id :ids) {
63         MMI::PointerEvent::PointerItem item;
64         if (pointerEvent->GetPointerItem(id, item)) {
65             TLOGD(WmsLogTag::WMS_EVENT, "all point info: id:%{public}d,x:%{private}d,y:%{private}d,"
66                 "isPressend:%{public}d,pressure:%{public}f,tiltX:%{public}f,tiltY:%{public}f",
67             actionId, item.GetWindowX(), item.GetWindowY(), item.IsPressed(), item.GetPressure(),
68             item.GetTiltX(), item.GetTiltY());
69         }
70     }
71 }
72 } // namespace
73 
IntentionEventManager()74 IntentionEventManager::IntentionEventManager() {}
~IntentionEventManager()75 IntentionEventManager::~IntentionEventManager() {}
76 
~InputEventListener()77 IntentionEventManager::InputEventListener::~InputEventListener()
78 {
79 }
80 
EnableInputEventListener(Ace::UIContent * uiContent,std::shared_ptr<AppExecFwk::EventHandler> eventHandler,wptr<Window> window)81 bool IntentionEventManager::EnableInputEventListener(Ace::UIContent* uiContent,
82     std::shared_ptr<AppExecFwk::EventHandler> eventHandler, wptr<Window> window)
83 {
84     if (uiContent == nullptr) {
85         TLOGE(WmsLogTag::WMS_EVENT, "uiContent is null");
86         return false;
87     }
88     if (eventHandler == nullptr) {
89         TLOGE(WmsLogTag::WMS_EVENT, "eventHandler is null");
90         return false;
91     }
92     auto listener =
93         std::make_shared<IntentionEventManager::InputEventListener>(uiContent, eventHandler, window);
94     MMI::InputManager::GetInstance()->SetWindowInputEventConsumer(listener, eventHandler);
95     TLOGI(WmsLogTag::WMS_EVENT, "SetWindowInputEventConsumer success");
96 
97     if (IS_BETA) {
98         // Xcollie's SetTimerCounter task is set with the params to record count and time of the input down event
99         int id = HiviewDFX::XCollie::GetInstance().SetTimerCount("FREQUENT_CLICK_WARNING", FREQUENT_CLICK_TIME_LIMIT,
100             FREQUENT_CLICK_COUNT_LIMIT);
101     }
102     return true;
103 }
104 
SetPointerEventStatus(int32_t fingerId,int32_t action,int32_t sourceType,const sptr<SceneSession> & sceneSession) const105 void IntentionEventManager::InputEventListener::SetPointerEventStatus(
106     int32_t fingerId, int32_t action, int32_t sourceType, const sptr<SceneSession>& sceneSession) const
107 {
108     switch (action) {
109         case MMI::PointerEvent::POINTER_ACTION_DOWN:
110             sceneSession->SetFingerPointerDownStatus(fingerId);
111             break;
112         case MMI::PointerEvent::POINTER_ACTION_UP:
113             sceneSession->RemoveFingerPointerDownStatus(fingerId);
114             break;
115         case MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN:
116             sceneSession->SetMousePointerDownEventStatus(true);
117             break;
118         case MMI::PointerEvent::POINTER_ACTION_BUTTON_UP:
119             sceneSession->SetMousePointerDownEventStatus(false);
120             break;
121         case MMI::PointerEvent::POINTER_ACTION_CANCEL:
122             if (sourceType == MMI::PointerEvent::SOURCE_TYPE_MOUSE) {
123                 sceneSession->SetMousePointerDownEventStatus(false);
124             } else {
125                 sceneSession->RemoveFingerPointerDownStatus(fingerId);
126             }
127             break;
128         default:
129             break;
130     }
131 }
132 
CheckPointerEvent(const std::shared_ptr<MMI::PointerEvent> pointerEvent) const133 bool IntentionEventManager::InputEventListener::CheckPointerEvent(
134     const std::shared_ptr<MMI::PointerEvent> pointerEvent) const
135 {
136     if (pointerEvent == nullptr) {
137         TLOGE(WmsLogTag::WMS_EVENT, "pointerEvent is null");
138         return false;
139     }
140     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEM:PointerEvent id:%d action:%d",
141         pointerEvent->GetId(), pointerEvent->GetPointerAction());
142     if (uiContent_ == nullptr) {
143         TLOGE(WmsLogTag::WMS_EVENT, "uiContent_ is null");
144         pointerEvent->MarkProcessed();
145         return false;
146     }
147     if (!SceneSessionManager::GetInstance().IsInputEventEnabled()) {
148         TLOGW(WmsLogTag::WMS_EVENT, "inputEvent is disabled temporarily, eventId is %{public}d", pointerEvent->GetId());
149         pointerEvent->MarkProcessed();
150         return false;
151     }
152     return true;
153 }
154 
OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const155 void IntentionEventManager::InputEventListener::OnInputEvent(
156     std::shared_ptr<MMI::PointerEvent> pointerEvent) const
157 {
158     if (!CheckPointerEvent(pointerEvent)) {
159         return;
160     }
161     LogPointInfo(pointerEvent);
162     int32_t action = pointerEvent->GetPointerAction();
163     uint32_t windowId = static_cast<uint32_t>(pointerEvent->GetTargetWindowId());
164     auto sceneSession = SceneSessionManager::GetInstance().GetSceneSession(windowId);
165     if (sceneSession == nullptr) {
166         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "The scene session is nullptr");
167         pointerEvent->MarkProcessed();
168         return;
169     }
170     auto dispatchTimes = pointerEvent->GetDispatchTimes();
171     if (dispatchTimes > 0) {
172         MMI::PointerEvent::PointerItem pointerItem;
173         auto pointerId = pointerEvent->GetPointerId();
174         if (pointerEvent->GetPointerItem(pointerId, pointerItem)) {
175             pointerItem.SetPointerId(pointerId + dispatchTimes * TRANSPARENT_FINGER_ID);
176             pointerEvent->UpdatePointerItem(pointerId, pointerItem);
177             pointerEvent->SetPointerId(pointerId + dispatchTimes * TRANSPARENT_FINGER_ID);
178         }
179     }
180     auto sourceType = pointerEvent->GetSourceType();
181     if (action != MMI::PointerEvent::POINTER_ACTION_MOVE) {
182         if (sourceType == MMI::PointerEvent::SOURCE_TYPE_MOUSE ||
183             sourceType == MMI::PointerEvent::SOURCE_TYPE_TOUCHSCREEN) {
184             SetPointerEventStatus(pointerEvent->GetPointerId(), action, sourceType, sceneSession);
185         }
186         static uint32_t eventId = 0;
187         TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "id:%{public}d,eid:%{public}d,wid:%{public}u"
188             ",wn:%{public}s,ac:%{public}d,sys:%{public}d", eventId++, pointerEvent->GetId(), windowId,
189             sceneSession->GetSessionInfo().abilityName_.c_str(), action, sceneSession->GetSessionInfo().isSystem_);
190     }
191     if (sceneSession->GetSessionInfo().isSystem_) {
192         sceneSession->SendPointerEventToUI(pointerEvent);
193         auto window = window_.promote();
194         if (window != nullptr) {
195             HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "SetTouchEvent, action:%d", action);
196             window->SetTouchEvent(action);
197         }
198         // notify touchOutside and touchDown event
199         if (action == MMI::PointerEvent::POINTER_ACTION_DOWN ||
200             action == MMI::PointerEvent::POINTER_ACTION_BUTTON_DOWN) {
201             MMI::PointerEvent::PointerItem pointerItem;
202             if (pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) {
203                 sceneSession->ProcessPointDownSession(pointerItem.GetDisplayX(), pointerItem.GetDisplayY());
204             }
205             if (IS_BETA) {
206                 /*
207                  * Triggers input down event recorded.
208                  * If the special num of the events reached within the sepcial time interval,
209                  * a panic behavior is reported.
210                  */
211                 HiviewDFX::XCollie::GetInstance().TriggerTimerCount("FREQUENT_CLICK_WARNING", true, "");
212             }
213         }
214     } else {
215         // transfer pointer event for move and drag
216         WSError ret = sceneSession->TransferPointerEvent(pointerEvent);
217         if (sceneSession->GetWindowType() == WindowType::WINDOW_TYPE_SYSTEM_FLOAT) {
218             sceneSession->NotifyOutsideDownEvent(pointerEvent);
219         }
220         if ((ret != WSError::WS_OK || static_cast<int32_t>(getprocpid()) != sceneSession->GetCallingPid()) &&
221             pointerEvent != nullptr) {
222             pointerEvent->MarkProcessed();
223         }
224     }
225 }
226 
SendKeyEventConsumedResultToSCB(const std::shared_ptr<MMI::KeyEvent> & keyEvent,bool isConsumed) const227 void IntentionEventManager::InputEventListener::SendKeyEventConsumedResultToSCB(
228     const std::shared_ptr<MMI::KeyEvent>& keyEvent, bool isConsumed) const
229 {
230     if ((keyEvent->GetKeyCode() == MMI::KeyEvent::KEYCODE_TAB ||
231         keyEvent->GetKeyCode() == MMI::KeyEvent::KEYCODE_ENTER) &&
232         keyEvent->GetKeyAction() == MMI::KeyEvent::KEY_ACTION_DOWN) {
233         TLOGD(WmsLogTag::WMS_EVENT, "keyCode:%{public}d, isConsumed:%{public}d",
234             keyEvent->GetKeyCode(), isConsumed);
235         SceneSessionManager::GetInstance().NotifyWatchGestureConsumeResult(keyEvent->GetKeyCode(), isConsumed);
236     }
237 }
238 
DispatchKeyEventCallback(int32_t focusedSessionId,std::shared_ptr<MMI::KeyEvent> keyEvent,bool consumed) const239 void IntentionEventManager::InputEventListener::DispatchKeyEventCallback(
240     int32_t focusedSessionId, std::shared_ptr<MMI::KeyEvent> keyEvent, bool consumed) const
241 {
242     if (keyEvent == nullptr) {
243         WLOGFW("keyEvent is null, focusedSessionId:%{public}" PRId32
244             ", consumed:%{public}" PRId32, focusedSessionId, consumed);
245         return;
246     }
247 
248     if (consumed) {
249         WLOGD("Input method has processed key event, id:%{public}" PRId32 ", focusedSessionId:%{public}" PRId32,
250             keyEvent->GetId(), focusedSessionId);
251         return;
252     }
253 
254     auto focusedSceneSession = SceneSessionManager::GetInstance().GetSceneSession(focusedSessionId);
255     if (focusedSceneSession == nullptr) {
256         WLOGFE("focusedSceneSession is null");
257         keyEvent->MarkProcessed();
258         return;
259     }
260 
261     if (uiContent_ == nullptr) {
262         WLOGFE("uiContent_ is null");
263         keyEvent->MarkProcessed();
264         return;
265     }
266 
267     SendKeyEventConsumedResultToSCB(keyEvent, focusedSceneSession->SendKeyEventToUI(keyEvent));
268 }
269 
OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const270 void IntentionEventManager::InputEventListener::OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const
271 {
272     if (keyEvent == nullptr) {
273         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "The key event is nullptr");
274         return;
275     }
276     HITRACE_METER_FMT(HITRACE_TAG_WINDOW_MANAGER, "IEM:KeyEvent id:%d", keyEvent->GetId());
277     if (!SceneSessionManager::GetInstance().IsInputEventEnabled()) {
278         TLOGD(WmsLogTag::WMS_INPUT_KEY_FLOW, "OnInputEvent is disabled temporarily");
279         keyEvent->MarkProcessed();
280         return;
281     }
282     auto focusedSessionId = SceneSessionManager::GetInstance().GetFocusedSessionId();
283     if (focusedSessionId == INVALID_SESSION_ID) {
284         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "focusedSessionId is invalid");
285         keyEvent->MarkProcessed();
286         return;
287     }
288     auto focusedSceneSession = SceneSessionManager::GetInstance().GetSceneSession(focusedSessionId);
289     if (focusedSceneSession == nullptr) {
290         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "focusedSceneSession is null");
291         keyEvent->MarkProcessed();
292         return;
293     }
294     auto isSystem = focusedSceneSession->GetSessionInfo().isSystem_;
295     static uint32_t eventId = 0;
296     TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "eid:%{public}d,InputId:%{public}d,wid:%{public}u"
297         ",fid:%{public}d,sys:%{public}d",
298         eventId++, keyEvent->GetId(), keyEvent->GetTargetWindowId(), focusedSessionId, isSystem);
299     if (!isSystem) {
300         WSError ret = focusedSceneSession->TransferKeyEvent(keyEvent);
301         if ((ret != WSError::WS_OK || static_cast<int32_t>(getprocpid()) != focusedSceneSession->GetCallingPid()) &&
302             keyEvent != nullptr) {
303             keyEvent->MarkProcessed();
304         }
305         return;
306     }
307     bool isConsumed = focusedSceneSession->SendKeyEventToUI(keyEvent, true);
308     if (isConsumed) {
309         SendKeyEventConsumedResultToSCB(keyEvent, isConsumed);
310         TLOGI(WmsLogTag::WMS_INPUT_KEY_FLOW, "SendToUI id:%{public}d isConsumed:%{public}d",
311             keyEvent->GetId(), static_cast<int>(isConsumed));
312         return;
313     }
314 #ifdef IMF_ENABLE
315     bool isKeyboardEvent = IsKeyboardEvent(keyEvent);
316     if (isKeyboardEvent) {
317         WLOGD("Async dispatch keyEvent to input method");
318         auto callback = [this, focusedSessionId] (std::shared_ptr<MMI::KeyEvent>& keyEvent, bool consumed) {
319             this->DispatchKeyEventCallback(focusedSessionId, keyEvent, consumed);
320         };
321         auto ret = MiscServices::InputMethodController::GetInstance()->DispatchKeyEvent(keyEvent, callback);
322         if (ret != 0) {
323             WLOGFE("DispatchKeyEvent failed, ret:%{public}d, id:%{public}d, focusedSessionId:%{public}d",
324                 ret, keyEvent->GetId(), focusedSessionId);
325             DispatchKeyEventCallback(focusedSessionId, keyEvent, false);
326         }
327         return;
328     }
329 #endif // IMF_ENABLE
330     TLOGD(WmsLogTag::WMS_INPUT_KEY_FLOW, "Syetem window scene, transfer key event to root scene");
331     if (uiContent_ == nullptr) {
332         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "uiContent_ is null");
333         keyEvent->MarkProcessed();
334         return;
335     }
336     SendKeyEventConsumedResultToSCB(keyEvent, focusedSceneSession->SendKeyEventToUI(keyEvent));
337 }
338 
IsKeyboardEvent(const std::shared_ptr<MMI::KeyEvent> & keyEvent) const339 bool IntentionEventManager::InputEventListener::IsKeyboardEvent(
340     const std::shared_ptr<MMI::KeyEvent>& keyEvent) const
341 {
342     int32_t keyCode = keyEvent->GetKeyCode();
343     bool isKeyFN = (keyCode == MMI::KeyEvent::KEYCODE_FN);
344     bool isKeyBack = (keyCode == MMI::KeyEvent::KEYCODE_BACK);
345     bool isKeyboard = (keyCode >= MMI::KeyEvent::KEYCODE_0 && keyCode <= MMI::KeyEvent::KEYCODE_NUMPAD_RIGHT_PAREN);
346     bool isKeySound = (keyCode == MMI::KeyEvent::KEYCODE_SOUND);
347     TLOGD(WmsLogTag::WMS_EVENT, "isKeyFN:%{public}d, isKeyboard:%{public}d", isKeyFN, isKeyboard);
348     return (isKeyFN || isKeyboard || isKeyBack || isKeySound);
349 }
350 
OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const351 void IntentionEventManager::InputEventListener::OnInputEvent(
352     std::shared_ptr<MMI::AxisEvent> axisEvent) const
353 {
354     if (axisEvent == nullptr) {
355         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "axisEvent is nullptr");
356         return;
357     }
358     if (uiContent_ == nullptr) {
359         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "uiContent_ is null");
360         axisEvent->MarkProcessed();
361         return;
362     }
363     if (!(uiContent_->ProcessAxisEvent(axisEvent))) {
364         TLOGE(WmsLogTag::WMS_INPUT_KEY_FLOW, "The UI content consumes the axis event failed.");
365         axisEvent->MarkProcessed();
366     }
367 }
368 }
369 } // namespace OHOS::Rosen
370