1 /*
2 * Copyright (c) 2022-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 "event_listener.h"
17
18 #include <linux/input.h>
19 #include <mutex>
20 #include <thread>
21 #include "dock/focus_manager.h"
22 #include "dock/input_device.h"
23 #include "page/page_manager.h"
24 #include "scope_guard.h"
25 #include "updater_ui_facade.h"
26
27 namespace Updater {
28 std::mutex CallBackDecorator::mtx_;
operator ()(OHOS::UIView & view,bool isAsync) const29 void CallBackDecorator::operator()(OHOS::UIView &view, bool isAsync) const
30 {
31 auto *page = view.GetParent();
32 if (page == nullptr) {
33 LOG(ERROR) << "view hasn't a parent";
34 return;
35 }
36 if (view.GetViewId() == nullptr) {
37 LOG(ERROR) << "view is invalid, please check your json config";
38 return;
39 }
40 std::string id = view.GetViewId();
41 std::string pageId {};
42 if (page->GetViewId() != nullptr) {
43 pageId = page->GetViewId();
44 }
45 // page should be visible
46 if (!page->IsVisible()) {
47 LOG(ERROR) << pageId << " is not visible";
48 return;
49 }
50 // component should be visible
51 if (!view.IsVisible()) {
52 LOG(ERROR) << id << " is not visible";
53 return;
54 }
55 if (isAsync) {
56 LOG(INFO) << "callback by async method";
57 // then can trigger callback by async method
58 std::thread t {
59 [cb = cb_, &view] () {
60 CallbackWithGuard(cb, view);
61 }
62 };
63 t.detach();
64 } else {
65 LOG(INFO) << "callback by sync method";
66 // then can trigger callback by sync method
67 CallbackWithGuard(cb_, view);
68 }
69 }
70
CallbackWithGuard(Callback cb,OHOS::UIView & view)71 void CallBackDecorator::CallbackWithGuard(Callback cb, OHOS::UIView &view)
72 {
73 std::unique_lock<std::mutex> lock(mtx_, std::defer_lock);
74 if (!lock.try_lock()) {
75 LOG(ERROR) << "try lock failed, only allow running one callback at the same time";
76 return;
77 }
78 if (cb.func != nullptr) {
79 cb.func(view);
80 }
81 }
82
83 bool LabelOnTouchListener::OnRelease(OHOS::UIView &view, [[maybe_unused]] const OHOS::ReleaseEvent &event)
84 {
85 // wrap cb_ with CallBackDecorator, then call operator()()
86 CallBackDecorator{cb_}(view, cb_.isAsync);
87 return isConsumed_;
88 }
89
90 bool BtnOnEventListener::OnClick(OHOS::UIView &view, [[maybe_unused]] const OHOS::ClickEvent &event)
91 {
92 CallBackDecorator{cb_}(view, cb_.isAsync);
93 return isConsumed_;
94 }
95
96 bool BtnOnEventListener::OnPress(OHOS::UIView &view, [[maybe_unused]] const OHOS::PressEvent &event)
97 {
98 KeyListener::SetButtonPressed(true);
99 return true;
100 }
101
102 bool BtnOnEventListener::OnRelease(OHOS::UIView &view, [[maybe_unused]] const OHOS::ReleaseEvent &event)
103 {
104 KeyListener::SetButtonPressed(false);
105 return true;
106 }
107
108 bool BtnOnEventListener::OnCancel(OHOS::UIView &view, [[maybe_unused]] const OHOS::CancelEvent &event)
109 {
110 KeyListener::SetButtonPressed(false);
111 return true;
112 }
113
114 bool BtnOnDragListener::OnDragStart(OHOS::UIView &view, [[maybe_unused]] const OHOS::DragEvent &event)
115 {
116 CallBackDecorator{cb_}(view, cb_.isAsync);
117 return isConsumed_;
118 }
119
OnDrag(OHOS::UIView & view,const OHOS::DragEvent & event)120 bool BtnOnDragListener::OnDrag(OHOS::UIView &view, const OHOS::DragEvent &event)
121 {
122 CallBackDecorator{cb_}(view, cb_.isAsync);
123 view.SetPosition(view.GetX() + event.GetDeltaX(), view.GetY() + event.GetDeltaY());
124 if (view.GetParent() != nullptr) {
125 view.GetParent()->Invalidate();
126 }
127 return isConsumed_;
128 }
129
130 bool BtnOnDragListener::OnDragEnd(OHOS::UIView &view, [[maybe_unused]] const OHOS::DragEvent &event)
131 {
132 CallBackDecorator{cb_}(view, cb_.isAsync);
133 return isConsumed_;
134 }
135
136 bool KeyListener::isButtonPressed_ {false};
137
OnKeyAct(OHOS::UIView & view,const OHOS::KeyEvent & event)138 bool KeyListener::OnKeyAct(OHOS::UIView &view, const OHOS::KeyEvent &event)
139 {
140 bool consumed = false;
141 switch (event.GetKeyId()) {
142 case KEY_POWER:
143 consumed = ProcessPowerKey(view, event);
144 break;
145 case KEY_VOLUMEUP:
146 case KEY_VOLUMEDOWN:
147 consumed = ProcessVolumeKey(view, event);
148 break;
149 default:
150 LOG(ERROR) << "unsupported key id";
151 }
152 return consumed;
153 }
154
ProcessPowerKey(OHOS::UIView & view,const OHOS::KeyEvent & event)155 bool KeyListener::ProcessPowerKey(OHOS::UIView &view, const OHOS::KeyEvent &event)
156 {
157 #ifndef UPDATER_UT
158 OHOS::UIView *pView = OHOS::FocusManager::GetInstance()->GetFocusedView();
159 if (pView == nullptr) {
160 LOG(ERROR) << "focused view is nullptr";
161 return false;
162 }
163 // triggering button press event by key only supports label button
164 if (pView->GetViewType() != OHOS::UI_LABEL_BUTTON) {
165 LOG(ERROR) << "focused view is not label button";
166 return false;
167 }
168 int16_t centerX = pView->GetX() + static_cast<int16_t>(static_cast<uint16_t>(pView->GetWidth()) >> 1u);
169 int16_t centerY = pView->GetY() + static_cast<int16_t>(static_cast<uint16_t>(pView->GetHeight()) >> 1u);
170 if (event.GetState() == OHOS::InputDevice::STATE_PRESS) {
171 LOG(DEBUG) << "OnPress";
172 pView->OnClickEvent(OHOS::Point { centerX, centerY });
173 }
174 #endif
175 return true;
176 }
177
ProcessVolumeKey(OHOS::UIView & view,const OHOS::KeyEvent & event)178 bool KeyListener::ProcessVolumeKey(OHOS::UIView &view, const OHOS::KeyEvent &event)
179 {
180 const static std::unordered_map<uint16_t, uint8_t> dirMap {
181 {KEY_VOLUMEUP, OHOS::FOCUS_DIRECTION_UP},
182 {KEY_VOLUMEDOWN, OHOS::FOCUS_DIRECTION_DOWN},
183 {KEY_UP, OHOS::FOCUS_DIRECTION_UP},
184 {KEY_DOWN, OHOS::FOCUS_DIRECTION_DOWN},
185 };
186 if (isButtonPressed_) {
187 return true;
188 }
189 if (auto it = dirMap.find(event.GetKeyId()); it != dirMap.end() &&
190 event.GetState() == OHOS::InputDevice::STATE_RELEASE) {
191 OHOS::FocusManager::GetInstance()->RequestFocusByDirection(it->second);
192 }
193 return true;
194 }
195
SetButtonPressed(bool isPressed)196 void KeyListener::SetButtonPressed(bool isPressed)
197 {
198 isButtonPressed_ = isPressed;
199 }
200 }
201