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