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