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