• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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/components_ng/event/focus_hub.h"
17 
18 #include <cinttypes>
19 
20 #include "base/geometry/ng/offset_t.h"
21 #include "base/geometry/ng/rect_t.h"
22 #include "base/log/dump_log.h"
23 #include "base/utils/utils.h"
24 #include "core/common/ace_application_info.h"
25 #include "core/components/theme/app_theme.h"
26 #include "core/components_ng/base/frame_node.h"
27 #include "core/components_ng/base/geometry_node.h"
28 #include "core/components_ng/event/gesture_event_hub.h"
29 #include "core/event/ace_event_handler.h"
30 #include "core/pipeline_ng/pipeline_context.h"
31 
32 namespace OHOS::Ace::NG {
33 
GetFrameNode() const34 RefPtr<FrameNode> FocusHub::GetFrameNode() const
35 {
36     auto eventHub = eventHub_.Upgrade();
37     return eventHub ? eventHub->GetFrameNode() : nullptr;
38 }
39 
GetGeometryNode() const40 RefPtr<GeometryNode> FocusHub::GetGeometryNode() const
41 {
42     auto frameNode = GetFrameNode();
43     return frameNode ? frameNode->GetGeometryNode() : nullptr;
44 }
45 
GetInspectorKey() const46 std::optional<std::string> FocusHub::GetInspectorKey() const
47 {
48     auto frameNode = GetFrameNode();
49     CHECK_NULL_RETURN_NOLOG(frameNode, std::nullopt);
50     return frameNode->GetInspectorId();
51 }
52 
GetParentFocusHub() const53 RefPtr<FocusHub> FocusHub::GetParentFocusHub() const
54 {
55     auto frameNode = GetFrameNode();
56     CHECK_NULL_RETURN_NOLOG(frameNode, nullptr);
57     auto parentNode = frameNode->GetFocusParent();
58     return parentNode ? parentNode->GetFocusHub() : nullptr;
59 }
60 
GetFrameName() const61 std::string FocusHub::GetFrameName() const
62 {
63     auto frameNode = GetFrameNode();
64     return frameNode ? frameNode->GetTag() : "NULL";
65 }
66 
GetFrameId() const67 int32_t FocusHub::GetFrameId() const
68 {
69     auto frameNode = GetFrameNode();
70     return frameNode ? frameNode->GetId() : -1;
71 }
72 
FlushChildrenFocusHub(std::list<RefPtr<FocusHub>> & focusNodes)73 std::list<RefPtr<FocusHub>>::iterator FocusHub::FlushChildrenFocusHub(std::list<RefPtr<FocusHub>>& focusNodes)
74 {
75     focusNodes.clear();
76     std::list<RefPtr<FrameNode>> childrenNode;
77     auto frameNode = GetFrameNode();
78     if (frameNode) {
79         frameNode->GetFocusChildren(childrenNode);
80     }
81     for (const auto& child : childrenNode) {
82         if (child->GetFocusHub()) {
83             focusNodes.emplace_back(child->GetFocusHub());
84         }
85     }
86     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
87     if (!lastFocusNode) {
88         return focusNodes.end();
89     }
90     return std::find(focusNodes.begin(), focusNodes.end(), lastFocusNode);
91 }
92 
HandleKeyEvent(const KeyEvent & keyEvent)93 bool FocusHub::HandleKeyEvent(const KeyEvent& keyEvent)
94 {
95     if (!IsCurrentFocus()) {
96         return false;
97     }
98     return OnKeyEvent(keyEvent);
99 }
100 
DumpFocusTree(int32_t depth)101 void FocusHub::DumpFocusTree(int32_t depth)
102 {
103     if (focusType_ == FocusType::NODE) {
104         DumpFocusNodeTree(depth);
105     } else if (focusType_ == FocusType::SCOPE) {
106         DumpFocusScopeTree(depth);
107     }
108 }
109 
DumpFocusNodeTree(int32_t depth)110 void FocusHub::DumpFocusNodeTree(int32_t depth)
111 {
112     if (DumpLog::GetInstance().GetDumpFile()) {
113         std::string information = GetFrameName();
114         if (IsCurrentFocus()) {
115             information += "(Node*)";
116         } else {
117             information += "(Node)";
118         }
119         information += (" id:" + std::to_string(GetFrameId()));
120         if (!IsFocusable()) {
121             information = "(-)" + information;
122         }
123         DumpLog::GetInstance().Print(depth, information, 0);
124     }
125 }
126 
DumpFocusScopeTree(int32_t depth)127 void FocusHub::DumpFocusScopeTree(int32_t depth)
128 {
129     std::list<RefPtr<FocusHub>> focusNodes;
130     FlushChildrenFocusHub(focusNodes);
131     if (DumpLog::GetInstance().GetDumpFile()) {
132         std::string information = GetFrameName();
133         if (IsCurrentFocus()) {
134             information += "(Scope*)";
135         } else {
136             information += "(Scope)";
137         }
138         information += (" id:" + std::to_string(GetFrameId()));
139         if (!IsFocusable()) {
140             information = "(-)" + information;
141         }
142         DumpLog::GetInstance().Print(depth, information, static_cast<int32_t>(focusNodes.size()));
143     }
144 
145     for (const auto& item : focusNodes) {
146         item->DumpFocusTree(depth + 1);
147     }
148 }
149 
RequestFocusImmediately(bool isWholePathFocusable)150 bool FocusHub::RequestFocusImmediately(bool isWholePathFocusable)
151 {
152     auto context = NG::PipelineContext::GetCurrentContext();
153     if (context && context->GetIsFocusingByTab()) {
154         if (!IsFocusableByTab()) {
155             return false;
156         }
157     }
158 
159     if (IsCurrentFocus()) {
160         return true;
161     }
162 
163     if (!IsFocusable()) {
164         return false;
165     }
166 
167     currentFocus_ = true;
168     UpdateAccessibilityFocusInfo();
169 
170     if (onPreFocusCallback_) {
171         onPreFocusCallback_();
172     }
173 
174     auto parent = GetParentFocusHub();
175     if (parent) {
176         parent->SwitchFocus(AceType::Claim(this));
177     } else {
178         LOGD("Switch focus. Has no parent.");
179     }
180 
181     HandleFocus();
182     return true;
183 }
184 
UpdateAccessibilityFocusInfo()185 void FocusHub::UpdateAccessibilityFocusInfo()
186 {
187     // Need update
188 }
189 
LostFocus(BlurReason reason)190 void FocusHub::LostFocus(BlurReason reason)
191 {
192     LOGD("Node %{public}s/%{public}d lost focus. Lost reason: %{public}d.", GetFrameName().c_str(), GetFrameId(),
193         reason);
194     if (IsCurrentFocus()) {
195         blurReason_ = reason;
196         currentFocus_ = false;
197         UpdateAccessibilityFocusInfo();
198         OnBlur();
199     }
200 }
201 
LostSelfFocus()202 void FocusHub::LostSelfFocus()
203 {
204     if (IsCurrentFocus()) {
205         SetFocusable(false);
206         SetFocusable(true);
207     }
208 }
209 
RemoveSelf()210 void FocusHub::RemoveSelf()
211 {
212     LOGD("Node %{public}s/%{public}d remove self.", GetFrameName().c_str(), GetFrameId());
213     auto parent = GetParentFocusHub();
214     if (parent) {
215         parent->RemoveChild(AceType::Claim(this));
216     } else {
217         LostFocus(BlurReason::FRAME_DESTROY);
218     }
219 }
220 
RemoveChild(const RefPtr<FocusHub> & focusNode)221 void FocusHub::RemoveChild(const RefPtr<FocusHub>& focusNode)
222 {
223     // Not belong to this focus scope.
224     if (!focusNode || focusNode->GetParentFocusHub() != this) {
225         return;
226     }
227 
228     std::list<RefPtr<FocusHub>> focusNodes;
229     auto itLastFocusNode = FlushChildrenFocusHub(focusNodes);
230 
231     if (focusNode->IsCurrentFocus()) {
232         LOGI("Target remove node: %{public}s/%{public}d is current focus. Need change focus to another.",
233             GetFrameName().c_str(), GetFrameId());
234         // Try to goto next focus, otherwise goto previous focus.
235         if (!GoToNextFocusLinear(FocusStep::TAB) && !GoToNextFocusLinear(FocusStep::SHIFT_TAB)) {
236             LOGD("Change focus failed. Remove self: %{public}s/%{public}d", GetFrameName().c_str(), GetFrameId());
237             lastWeakFocusNode_ = nullptr;
238             RemoveSelf();
239         }
240         focusNode->LostFocus(BlurReason::FRAME_DESTROY);
241     } else {
242         if (itLastFocusNode != focusNodes.end() && (*itLastFocusNode) == focusNode) {
243             lastWeakFocusNode_ = nullptr;
244         }
245     }
246 
247     auto it = std::find(focusNodes.begin(), focusNodes.end(), focusNode);
248     if (it == focusNodes.end()) {
249         return;
250     }
251     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
252     if (lastFocusNode == focusNode) {
253         lastWeakFocusNode_ = nullptr;
254     }
255 }
256 
257 // Need update RebuildChild function
258 
IsFocusable()259 bool FocusHub::IsFocusable()
260 {
261     if (focusType_ == FocusType::NODE) {
262         return IsFocusableNode();
263     }
264     if (focusType_ == FocusType::SCOPE) {
265         return IsFocusableScope();
266     }
267     return false;
268 }
269 
IsFocusableScope()270 bool FocusHub::IsFocusableScope()
271 {
272     if (!IsFocusableNode()) {
273         return false;
274     }
275     std::list<RefPtr<FocusHub>> focusNodes;
276     FlushChildrenFocusHub(focusNodes);
277     // TODO: Container without child can be focusable
278     return std::any_of(focusNodes.begin(), focusNodes.end(),
279         [](const RefPtr<FocusHub>& focusNode) { return focusNode->IsFocusable(); });
280 }
281 
IsFocusableNode()282 bool FocusHub::IsFocusableNode()
283 {
284     return IsEnabled() && IsShow() && focusable_ && parentFocusable_;
285 }
286 
SetFocusable(bool focusable)287 void FocusHub::SetFocusable(bool focusable)
288 {
289     LOGD("Set node: %{public}s/%{public}d focusable from %{public}d to %{public}d", GetFrameName().c_str(),
290         GetFrameId(), focusable_, focusable);
291     if (focusable_ == focusable) {
292         return;
293     }
294     focusable_ = focusable;
295     RefreshParentFocusable(IsFocusableNode());
296     RefreshFocus();
297     MarkRootFocusNeedUpdate();
298 }
299 
IsEnabled() const300 bool FocusHub::IsEnabled() const
301 {
302     auto eventHub = eventHub_.Upgrade();
303     return eventHub ? eventHub->IsEnabled() : true;
304 }
305 
SetEnabled(bool enabled)306 void FocusHub::SetEnabled(bool enabled)
307 {
308     LOGD("Set node: %{public}s/%{public}d enabled to %{public}d", GetFrameName().c_str(), GetFrameId(), enabled);
309     if (focusType_ == FocusType::NODE) {
310         SetEnabledNode(enabled);
311     } else if (focusType_ == FocusType::SCOPE) {
312         SetEnabledScope(enabled);
313     }
314     MarkRootFocusNeedUpdate();
315 }
316 
SetEnabledNode(bool enabled)317 void FocusHub::SetEnabledNode(bool enabled)
318 {
319     if (!enabled) {
320         RefreshFocus();
321     }
322 }
323 
SetEnabledScope(bool enabled)324 void FocusHub::SetEnabledScope(bool enabled)
325 {
326     SetEnabledNode(enabled);
327     RefreshParentFocusable(IsFocusableNode());
328 }
329 
IsShow() const330 bool FocusHub::IsShow() const
331 {
332     auto frameNode = GetFrameNode();
333     CHECK_NULL_RETURN(frameNode, true);
334     bool curIsVisible = frameNode->IsVisible();
335     auto parent = frameNode->GetParent();
336     while (parent) {
337         auto parentFrame = AceType::DynamicCast<FrameNode>(parent);
338         if (parentFrame && !parentFrame->IsVisible()) {
339             curIsVisible = false;
340             break;
341         }
342         parent = parent->GetParent();
343     }
344     return curIsVisible;
345 }
346 
SetShow(bool show)347 void FocusHub::SetShow(bool show)
348 {
349     if (focusType_ == FocusType::NODE) {
350         SetShowNode(show);
351     } else if (focusType_ == FocusType::SCOPE) {
352         SetShowScope(show);
353     }
354     MarkRootFocusNeedUpdate();
355 }
356 
SetShowNode(bool show)357 void FocusHub::SetShowNode(bool show)
358 {
359     if (!show) {
360         RefreshFocus();
361     }
362 }
363 
SetShowScope(bool show)364 void FocusHub::SetShowScope(bool show)
365 {
366     SetShowNode(show);
367 }
368 
MarkRootFocusNeedUpdate()369 void FocusHub::MarkRootFocusNeedUpdate()
370 {
371     if (focusType_ != FocusType::NODE || !IsFocusable()) {
372         return;
373     }
374     auto pipeline = PipelineContext::GetCurrentContext();
375     CHECK_NULL_VOID(pipeline);
376     pipeline->MarkRootFocusNeedUpdate();
377 }
378 
IsCurrentFocusWholePath()379 bool FocusHub::IsCurrentFocusWholePath()
380 {
381     if (!currentFocus_) {
382         return false;
383     }
384     if (focusType_ == FocusType::NODE) {
385         return true;
386     }
387     if (focusType_ == FocusType::SCOPE) {
388         std::list<RefPtr<FocusHub>> focusNodes;
389         auto itLastFocusNode = FlushChildrenFocusHub(focusNodes);
390         if (itLastFocusNode == focusNodes.end() || !(*itLastFocusNode)) {
391             return false;
392         }
393         return (*itLastFocusNode)->IsCurrentFocusWholePath();
394     }
395     return false;
396 }
397 
SetIsFocusOnTouch(bool isFocusOnTouch)398 void FocusHub::SetIsFocusOnTouch(bool isFocusOnTouch)
399 {
400     LOGD("Set node: %{public}s/%{public}d focusOnTouch to %{public}d", GetFrameName().c_str(), GetFrameId(),
401         isFocusOnTouch);
402     if (!focusCallbackEvents_) {
403         focusCallbackEvents_ = MakeRefPtr<FocusCallbackEvents>();
404     }
405     if (focusCallbackEvents_->IsFocusOnTouch().has_value() &&
406         focusCallbackEvents_->IsFocusOnTouch().value() == isFocusOnTouch) {
407         return;
408     }
409     focusCallbackEvents_->SetIsFocusOnTouch(isFocusOnTouch);
410 
411     auto frameNode = GetFrameNode();
412     CHECK_NULL_VOID(frameNode);
413     auto gesture = frameNode->GetOrCreateGestureEventHub();
414     CHECK_NULL_VOID(gesture);
415 
416     if (!isFocusOnTouch && !focusOnTouchListener_) {
417         return;
418     }
419     if (!isFocusOnTouch && focusOnTouchListener_) {
420         gesture->RemoveTouchEvent(focusOnTouchListener_);
421         return;
422     }
423     if (!focusOnTouchListener_) {
424         auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
425             auto focusHub = weak.Upgrade();
426             if (focusHub && info.GetTouches().front().GetTouchType() == TouchType::UP) {
427                 focusHub->RequestFocusImmediately();
428             }
429         };
430         focusOnTouchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
431     }
432     gesture->AddTouchEvent(focusOnTouchListener_);
433 }
434 
SetIsDefaultFocus(bool isDefaultFocus)435 void FocusHub::SetIsDefaultFocus(bool isDefaultFocus)
436 {
437     LOGD("Set node: %{public}s/%{public}d defaultFocus to %{public}d", GetFrameName().c_str(), GetFrameId(),
438         isDefaultFocus);
439     if (!focusCallbackEvents_) {
440         focusCallbackEvents_ = MakeRefPtr<FocusCallbackEvents>();
441     }
442     focusCallbackEvents_->SetIsDefaultFocus(isDefaultFocus);
443 
444     auto pipeline = PipelineContext::GetCurrentContext();
445     CHECK_NULL_VOID(pipeline);
446     auto rootNode = pipeline->GetRootElement();
447     CHECK_NULL_VOID(rootNode);
448     auto stageManager = pipeline->GetStageManager();
449     CHECK_NULL_VOID(stageManager);
450     auto lastPage = stageManager->GetLastPage();
451     auto mainNode = lastPage ? lastPage : rootNode;
452     CHECK_NULL_VOID(mainNode);
453     auto mainFocusHub = mainNode->GetFocusHub();
454     CHECK_NULL_VOID(mainFocusHub);
455 
456     auto defaultFocusNode = mainFocusHub->GetChildFocusNodeByType();
457     CHECK_NULL_VOID_NOLOG(defaultFocusNode);
458     mainFocusHub->SetDefaultFocusNode(AceType::WeakClaim(AceType::RawPtr(defaultFocusNode)));
459 }
SetIsDefaultGroupFocus(bool isDefaultGroupFocus)460 void FocusHub::SetIsDefaultGroupFocus(bool isDefaultGroupFocus)
461 {
462     if (!focusCallbackEvents_) {
463         focusCallbackEvents_ = MakeRefPtr<FocusCallbackEvents>();
464     }
465     focusCallbackEvents_->SetIsDefaultGroupFocus(isDefaultGroupFocus);
466 }
467 
RefreshFocus()468 void FocusHub::RefreshFocus()
469 {
470     if (!IsCurrentFocus()) {
471         return;
472     }
473 
474     // lost current focus and request another focus
475     auto parent = GetParentFocusHub();
476 
477     // current node is root node
478     if (!parent) {
479         LostFocus();
480         return;
481     }
482     while (!parent->IsFocusable()) {
483         // parent node is root node
484         if (!parent->GetParentFocusHub()) {
485             parent->LostFocus();
486             return;
487         }
488         parent = parent->GetParentFocusHub();
489     }
490     parent->LostFocus();
491     parent->RequestFocusImmediately();
492 }
493 
OnKeyEvent(const KeyEvent & keyEvent)494 bool FocusHub::OnKeyEvent(const KeyEvent& keyEvent)
495 {
496     if (focusType_ == FocusType::SCOPE) {
497         return OnKeyEventScope(keyEvent);
498     }
499     if (focusType_ == FocusType::NODE) {
500         return OnKeyEventNode(keyEvent);
501     }
502     LOGE("Current node focus type: %{public}d is invalid.", focusType_);
503     return false;
504 }
505 
OnKeyEventNode(const KeyEvent & keyEvent)506 bool FocusHub::OnKeyEventNode(const KeyEvent& keyEvent)
507 {
508     ACE_DCHECK(IsCurrentFocus());
509 
510     auto retInternal = false;
511     auto pipeline = PipelineContext::GetCurrentContext();
512     bool isBypassInner = keyEvent.IsKey({ KeyCode::KEY_TAB }) && pipeline && pipeline->IsTabJustTriggerOnKeyEvent();
513     if (!isBypassInner && !onKeyEventsInternal_.empty()) {
514         retInternal = ProcessOnKeyEventInternal(keyEvent);
515     }
516     LOGD("OnKeyEventInteral: Node %{public}s/%{public}d consume KeyEvent(code:%{public}d, action:%{public}d) return: "
517          "%{public}d",
518         GetFrameName().c_str(), GetFrameId(), keyEvent.code, keyEvent.action, retInternal);
519 
520     auto info = KeyEventInfo(keyEvent);
521     if (pipeline &&
522         (pipeline->IsKeyInPressed(KeyCode::KEY_META_LEFT) || pipeline->IsKeyInPressed(KeyCode::KEY_META_RIGHT))) {
523         info.SetMetaKey(1);
524     }
525     auto retCallback = false;
526     auto onKeyEventCallback = GetOnKeyCallback();
527     if (onKeyEventCallback) {
528         onKeyEventCallback(info);
529         retCallback = info.IsStopPropagation();
530     }
531     LOGD("OnKeyEvent: Node %{public}s/%{public}d consume KeyEvent(code:%{public}d, action:%{public}d) return: "
532          "%{public}d",
533         GetFrameName().c_str(), GetFrameId(), keyEvent.code, keyEvent.action, retCallback);
534 
535     if (!retInternal && !retCallback && keyEvent.action == KeyAction::DOWN) {
536         auto ret = false;
537         switch (keyEvent.code) {
538             case KeyCode::KEY_SPACE:
539             case KeyCode::KEY_ENTER:
540             case KeyCode::KEY_NUMPAD_ENTER:
541                 ret = OnClick(keyEvent);
542                 break;
543             default:;
544         }
545         return ret;
546     }
547     return retInternal || retCallback;
548 }
549 
OnKeyEventScope(const KeyEvent & keyEvent)550 bool FocusHub::OnKeyEventScope(const KeyEvent& keyEvent)
551 {
552     ACE_DCHECK(IsCurrentFocus());
553     std::list<RefPtr<FocusHub>> focusNodes;
554     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
555     if (lastFocusNode && lastFocusNode->HandleKeyEvent(keyEvent)) {
556         LOGI("OnKeyEvent: Node %{public}s/%{public}d will not handle KeyEvent(code:%{public}d, action:%{public}d). "
557              "Because its child %{public}s/%{public}d already has consumed this event.",
558             GetFrameName().c_str(), GetFrameId(), keyEvent.code, keyEvent.action, lastFocusNode->GetFrameName().c_str(),
559             lastFocusNode->GetFrameId());
560         return true;
561     }
562 
563     if (OnKeyEventNode(keyEvent)) {
564         return true;
565     }
566 
567     if (keyEvent.action != KeyAction::DOWN) {
568         return false;
569     }
570 
571     auto pipeline = PipelineContext::GetCurrentContext();
572     CHECK_NULL_RETURN(pipeline, false);
573     if (!pipeline->GetIsFocusActive()) {
574         return false;
575     }
576     if (keyEvent.IsKey({ KeyCode::KEY_TAB }) && pipeline->IsTabJustTriggerOnKeyEvent()) {
577         return false;
578     }
579 
580     ScrollToLastFocusIndex();
581     if (!CalculatePosition()) {
582         return false;
583     }
584 
585     switch (keyEvent.code) {
586         case KeyCode::TV_CONTROL_UP:
587             return RequestNextFocus(FocusStep::UP, GetRect());
588         case KeyCode::TV_CONTROL_DOWN:
589             return RequestNextFocus(FocusStep::DOWN, GetRect());
590         case KeyCode::TV_CONTROL_LEFT:
591             return RequestNextFocus(FocusStep::LEFT, GetRect());
592         case KeyCode::TV_CONTROL_RIGHT:
593             return RequestNextFocus(FocusStep::RIGHT, GetRect());
594         case KeyCode::KEY_TAB: {
595             auto context = NG::PipelineContext::GetCurrentContext();
596             bool ret = false;
597             if (keyEvent.pressedCodes.size() == 1) {
598                 context->SetIsFocusingByTab(true);
599                 ret = RequestNextFocus(FocusStep::TAB, GetRect());
600                 auto focusParent = GetParentFocusHub();
601                 if (!focusParent || !focusParent->IsCurrentFocus()) {
602                     ret = FocusToHeadOrTailChild(true);
603                 }
604                 context->SetIsFocusingByTab(false);
605             } else if (keyEvent.IsShiftWith(KeyCode::KEY_TAB)) {
606                 context->SetIsFocusingByTab(true);
607                 ret = RequestNextFocus(FocusStep::SHIFT_TAB, GetRect());
608                 auto focusParent = GetParentFocusHub();
609                 if (!focusParent || !focusParent->IsCurrentFocus()) {
610                     ret = FocusToHeadOrTailChild(false);
611                 }
612                 context->SetIsFocusingByTab(false);
613             }
614             return ret;
615         }
616         case KeyCode::KEY_MOVE_HOME:
617             return RequestNextFocus(FocusStep::LEFT_END, GetRect()) || RequestNextFocus(FocusStep::UP_END, GetRect());
618         case KeyCode::KEY_MOVE_END:
619             return RequestNextFocus(FocusStep::RIGHT_END, GetRect()) ||
620                    RequestNextFocus(FocusStep::DOWN_END, GetRect());
621         default:
622             return false;
623     }
624 }
625 
RequestFocus() const626 void FocusHub::RequestFocus() const
627 {
628     if (IsCurrentFocus()) {
629         return;
630     }
631     auto context = NG::PipelineContext::GetCurrentContext();
632     CHECK_NULL_VOID(context);
633     context->AddDirtyFocus(GetFrameNode());
634 }
635 
RequestFocusWithDefaultFocusFirstly() const636 void FocusHub::RequestFocusWithDefaultFocusFirstly() const
637 {
638     auto context = NG::PipelineContext::GetCurrentContext();
639     CHECK_NULL_VOID(context);
640     context->AddDirtyDefaultFocus(GetFrameNode());
641 }
642 
RequestNextFocus(FocusStep moveStep,const RectF & rect)643 bool FocusHub::RequestNextFocus(FocusStep moveStep, const RectF& rect)
644 {
645     LOGI("Request next focus on node: %{public}s/%{public}d by step: %{public}d.", GetFrameName().c_str(), GetFrameId(),
646         moveStep);
647     SetScopeFocusAlgorithm();
648     if (!focusAlgorithm_.getNextFocusNode) {
649         if (focusAlgorithm_.scopeType == ScopeType::PROJECT_AREA) {
650             auto lastFocusNode = lastWeakFocusNode_.Upgrade();
651             CHECK_NULL_RETURN(lastFocusNode, false);
652             RefPtr<FocusHub> nextFocusHub = nullptr;
653             if (IsFocusStepTab(moveStep)) {
654                 nextFocusHub = lastFocusNode->GetNearestNodeByProjectArea(
655                     GetChildren(), moveStep == FocusStep::TAB ? FocusStep::RIGHT : FocusStep::LEFT);
656             }
657             if (!nextFocusHub) {
658                 nextFocusHub = lastFocusNode->GetNearestNodeByProjectArea(GetChildren(), moveStep);
659             }
660             if (!nextFocusHub) {
661                 LOGI("Request next focus failed becase cannot find next node by project area.");
662                 return false;
663             }
664             auto ret = TryRequestFocus(nextFocusHub, rect, moveStep);
665             LOGI("Request next focus by project area. Next focus node is %{public}s/%{public}d. Return %{public}d",
666                 nextFocusHub->GetFrameName().c_str(), nextFocusHub->GetFrameId(), ret);
667             return ret;
668         }
669         if (!IsFocusStepTab(moveStep) && focusAlgorithm_.isVertical != IsFocusStepVertical(moveStep)) {
670             LOGI("Request next focus failed because direction of node(%{pubic}d) is different with step(%{public}d).",
671                 focusAlgorithm_.isVertical, IsFocusStepVertical(moveStep));
672             return false;
673         }
674         auto ret = GoToNextFocusLinear(moveStep, rect);
675         LOGI("Request next focus by default linear algorithm. Return %{public}d.", ret);
676         return ret;
677     }
678     WeakPtr<FocusHub> nextFocusHubWeak;
679     focusAlgorithm_.getNextFocusNode(moveStep, lastWeakFocusNode_, nextFocusHubWeak);
680     auto nextFocusHub = nextFocusHubWeak.Upgrade();
681     if (!nextFocusHub) {
682         LOGI("Request next focus failed becase custom focus algorithm return null.");
683         return false;
684     }
685     auto ret = TryRequestFocus(nextFocusHub, rect, moveStep);
686     LOGI("Request next focus by custom algorithm. Next focus node is %{public}s/%{public}d. Return %{public}d",
687         nextFocusHub->GetFrameName().c_str(), nextFocusHub->GetFrameId(), ret);
688     return ret;
689 }
690 
FocusToHeadOrTailChild(bool isHead)691 bool FocusHub::FocusToHeadOrTailChild(bool isHead)
692 {
693     if (focusType_ != FocusType::SCOPE && IsFocusableWholePath()) {
694         return RequestFocusImmediately();
695     }
696     std::list<RefPtr<FocusHub>> focusNodes;
697     FlushChildrenFocusHub(focusNodes);
698     if (isHead) {
699         return std::any_of(focusNodes.begin(), focusNodes.end(),
700             [](const RefPtr<FocusHub>& node) { return node->FocusToHeadOrTailChild(true); });
701     }
702     return std::any_of(focusNodes.rbegin(), focusNodes.rend(),
703         [](const RefPtr<FocusHub>& node) { return node->FocusToHeadOrTailChild(false); });
704 }
705 
RefreshParentFocusable(bool focusable)706 void FocusHub::RefreshParentFocusable(bool focusable)
707 {
708     if (focusType_ != FocusType::SCOPE) {
709         return;
710     }
711     std::list<RefPtr<FocusHub>> focusNodes;
712     FlushChildrenFocusHub(focusNodes);
713     for (auto& item : focusNodes) {
714         if (focusable != item->IsParentFocusable()) {
715             item->SetParentFocusable(focusable);
716             item->RefreshParentFocusable(item->IsFocusableNode());
717         }
718     }
719 }
720 
OnClick(const KeyEvent & event)721 bool FocusHub::OnClick(const KeyEvent& event)
722 {
723     auto onClickCallback = GetOnClickCallback();
724     if (onClickCallback) {
725         auto info = GestureEvent();
726         info.SetTimeStamp(event.timeStamp);
727         auto geometryNode = GetGeometryNode();
728         CHECK_NULL_RETURN_NOLOG(geometryNode, false);
729         auto rect = geometryNode->GetFrameRect();
730         info.SetGlobalLocation(Offset((rect.Left() + rect.Right()) / 2, (rect.Top() + rect.Bottom()) / 2));
731         info.SetLocalLocation(Offset((rect.Right() - rect.Left()) / 2, (rect.Bottom() - rect.Top()) / 2));
732         info.SetSourceDevice(event.sourceType);
733         info.SetDeviceId(event.deviceId);
734         LOGD("FocusHub::OnClick: Do click callback on %{public}s/%{public}d with key event{ "
735              "Global(%{public}f,%{public}f), Local(%{public}f,%{public}f), SourceType(%{public}d), "
736              "DeviceId(%{public}" PRId64 ") }",
737             GetFrameName().c_str(), GetFrameId(), info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY(),
738             info.GetLocalLocation().GetX(), info.GetLocalLocation().GetY(), info.GetSourceDevice(), info.GetDeviceId());
739         onClickCallback(info);
740         return true;
741     }
742     return false;
743 }
744 
SwitchFocus(const RefPtr<FocusHub> & focusNode)745 void FocusHub::SwitchFocus(const RefPtr<FocusHub>& focusNode)
746 {
747     if (focusType_ != FocusType::SCOPE) {
748         LOGE("SwitchFocus: parent focus node is not a scope!");
749         return;
750     }
751     std::list<RefPtr<FocusHub>> focusNodes;
752     FlushChildrenFocusHub(focusNodes);
753 
754     auto it = std::find(focusNodes.begin(), focusNodes.end(), focusNode);
755     if (it == focusNodes.end()) {
756         LOGE("SwitchFocus: Can't find node: %{public}s/%{public}d in parent: %{public}s/%{public}d 's children",
757             focusNode->GetFrameName().c_str(), focusNode->GetFrameId(), GetFrameName().c_str(), GetFrameId());
758     }
759 
760     auto focusNodeNeedBlur = lastWeakFocusNode_.Upgrade();
761     lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(focusNode));
762 
763     if (focusNodeNeedBlur) {
764         LOGD("Switch focus from %{public}s/%{public}d to %{public}s/%{public}d",
765             focusNodeNeedBlur->GetFrameName().c_str(), focusNodeNeedBlur->GetFrameId(),
766             focusNode->GetFrameName().c_str(), focusNode->GetFrameId());
767     } else {
768         LOGD("Switch focus from NULL/NULL to %{public}s/%{public}d", focusNode->GetFrameName().c_str(),
769             focusNode->GetFrameId());
770     }
771     if (IsCurrentFocus()) {
772         if (focusNodeNeedBlur && focusNodeNeedBlur != focusNode) {
773             focusNodeNeedBlur->LostFocus();
774         }
775     } else {
776         RequestFocusImmediately(true);
777     }
778 }
779 
GoToNextFocusLinear(FocusStep step,const RectF & rect)780 bool FocusHub::GoToNextFocusLinear(FocusStep step, const RectF& rect)
781 {
782     if (step == FocusStep::NONE) {
783         LOGI("Invalid step: %{public}d of scope: %{public}s/%{public}d", step, GetFrameName().c_str(), GetFrameId());
784         return false;
785     }
786     bool reverse = !IsFocusStepForward(step);
787     if (AceApplicationInfo::GetInstance().IsRightToLeft()) {
788         reverse = !reverse;
789     }
790     std::list<RefPtr<FocusHub>> focusNodes;
791     auto itNewFocusNode = FlushChildrenFocusHub(focusNodes);
792     if (focusNodes.empty()) {
793         LOGW("FocusNode: %{public}s/%{public}d has no next child focus node to go.", GetFrameName().c_str(),
794             GetFrameId());
795         return false;
796     }
797     if (itNewFocusNode == focusNodes.end()) {
798         itNewFocusNode = focusNodes.begin();
799     }
800     if (reverse) {
801         if (itNewFocusNode == focusNodes.begin()) {
802             itNewFocusNode = focusNodes.end();
803             return false;
804         }
805         --itNewFocusNode;
806 
807         while (itNewFocusNode != focusNodes.begin()) {
808             if (TryRequestFocus(*itNewFocusNode, rect, step)) {
809                 return true;
810             }
811             --itNewFocusNode;
812         }
813         if (itNewFocusNode == focusNodes.begin()) {
814             if (TryRequestFocus(*itNewFocusNode, rect, step)) {
815                 return true;
816             }
817         }
818     } else {
819         if (itNewFocusNode != focusNodes.end()) {
820             ++itNewFocusNode;
821         }
822         while (itNewFocusNode != focusNodes.end()) {
823             if (TryRequestFocus(*itNewFocusNode, rect, step)) {
824                 return true;
825             }
826             ++itNewFocusNode;
827         }
828     }
829 
830     return false;
831 }
832 
TryRequestFocus(const RefPtr<FocusHub> & focusNode,const RectF & rect,FocusStep step)833 bool FocusHub::TryRequestFocus(const RefPtr<FocusHub>& focusNode, const RectF& rect, FocusStep step)
834 {
835     if (IsFocusStepTab(step) && focusNode->AcceptFocusOfSpecifyChild(step)) {
836         return focusNode->RequestFocusImmediately();
837     }
838     if (rect.IsValid()) {
839         RectF childRect;
840         if (!CalculateRect(focusNode, childRect) ||
841             !focusNode->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
842             return false;
843         }
844     }
845     return focusNode->RequestFocusImmediately();
846 }
847 
CalculatePosition()848 bool FocusHub::CalculatePosition()
849 {
850     std::list<RefPtr<FocusHub>> focusNodes;
851     FlushChildrenFocusHub(focusNodes);
852     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
853     CHECK_NULL_RETURN(lastFocusNode, false);
854 
855     RectF childRect;
856     if (!CalculateRect(lastFocusNode, childRect)) {
857         return false;
858     }
859 
860     if (lastFocusNode->IsChild()) {
861         auto lastFocusGeometryNode = lastFocusNode->GetGeometryNode();
862         CHECK_NULL_RETURN(lastFocusGeometryNode, false);
863         RectF rect(childRect.GetOffset(), lastFocusGeometryNode->GetFrameSize());
864         lastFocusNode->SetRect(rect);
865         SetRect(rect);
866     } else {
867         SetRect(lastFocusNode->GetRect() + childRect.GetOffset());
868     }
869 
870     return true;
871 }
872 
SetScopeFocusAlgorithm()873 void FocusHub::SetScopeFocusAlgorithm()
874 {
875     auto frame = GetFrameNode();
876     CHECK_NULL_VOID(frame);
877     auto pattern = frame->GetPattern();
878     CHECK_NULL_VOID(pattern);
879     focusAlgorithm_ = pattern->GetScopeFocusAlgorithm();
880 }
881 
SetLastFocusNodeIndex(const RefPtr<FocusHub> & focusNode)882 void FocusHub::SetLastFocusNodeIndex(const RefPtr<FocusHub>& focusNode)
883 {
884     auto frame = GetFrameNode();
885     CHECK_NULL_VOID(frame);
886     auto pattern = frame->GetPattern();
887     CHECK_NULL_VOID(pattern);
888     lastFocusNodeIndex_ = pattern->GetFocusNodeIndex(focusNode);
889 }
890 
ScrollToLastFocusIndex() const891 void FocusHub::ScrollToLastFocusIndex() const
892 {
893     if (lastFocusNodeIndex_ == -1) {
894         LOGD("Last focus node index is -1. Do not need scroll.");
895         return;
896     }
897     auto frame = GetFrameNode();
898     CHECK_NULL_VOID(frame);
899     auto pattern = frame->GetPattern();
900     CHECK_NULL_VOID(pattern);
901     pattern->ScrollToFocusNodeIndex(lastFocusNodeIndex_);
902 }
903 
OnFocus()904 void FocusHub::OnFocus()
905 {
906     if (focusType_ == FocusType::NODE) {
907         OnFocusNode();
908     } else if (focusType_ == FocusType::SCOPE) {
909         OnFocusScope();
910     } else {
911         LOGE("Current node focus type: %{public}d is invalid.", focusType_);
912     }
913 }
914 
OnBlur()915 void FocusHub::OnBlur()
916 {
917     if (focusType_ == FocusType::NODE) {
918         OnBlurNode();
919     } else if (focusType_ == FocusType::SCOPE) {
920         OnBlurScope();
921     } else {
922         LOGE("Current node focus type: %{public}d is invalid.", focusType_);
923     }
924 }
925 
OnFocusNode()926 void FocusHub::OnFocusNode()
927 {
928     LOGD("FocusHub: Node(%{public}s/%{public}d) on focus", GetFrameName().c_str(), GetFrameId());
929     if (onFocusInternal_) {
930         onFocusInternal_();
931     }
932     auto onFocusCallback = GetOnFocusCallback();
933     if (onFocusCallback) {
934         onFocusCallback();
935     }
936     auto parentFocusHub = GetParentFocusHub();
937     if (parentFocusHub) {
938         parentFocusHub->SetLastFocusNodeIndex(AceType::Claim(this));
939     }
940     HandleParentScroll(); // If current focus node has a scroll parent. Handle the scroll event.
941     PaintFocusState();
942     auto frameNode = GetFrameNode();
943     CHECK_NULL_VOID_NOLOG(frameNode);
944     frameNode->OnAccessibilityEvent(AccessibilityEventType::FOCUS);
945 }
946 
OnBlurNode()947 void FocusHub::OnBlurNode()
948 {
949     LOGD("FocusHub: Node(%{public}s/%{public}d) on blur", GetFrameName().c_str(), GetFrameId());
950     if (onBlurInternal_) {
951         onBlurInternal_();
952     }
953     if (onBlurReasonInternal_) {
954         LOGI("FocusHub: Node(%{public}s/%{public}d) 's blur reason is %{public}d", GetFrameName().c_str(), GetFrameId(),
955             blurReason_);
956         onBlurReasonInternal_(blurReason_);
957     }
958     auto onBlurCallback = GetOnBlurCallback();
959     if (onBlurCallback) {
960         onBlurCallback();
961     }
962     if (blurReason_ != BlurReason::FRAME_DESTROY) {
963         ClearFocusState();
964     }
965 }
966 
CheckFocusStateStyle(bool onFocus)967 void FocusHub::CheckFocusStateStyle(bool onFocus)
968 {
969     auto eventHub = eventHub_.Upgrade();
970     CHECK_NULL_VOID(eventHub);
971     if (onFocus) {
972         eventHub->UpdateCurrentUIState(UI_STATE_FOCUSED);
973     } else {
974         eventHub->ResetCurrentUIState(UI_STATE_FOCUSED);
975     }
976 }
977 
HasFocusStateStyle()978 bool FocusHub::HasFocusStateStyle()
979 {
980     auto eventHub = eventHub_.Upgrade();
981     CHECK_NULL_RETURN(eventHub, false);
982     return eventHub->HasStateStyle(UI_STATE_FOCUSED);
983 }
984 
OnFocusScope()985 void FocusHub::OnFocusScope()
986 {
987     std::list<RefPtr<FocusHub>> focusNodes;
988     auto itLastFocusNode = FlushChildrenFocusHub(focusNodes);
989     if (focusNodes.empty()) {
990         LOGE("OnFocusScope focus nodes is empty. No child will be focused.");
991         return;
992     }
993 
994     auto itFocusNode = itLastFocusNode;
995     do {
996         if (itLastFocusNode == focusNodes.end()) {
997             itLastFocusNode = focusNodes.begin();
998             lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itLastFocusNode));
999             if (itLastFocusNode == itFocusNode) {
1000                 break;
1001             }
1002         }
1003         lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itLastFocusNode));
1004         if ((*itLastFocusNode)->RequestFocusImmediately()) {
1005             OnFocusNode();
1006             return;
1007         }
1008     } while ((++itLastFocusNode) != itFocusNode);
1009 
1010     // Not found any focusable node, clear focus.
1011     itLastFocusNode = focusNodes.end();
1012     lastWeakFocusNode_ = nullptr;
1013 }
1014 
OnBlurScope()1015 void FocusHub::OnBlurScope()
1016 {
1017     std::list<RefPtr<FocusHub>> focusNodes;
1018     FlushChildrenFocusHub(focusNodes);
1019     OnBlurNode();
1020     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
1021     if (lastFocusNode) {
1022         lastFocusNode->LostFocus(blurReason_);
1023     }
1024 }
1025 
PaintFocusState(bool isNeedStateStyles)1026 bool FocusHub::PaintFocusState(bool isNeedStateStyles)
1027 {
1028     auto context = PipelineContext::GetCurrentContext();
1029     CHECK_NULL_RETURN(context, false);
1030     auto frameNode = GetFrameNode();
1031     CHECK_NULL_RETURN(frameNode, false);
1032     auto renderContext = frameNode->GetRenderContext();
1033     CHECK_NULL_RETURN(renderContext, false);
1034     if (!context->GetIsFocusActive() || !IsNeedPaintFocusState()) {
1035         return false;
1036     }
1037 
1038     bool stateStylesResult = false;
1039     if (isNeedStateStyles) {
1040         // do focus state style.
1041         CheckFocusStateStyle(true);
1042         stateStylesResult = true;
1043     }
1044 
1045     if (focusStyleType_ == FocusStyleType::NONE) {
1046         return stateStylesResult;
1047     }
1048 
1049     if (focusStyleType_ == FocusStyleType::CUSTOM_REGION) {
1050         CHECK_NULL_RETURN(getInnerFocusRectFunc_, false);
1051         RoundRect focusRectInner;
1052         focusRectInner.SetRect({ -1, -1, -1, -1 });
1053         getInnerFocusRectFunc_(focusRectInner);
1054         if (!focusRectInner.GetRect().IsValid()) {
1055             return false;
1056         }
1057         return PaintInnerFocusState(focusRectInner);
1058     }
1059 
1060     auto appTheme = context->GetTheme<AppTheme>();
1061     CHECK_NULL_RETURN(appTheme, false);
1062     Color paintColor;
1063     if (HasPaintColor()) {
1064         paintColor = GetPaintColor();
1065     } else {
1066         paintColor = appTheme->GetFocusColor();
1067     }
1068     Dimension paintWidth;
1069     if (HasPaintWidth()) {
1070         paintWidth = GetPaintWidth();
1071     } else {
1072         paintWidth = appTheme->GetFocusWidthVp();
1073     }
1074 
1075     if (focusStyleType_ == FocusStyleType::CUSTOM_BORDER) {
1076         if (!HasPaintRect()) {
1077             LOGE("PaintFocusState: frame rect has no value while focus style is CUSTOMIZE");
1078             return false;
1079         }
1080         renderContext->PaintFocusState(GetPaintRect(), paintColor, paintWidth);
1081         return true;
1082     }
1083 
1084     Dimension focusPaddingVp = Dimension(0.0, DimensionUnit::VP);
1085     if (HasFocusPadding()) {
1086         focusPaddingVp = GetFocusPadding();
1087     } else {
1088         if (focusStyleType_ == FocusStyleType::INNER_BORDER) {
1089             focusPaddingVp = -appTheme->GetFocusWidthVp();
1090         } else if (focusStyleType_ == FocusStyleType::OUTER_BORDER) {
1091             focusPaddingVp = appTheme->GetFocusOutPaddingVp();
1092         }
1093     }
1094     if (HasPaintRect()) {
1095         renderContext->PaintFocusState(GetPaintRect(), focusPaddingVp, paintColor, paintWidth);
1096     } else {
1097         renderContext->PaintFocusState(focusPaddingVp, paintColor, paintWidth);
1098     }
1099     return true;
1100 }
1101 
PaintAllFocusState()1102 bool FocusHub::PaintAllFocusState()
1103 {
1104     if (PaintFocusState()) {
1105         return true;
1106     }
1107     std::list<RefPtr<FocusHub>> focusNodes;
1108     FlushChildrenFocusHub(focusNodes);
1109     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
1110     if (lastFocusNode) {
1111         return lastFocusNode->PaintAllFocusState();
1112     }
1113     if (onPaintFocusStateCallback_) {
1114         return onPaintFocusStateCallback_();
1115     }
1116     return false;
1117 }
1118 
PaintInnerFocusState(const RoundRect & paintRect)1119 bool FocusHub::PaintInnerFocusState(const RoundRect& paintRect)
1120 {
1121     auto context = PipelineContext::GetCurrentContext();
1122     CHECK_NULL_RETURN(context, false);
1123     auto frameNode = GetFrameNode();
1124     CHECK_NULL_RETURN(frameNode, false);
1125     auto renderContext = frameNode->GetRenderContext();
1126     CHECK_NULL_RETURN(renderContext, false);
1127     if (!context->GetIsFocusActive() || !IsNeedPaintFocusState()) {
1128         return false;
1129     }
1130     auto appTheme = context->GetTheme<AppTheme>();
1131     CHECK_NULL_RETURN(appTheme, false);
1132     Color paintColor;
1133     if (HasPaintColor()) {
1134         paintColor = GetPaintColor();
1135     } else {
1136         paintColor = appTheme->GetFocusColor();
1137     }
1138     Dimension paintWidth;
1139     if (HasPaintWidth()) {
1140         paintWidth = GetPaintWidth();
1141     } else {
1142         paintWidth = appTheme->GetFocusWidthVp();
1143     }
1144     renderContext->ClearFocusState();
1145     renderContext->PaintFocusState(paintRect, paintColor, paintWidth);
1146     return true;
1147 }
1148 
ClearFocusState(bool isNeedStateStyles)1149 void FocusHub::ClearFocusState(bool isNeedStateStyles)
1150 {
1151     if (isNeedStateStyles) {
1152         // check focus state style.
1153         CheckFocusStateStyle(false);
1154     }
1155     if (onClearFocusStateCallback_) {
1156         onClearFocusStateCallback_();
1157     }
1158     if (focusStyleType_ != FocusStyleType::NONE) {
1159         auto frameNode = GetFrameNode();
1160         CHECK_NULL_VOID(frameNode);
1161         auto renderContext = frameNode->GetRenderContext();
1162         CHECK_NULL_VOID(renderContext);
1163         renderContext->ClearFocusState();
1164     }
1165 }
1166 
ClearAllFocusState()1167 void FocusHub::ClearAllFocusState()
1168 {
1169     ClearFocusState();
1170     std::list<RefPtr<FocusHub>> focusNodes;
1171     FlushChildrenFocusHub(focusNodes);
1172     auto lastFocusNode = lastWeakFocusNode_.Upgrade();
1173     if (lastFocusNode) {
1174         lastFocusNode->ClearAllFocusState();
1175     }
1176 }
1177 
IsNeedPaintFocusState()1178 bool FocusHub::IsNeedPaintFocusState()
1179 {
1180     if (focusType_ == FocusType::DISABLE || (focusStyleType_ == FocusStyleType::NONE && !HasFocusStateStyle())) {
1181         return false;
1182     }
1183     if (focusType_ == FocusType::NODE) {
1184         return true;
1185     }
1186     std::list<RefPtr<FocusHub>> focusNodes;
1187     FlushChildrenFocusHub(focusNodes);
1188     return std::none_of(focusNodes.begin(), focusNodes.end(),
1189         [](const RefPtr<FocusHub>& node) { return node->IsNeedPaintFocusState(); });
1190 }
1191 
AcceptFocusOfSpecifyChild(FocusStep step)1192 bool FocusHub::AcceptFocusOfSpecifyChild(FocusStep step)
1193 {
1194     if (focusType_ == FocusType::NODE) {
1195         return IsFocusable();
1196     }
1197     if (focusType_ != FocusType::SCOPE) {
1198         return false;
1199     }
1200     std::list<RefPtr<FocusHub>> focusNodes;
1201     FlushChildrenFocusHub(focusNodes);
1202     if (focusNodes.empty()) {
1203         return false;
1204     }
1205     if (step == FocusStep::TAB) {
1206         auto iterNewFocusNode = focusNodes.begin();
1207         while (iterNewFocusNode != focusNodes.end()) {
1208             if (*iterNewFocusNode && (*iterNewFocusNode)->AcceptFocusOfSpecifyChild(step)) {
1209                 lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*iterNewFocusNode));
1210                 return true;
1211             }
1212             ++iterNewFocusNode;
1213         }
1214     } else if (step == FocusStep::SHIFT_TAB) {
1215         auto iterNewFocusNode = focusNodes.rbegin();
1216         while (iterNewFocusNode != focusNodes.rend()) {
1217             if (*iterNewFocusNode && (*iterNewFocusNode)->AcceptFocusOfSpecifyChild(step)) {
1218                 lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*iterNewFocusNode));
1219                 return true;
1220             }
1221             ++iterNewFocusNode;
1222         }
1223     } else {
1224         LOGI("Invalid focus step: %{public}d for %{public}s/%{public}d specify focus child.", step,
1225             GetFrameName().c_str(), GetFrameId());
1226     }
1227     return false;
1228 }
1229 
AcceptFocusOfLastFocus()1230 bool FocusHub::AcceptFocusOfLastFocus()
1231 {
1232     if (focusType_ == FocusType::SCOPE) {
1233         auto lastFocusNode = lastWeakFocusNode_.Upgrade();
1234         return lastFocusNode ? lastFocusNode->AcceptFocusOfLastFocus() : false;
1235     }
1236     if (focusType_ == FocusType::NODE) {
1237         return IsFocusable();
1238     }
1239     return false;
1240 }
1241 
AcceptFocusByRectOfLastFocus(const RectF & rect)1242 bool FocusHub::AcceptFocusByRectOfLastFocus(const RectF& rect)
1243 {
1244     if (focusType_ == FocusType::NODE) {
1245         return AcceptFocusByRectOfLastFocusNode(rect);
1246     }
1247     if (focusType_ == FocusType::SCOPE) {
1248         return AcceptFocusByRectOfLastFocusFlex(rect);
1249     }
1250     return false;
1251 }
1252 
AcceptFocusByRectOfLastFocusNode(const RectF & rect)1253 bool FocusHub::AcceptFocusByRectOfLastFocusNode(const RectF& rect)
1254 {
1255     return IsFocusable();
1256 }
1257 
AcceptFocusByRectOfLastFocusScope(const RectF & rect)1258 bool FocusHub::AcceptFocusByRectOfLastFocusScope(const RectF& rect)
1259 {
1260     std::list<RefPtr<FocusHub>> focusNodes;
1261     auto itLastFocusNode = FlushChildrenFocusHub(focusNodes);
1262     if (focusNodes.empty()) {
1263         return false;
1264     }
1265     auto itFocusNode = itLastFocusNode;
1266     do {
1267         if (itLastFocusNode == focusNodes.end()) {
1268             itLastFocusNode = focusNodes.begin();
1269             lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itLastFocusNode));
1270             if (itLastFocusNode == itFocusNode) {
1271                 break;
1272             }
1273         }
1274         RectF childRect;
1275         if (!CalculateRect(*itLastFocusNode, childRect)) {
1276             continue;
1277         }
1278 
1279         if ((*itLastFocusNode)->AcceptFocusByRectOfLastFocus(rect - childRect.GetOffset())) {
1280             lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itLastFocusNode));
1281             return true;
1282         }
1283     } while ((++itLastFocusNode) != itFocusNode);
1284     if (itLastFocusNode == focusNodes.end()) {
1285         lastWeakFocusNode_ = nullptr;
1286     } else {
1287         lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itLastFocusNode));
1288     }
1289 
1290     return false;
1291 }
1292 
AcceptFocusByRectOfLastFocusFlex(const RectF & rect)1293 bool FocusHub::AcceptFocusByRectOfLastFocusFlex(const RectF& rect)
1294 {
1295     if (!rect.IsValid()) {
1296         LOGE("the rect is not valid");
1297         return false;
1298     }
1299 
1300     std::list<RefPtr<FocusHub>> focusNodes;
1301     FlushChildrenFocusHub(focusNodes);
1302     OffsetF offset;
1303     auto itNewFocusNode = focusNodes.end();
1304     double minVal = std::numeric_limits<double>::max();
1305     for (auto it = focusNodes.begin(); it != focusNodes.end(); ++it) {
1306         if (!(*it)->IsFocusable()) {
1307             continue;
1308         }
1309 
1310         RectF childRect;
1311         if (!CalculateRect(*it, childRect)) {
1312             continue;
1313         }
1314 
1315         OffsetF vec = childRect.Center() - rect.Center();
1316         double val = (vec.GetX() * vec.GetX()) + (vec.GetY() * vec.GetY());
1317         if (minVal > val) {
1318             minVal = val;
1319             itNewFocusNode = it;
1320             offset = childRect.GetOffset();
1321         }
1322     }
1323 
1324     if (itNewFocusNode != focusNodes.end() && (*itNewFocusNode)->AcceptFocusByRectOfLastFocus(rect - offset)) {
1325         lastWeakFocusNode_ = AceType::WeakClaim(AceType::RawPtr(*itNewFocusNode));
1326         return true;
1327     }
1328     return false;
1329 }
1330 
CalculateRect(const RefPtr<FocusHub> & childNode,RectF & rect) const1331 bool FocusHub::CalculateRect(const RefPtr<FocusHub>& childNode, RectF& rect) const
1332 {
1333     auto childGeometryNode = childNode->GetGeometryNode();
1334     CHECK_NULL_RETURN(childGeometryNode, false);
1335     rect = childGeometryNode->GetFrameRect();
1336     return true;
1337 }
1338 
IsFocusableByTab()1339 bool FocusHub::IsFocusableByTab()
1340 {
1341     if (focusType_ == FocusType::NODE) {
1342         return IsFocusableNodeByTab();
1343     }
1344     if (focusType_ == FocusType::SCOPE) {
1345         return IsFocusableScopeByTab();
1346     }
1347     LOGE("Current node focus type: %{public}d is invalid.", focusType_);
1348     return false;
1349 }
1350 
IsFocusableNodeByTab()1351 bool FocusHub::IsFocusableNodeByTab()
1352 {
1353     auto parent = GetParentFocusHub();
1354     CHECK_NULL_RETURN_NOLOG(parent, GetTabIndex() == 0);
1355     return (GetTabIndex() == 0) && (parent->GetTabIndex() == 0);
1356 }
1357 
IsFocusableScopeByTab()1358 bool FocusHub::IsFocusableScopeByTab()
1359 {
1360     std::list<RefPtr<FocusHub>> focusNodes;
1361     FlushChildrenFocusHub(focusNodes);
1362     if (!IsFocusableNodeByTab()) {
1363         return false;
1364     }
1365     if (focusNodes.empty()) {
1366         return true;
1367     }
1368     return std::any_of(focusNodes.begin(), focusNodes.end(),
1369         [](const RefPtr<FocusHub>& focusNode) { return focusNode->IsFocusableByTab(); });
1370 }
1371 
IsFocusableWholePath()1372 bool FocusHub::IsFocusableWholePath()
1373 {
1374     auto parent = GetParentFocusHub();
1375     while (parent) {
1376         if (!parent->IsFocusable()) {
1377             return false;
1378         }
1379         parent = parent->GetParentFocusHub();
1380     }
1381     return IsFocusable();
1382 }
1383 
CollectTabIndexNodes(TabIndexNodeList & tabIndexNodes)1384 void FocusHub::CollectTabIndexNodes(TabIndexNodeList& tabIndexNodes)
1385 {
1386     std::list<RefPtr<FocusHub>> focusNodes;
1387     FlushChildrenFocusHub(focusNodes);
1388     if (GetFocusType() == FocusType::SCOPE && IsFocusable()) {
1389         if (focusNodes.size() == 1 && focusNodes.front()->GetFocusType() != FocusType::SCOPE) {
1390             if (GetTabIndex() > 0) {
1391                 tabIndexNodes.emplace_back(GetTabIndex(), WeakClaim(this));
1392             }
1393             return;
1394         }
1395         for (auto& child : focusNodes) {
1396             child->CollectTabIndexNodes(tabIndexNodes);
1397         }
1398     }
1399     if (IsFocusable() && GetTabIndex() > 0) {
1400         tabIndexNodes.emplace_back(GetTabIndex(), WeakClaim(this));
1401     }
1402 }
1403 
GoToFocusByTabNodeIdx(TabIndexNodeList & tabIndexNodes,int32_t tabNodeIdx)1404 bool FocusHub::GoToFocusByTabNodeIdx(TabIndexNodeList& tabIndexNodes, int32_t tabNodeIdx)
1405 {
1406     auto iter = tabIndexNodes.begin();
1407     std::advance(iter, tabNodeIdx);
1408     if (iter == tabIndexNodes.end()) {
1409         LOGE("Tab index node is not found");
1410         return false;
1411     }
1412     auto nodeNeedToFocus = (*iter).second.Upgrade();
1413     if (!nodeNeedToFocus) {
1414         LOGE("Tab index node is null");
1415         return false;
1416     }
1417     LOGI("Focus on tab index node(%{public}d)", tabNodeIdx);
1418     if (nodeNeedToFocus->GetFocusType() == FocusType::SCOPE && !nodeNeedToFocus->IsDefaultGroupHasFocused()) {
1419         auto defaultFocusNode = nodeNeedToFocus->GetChildFocusNodeByType(FocusNodeType::GROUP_DEFAULT);
1420         if (defaultFocusNode) {
1421             if (!defaultFocusNode->IsFocusableWholePath()) {
1422                 LOGW("node(%{public}d) is not focusable", tabNodeIdx);
1423                 return false;
1424             }
1425             nodeNeedToFocus->SetIsDefaultGroupHasFocused(true);
1426             return defaultFocusNode->RequestFocusImmediately();
1427         }
1428     }
1429     if (!nodeNeedToFocus->IsFocusableWholePath()) {
1430         LOGW("node(%{public}d) is not focusable", tabNodeIdx);
1431         return false;
1432     }
1433     return nodeNeedToFocus->RequestFocusImmediately();
1434 }
1435 
GetChildFocusNodeByType(FocusNodeType nodeType)1436 RefPtr<FocusHub> FocusHub::GetChildFocusNodeByType(FocusNodeType nodeType)
1437 {
1438     if (nodeType == FocusNodeType::DEFAULT && IsDefaultFocus() && IsFocusable()) {
1439         return AceType::Claim(this);
1440     }
1441     if (nodeType == FocusNodeType::GROUP_DEFAULT && IsDefaultGroupFocus() && IsFocusable()) {
1442         return AceType::Claim(this);
1443     }
1444     if (focusType_ != FocusType::SCOPE) {
1445         return nullptr;
1446     }
1447     std::list<RefPtr<FocusHub>> focusNodes;
1448     FlushChildrenFocusHub(focusNodes);
1449     for (const auto& child : focusNodes) {
1450         auto findNode = child->GetChildFocusNodeByType(nodeType);
1451         if (findNode) {
1452             return findNode;
1453         }
1454     }
1455     return nullptr;
1456 }
1457 
GetChildFocusNodeById(const std::string & id)1458 RefPtr<FocusHub> FocusHub::GetChildFocusNodeById(const std::string& id)
1459 {
1460     if (id.empty()) {
1461         return nullptr;
1462     }
1463     if (GetInspectorKey().has_value() && GetInspectorKey().value() == id) {
1464         return AceType::Claim(this);
1465     }
1466     if (focusType_ == FocusType::SCOPE) {
1467         std::list<RefPtr<FocusHub>> focusNodes;
1468         FlushChildrenFocusHub(focusNodes);
1469         for (const auto& child : focusNodes) {
1470             auto findNode = child->GetChildFocusNodeById(id);
1471             if (findNode) {
1472                 return findNode;
1473             }
1474         }
1475     }
1476     return nullptr;
1477 }
1478 
HandleParentScroll() const1479 void FocusHub::HandleParentScroll() const
1480 {
1481     auto context = PipelineContext::GetCurrentContext();
1482     CHECK_NULL_VOID(context);
1483     if (!context->GetIsFocusActive() || (focusType_ != FocusType::NODE && !isFocusUnit_)) {
1484         return;
1485     }
1486     auto parent = GetParentFocusHub();
1487     RefPtr<FrameNode> parentFrame;
1488     RefPtr<Pattern> parentPattern;
1489     while (parent) {
1490         if (parent->isFocusUnit_) {
1491             return;
1492         }
1493         parentFrame = parent->GetFrameNode();
1494         if (!parentFrame) {
1495             parent = parent->GetParentFocusHub();
1496             continue;
1497         }
1498         parentPattern = parentFrame->GetPattern();
1499         if (parentPattern && parentPattern->ScrollToNode(GetFrameNode())) {
1500             return;
1501         }
1502         parent = parent->GetParentFocusHub();
1503     }
1504 }
1505 
RequestFocusImmediatelyById(const std::string & id)1506 bool FocusHub::RequestFocusImmediatelyById(const std::string& id)
1507 {
1508     auto focusNode = GetChildFocusNodeById(id);
1509     if (!focusNode) {
1510         LOGI("Request focus id: %{public}s can not found.", id.c_str());
1511         return false;
1512     }
1513     auto result = true;
1514     if (!focusNode->IsFocusable()) {
1515         LOGI("Request focus id: %{public}s is not focusable.", id.c_str());
1516         result = false;
1517     }
1518     LOGI("Request focus immediately by id: %{public}s. The node is %{public}s/%{public}d.", id.c_str(),
1519         focusNode->GetFrameName().c_str(), focusNode->GetFrameId());
1520     focusNode->RequestFocus();
1521     return result;
1522 }
1523 
GetFocusingTabNodeIdx(TabIndexNodeList & tabIndexNodes)1524 int32_t FocusHub::GetFocusingTabNodeIdx(TabIndexNodeList& tabIndexNodes)
1525 {
1526     if (tabIndexNodes.empty()) {
1527         LOGD("No tabIndex node exist in this page.");
1528         return NONE_TAB_FOCUSED_INDEX;
1529     }
1530     if (isFirstFocusInPage_) {
1531         isFirstFocusInPage_ = false;
1532         return DEFAULT_TAB_FOCUSED_INDEX;
1533     }
1534     int32_t res = NONE_TAB_FOCUSED_INDEX;
1535     int32_t i = 0;
1536     for (auto& wpNode : tabIndexNodes) {
1537         auto node = wpNode.second.Upgrade();
1538         if (node && node->IsCurrentFocus()) {
1539             res = i;
1540             break;
1541         }
1542         ++i;
1543     }
1544     return res;
1545 }
1546 
HandleFocusByTabIndex(const KeyEvent & event,const RefPtr<FocusHub> & mainFocusHub)1547 bool FocusHub::HandleFocusByTabIndex(const KeyEvent& event, const RefPtr<FocusHub>& mainFocusHub)
1548 {
1549     if (event.code != KeyCode::KEY_TAB || event.action != KeyAction::DOWN) {
1550         return false;
1551     }
1552     CHECK_NULL_RETURN(mainFocusHub, false);
1553     TabIndexNodeList tabIndexNodes;
1554     tabIndexNodes.clear();
1555     mainFocusHub->CollectTabIndexNodes(tabIndexNodes);
1556     if (tabIndexNodes.empty()) {
1557         return false;
1558     }
1559     tabIndexNodes.sort([](std::pair<int32_t, WeakPtr<FocusHub>>& a, std::pair<int32_t, WeakPtr<FocusHub>>& b) {
1560         return a.first < b.first;
1561     });
1562     int32_t curTabFocusIndex = mainFocusHub->GetFocusingTabNodeIdx(tabIndexNodes);
1563     if ((curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) &&
1564         curTabFocusIndex != DEFAULT_TAB_FOCUSED_INDEX && curTabFocusIndex != NONE_TAB_FOCUSED_INDEX) {
1565         LOGI("Current focused tabIndex node: %{public}d. Use default focus system.", curTabFocusIndex);
1566         return false;
1567     }
1568     if (curTabFocusIndex == DEFAULT_TAB_FOCUSED_INDEX || curTabFocusIndex == NONE_TAB_FOCUSED_INDEX) {
1569         curTabFocusIndex = 0;
1570     } else {
1571         if (event.IsShiftWith(KeyCode::KEY_TAB)) {
1572             LOGI("RequestNextFocus by 'SHIFT-TAB'");
1573             --curTabFocusIndex;
1574         } else {
1575             LOGI("RequestNextFocus by 'TAB'");
1576             ++curTabFocusIndex;
1577         }
1578     }
1579     if (curTabFocusIndex < 0 || curTabFocusIndex >= static_cast<int32_t>(tabIndexNodes.size())) {
1580         curTabFocusIndex = (curTabFocusIndex + tabIndexNodes.size()) % tabIndexNodes.size();
1581     }
1582     return GoToFocusByTabNodeIdx(tabIndexNodes, curTabFocusIndex);
1583 }
1584 
GetProjectAreaOnRect(const RectF & rect,const RectF & projectRect,FocusStep step)1585 double FocusHub::GetProjectAreaOnRect(const RectF& rect, const RectF& projectRect, FocusStep step)
1586 {
1587     float areaWidth = 0.0;
1588     float areaHeight = 0.0;
1589     switch (step) {
1590         case FocusStep::UP:
1591             if (rect.Top() < projectRect.Top() && rect.Right() > projectRect.Left() &&
1592                 rect.Left() < projectRect.Right()) {
1593                 areaWidth = std::min(rect.Right(), projectRect.Right()) - std::max(rect.Left(), projectRect.Left());
1594                 areaHeight = std::min(rect.Bottom(), projectRect.Top()) - rect.Top();
1595             }
1596             break;
1597         case FocusStep::DOWN:
1598             if (rect.Bottom() > projectRect.Bottom() && rect.Right() > projectRect.Left() &&
1599                 rect.Left() < projectRect.Right()) {
1600                 areaWidth = std::min(rect.Right(), projectRect.Right()) - std::max(rect.Left(), projectRect.Left());
1601                 areaHeight = rect.Bottom() - std::max(rect.Top(), projectRect.Bottom());
1602             }
1603             break;
1604         case FocusStep::LEFT:
1605             if (rect.Left() < projectRect.Left() && rect.Bottom() > projectRect.Top() &&
1606                 rect.Top() < projectRect.Bottom()) {
1607                 areaWidth = std::min(rect.Right(), projectRect.Left()) - rect.Left();
1608                 areaHeight = std::min(rect.Bottom(), projectRect.Bottom()) - std::max(rect.Top(), projectRect.Top());
1609             }
1610             break;
1611         case FocusStep::RIGHT:
1612             if (rect.Right() > projectRect.Right() && rect.Bottom() > projectRect.Top() &&
1613                 rect.Top() < projectRect.Bottom()) {
1614                 areaWidth = rect.Right() - std::max(rect.Left(), projectRect.Right());
1615                 areaHeight = std::min(rect.Bottom(), projectRect.Bottom()) - std::max(rect.Top(), projectRect.Top());
1616             }
1617             break;
1618         default:
1619             break;
1620     }
1621     return areaWidth * areaHeight;
1622 }
1623 
GetNearestNodeByProjectArea(const std::list<RefPtr<FocusHub>> & allNodes,FocusStep step)1624 RefPtr<FocusHub> FocusHub::GetNearestNodeByProjectArea(const std::list<RefPtr<FocusHub>>& allNodes, FocusStep step)
1625 {
1626     CHECK_NULL_RETURN(!allNodes.empty(), nullptr);
1627     auto curFrameNode = GetFrameNode();
1628     CHECK_NULL_RETURN(curFrameNode, nullptr);
1629     auto curFrameOffset = curFrameNode->GetOffsetRelativeToWindow();
1630     auto curGeometryNode = curFrameNode->GetGeometryNode();
1631     CHECK_NULL_RETURN(curGeometryNode, nullptr);
1632     RectF curFrameRect = RectF(curFrameOffset, curGeometryNode->GetFrameRect().GetSize());
1633     curFrameRect.SetOffset(curFrameOffset);
1634     LOGD("Current focus node is %{public}s/%{public}d. Rect is {%{public}f,%{public}f,%{public}f,%{public}f}.",
1635         GetFrameName().c_str(), GetFrameId(), curFrameRect.Left(), curFrameRect.Top(), curFrameRect.Right(),
1636         curFrameRect.Bottom());
1637     bool isTabStep = IsFocusStepTab(step);
1638     double resDistance = !isTabStep ? std::numeric_limits<double>::max() : 0.0f;
1639     RefPtr<FocusHub> nextNode;
1640     for (const auto& node : allNodes) {
1641         if (!node || AceType::RawPtr(node) == this) {
1642             continue;
1643         }
1644         auto frameNode = node->GetFrameNode();
1645         if (!frameNode) {
1646             continue;
1647         }
1648         auto frameOffset = frameNode->GetOffsetRelativeToWindow();
1649         auto geometryNode = frameNode->GetGeometryNode();
1650         if (!geometryNode) {
1651             continue;
1652         }
1653         RectF frameRect = RectF(frameOffset, geometryNode->GetFrameRect().GetSize());
1654         auto realStep = step;
1655         if (step == FocusStep::TAB) {
1656             frameRect -= OffsetF(0, curFrameRect.Height());
1657             realStep = FocusStep::LEFT;
1658         } else if (step == FocusStep::SHIFT_TAB) {
1659             frameRect += OffsetF(0, curFrameRect.Height());
1660             realStep = FocusStep::RIGHT;
1661         }
1662         auto projectArea = GetProjectAreaOnRect(frameRect, curFrameRect, realStep);
1663         if (Positive(projectArea)) {
1664             OffsetF vec = frameRect.Center() - curFrameRect.Center();
1665             double val = (vec.GetX() * vec.GetX()) + (vec.GetY() * vec.GetY());
1666             if ((!isTabStep && val < resDistance) || (isTabStep && val > resDistance)) {
1667                 resDistance = val;
1668                 nextNode = node;
1669             }
1670         }
1671     }
1672     LOGD("Next focus node is %{public}s/%{public}d. Min distance is %{public}f.",
1673         nextNode ? nextNode->GetFrameName().c_str() : "NULL", nextNode ? nextNode->GetFrameId() : -1, resDistance);
1674     return nextNode;
1675 }
1676 
1677 } // namespace OHOS::Ace::NG
1678