1 /*
2  * Copyright (c) 2021-2022 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 "core/focus/focus_node.h"
17 
18 #include <algorithm>
19 #include <atomic>
20 #include <cinttypes>
21 
22 #include "base/log/dump_log.h"
23 #include "base/log/log.h"
24 #include "core/common/ace_application_info.h"
25 #include "core/components/flex/flex_element.h"
26 #include "core/event/ace_event_handler.h"
27 #include "core/gestures/click_recognizer.h"
28 #include "core/pipeline/base/composed_element.h"
29 #include "core/pipeline/base/render_element.h"
30 
31 namespace OHOS::Ace {
32 namespace {
33 
GetRenderNode(const RefPtr<FocusNode> & node)34 inline RefPtr<RenderNode> GetRenderNode(const RefPtr<FocusNode>& node)
35 {
36     auto element = AceType::DynamicCast<RenderElement>(node);
37     if (!element) {
38         auto composedElement = AceType::DynamicCast<ComposedElement>(node);
39         if (composedElement) {
40             auto child = composedElement->GetChildren().front();
41             return child ? child->GetRenderNode() : nullptr;
42         }
43         return nullptr;
44     }
45     return element->GetRenderNode();
46 }
47 
48 } // namespace
49 
GenerateFocusIndex()50 int32_t FocusNode::GenerateFocusIndex()
51 {
52     static std::atomic<int32_t> counter { 1 };
53     return counter.fetch_add(1, std::memory_order_relaxed);
54 }
55 
HandleKeyEvent(const KeyEvent & keyEvent)56 bool FocusNode::HandleKeyEvent(const KeyEvent& keyEvent)
57 {
58     if (!IsCurrentFocus()) {
59         return false;
60     }
61     if (OnKeyEvent(keyEvent)) {
62         return true;
63     }
64 
65     auto element = AceType::DynamicCast<Element>(this);
66     if (!element) {
67         return false;
68     }
69     auto context = element->GetContext().Upgrade();
70     if (!context) {
71         return false;
72     }
73 
74     switch (keyEvent.code) {
75         case KeyCode::KEY_ENTER:
76         case KeyCode::KEY_NUMPAD_ENTER:
77         case KeyCode::KEY_DPAD_CENTER:
78             if (keyEvent.action != KeyAction::DOWN) {
79                 return false;
80             }
81             if (context->GetIsDeclarative()) {
82                 return OnClick(keyEvent);
83             }
84             OnClick();
85             return true;
86 
87         default:
88             return false;
89     }
90 }
91 
CollectTabIndexNodes(TabIndexNodeList & tabIndexNodes)92 void FocusNode::CollectTabIndexNodes(TabIndexNodeList& tabIndexNodes)
93 {
94     RefPtr<FocusNode> node = AceType::Claim(this);
95     CHECK_NULL_VOID(node);
96     RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(node);
97     if (scope && scope->IsFocusable()) {
98         auto children = scope->GetChildrenList();
99         if (children.size() == 1 && !AceType::DynamicCast<FocusGroup>(children.front())) {
100             if (scope->GetTabIndex() > 0) {
101                 tabIndexNodes.emplace_back(scope->GetTabIndex(), WeakClaim(AceType::RawPtr(scope)));
102             }
103             return;
104         }
105         for (auto& child : children) {
106             child->CollectTabIndexNodes(tabIndexNodes);
107         }
108     }
109     if (node->IsFocusable() && node->GetTabIndex() > 0) {
110         tabIndexNodes.emplace_back(node->GetTabIndex(), WeakClaim(AceType::RawPtr(node)));
111     }
112 }
113 
GoToFocusByTabNodeIdx(TabIndexNodeList & tabIndexNodes,int32_t tabNodeIdx)114 bool FocusNode::GoToFocusByTabNodeIdx(TabIndexNodeList& tabIndexNodes, int32_t tabNodeIdx)
115 {
116     auto iter = tabIndexNodes.begin();
117     std::advance(iter, tabNodeIdx);
118     if (iter == tabIndexNodes.end()) {
119         LOGE("Tab index node is not found");
120         return false;
121     }
122     auto nodeNeedToFocus = (*iter).second.Upgrade();
123     if (!nodeNeedToFocus) {
124         LOGE("Tab index node is null");
125         return false;
126     }
127     LOGI("Focus on tab index node(%{public}d)", tabNodeIdx);
128     auto scopeNeedToFocus = AceType::DynamicCast<FocusGroup>(nodeNeedToFocus);
129     if (scopeNeedToFocus && !scopeNeedToFocus->IsGroupDefaultFocused()) {
130         auto defaultFocusNode = nodeNeedToFocus->GetChildDefaultFocusNode(false);
131         if (defaultFocusNode) {
132             if (!defaultFocusNode->IsFocusableWholePath()) {
133                 LOGW("node(%{public}d) is not focusable", tabNodeIdx);
134                 return false;
135             }
136             scopeNeedToFocus->SetIsGroupDefaultFocused(true);
137             return defaultFocusNode->RequestFocusImmediately();
138         }
139     }
140     if (!nodeNeedToFocus->IsFocusableWholePath()) {
141         LOGW("node(%{public}d) is not focusable", tabNodeIdx);
142         return false;
143     }
144     return nodeNeedToFocus->RequestFocusImmediately();
145 }
146 
HandleFocusByTabIndex(const KeyEvent & event,const RefPtr<FocusGroup> & mainNode)147 bool FocusNode::HandleFocusByTabIndex(const KeyEvent& event, const RefPtr<FocusGroup>& mainNode)
148 {
149     if (event.code != KeyCode::KEY_TAB || event.action != KeyAction::DOWN) {
150         return false;
151     }
152     if (!mainNode) {
153         LOGE("Current page node is not exit. Can't handle focus by tabIndex.");
154         return false;
155     }
156     TabIndexNodeList tabIndexNodes;
157     tabIndexNodes.clear();
158     mainNode->CollectTabIndexNodes(tabIndexNodes);
159     tabIndexNodes.sort([](std::pair<int32_t, WeakPtr<FocusNode>>& a, std::pair<int32_t, WeakPtr<FocusNode>>& b) {
160         return a.first < b.first;
161     });
162     int32_t curTabFocusIndex = mainNode->GetFocusingTabNodeIdx(tabIndexNodes);
163     if ((curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) &&
164         curTabFocusIndex != DEFAULT_TAB_FOCUSED_INDEX) {
165         LOGI("Current focused tabIndex node: %{public}d. Use default focus system.", curTabFocusIndex);
166         return false;
167     }
168     if (curTabFocusIndex == DEFAULT_TAB_FOCUSED_INDEX) {
169         curTabFocusIndex = 0;
170     } else {
171         if (event.IsShiftWith(KeyCode::KEY_TAB)) {
172             LOGI("RequestNextFocus by 'SHIFT-TAB'");
173             --curTabFocusIndex;
174         } else {
175             LOGI("RequestNextFocus by 'TAB'");
176             ++curTabFocusIndex;
177         }
178     }
179     if (curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) {
180         LOGI("Focus from tab index node to normal node. Use default focus system.");
181         return false;
182     }
183     return GoToFocusByTabNodeIdx(tabIndexNodes, curTabFocusIndex);
184 }
185 
DumpFocus()186 void FocusNode::DumpFocus() {}
187 
DumpFocusTree(int32_t depth)188 void FocusNode::DumpFocusTree(int32_t depth)
189 {
190     if (DumpLog::GetInstance().GetDumpFile()) {
191         DumpFocus();
192         std::string information = AceType::TypeName(this);
193         if (IsCurrentFocus()) {
194             information += "(Node*)";
195         } else {
196             information += "(Node)";
197         }
198 
199         if (!IsFocusable()) {
200             information = "(-)" + information;
201         }
202         DumpLog::GetInstance().Print(depth, information, 0);
203     }
204 }
205 
IsFocusableByTab() const206 bool FocusNode::IsFocusableByTab() const
207 {
208     auto parent = GetParent().Upgrade();
209     if (parent) {
210         return (tabIndex_ == 0) && (parent->tabIndex_ == 0);
211     }
212     return tabIndex_ == 0;
213 }
214 
IsFocusableWholePath() const215 bool FocusNode::IsFocusableWholePath() const
216 {
217     auto parent = GetParent().Upgrade();
218     while (parent) {
219         if (!parent->IsFocusable()) {
220             return false;
221         }
222         parent = parent->GetParent().Upgrade();
223     }
224     return IsFocusable();
225 }
226 
RequestFocusImmediately()227 bool FocusNode::RequestFocusImmediately()
228 {
229     auto renderNode = GetRenderNode(AceType::Claim(this));
230     if (renderNode) {
231         auto context = renderNode->GetContext().Upgrade();
232         if (context && context->IsJsCard()) {
233             return false;
234         }
235         if (context && context->GetIsFocusingByTab()) {
236             if (!IsFocusableByTab()) {
237                 return false;
238             }
239         }
240     }
241     if (IsCurrentFocus()) {
242         return true;
243     }
244 
245     if (!IsFocusable()) {
246         return false;
247     }
248 
249     currentFocus_ = true;
250     UpdateAccessibilityFocusInfo();
251     auto parent = GetParent().Upgrade();
252     if (parent) {
253         parent->SwitchFocus(AceType::Claim(this));
254     }
255 
256     HandleFocus();
257     return true;
258 }
259 
GetChildDefaultFocusNode(bool isGetDefaultFocus)260 RefPtr<FocusNode> FocusNode::GetChildDefaultFocusNode(bool isGetDefaultFocus)
261 {
262     if (isGetDefaultFocus && isDefaultFocus_ && IsFocusable()) {
263         return AceType::Claim(this);
264     }
265     if (!isGetDefaultFocus && isDefaultGroupFocus_ && IsFocusable()) {
266         return AceType::Claim(this);
267     }
268     RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(AceType::Claim(this));
269     if (!scope) {
270         return nullptr;
271     }
272     auto children = scope->GetChildrenList();
273     for (const auto& child : children) {
274         auto findNode = child->GetChildDefaultFocusNode(isGetDefaultFocus);
275         if (findNode) {
276             return findNode;
277         }
278     }
279     return nullptr;
280 }
281 
GetChildFocusNodeById(const std::string & id)282 RefPtr<FocusNode> FocusNode::GetChildFocusNodeById(const std::string& id)
283 {
284     if (id.empty()) {
285         return nullptr;
286     }
287     if (GetInspectorKey() == id) {
288         return AceType::Claim(this);
289     }
290     RefPtr<FocusGroup> scope = AceType::DynamicCast<FocusGroup>(AceType::Claim(this));
291     if (scope) {
292         auto children = scope->GetChildrenList();
293         for (const auto& child : children) {
294             auto findNode = child->GetChildFocusNodeById(id);
295             if (findNode) {
296                 return findNode;
297             }
298         }
299     }
300     return nullptr;
301 }
302 
RequestFocusImmediatelyById(const std::string & id)303 bool FocusNode::RequestFocusImmediatelyById(const std::string& id)
304 {
305     auto focusNode = GetChildFocusNodeById(id);
306     if (!focusNode) {
307         LOGW("Can not find focus node by id: %{public}s", id.c_str());
308         return false;
309     }
310     if (!focusNode->IsFocusableWholePath()) {
311         return false;
312     }
313     return focusNode->RequestFocusImmediately();
314 }
315 
UpdateAccessibilityFocusInfo()316 void FocusNode::UpdateAccessibilityFocusInfo()
317 {
318     auto renderNode = GetRenderNode(AceType::Claim(this));
319     if (!renderNode) {
320         LOGW("FocusNode renderNode is null.");
321         return;
322     }
323     auto accessibilityNode = renderNode->GetAccessibilityNode().Upgrade();
324     if (!accessibilityNode) {
325         return;
326     }
327     accessibilityNode->SetFocusedState(currentFocus_);
328 }
329 
LostFocus(BlurReason reason)330 void FocusNode::LostFocus(BlurReason reason)
331 {
332     if (IsCurrentFocus()) {
333         blurReason_ = reason;
334         currentFocus_ = false;
335         UpdateAccessibilityFocusInfo();
336         OnBlur();
337     }
338 }
339 
LostSelfFocus()340 void FocusNode::LostSelfFocus()
341 {
342     if (IsCurrentFocus()) {
343         SetFocusable(false);
344         SetFocusable(true);
345     }
346 }
347 
RemoveSelf()348 void FocusNode::RemoveSelf()
349 {
350     auto parent = parent_.Upgrade();
351     if (parent) {
352         parent->RemoveChild(AceType::Claim(this));
353     }
354 }
355 
SetFocusable(bool focusable)356 void FocusNode::SetFocusable(bool focusable)
357 {
358     if (focusable_ == focusable) {
359         return;
360     }
361     focusable_ = focusable;
362     RefreshParentFocusable(FocusNode::IsFocusable());
363     RefreshFocus();
364 }
365 
SetEnabled(bool enabled)366 void FocusNode::SetEnabled(bool enabled)
367 {
368     enabled_ = enabled;
369     if (!enabled) {
370         RefreshFocus();
371     }
372 }
373 
SetShow(bool show)374 void FocusNode::SetShow(bool show)
375 {
376     show_ = show;
377     if (!show) {
378         RefreshFocus();
379     }
380 }
381 
RefreshFocus()382 void FocusNode::RefreshFocus()
383 {
384     if (!IsCurrentFocus()) {
385         return;
386     }
387 
388     // lost current focus and request another focus
389     auto parent = GetParent().Upgrade();
390     // current node is root node
391     if (!parent) {
392         LostFocus();
393         return;
394     }
395     while (!parent->IsFocusable()) {
396         // parent node is root node
397         if (!parent->GetParent().Upgrade()) {
398             parent->LostFocus();
399             return;
400         }
401         parent = parent->GetParent().Upgrade();
402     }
403     parent->LostFocus();
404     parent->RequestFocusImmediately();
405 }
406 
OnKeyEvent(const KeyEvent & keyEvent)407 bool FocusNode::OnKeyEvent(const KeyEvent& keyEvent)
408 {
409     auto element = AceType::DynamicCast<Element>(this);
410     if (!element) {
411         return false;
412     }
413     auto context = element->GetContext().Upgrade();
414     if (!context) {
415         return false;
416     }
417     if (context->GetIsDeclarative()) {
418         auto info = std::make_shared<KeyEventInfo>(keyEvent);
419         if (!onKeyEventCallback_) {
420             return false;
421         }
422         onKeyEventCallback_(info);
423         return info->IsStopPropagation();
424     } else {
425         if (onKeyCallback_) {
426             return onKeyCallback_(keyEvent);
427         }
428     }
429     return false;
430 }
431 
RefreshParentFocusable(bool focusable)432 void FocusNode::RefreshParentFocusable(bool focusable)
433 {
434     // do nothing
435 }
436 
RequestFocus()437 void FocusNode::RequestFocus()
438 {
439     if (IsCurrentFocus()) {
440         return;
441     }
442 
443     auto element = AceType::DynamicCast<Element>(this);
444     if (!element) {
445         return;
446     }
447     auto context = element->GetContext().Upgrade();
448     if (context) {
449         context->AddDirtyFocus(AceType::Claim(this));
450     } else {
451         LOGE("fail to add dirty focus due to context is null");
452     }
453 }
454 
OnClick(const KeyEvent & event)455 bool FocusNode::OnClick(const KeyEvent& event)
456 {
457     if (onClickEventCallback_) {
458         auto info = std::make_shared<ClickInfo>(-1);
459         info->SetTimeStamp(event.timeStamp);
460         info->SetGlobalLocation(
461             Offset((GetRect().Left() + GetRect().Right()) / 2, (GetRect().Top() + GetRect().Bottom()) / 2));
462         info->SetLocalLocation(
463             Offset((GetRect().Right() - GetRect().Left()) / 2, (GetRect().Bottom() - GetRect().Top()) / 2));
464         info->SetSourceDevice(static_cast<SourceType>(event.sourceType));
465         info->SetDeviceId(event.deviceId);
466         onClickEventCallback_(info);
467         return true;
468     }
469     return false;
470 }
471 
AddChild(const RefPtr<FocusNode> & focusNode)472 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode)
473 {
474     // Already belong to any focus scope.
475     if (!focusNode || !focusNode->GetParent().Invalid()) {
476         return;
477     }
478 
479     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
480     if (it == focusNodes_.end()) {
481         focusNodes_.emplace_back(focusNode);
482         focusNode->SetParent(AceType::WeakClaim(this));
483     }
484 }
485 
AddChild(const RefPtr<FocusNode> & focusNode,const RefPtr<FocusNode> & nextFocusNode)486 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode, const RefPtr<FocusNode>& nextFocusNode)
487 {
488     // Already belong to any focus scope.
489     if (!focusNode || !focusNode->GetParent().Invalid()) {
490         return;
491     }
492 
493     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
494     auto pos = std::find(focusNodes_.begin(), focusNodes_.end(), nextFocusNode);
495     if (it == focusNodes_.end()) {
496         focusNodes_.insert(pos, focusNode);
497         focusNode->SetParent(AceType::WeakClaim(this));
498     }
499 }
500 
DumpFocusTree(int32_t depth)501 void FocusGroup::DumpFocusTree(int32_t depth)
502 {
503     if (DumpLog::GetInstance().GetDumpFile()) {
504         DumpFocus();
505         std::string information = AceType::TypeName(this);
506         if (IsCurrentFocus()) {
507             information += "(Scope*)";
508         } else {
509             information += "(Scope)";
510         }
511 
512         if (!IsFocusable()) {
513             information = "(-)" + information;
514         }
515         DumpLog::GetInstance().Print(depth, information, focusNodes_.size());
516     }
517 
518     for (const auto& item : focusNodes_) {
519         item->DumpFocusTree(depth + 1);
520     }
521 }
522 
RemoveChild(const RefPtr<FocusNode> & focusNode)523 void FocusGroup::RemoveChild(const RefPtr<FocusNode>& focusNode)
524 {
525     // Not belong to this focus scope.
526     if (!focusNode || focusNode->GetParent() != this) {
527         return;
528     }
529 
530     if (focusNode->IsCurrentFocus()) {
531         // Try to goto next focus, otherwise goto previous focus.
532         if (!GoToNextFocus(true) && !GoToNextFocus(false)) {
533             itLastFocusNode_ = focusNodes_.end();
534         }
535         focusNode->LostFocus();
536     } else {
537         if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_) == focusNode) {
538             itLastFocusNode_ = focusNodes_.end();
539         }
540     }
541 
542     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
543     if (it == focusNodes_.end()) {
544         return;
545     }
546     if (itLastFocusNode_ == it) {
547         itLastFocusNode_ = focusNodes_.end();
548     }
549     focusNode->SetParent(nullptr);
550     focusNodes_.erase(it);
551 }
552 
SwitchFocus(const RefPtr<FocusNode> & focusNode)553 void FocusGroup::SwitchFocus(const RefPtr<FocusNode>& focusNode)
554 {
555     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
556     ACE_DCHECK(it != focusNodes_.end());
557 
558     auto itFocusNode = itLastFocusNode_;
559     itLastFocusNode_ = it;
560 
561     if (IsCurrentFocus()) {
562         if (itFocusNode != focusNodes_.end() && itFocusNode != it) {
563             (*itFocusNode)->LostFocus();
564         }
565     } else {
566         RequestFocusImmediately();
567     }
568 }
569 
IsFocusable() const570 bool FocusGroup::IsFocusable() const
571 {
572     if (!FocusNode::IsFocusable()) {
573         return false;
574     }
575     return std::any_of(focusNodes_.begin(), focusNodes_.end(),
576         [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusable(); });
577 }
578 
IsFocusableByTab() const579 bool FocusGroup::IsFocusableByTab() const
580 {
581     if (!FocusNode::IsFocusableByTab()) {
582         return false;
583     }
584     if (focusNodes_.empty()) {
585         return true;
586     }
587     return std::any_of(focusNodes_.begin(), focusNodes_.end(),
588         [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusableByTab(); });
589 }
590 
GoToNextFocus(bool reverse,const Rect & rect)591 bool FocusGroup::GoToNextFocus(bool reverse, const Rect& rect)
592 {
593     if (focusNodes_.empty()) {
594         return false;
595     }
596     auto itNewFocusNode = itLastFocusNode_;
597     if (itNewFocusNode == focusNodes_.end()) {
598         itNewFocusNode = focusNodes_.begin();
599     }
600     if (reverse) {
601         if (itNewFocusNode == focusNodes_.begin()) {
602             itNewFocusNode = focusNodes_.end();
603             return false;
604         } else {
605             --itNewFocusNode;
606         }
607         while (itNewFocusNode != focusNodes_.begin()) {
608             if (TryRequestFocus(*itNewFocusNode, rect)) {
609                 return true;
610             }
611             --itNewFocusNode;
612         }
613         if (itNewFocusNode == focusNodes_.begin()) {
614             if (TryRequestFocus(*itNewFocusNode, rect)) {
615                 return true;
616             }
617         }
618     } else {
619         if (itNewFocusNode != focusNodes_.end()) {
620             ++itNewFocusNode;
621         }
622         while (itNewFocusNode != focusNodes_.end()) {
623             if (TryRequestFocus(*itNewFocusNode, rect)) {
624                 return true;
625             }
626             ++itNewFocusNode;
627         }
628     }
629 
630     return false;
631 }
632 
OnKeyEvent(const KeyEvent & keyEvent)633 bool FocusGroup::OnKeyEvent(const KeyEvent& keyEvent)
634 {
635     ACE_DCHECK(IsCurrentFocus());
636     if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_)->HandleKeyEvent(keyEvent)) {
637         return true;
638     }
639 
640     if (FocusNode::OnKeyEvent(keyEvent)) {
641         return true;
642     }
643 
644     if (keyEvent.action != KeyAction::DOWN) {
645         return false;
646     }
647 
648     if (!CalculatePosition()) {
649         return false;
650     }
651 
652     OnFocusMove(keyEvent.code);
653     switch (keyEvent.code) {
654         case KeyCode::TV_CONTROL_UP:
655             LOGI("RequestNextFocus 'UP' by KeyCode(%{public}d)", keyEvent.code);
656             return RequestNextFocus(true, true, GetRect());
657         case KeyCode::TV_CONTROL_DOWN:
658             LOGI("RequestNextFocus 'DOWN' by KeyCode(%{public}d)", keyEvent.code);
659             return RequestNextFocus(true, false, GetRect());
660         case KeyCode::TV_CONTROL_LEFT:
661             LOGI("RequestNextFocus 'LEFT' by KeyCode(%{public}d)", keyEvent.code);
662             return RequestNextFocus(false, !AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
663         case KeyCode::TV_CONTROL_RIGHT:
664             LOGI("RequestNextFocus 'RIGHT' by KeyCode(%{public}d)", keyEvent.code);
665             return RequestNextFocus(false, AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
666         case KeyCode::KEY_TAB: {
667             auto element = AceType::DynamicCast<Element>(this);
668             if (!element) {
669                 return false;
670             }
671             auto context = element->GetContext().Upgrade();
672             if (!context) {
673                 return false;
674             }
675             bool ret = false;
676             if (keyEvent.pressedCodes.size() == 1) {
677                 LOGI("RequestNextFocus 'TAB' by KeyCode(%{public}d)", keyEvent.code);
678                 context->SetIsFocusingByTab(true);
679                 ret = RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
680                 context->SetIsFocusingByTab(false);
681             } else {
682                 LOGI("RequestNextFocus 'SHIFT-TAB' by KeyCode(%{public}d)", keyEvent.code);
683                 if (keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_TAB }) ||
684                     keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_TAB })) {
685                     context->SetIsFocusingByTab(true);
686                     ret = RequestNextFocus(false, true, GetRect()) || RequestNextFocus(true, true, GetRect());
687                     context->SetIsFocusingByTab(false);
688                 }
689             }
690             return ret;
691         }
692         default:
693             return false;
694     }
695 }
696 
CalculatePosition()697 bool FocusGroup::CalculatePosition()
698 {
699     if (itLastFocusNode_ == focusNodes_.end()) {
700         return false;
701     }
702 
703     Rect childRect;
704     if (!CalculateRect(*itLastFocusNode_, childRect)) {
705         return false;
706     }
707 
708     if ((*itLastFocusNode_)->IsChild()) {
709         auto renderNode = GetRenderNode(*itLastFocusNode_);
710         if (!renderNode) {
711             return false;
712         }
713 
714         Rect rect(childRect.GetOffset(), renderNode->GetLayoutSize());
715         (*itLastFocusNode_)->SetRect(rect);
716         SetRect(rect);
717     } else {
718         SetRect((*itLastFocusNode_)->GetRect() + childRect.GetOffset());
719     }
720 
721     return true;
722 }
723 
OnFocus()724 void FocusGroup::OnFocus()
725 {
726     if (focusNodes_.empty()) {
727         return;
728     }
729 
730     auto itFocusNode = itLastFocusNode_;
731     do {
732         if (itLastFocusNode_ == focusNodes_.end()) {
733             itLastFocusNode_ = focusNodes_.begin();
734             if (itLastFocusNode_ == itFocusNode) {
735                 break;
736             }
737         }
738         if ((*itLastFocusNode_)->RequestFocusImmediately()) {
739             FocusNode::OnFocus();
740             return;
741         }
742     } while ((++itLastFocusNode_) != itFocusNode);
743 
744     // Not found any focusable node, clear focus.
745     itLastFocusNode_ = focusNodes_.end();
746 }
747 
OnBlur()748 void FocusGroup::OnBlur()
749 {
750     FocusNode::OnBlur();
751 
752     if (itLastFocusNode_ != focusNodes_.end() && *itLastFocusNode_) {
753         (*itLastFocusNode_)->LostFocus(blurReason_);
754     }
755 }
756 
SetShow(bool show)757 void FocusGroup::SetShow(bool show)
758 {
759     FocusNode::SetShow(show);
760     RefreshParentFocusable(FocusNode::IsFocusable());
761 }
762 
SetEnabled(bool enabled)763 void FocusGroup::SetEnabled(bool enabled)
764 {
765     FocusNode::SetEnabled(enabled);
766     RefreshParentFocusable(FocusNode::IsFocusable());
767 }
768 
TryRequestFocus(const RefPtr<FocusNode> & focusNode,const Rect & rect)769 bool FocusGroup::TryRequestFocus(const RefPtr<FocusNode>& focusNode, const Rect& rect)
770 {
771     if (rect.IsValid()) {
772         Rect childRect;
773         if (!CalculateRect(focusNode, childRect) ||
774             !focusNode->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
775             return false;
776         }
777     }
778     return focusNode->RequestFocusImmediately();
779 }
780 
AcceptFocusByRectOfLastFocus(const Rect & rect)781 bool FocusGroup::AcceptFocusByRectOfLastFocus(const Rect& rect)
782 {
783     if (focusNodes_.empty()) {
784         return false;
785     }
786 
787     auto itFocusNode = itLastFocusNode_;
788     do {
789         if (itLastFocusNode_ == focusNodes_.end()) {
790             itLastFocusNode_ = focusNodes_.begin();
791             if (itLastFocusNode_ == itFocusNode) {
792                 break;
793             }
794         }
795         Rect childRect;
796         if (!CalculateRect(*itLastFocusNode_, childRect)) {
797             continue;
798         }
799 
800         if ((*itLastFocusNode_)->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
801             return true;
802         }
803     } while ((++itLastFocusNode_) != itFocusNode);
804 
805     return false;
806 }
807 
CalculateRect(const RefPtr<FocusNode> & node,Rect & rect)808 bool FocusGroup::CalculateRect(const RefPtr<FocusNode>& node, Rect& rect)
809 {
810     auto renderNode = GetRenderNode(AceType::Claim(this));
811     if (!renderNode) {
812         return false;
813     }
814     Offset nowOffset = renderNode->GetOffsetFromOrigin(Offset());
815 
816     renderNode = GetRenderNode(node);
817     if (!renderNode) {
818         return false;
819     }
820     Offset childOffset = renderNode->GetOffsetFromOrigin(Offset());
821     rect.SetRect(childOffset - nowOffset, renderNode->GetLayoutSize());
822     return true;
823 }
824 
RefreshParentFocusable(bool focusable)825 void FocusGroup::RefreshParentFocusable(bool focusable)
826 {
827     for (auto& item : focusNodes_) {
828         if (focusable != item->IsParentFocusable()) {
829             item->SetParentFocusable(focusable);
830             item->RefreshParentFocusable(item->FocusNode::IsFocusable());
831         }
832     }
833 }
834 
RebuildChild(std::list<RefPtr<FocusNode>> && rebuildFocusNodes)835 void FocusGroup::RebuildChild(std::list<RefPtr<FocusNode>>&& rebuildFocusNodes)
836 {
837     if (rebuildFocusNodes.empty()) {
838         return;
839     }
840 
841     focusNodes_ = std::move(rebuildFocusNodes);
842     itLastFocusNode_ = focusNodes_.end();
843     if (!IsCurrentFocus()) {
844         return;
845     }
846 
847     auto it = focusNodes_.begin();
848     while (it != focusNodes_.end()) {
849         if ((*it)->IsCurrentFocus()) {
850             itLastFocusNode_ = it;
851             return;
852         }
853         ++it;
854     }
855 
856     LostFocus();
857     itLastFocusNode_ = focusNodes_.end();
858     RequestFocusImmediately();
859 }
860 
GetFocusingTabNodeIdx(TabIndexNodeList & tabIndexNodes)861 int32_t FocusGroup::GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes)
862 {
863     if (tabIndexNodes.empty()) {
864         return NONE_TAB_FOCUSED_INDEX;
865     }
866     if (isFirstFocusInPage_) {
867         isFirstFocusInPage_ = false;
868         return DEFAULT_TAB_FOCUSED_INDEX;
869     }
870     int32_t res = NONE_TAB_FOCUSED_INDEX;
871     int32_t i = 0;
872     for (auto& wpNode : tabIndexNodes) {
873         auto node = wpNode.second.Upgrade();
874         if (node && node->IsCurrentFocus()) {
875             res = i;
876             break;
877         }
878         ++i;
879     }
880     return res;
881 }
882 
883 } // namespace OHOS::Ace
884