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