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