1 /*
2 * Copyright (c) 2020-2021 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 "dock/focus_manager.h"
17 #if ENABLE_FOCUS_MANAGER
18 #include "components/root_view.h"
19 #include "gfx_utils/graphic_math.h"
20
21 #include "common/input_method_manager.h"
22
23 namespace OHOS {
GetInstance()24 FocusManager* FocusManager::GetInstance()
25 {
26 static FocusManager instance;
27 return &instance;
28 }
29
RequestFocus(UIView * view)30 bool FocusManager::RequestFocus(UIView* view)
31 {
32 if (view == nullptr || view == focusView_ || !view->IsFocusable() ||
33 !view->IsVisible()) {
34 return false;
35 }
36 lastFocusView_ = focusView_;
37 focusView_ = view;
38
39 UIViewGroup* rootView = RootView::GetInstance();
40 if (RootView::FindSubView(*rootView, lastFocusView_)) {
41 lastFocusView_->Blur();
42 }
43 focusView_->Focus();
44
45 UIViewType viewType = focusView_->GetViewType();
46 // show keyboard if the view is edittable
47 if (viewType == UI_EDIT_TEXT) {
48 InputMethodManager::GetInstance().ShowInputMethod(focusView_);
49 }
50
51 return true;
52 }
53
ClearFocus()54 bool FocusManager::ClearFocus()
55 {
56 if (focusView_ == nullptr) {
57 return false;
58 }
59 lastFocusView_ = focusView_;
60 focusView_->Blur();
61 focusView_ = nullptr;
62 return true;
63 }
64
RequestFocusByDirection(uint8_t direction)65 bool FocusManager::RequestFocusByDirection(uint8_t direction)
66 {
67 if (focusView_ != nullptr) {
68 UIView* candidate = nullptr;
69 if (GetNextFocus(focusView_, candidate, direction)) {
70 return RequestFocus(candidate);
71 }
72 }
73 return false;
74 }
75
CompareCandidates(UIView * focusedView,UIView * & candidate,UIView * current,uint8_t direction)76 bool FocusManager::CompareCandidates(UIView* focusedView, UIView*& candidate, UIView* current, uint8_t direction)
77 {
78 if (current == focusedView) {
79 return false;
80 }
81 bool res = false;
82 switch (direction) {
83 case FOCUS_DIRECTION_UP: {
84 res = CompareCandidatesByUp(focusedView, candidate, current);
85 break;
86 }
87 case FOCUS_DIRECTION_DOWN: {
88 res = CompareCandidatesByDown(focusedView, candidate, current);
89 break;
90 }
91 case FOCUS_DIRECTION_LEFT: {
92 res = CompareCandidatesByLeft(focusedView, candidate, current);
93 break;
94 }
95 case FOCUS_DIRECTION_RIGHT: {
96 res = CompareCandidatesByRight(focusedView, candidate, current);
97 break;
98 }
99 default:
100 return false;
101 }
102 return res;
103 }
104
IsAtSameCol(const Rect & rect1,const Rect & rect2)105 bool FocusManager::IsAtSameCol(const Rect& rect1, const Rect& rect2)
106 {
107 return ((rect1.GetLeft() < rect2.GetRight()) && (rect1.GetRight() > rect2.GetLeft()));
108 }
109
IsAtSameRow(const Rect & rect1,const Rect & rect2)110 bool FocusManager::IsAtSameRow(const Rect& rect1, const Rect& rect2)
111 {
112 return ((rect1.GetBottom() < rect2.GetTop()) && (rect1.GetTop() > rect2.GetBottom()));
113 }
114
CompareCandidatesByUp(UIView * focusedView,UIView * & candidate,UIView * current)115 bool FocusManager::CompareCandidatesByUp(UIView* focusedView, UIView*& candidate, UIView* current)
116 {
117 Rect focusedViewRect = focusedView->GetRect();
118 Rect currentRect = current->GetRect();
119 if (currentRect.GetBottom() >= focusedViewRect.GetBottom()) {
120 return false;
121 }
122 if (candidate != nullptr) {
123 Rect candidateRect = candidate->GetRect();
124 if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) {
125 return currentRect.GetBottom() > candidateRect.GetBottom();
126 }
127 return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect);
128 }
129 return true;
130 }
131
CompareCandidatesByDown(UIView * focusedView,UIView * & candidate,UIView * current)132 bool FocusManager::CompareCandidatesByDown(UIView* focusedView, UIView*& candidate, UIView* current)
133 {
134 Rect focusedViewRect = focusedView->GetRect();
135 Rect currentRect = current->GetRect();
136 if (currentRect.GetTop() <= focusedViewRect.GetTop()) {
137 return false;
138 }
139 if (candidate != nullptr) {
140 Rect candidateRect = candidate->GetRect();
141 if (IsAtSameCol(focusedViewRect, currentRect) && IsAtSameCol(focusedViewRect, candidateRect)) {
142 return currentRect.GetTop() < candidateRect.GetTop();
143 }
144 return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect);
145 }
146 return true;
147 }
148
CompareCandidatesByLeft(UIView * focusedView,UIView * & candidate,UIView * current)149 bool FocusManager::CompareCandidatesByLeft(UIView* focusedView, UIView*& candidate, UIView* current)
150 {
151 Rect focusedViewRect = focusedView->GetRect();
152 Rect currentRect = current->GetRect();
153 if (currentRect.GetRight() >= focusedViewRect.GetRight()) {
154 return false;
155 }
156 if (candidate != nullptr) {
157 Rect candidateRect = candidate->GetRect();
158 if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) {
159 return currentRect.GetRight() > candidateRect.GetRight();
160 }
161 return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect);
162 }
163 return true;
164 }
165
CompareCandidatesByRight(UIView * focusedView,UIView * & candidate,UIView * current)166 bool FocusManager::CompareCandidatesByRight(UIView* focusedView, UIView*& candidate, UIView* current)
167 {
168 Rect focusedViewRect = focusedView->GetRect();
169 Rect currentRect = current->GetRect();
170 if (currentRect.GetLeft() <= focusedViewRect.GetLeft()) {
171 return false;
172 }
173 if (candidate != nullptr) {
174 Rect candidateRect = candidate->GetRect();
175 if (IsAtSameRow(focusedViewRect, currentRect) && IsAtSameRow(focusedViewRect, candidateRect)) {
176 return currentRect.GetLeft() < candidateRect.GetLeft();
177 }
178 return CompareCandidatesDistance(focusedViewRect, candidateRect, currentRect);
179 }
180 return true;
181 }
182
CompareCandidatesDistance(const Rect & focused,const Rect & candidate,const Rect & current)183 bool FocusManager::CompareCandidatesDistance(const Rect& focused, const Rect& candidate, const Rect& current)
184 {
185 uint64_t xDiff1 = focused.GetX() - candidate.GetX();
186 uint64_t yDiff1 = focused.GetY() - candidate.GetY();
187 uint64_t xDiff2 = focused.GetX() - current.GetX();
188 uint64_t yDiff2 = focused.GetY() - current.GetY();
189 uint64_t distance1 = xDiff1 * xDiff1 + yDiff1 * yDiff1;
190 uint64_t distance2 = xDiff2 * xDiff2 + yDiff2 * yDiff2;
191 return distance2 < distance1;
192 }
193
GetNextFocus(UIView * focusedView,UIView * & candidate,uint8_t direction)194 bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, uint8_t direction)
195 {
196 UIView* parent = focusedView->GetParent();
197 if (parent == nullptr) {
198 return false;
199 }
200 UIView* child = nullptr;
201 bool isFoundBestCandidate = false;
202 UIView* current = focusedView;
203 while (parent != nullptr) {
204 if (isFoundBestCandidate) {
205 return true;
206 }
207 child = static_cast<UIViewGroup*>(parent)->GetChildrenHead();
208 while (child != nullptr) {
209 if (child == current) {
210 child = child->GetNextSibling();
211 continue;
212 }
213 if (child->IsViewGroup()) {
214 if (GetNextFocus(focusedView, candidate, static_cast<UIViewGroup*>(child), direction)) {
215 isFoundBestCandidate = true;
216 }
217 } else {
218 if (GetNextFocus(focusedView, candidate, child, direction)) {
219 isFoundBestCandidate = true;
220 }
221 }
222 child = child->GetNextSibling();
223 }
224 if (isFoundBestCandidate) {
225 return true;
226 } else {
227 current = parent;
228 }
229 parent = parent->GetParent();
230 }
231 return false;
232 }
233
GetNextFocus(UIView * focusedView,UIView * & candidate,UIView * view,uint8_t direction)234 bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIView* view, uint8_t direction)
235 {
236 UIView* current = view;
237 if (!current->IsVisible() || !current->IsFocusable()) {
238 return false;
239 }
240 if (CompareCandidates(focusedView, candidate, current, direction)) {
241 candidate = current;
242 return true;
243 }
244 return false;
245 }
246
GetNextFocus(UIView * focusedView,UIView * & candidate,UIViewGroup * viewGroup,uint8_t direction)247 bool FocusManager::GetNextFocus(UIView* focusedView, UIView*& candidate, UIViewGroup* viewGroup, uint8_t direction)
248 {
249 UIViewGroup* current = viewGroup;
250 if (!current->IsVisible() || !current->IsFocusable()) {
251 return false;
252 }
253 if (current->IsInterceptFocus()) {
254 return GetNextFocus(focusedView, candidate, static_cast<UIView*>(current), direction);
255 }
256
257 UIView* child = current->GetChildrenHead();
258 bool childFocusable = false;
259 while (child != nullptr) {
260 if (child == focusedView) {
261 child = child->GetNextSibling();
262 continue;
263 }
264 if (child->IsViewGroup()) {
265 if (GetNextFocus(focusedView, candidate, static_cast<UIViewGroup*>(child), direction)) {
266 childFocusable = true;
267 }
268 } else if (GetNextFocus(focusedView, candidate, child, direction)) {
269 childFocusable = true;
270 }
271 child = child->GetNextSibling();
272 }
273 return childFocusable;
274 }
275 }
276 #endif
277