• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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/manager/focus/focus_view.h"
17 
18 #include "core/pipeline_ng/pipeline_context.h"
19 
20 namespace OHOS::Ace::NG {
21 
FocusViewShow(bool isTriggerByStep)22 void FocusView::FocusViewShow(bool isTriggerByStep)
23 {
24     if (GetFrameName() == V2::NAVBAR_ETS_TAG ||
25         GetFrameName() == V2::NAVDESTINATION_VIEW_ETS_TAG ||
26         GetFrameName() == V2::MENU_ETS_TAG) {
27         if (!GetFocusViewFocusable()) {
28             TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d is not focusable, cannot be shown",
29                 GetFrameName().c_str(), GetFrameId());
30             return;
31         }
32     }
33     TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d show", GetFrameName().c_str(), GetFrameId());
34     auto viewRootScope = GetViewRootScope();
35     if (viewRootScope && GetIsViewRootScopeFocused()) {
36         viewRootScope->SetFocusDependence(FocusDependence::SELF);
37     }
38     isViewHasFocused_ = false;
39     auto node = GetFrameNode();
40     CHECK_NULL_VOID(node);
41     auto pipeline = node->GetContextRefPtr();
42     CHECK_NULL_VOID(pipeline);
43     auto focusManager = pipeline->GetFocusManager();
44     CHECK_NULL_VOID(focusManager);
45     focusManager->FocusViewShow(AceType::Claim(this), isTriggerByStep);
46     pipeline->RequestFrame();
47 }
48 
FocusViewHide()49 void FocusView::FocusViewHide()
50 {
51     TAG_LOGI(AceLogTag::ACE_FOCUS, "View: %{public}s/%{public}d hide", GetFrameName().c_str(), GetFrameId());
52     auto node = GetFrameNode();
53     CHECK_NULL_VOID(node);
54     auto pipeline = node->GetContextRefPtr();
55     CHECK_NULL_VOID(pipeline);
56     auto focusManager = pipeline->GetFocusManager();
57     CHECK_NULL_VOID(focusManager);
58     focusManager->FocusViewHide(AceType::Claim(this));
59     pipeline->RequestFrame();
60 }
61 
FocusViewClose(bool isDetachFromTree)62 void FocusView::FocusViewClose(bool isDetachFromTree)
63 {
64     if (!isViewHasShow_) {
65         TAG_LOGD(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d has not been shown",
66             GetFrameName().c_str(), GetFrameId());
67         return;
68     }
69     TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d close", GetFrameName().c_str(), GetFrameId());
70     auto node = GetFrameNode();
71     CHECK_NULL_VOID(node);
72     auto pipeline = node->GetContextRefPtr();
73     CHECK_NULL_VOID(pipeline);
74     auto focusManager = pipeline->GetFocusManager();
75     CHECK_NULL_VOID(focusManager);
76     focusManager->FocusViewClose(AceType::Claim(this), isDetachFromTree);
77     pipeline->RequestFrame();
78 }
79 
GetFrameNode()80 RefPtr<FrameNode> FocusView::GetFrameNode()
81 {
82     auto focusViewPattern = AceType::DynamicCast<Pattern>(AceType::Claim(this));
83     CHECK_NULL_RETURN(focusViewPattern, nullptr);
84     return focusViewPattern->GetHost();
85 }
86 
GetFrameName()87 std::string FocusView::GetFrameName()
88 {
89     auto focusViewPattern = AceType::DynamicCast<Pattern>(AceType::Claim(this));
90     CHECK_NULL_RETURN(focusViewPattern, "NULL");
91     auto focusViewFrame = focusViewPattern->GetHost();
92     CHECK_NULL_RETURN(focusViewFrame, "NULL");
93     return focusViewFrame->GetTag();
94 }
95 
GetFrameId()96 int32_t FocusView::GetFrameId()
97 {
98     auto focusViewPattern = AceType::DynamicCast<Pattern>(AceType::Claim(this));
99     CHECK_NULL_RETURN(focusViewPattern, -1);
100     auto focusViewFrame = focusViewPattern->GetHost();
101     CHECK_NULL_RETURN(focusViewFrame, -1);
102     return focusViewFrame->GetId();
103 }
104 
LostViewFocus()105 void FocusView::LostViewFocus()
106 {
107     TAG_LOGI(
108         AceLogTag::ACE_FOCUS, "View: %{public}s/%{public}d lost focus", GetFrameName().c_str(), GetFrameId());
109     auto focusViewHub = GetFocusHub();
110     CHECK_NULL_VOID(focusViewHub);
111     if (focusViewHub->IsCurrentFocus()) {
112         focusViewHub->LostFocus(BlurReason::VIEW_SWITCH);
113     }
114 }
115 
GetFocusHub()116 RefPtr<FocusHub> FocusView::GetFocusHub()
117 {
118     auto focusViewPattern = AceType::DynamicCast<Pattern>(AceType::Claim(this));
119     CHECK_NULL_RETURN(focusViewPattern, nullptr);
120     auto focusViewFrame = focusViewPattern->GetHost();
121     CHECK_NULL_RETURN(focusViewFrame, nullptr);
122     auto focusViewHub = focusViewFrame->GetFocusHub();
123     return focusViewHub;
124 }
125 
GetCurrentFocusView()126 RefPtr<FocusView> FocusView::GetCurrentFocusView()
127 {
128     auto pipeline = PipelineContext::GetCurrentContextSafely();
129     CHECK_NULL_RETURN(pipeline, nullptr);
130     auto focusManager = pipeline->GetFocusManager();
131     CHECK_NULL_RETURN(focusManager, nullptr);
132     return focusManager->GetLastFocusView().Upgrade();
133 }
134 
GetEntryFocusView()135 RefPtr<FocusView> FocusView::GetEntryFocusView()
136 {
137     if (IsEntryFocusView()) {
138         return AceType::Claim(this);
139     }
140     auto focusViewHub = GetFocusHub();
141     auto parentFocusHub = focusViewHub ? focusViewHub->GetParentFocusHub() : nullptr;
142     while (parentFocusHub) {
143         auto parentFrame = parentFocusHub->GetFrameNode();
144         auto parentFocusView = parentFrame ? parentFrame->GetPattern<FocusView>() : nullptr;
145         if (!parentFocusView) {
146             parentFocusHub = parentFocusHub->GetParentFocusHub();
147             continue;
148         }
149         if (parentFocusView->IsEntryFocusView()) {
150             return parentFocusView;
151         }
152         parentFocusHub = parentFocusHub->GetParentFocusHub();
153     }
154     return AceType::Claim(this);
155 }
156 
GetViewRootScope()157 RefPtr<FocusHub> FocusView::GetViewRootScope()
158 {
159     auto rootScopeSpecified = rootScopeSpecified_.Upgrade();
160     if (rootScopeSpecified) {
161         return rootScopeSpecified;
162     }
163     auto focusViewPattern = AceType::DynamicCast<Pattern>(AceType::Claim(this));
164     CHECK_NULL_RETURN(focusViewPattern, nullptr);
165     auto focusViewFrame = focusViewPattern->GetHost();
166     CHECK_NULL_RETURN(focusViewFrame, nullptr);
167     auto focusViewHub = focusViewFrame->GetFocusHub();
168     CHECK_NULL_RETURN(focusViewHub, nullptr);
169     std::list<int32_t> rootScopeDeepth = GetRouteOfFirstScope();
170     RefPtr<FocusHub> rootScope = focusViewHub;
171     for (auto index : rootScopeDeepth) {
172         bool hit = rootScope->AnyChildFocusHub([&rootScope, &index](const RefPtr<FocusHub>& focusNode) {
173             if (--index < 0) {
174                 rootScope = focusNode;
175                 return true;
176             }
177             return false;
178         });
179         if (!hit) {
180             TAG_LOGD(AceLogTag::ACE_FOCUS, "Index: %{public}d of %{public}s/%{public}d 's children is invalid.", index,
181                 rootScope->GetFrameName().c_str(), rootScope->GetFrameId());
182             return focusViewHub;
183         }
184     }
185     CHECK_NULL_RETURN(rootScope, nullptr);
186     auto node = GetFrameNode();
187     CHECK_NULL_RETURN(node, nullptr);
188     auto pipeline = node->GetContextRefPtr();
189     auto screenNode = pipeline ? pipeline->GetScreenNode() : nullptr;
190     auto screenFocusHub = screenNode ? screenNode->GetFocusHub() : nullptr;
191     if (rootScope->GetFocusType() != FocusType::SCOPE || (screenFocusHub && rootScope == screenFocusHub)) {
192         rootScope = rootScope->GetParentFocusHub();
193     }
194     if (rootScope != focusViewHub) {
195         focusViewHub->SetFocusDependence(FocusDependence::AUTO);
196     }
197     return rootScope;
198 }
199 
IsViewRootScopeHasLastFocus()200 bool FocusView::IsViewRootScopeHasLastFocus()
201 {
202     /*
203     * - Page1(FocusView)
204     *     - Column(rootScope)
205     *     - SheetPage(lastFocus)
206     * - *Page2(FocusView)
207     *     - *Column(rootScope)
208     *
209     * SheetPage is the last focused child of Page1, Page2 gets focus now.
210     * When Page1 shows again, SheetPage should get focus rather than Column gets focus.
211     */
212     auto focusViewHub = GetFocusHub();
213     CHECK_NULL_RETURN(focusViewHub, false);
214     auto weakLastFocusHub = focusViewHub->GetLastWeakFocusNode();
215     auto lastFocusHub = weakLastFocusHub.Upgrade();
216     CHECK_NULL_RETURN(lastFocusHub, true);
217 
218     std::list<int32_t> rootScopeDeepth = GetRouteOfFirstScope();
219     RefPtr<FocusHub> rootScope = focusViewHub;
220 
221     if (rootScopeDeepth.empty()) {
222         return true;
223     }
224     for (auto index : rootScopeDeepth) {
225         bool hit = rootScope->AnyChildFocusHub([&rootScope, &index](const RefPtr<FocusHub>& focusNode) {
226             if (--index < 0) {
227                 rootScope = focusNode;
228                 return true;
229             }
230             return false;
231         });
232         if (!hit) {
233             TAG_LOGD(AceLogTag::ACE_FOCUS, "Index: %{public}d of %{public}s/%{public}d 's children is invalid.", index,
234                 rootScope->GetFrameName().c_str(), rootScope->GetFrameId());
235             return false;
236         }
237         if (rootScope == lastFocusHub) {
238             return true;
239         }
240     }
241     return false;
242 }
243 
SetIsViewRootScopeFocused(bool isViewRootScopeFocused)244 void FocusView::SetIsViewRootScopeFocused(bool isViewRootScopeFocused)
245 {
246     isViewRootScopeFocused_ = isViewRootScopeFocused;
247     auto viewRootScope = GetViewRootScope();
248     CHECK_NULL_VOID(viewRootScope);
249     viewRootScope->SetFocusDependence(isViewRootScopeFocused ? FocusDependence::SELF : FocusDependence::AUTO);
250 }
251 
IsRootScopeCurrentFocus()252 bool FocusView::IsRootScopeCurrentFocus()
253 {
254     auto viewRootScope = GetViewRootScope();
255     return viewRootScope ? viewRootScope->IsCurrentFocus() : false;
256 }
257 
IsChildFocusViewOf(const RefPtr<FocusView> & parent)258 bool FocusView::IsChildFocusViewOf(const RefPtr<FocusView>& parent)
259 {
260     auto focusViewHub = GetFocusHub();
261     auto parentFocusHub = focusViewHub ? focusViewHub->GetParentFocusHub() : nullptr;
262     while (parentFocusHub) {
263         auto parentFrame = parentFocusHub->GetFrameNode();
264         auto parentFocusView = parentFrame ? parentFrame->GetPattern<FocusView>() : nullptr;
265         if (!parentFocusView) {
266             parentFocusHub = parentFocusHub->GetParentFocusHub();
267             continue;
268         }
269         if (parentFocusView == parent) {
270             return true;
271         }
272         parentFocusHub = parentFocusHub->GetParentFocusHub();
273     }
274     return false;
275 }
276 
HasParentFocusHub()277 bool FocusView::HasParentFocusHub()
278 {
279     auto focusViewHub = GetFocusHub();
280     CHECK_NULL_RETURN(focusViewHub, false);
281     return focusViewHub->GetParentFocusHub() != nullptr;
282 }
283 
HandleDefaultFocusNode(const RefPtr<FocusHub> & defaultFocusNode,bool isViewRootScopeHasChildFocused)284 std::pair<bool, bool> FocusView::HandleDefaultFocusNode(
285     const RefPtr<FocusHub>& defaultFocusNode, bool isViewRootScopeHasChildFocused)
286 {
287     std::pair<bool, bool> pair = {false, false};
288     if (neverShown_ && !isViewRootScopeHasChildFocused) {
289         if (!defaultFocusNode) {
290             TAG_LOGD(AceLogTag::ACE_FOCUS, "Focus view has no default focus.");
291         } else if (!defaultFocusNode->IsFocusableWholePath()) {
292             TAG_LOGI(AceLogTag::ACE_FOCUS, "Default focus node: %{public}s/%{public}d is not focusable",
293                 defaultFocusNode->GetFrameName().c_str(), defaultFocusNode->GetFrameId());
294         } else {
295             SetIsViewRootScopeFocused(false);
296             auto ret = defaultFocusNode->RequestFocusImmediatelyInner();
297             FocusViewDidShow(defaultFocusNode);
298             TAG_LOGD(AceLogTag::ACE_FOCUS, "Request focus on default focus: %{public}s/%{public}d return: %{public}d.",
299                 defaultFocusNode->GetFrameName().c_str(), defaultFocusNode->GetFrameId(), ret);
300             pair = {true, ret};
301         }
302     }
303     return pair;
304 }
305 
RequestDefaultFocus()306 bool FocusView::RequestDefaultFocus()
307 {
308     TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on focusView: %{public}s/%{public}d.", GetFrameName().c_str(),
309         GetFrameId());
310     auto focusViewHub = GetFocusHub();
311     CHECK_NULL_RETURN(focusViewHub, false);
312     if (focusViewHub->GetFocusType() != FocusType::SCOPE || !focusViewHub->IsFocusableNode()) {
313         return false;
314     }
315     auto viewRootScope = GetViewRootScope();
316     CHECK_NULL_RETURN(viewRootScope, false);
317     isViewHasFocused_ = true;
318     auto defaultFocusNode = focusViewHub->GetChildFocusNodeByType(FocusNodeType::DEFAULT);
319 
320     auto isViewRootScopeHasChildFocused = viewRootScope->HasFocusedChild();
321     auto node = GetFrameNode();
322     CHECK_NULL_RETURN(node, false);
323     auto pipeline = node->GetContextRefPtr();
324     CHECK_NULL_RETURN(pipeline, false);
325     auto focusManager = pipeline->GetFocusManager();
326     CHECK_NULL_RETURN(focusManager, false);
327     if (!focusManager->IsAutoFocusTransfer()) {
328         std::pair<bool, bool> pair = HandleDefaultFocusNode(defaultFocusNode, isViewRootScopeHasChildFocused);
329         CHECK_NULL_RETURN(!pair.second, false);
330         return focusManager->RearrangeViewStack();
331     }
332 
333     std::pair<bool, bool> pair = HandleDefaultFocusNode(defaultFocusNode, isViewRootScopeHasChildFocused);
334     if (pair.first) {
335         return pair.second;
336     }
337     if (isViewRootScopeFocused_ && IsViewRootScopeHasLastFocus()) {
338         SetIsViewRootScopeFocused(true);
339         auto ret = viewRootScope->RequestFocusImmediatelyInner(FocusReason::VIEW_SWITCH);
340         // set neverShown_ false when request focus on focus view success
341         neverShown_ &= !ret;
342         TAG_LOGD(AceLogTag::ACE_FOCUS, "Request focus on root scope: %{public}s/%{public}d return: %{public}d.",
343             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId(), ret);
344         return ret;
345     }
346     auto lastViewFocusNode = focusViewHub->GetFocusLeaf();
347     CHECK_NULL_RETURN(lastViewFocusNode, false);
348     SetIsViewRootScopeFocused(false);
349     bool ret = false;
350     if (focusViewHub->IsCurrentFocus()) {
351         focusViewHub->InheritFocus();
352         ret = true;
353     } else {
354         ret = lastViewFocusNode->RequestFocusImmediatelyInner(FocusReason::VIEW_SWITCH);
355     }
356     // set neverShown_ false when request focus on focus view success
357     neverShown_ &= !ret;
358     TAG_LOGD(AceLogTag::ACE_FOCUS, "Request focus on focus view ret: %{public}d.", ret);
359     return ret;
360 }
361 
TriggerFocusMove()362 bool FocusView::TriggerFocusMove()
363 {
364     TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d trigger focus move.", GetFrameName().c_str(),
365         GetFrameId());
366     auto viewRootScope = GetViewRootScope();
367     CHECK_NULL_RETURN(viewRootScope, false);
368     if (!viewRootScope->IsCurrentFocus()) {
369         TAG_LOGI(AceLogTag::ACE_FOCUS,
370             "Current view root: %{public}s/%{public}d is not on focusing. Cannot trigger focus move.",
371             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId());
372         return false;
373     }
374     if (viewRootScope->GetFocusDependence() != FocusDependence::SELF) {
375         TAG_LOGI(AceLogTag::ACE_FOCUS,
376             "Current view root: %{public}s/%{public}d is not focus depend self. Do not trigger focus move.",
377             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId());
378         return false;
379     }
380 
381     auto viewFocusHub = GetFocusHub();
382     CHECK_NULL_RETURN(viewFocusHub, false);
383     TabIndexNodeList tabIndexNodes;
384     tabIndexNodes.clear();
385     viewFocusHub->CollectTabIndexNodes(tabIndexNodes);
386     if (tabIndexNodes.empty()) {
387         // No tabIndex node in current main view. Extend focus from viewRootScope to children.
388         FocusViewDidShow(viewFocusHub);
389         SetIsViewRootScopeFocused(false);
390         viewRootScope->InheritFocus();
391         return true;
392     }
393 
394     // First tabIndex node need get focus.
395     tabIndexNodes.sort([](std::pair<int32_t, WeakPtr<FocusHub>>& a, std::pair<int32_t, WeakPtr<FocusHub>>& b) {
396         return a.first < b.first;
397     });
398     return viewFocusHub->GoToFocusByTabNodeIdx(tabIndexNodes, 0);
399 }
400 
GetFocusViewFocusable()401 bool FocusView::GetFocusViewFocusable()
402 {
403     auto focusViewHub = GetFocusHub();
404     CHECK_NULL_RETURN(focusViewHub, false);
405     if (!focusViewHub->IsSelfFocusableWholePath()) {
406         return false;
407     }
408     return true;
409 }
410 
FocusViewDidShow(const RefPtr<FocusHub> & focusHub)411 void FocusView::FocusViewDidShow(const RefPtr<FocusHub>& focusHub)
412 {
413     if (!focusHub) {
414         TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d reset shown flag.",
415             GetFrameName().c_str(), GetFrameId());
416         neverShown_ = false;
417         return;
418     }
419     for (RefPtr<UINode> node = focusHub->GetFrameNode(); node; node = node->GetParent()) {
420         auto frameNode = DynamicCast<FrameNode>(node);
421         CHECK_NULL_CONTINUE(frameNode);
422         auto focusView = frameNode->GetPattern<FocusView>();
423         CHECK_NULL_CONTINUE(focusView);
424         CHECK_EQUAL_VOID(focusView->neverShown_, false);
425         TAG_LOGI(AceLogTag::ACE_FOCUS, "view: %{public}s/%{public}d first show, node: %{public}s",
426             focusView->GetFrameName().c_str(), focusView->GetFrameId(), focusHub->GetFrameName().c_str());
427         focusView->neverShown_ = false;
428     }
429 }
430 } // namespace OHOS::Ace::NG
431