• 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 <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 
391     // current node is root node
392     if (!parent) {
393         LostFocus();
394         return;
395     }
396     while (!parent->IsFocusable()) {
397         // parent node is root node
398         if (!parent->GetParent().Upgrade()) {
399             parent->LostFocus();
400             return;
401         }
402         parent = parent->GetParent().Upgrade();
403     }
404     parent->LostFocus();
405     parent->RequestFocusImmediately();
406 }
407 
OnKeyEvent(const KeyEvent & keyEvent)408 bool FocusNode::OnKeyEvent(const KeyEvent& keyEvent)
409 {
410     auto element = AceType::DynamicCast<Element>(this);
411     if (!element) {
412         return false;
413     }
414     auto context = element->GetContext().Upgrade();
415     if (!context) {
416         return false;
417     }
418     if (context->GetIsDeclarative()) {
419         auto info = std::make_shared<KeyEventInfo>(keyEvent);
420         if (!onKeyEventCallback_) {
421             return false;
422         }
423 #ifdef LINUX_PLATFORM
424         LOGI("FocusNode::OnKeyEvent: Do key callback on %{public}s with key event{ Code(%{public}d), "
425              "Action(%{public}d), "
426              "SourceType(%{public}d), DeviceId(%{public}" PRId64 ") }. Return: %{public}d",
427             AceType::TypeName(this), info->GetKeyCode(), info->GetKeyType(), info->GetSourceDevice(),
428             info->GetDeviceId(), info->IsStopPropagation());
429 #else
430         LOGI("FocusNode::OnKeyEvent: Do key callback on %{public}s with key event{ Code(%{public}d), "
431              "Action(%{public}d), "
432              "SourceType(%{public}d), DeviceId(%{public}" PRId64 "), Time(%{public}lld) }. Return: %{public}d",
433             AceType::TypeName(this), info->GetKeyCode(), info->GetKeyType(), info->GetSourceDevice(),
434             info->GetDeviceId(), info->GetTimeStamp().time_since_epoch().count(), info->IsStopPropagation());
435 #endif
436         onKeyEventCallback_(info);
437         return info->IsStopPropagation();
438     } else {
439         if (onKeyCallback_) {
440             return onKeyCallback_(keyEvent);
441         }
442     }
443     return false;
444 }
445 
RefreshParentFocusable(bool focusable)446 void FocusNode::RefreshParentFocusable(bool focusable)
447 {
448     // do nothing
449 }
450 
RequestFocus()451 void FocusNode::RequestFocus()
452 {
453     if (IsCurrentFocus()) {
454         return;
455     }
456 
457     auto element = AceType::DynamicCast<Element>(this);
458     if (!element) {
459         return;
460     }
461     auto context = element->GetContext().Upgrade();
462     if (context) {
463         context->AddDirtyFocus(AceType::Claim(this));
464     } else {
465         LOGE("fail to add dirty focus due to context is null");
466     }
467 }
468 
OnClick(const KeyEvent & event)469 bool FocusNode::OnClick(const KeyEvent& event)
470 {
471     if (onClickEventCallback_) {
472         auto info = std::make_shared<ClickInfo>(-1);
473         info->SetTimeStamp(event.timeStamp);
474         info->SetGlobalLocation(
475             Offset((GetRect().Left() + GetRect().Right()) / 2, (GetRect().Top() + GetRect().Bottom()) / 2));
476         info->SetLocalLocation(
477             Offset((GetRect().Right() - GetRect().Left()) / 2, (GetRect().Bottom() - GetRect().Top()) / 2));
478         info->SetSourceDevice(static_cast<SourceType>(event.sourceType));
479         info->SetDeviceId(event.deviceId);
480 #ifdef LINUX_PLATFORM
481         LOGI("FocusNode::OnClick: Do click callback on %{public}s with key event{ Global(%{public}f,%{public}f), "
482              "Local(%{public}f,%{public}f), SourceType(%{public}d), DeviceId(%{public}" PRId64 ")}",
483             AceType::TypeName(this), info->GetGlobalLocation().GetX(), info->GetGlobalLocation().GetY(),
484             info->GetLocalLocation().GetX(), info->GetLocalLocation().GetY(), info->GetSourceDevice(),
485             info->GetDeviceId());
486 #else
487         LOGI("FocusNode::OnClick: Do click callback on %{public}s with key event{ Global(%{public}f,%{public}f), "
488              "Local(%{public}f,%{public}f), SourceType(%{public}d), DeviceId(%{public}" PRId64
489              "), Time(%{public}lld) }",
490             AceType::TypeName(this), info->GetGlobalLocation().GetX(), info->GetGlobalLocation().GetY(),
491             info->GetLocalLocation().GetX(), info->GetLocalLocation().GetY(), info->GetSourceDevice(),
492             info->GetDeviceId(), info->GetTimeStamp().time_since_epoch().count());
493 #endif
494         onClickEventCallback_(info);
495         return true;
496     }
497     return false;
498 }
499 
AddChild(const RefPtr<FocusNode> & focusNode)500 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode)
501 {
502     // Already belong to any focus scope.
503     if (!focusNode || !focusNode->GetParent().Invalid()) {
504         return;
505     }
506 
507     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
508     if (it == focusNodes_.end()) {
509         focusNodes_.emplace_back(focusNode);
510         focusNode->SetParent(AceType::WeakClaim(this));
511     }
512 }
513 
AddChild(const RefPtr<FocusNode> & focusNode,const RefPtr<FocusNode> & nextFocusNode)514 void FocusGroup::AddChild(const RefPtr<FocusNode>& focusNode, const RefPtr<FocusNode>& nextFocusNode)
515 {
516     // Already belong to any focus scope.
517     if (!focusNode || !focusNode->GetParent().Invalid()) {
518         return;
519     }
520 
521     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
522     auto pos = std::find(focusNodes_.begin(), focusNodes_.end(), nextFocusNode);
523     if (it == focusNodes_.end()) {
524         focusNodes_.insert(pos, focusNode);
525         focusNode->SetParent(AceType::WeakClaim(this));
526     }
527 }
528 
DumpFocusTree(int32_t depth)529 void FocusGroup::DumpFocusTree(int32_t depth)
530 {
531     if (DumpLog::GetInstance().GetDumpFile()) {
532         DumpFocus();
533         std::string information = AceType::TypeName(this);
534         if (IsCurrentFocus()) {
535             information += "(Scope*)";
536         } else {
537             information += "(Scope)";
538         }
539 
540         if (!IsFocusable()) {
541             information = "(-)" + information;
542         }
543         DumpLog::GetInstance().Print(depth, information, focusNodes_.size());
544     }
545 
546     for (const auto& item : focusNodes_) {
547         item->DumpFocusTree(depth + 1);
548     }
549 }
550 
RemoveChild(const RefPtr<FocusNode> & focusNode)551 void FocusGroup::RemoveChild(const RefPtr<FocusNode>& focusNode)
552 {
553     // Not belong to this focus scope.
554     if (!focusNode || focusNode->GetParent() != this) {
555         return;
556     }
557 
558     if (focusNode->IsCurrentFocus()) {
559         // Try to goto next focus, otherwise goto previous focus.
560         if (!GoToNextFocus(true) && !GoToNextFocus(false)) {
561             itLastFocusNode_ = focusNodes_.end();
562         }
563         focusNode->LostFocus();
564     } else {
565         if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_) == focusNode) {
566             itLastFocusNode_ = focusNodes_.end();
567         }
568     }
569 
570     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
571     if (it == focusNodes_.end()) {
572         return;
573     }
574     if (itLastFocusNode_ == it) {
575         itLastFocusNode_ = focusNodes_.end();
576     }
577     focusNode->SetParent(nullptr);
578     focusNodes_.erase(it);
579 }
580 
SwitchFocus(const RefPtr<FocusNode> & focusNode)581 void FocusGroup::SwitchFocus(const RefPtr<FocusNode>& focusNode)
582 {
583     auto it = std::find(focusNodes_.begin(), focusNodes_.end(), focusNode);
584     ACE_DCHECK(it != focusNodes_.end());
585 
586     auto itFocusNode = itLastFocusNode_;
587     itLastFocusNode_ = it;
588 
589     if (IsCurrentFocus()) {
590         if (itFocusNode != focusNodes_.end() && itFocusNode != it) {
591             (*itFocusNode)->LostFocus();
592         }
593     } else {
594         RequestFocusImmediately();
595     }
596 }
597 
IsFocusable() const598 bool FocusGroup::IsFocusable() const
599 {
600     if (!FocusNode::IsFocusable()) {
601         return false;
602     }
603     return std::any_of(focusNodes_.begin(), focusNodes_.end(),
604         [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusable(); });
605 }
606 
IsFocusableByTab() const607 bool FocusGroup::IsFocusableByTab() const
608 {
609     if (!FocusNode::IsFocusableByTab()) {
610         return false;
611     }
612     if (focusNodes_.empty()) {
613         return true;
614     }
615     return std::any_of(focusNodes_.begin(), focusNodes_.end(),
616         [](const RefPtr<FocusNode>& focusNode) { return focusNode->IsFocusableByTab(); });
617 }
618 
GoToNextFocus(bool reverse,const Rect & rect)619 bool FocusGroup::GoToNextFocus(bool reverse, const Rect& rect)
620 {
621     if (focusNodes_.empty()) {
622         return false;
623     }
624     auto itNewFocusNode = itLastFocusNode_;
625     if (itNewFocusNode == focusNodes_.end()) {
626         itNewFocusNode = focusNodes_.begin();
627     }
628     if (reverse) {
629         if (itNewFocusNode == focusNodes_.begin()) {
630             itNewFocusNode = focusNodes_.end();
631             return false;
632         } else {
633             --itNewFocusNode;
634         }
635         while (itNewFocusNode != focusNodes_.begin()) {
636             if (TryRequestFocus(*itNewFocusNode, rect)) {
637                 return true;
638             }
639             --itNewFocusNode;
640         }
641         if (itNewFocusNode == focusNodes_.begin()) {
642             if (TryRequestFocus(*itNewFocusNode, rect)) {
643                 return true;
644             }
645         }
646     } else {
647         if (itNewFocusNode != focusNodes_.end()) {
648             ++itNewFocusNode;
649         }
650         while (itNewFocusNode != focusNodes_.end()) {
651             if (TryRequestFocus(*itNewFocusNode, rect)) {
652                 return true;
653             }
654             ++itNewFocusNode;
655         }
656     }
657 
658     return false;
659 }
660 
OnKeyEvent(const KeyEvent & keyEvent)661 bool FocusGroup::OnKeyEvent(const KeyEvent& keyEvent)
662 {
663     ACE_DCHECK(IsCurrentFocus());
664     if (itLastFocusNode_ != focusNodes_.end() && (*itLastFocusNode_)->HandleKeyEvent(keyEvent)) {
665         return true;
666     }
667 
668     if (FocusNode::OnKeyEvent(keyEvent)) {
669         return true;
670     }
671 
672     if (keyEvent.action != KeyAction::DOWN) {
673         return false;
674     }
675 
676     if (!CalculatePosition()) {
677         return false;
678     }
679 
680     LOGD("Position information: Node is %{public}s, X: %{public}lf Y: %{public}lf W: %{public}lf H: %{public}lf",
681         AceType::TypeName(this), GetRect().Left(), GetRect().Top(), GetRect().Width(), GetRect().Height());
682 
683     OnFocusMove(keyEvent.code);
684     switch (keyEvent.code) {
685         case KeyCode::TV_CONTROL_UP:
686             LOGI("RequestNextFocus 'UP' by KeyCode(%{public}d)", keyEvent.code);
687             return RequestNextFocus(true, true, GetRect());
688         case KeyCode::TV_CONTROL_DOWN:
689             LOGI("RequestNextFocus 'DOWN' by KeyCode(%{public}d)", keyEvent.code);
690             return RequestNextFocus(true, false, GetRect());
691         case KeyCode::TV_CONTROL_LEFT:
692             LOGI("RequestNextFocus 'LEFT' by KeyCode(%{public}d)", keyEvent.code);
693             return RequestNextFocus(false, !AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
694         case KeyCode::TV_CONTROL_RIGHT:
695             LOGI("RequestNextFocus 'RIGHT' by KeyCode(%{public}d)", keyEvent.code);
696             return RequestNextFocus(false, AceApplicationInfo::GetInstance().IsRightToLeft(), GetRect());
697         case KeyCode::KEY_TAB: {
698             auto element = AceType::DynamicCast<Element>(this);
699             if (!element) {
700                 return false;
701             }
702             auto context = element->GetContext().Upgrade();
703             if (!context) {
704                 return false;
705             }
706             bool ret = false;
707             if (keyEvent.pressedCodes.size() == 1) {
708                 LOGI("RequestNextFocus 'TAB' by KeyCode(%{public}d)", keyEvent.code);
709                 context->SetIsFocusingByTab(true);
710                 ret = RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
711                 context->SetIsFocusingByTab(false);
712             } else {
713                 LOGI("RequestNextFocus 'SHIFT-TAB' by KeyCode(%{public}d)", keyEvent.code);
714                 if (keyEvent.IsKey({ KeyCode::KEY_SHIFT_LEFT, KeyCode::KEY_TAB }) ||
715                     keyEvent.IsKey({ KeyCode::KEY_SHIFT_RIGHT, KeyCode::KEY_TAB })) {
716                     context->SetIsFocusingByTab(true);
717                     ret = RequestNextFocus(false, true, GetRect()) || RequestNextFocus(true, true, GetRect());
718                     context->SetIsFocusingByTab(false);
719                 }
720             }
721             return ret;
722         }
723         default:
724             return false;
725     }
726 }
727 
CalculatePosition()728 bool FocusGroup::CalculatePosition()
729 {
730     if (itLastFocusNode_ == focusNodes_.end()) {
731         return false;
732     }
733 
734     Rect childRect;
735     if (!CalculateRect(*itLastFocusNode_, childRect)) {
736         return false;
737     }
738 
739     if ((*itLastFocusNode_)->IsChild()) {
740         auto renderNode = GetRenderNode(*itLastFocusNode_);
741         if (!renderNode) {
742             return false;
743         }
744 
745         Rect rect(childRect.GetOffset(), renderNode->GetLayoutSize());
746         (*itLastFocusNode_)->SetRect(rect);
747         SetRect(rect);
748     } else {
749         SetRect((*itLastFocusNode_)->GetRect() + childRect.GetOffset());
750     }
751 
752     return true;
753 }
754 
OnFocus()755 void FocusGroup::OnFocus()
756 {
757     if (focusNodes_.empty()) {
758         return;
759     }
760 
761     auto itFocusNode = itLastFocusNode_;
762     do {
763         if (itLastFocusNode_ == focusNodes_.end()) {
764             itLastFocusNode_ = focusNodes_.begin();
765             if (itLastFocusNode_ == itFocusNode) {
766                 break;
767             }
768         }
769         if ((*itLastFocusNode_)->RequestFocusImmediately()) {
770             FocusNode::OnFocus();
771             return;
772         }
773     } while ((++itLastFocusNode_) != itFocusNode);
774 
775     // Not found any focusable node, clear focus.
776     itLastFocusNode_ = focusNodes_.end();
777 }
778 
OnBlur()779 void FocusGroup::OnBlur()
780 {
781     FocusNode::OnBlur();
782 
783     if (itLastFocusNode_ != focusNodes_.end() && *itLastFocusNode_) {
784         (*itLastFocusNode_)->LostFocus(blurReason_);
785     }
786 }
787 
SetShow(bool show)788 void FocusGroup::SetShow(bool show)
789 {
790     FocusNode::SetShow(show);
791     RefreshParentFocusable(FocusNode::IsFocusable());
792 }
793 
SetEnabled(bool enabled)794 void FocusGroup::SetEnabled(bool enabled)
795 {
796     FocusNode::SetEnabled(enabled);
797     RefreshParentFocusable(FocusNode::IsFocusable());
798 }
799 
TryRequestFocus(const RefPtr<FocusNode> & focusNode,const Rect & rect)800 bool FocusGroup::TryRequestFocus(const RefPtr<FocusNode>& focusNode, const Rect& rect)
801 {
802     if (rect.IsValid()) {
803         Rect childRect;
804         if (!CalculateRect(focusNode, childRect) ||
805             !focusNode->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
806             return false;
807         }
808     }
809     return focusNode->RequestFocusImmediately();
810 }
811 
AcceptFocusByRectOfLastFocus(const Rect & rect)812 bool FocusGroup::AcceptFocusByRectOfLastFocus(const Rect& rect)
813 {
814     if (focusNodes_.empty()) {
815         return false;
816     }
817 
818     auto itFocusNode = itLastFocusNode_;
819     do {
820         if (itLastFocusNode_ == focusNodes_.end()) {
821             itLastFocusNode_ = focusNodes_.begin();
822             if (itLastFocusNode_ == itFocusNode) {
823                 break;
824             }
825         }
826         Rect childRect;
827         if (!CalculateRect(*itLastFocusNode_, childRect)) {
828             continue;
829         }
830 
831         if ((*itLastFocusNode_)->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
832             return true;
833         }
834     } while ((++itLastFocusNode_) != itFocusNode);
835 
836     return false;
837 }
838 
CalculateRect(const RefPtr<FocusNode> & node,Rect & rect)839 bool FocusGroup::CalculateRect(const RefPtr<FocusNode>& node, Rect& rect)
840 {
841     auto renderNode = GetRenderNode(AceType::Claim(this));
842     if (!renderNode) {
843         return false;
844     }
845     Offset nowOffset = renderNode->GetOffsetFromOrigin(Offset());
846 
847     renderNode = GetRenderNode(node);
848     if (!renderNode) {
849         return false;
850     }
851     Offset childOffset = renderNode->GetOffsetFromOrigin(Offset());
852     rect.SetRect(childOffset - nowOffset, renderNode->GetLayoutSize());
853     return true;
854 }
855 
RefreshParentFocusable(bool focusable)856 void FocusGroup::RefreshParentFocusable(bool focusable)
857 {
858     for (auto& item : focusNodes_) {
859         if (focusable != item->IsParentFocusable()) {
860             item->SetParentFocusable(focusable);
861             item->RefreshParentFocusable(item->FocusNode::IsFocusable());
862         }
863     }
864 }
865 
RebuildChild(std::list<RefPtr<FocusNode>> && rebuildFocusNodes)866 void FocusGroup::RebuildChild(std::list<RefPtr<FocusNode>>&& rebuildFocusNodes)
867 {
868     if (rebuildFocusNodes.empty()) {
869         return;
870     }
871 
872     focusNodes_ = std::move(rebuildFocusNodes);
873     itLastFocusNode_ = focusNodes_.end();
874     if (!IsCurrentFocus()) {
875         return;
876     }
877 
878     auto it = focusNodes_.begin();
879     while (it != focusNodes_.end()) {
880         if ((*it)->IsCurrentFocus()) {
881             itLastFocusNode_ = it;
882             return;
883         }
884         ++it;
885     }
886 
887     LostFocus();
888     itLastFocusNode_ = focusNodes_.end();
889     RequestFocusImmediately();
890 }
891 
GetFocusingTabNodeIdx(TabIndexNodeList & tabIndexNodes)892 int32_t FocusGroup::GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes)
893 {
894     if (tabIndexNodes.empty()) {
895         LOGD("No tabIndex node exist in this page.");
896         return NONE_TAB_FOCUSED_INDEX;
897     }
898     if (isFirstFocusInPage_) {
899         isFirstFocusInPage_ = false;
900         return DEFAULT_TAB_FOCUSED_INDEX;
901     }
902     int32_t res = NONE_TAB_FOCUSED_INDEX;
903     int32_t i = 0;
904     for (auto& wpNode : tabIndexNodes) {
905         auto node = wpNode.second.Upgrade();
906         if (node && node->IsCurrentFocus()) {
907             res = i;
908             break;
909         }
910         ++i;
911     }
912     return res;
913 }
914 
915 } // namespace OHOS::Ace
916