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 
SetIsViewRootScopeFocused(bool isViewRootScopeFocused)203 void FocusView::SetIsViewRootScopeFocused(bool isViewRootScopeFocused)
204 {
205     isViewRootScopeFocused_ = isViewRootScopeFocused;
206     auto viewRootScope = GetViewRootScope();
207     CHECK_NULL_VOID(viewRootScope);
208     viewRootScope->SetFocusDependence(isViewRootScopeFocused ? FocusDependence::SELF : FocusDependence::AUTO);
209 }
210 
IsRootScopeCurrentFocus()211 bool FocusView::IsRootScopeCurrentFocus()
212 {
213     auto viewRootScope = GetViewRootScope();
214     return viewRootScope ? viewRootScope->IsCurrentFocus() : false;
215 }
216 
IsChildFocusViewOf(const RefPtr<FocusView> & parent)217 bool FocusView::IsChildFocusViewOf(const RefPtr<FocusView>& parent)
218 {
219     auto focusViewHub = GetFocusHub();
220     auto parentFocusHub = focusViewHub ? focusViewHub->GetParentFocusHub() : nullptr;
221     while (parentFocusHub) {
222         auto parentFrame = parentFocusHub->GetFrameNode();
223         auto parentFocusView = parentFrame ? parentFrame->GetPattern<FocusView>() : nullptr;
224         if (!parentFocusView) {
225             parentFocusHub = parentFocusHub->GetParentFocusHub();
226             continue;
227         }
228         if (parentFocusView == parent) {
229             return true;
230         }
231         parentFocusHub = parentFocusHub->GetParentFocusHub();
232     }
233     return false;
234 }
235 
HasParentFocusHub()236 bool FocusView::HasParentFocusHub()
237 {
238     auto focusViewHub = GetFocusHub();
239     CHECK_NULL_RETURN(focusViewHub, false);
240     return focusViewHub->GetParentFocusHub() != nullptr;
241 }
242 
HandleDefaultFocusNode(const RefPtr<FocusHub> & defaultFocusNode,bool isViewRootScopeHasChildFocused)243 std::pair<bool, bool> FocusView::HandleDefaultFocusNode(
244     const RefPtr<FocusHub>& defaultFocusNode, bool isViewRootScopeHasChildFocused)
245 {
246     std::pair<bool, bool> pair = {false, false};
247     if (neverShown_ && !isViewRootScopeHasChildFocused) {
248         if (!defaultFocusNode) {
249             TAG_LOGI(AceLogTag::ACE_FOCUS, "Focus view has no default focus.");
250         } else if (!defaultFocusNode->IsFocusableWholePath()) {
251             TAG_LOGI(AceLogTag::ACE_FOCUS, "Default focus node: %{public}s/%{public}d is not focusable",
252                 defaultFocusNode->GetFrameName().c_str(), defaultFocusNode->GetFrameId());
253         } else {
254             SetIsViewRootScopeFocused(false);
255             auto ret = defaultFocusNode->RequestFocusImmediatelyInner();
256             FocusViewDidShow(defaultFocusNode);
257             TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on default focus: %{public}s/%{public}d return: %{public}d.",
258                 defaultFocusNode->GetFrameName().c_str(), defaultFocusNode->GetFrameId(), ret);
259             pair = {true, ret};
260         }
261     }
262     return pair;
263 }
264 
RequestDefaultFocus()265 bool FocusView::RequestDefaultFocus()
266 {
267     TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on focus view: %{public}s/%{public}d.", GetFrameName().c_str(),
268         GetFrameId());
269     auto focusViewHub = GetFocusHub();
270     CHECK_NULL_RETURN(focusViewHub, false);
271     if (focusViewHub->GetFocusType() != FocusType::SCOPE || !focusViewHub->IsFocusableNode()) {
272         return false;
273     }
274     auto viewRootScope = GetViewRootScope();
275     CHECK_NULL_RETURN(viewRootScope, false);
276     isViewHasFocused_ = true;
277     auto defaultFocusNode = focusViewHub->GetChildFocusNodeByType(FocusNodeType::DEFAULT);
278 
279     auto isViewRootScopeHasChildFocused = viewRootScope->HasFocusedChild();
280     auto node = GetFrameNode();
281     CHECK_NULL_RETURN(node, false);
282     auto pipeline = node->GetContextRefPtr();
283     CHECK_NULL_RETURN(pipeline, false);
284     auto focusManager = pipeline->GetFocusManager();
285     CHECK_NULL_RETURN(focusManager, false);
286     if (!focusManager->IsAutoFocusTransfer()) {
287         std::pair<bool, bool> pair = HandleDefaultFocusNode(defaultFocusNode, isViewRootScopeHasChildFocused);
288         CHECK_NULL_RETURN(!pair.second, false);
289         return focusManager->RearrangeViewStack();
290     }
291 
292     std::pair<bool, bool> pair = HandleDefaultFocusNode(defaultFocusNode, isViewRootScopeHasChildFocused);
293     if (pair.first) {
294         return pair.second;
295     }
296     if (isViewRootScopeFocused_ && viewRootScope) {
297         SetIsViewRootScopeFocused(true);
298         auto ret = viewRootScope->RequestFocusImmediatelyInner();
299         TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on view root scope: %{public}s/%{public}d return: %{public}d.",
300             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId(), ret);
301         return ret;
302     }
303     auto lastViewFocusNode = focusViewHub->GetFocusLeaf();
304     CHECK_NULL_RETURN(lastViewFocusNode, false);
305     SetIsViewRootScopeFocused(false);
306     bool ret = false;
307     if (focusViewHub->IsCurrentFocus()) {
308         focusViewHub->InheritFocus();
309         ret = true;
310     } else {
311         ret = lastViewFocusNode->RequestFocusImmediatelyInner();
312     }
313     TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on focus view return: %{public}d.", ret);
314     return ret;
315 }
316 
TriggerFocusMove()317 bool FocusView::TriggerFocusMove()
318 {
319     TAG_LOGI(AceLogTag::ACE_FOCUS, "Focus view: %{public}s/%{public}d trigger focus move.", GetFrameName().c_str(),
320         GetFrameId());
321     auto viewRootScope = GetViewRootScope();
322     CHECK_NULL_RETURN(viewRootScope, false);
323     if (!viewRootScope->IsCurrentFocus()) {
324         TAG_LOGI(AceLogTag::ACE_FOCUS,
325             "Current view root: %{public}s/%{public}d is not on focusing. Cannot trigger focus move.",
326             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId());
327         return false;
328     }
329     if (viewRootScope->GetFocusDependence() != FocusDependence::SELF) {
330         TAG_LOGI(AceLogTag::ACE_FOCUS,
331             "Current view root: %{public}s/%{public}d is not focus depend self. Do not trigger focus move.",
332             viewRootScope->GetFrameName().c_str(), viewRootScope->GetFrameId());
333         return false;
334     }
335 
336     auto viewFocusHub = GetFocusHub();
337     CHECK_NULL_RETURN(viewFocusHub, false);
338     TabIndexNodeList tabIndexNodes;
339     tabIndexNodes.clear();
340     viewFocusHub->CollectTabIndexNodes(tabIndexNodes);
341     if (tabIndexNodes.empty()) {
342         // No tabIndex node in current main view. Extend focus from viewRootScope to children.
343         FocusViewDidShow(viewFocusHub);
344         SetIsViewRootScopeFocused(false);
345         viewRootScope->InheritFocus();
346         return true;
347     }
348 
349     // First tabIndex node need get focus.
350     tabIndexNodes.sort([](std::pair<int32_t, WeakPtr<FocusHub>>& a, std::pair<int32_t, WeakPtr<FocusHub>>& b) {
351         return a.first < b.first;
352     });
353     return viewFocusHub->GoToFocusByTabNodeIdx(tabIndexNodes, 0);
354 }
355 
GetFocusViewFocusable()356 bool FocusView::GetFocusViewFocusable()
357 {
358     auto focusViewHub = GetFocusHub();
359     CHECK_NULL_RETURN(focusViewHub, false);
360     if (!focusViewHub->IsSelfFocusableWholePath()) {
361         return false;
362     }
363     return true;
364 }
365 
FocusViewDidShow(const RefPtr<FocusHub> & focusHub)366 void FocusView::FocusViewDidShow(const RefPtr<FocusHub>& focusHub)
367 {
368     if (!focusHub) {
369         TAG_LOGI(AceLogTag::ACE_FOCUS, "Focus view: %{public}s/%{public}d reset shown flag.",
370             GetFrameName().c_str(), GetFrameId());
371         neverShown_ = false;
372         return;
373     }
374     RefPtr<UINode> node = focusHub->GetFrameNode();
375     do {
376         auto frameNode = DynamicCast<FrameNode>(node);
377         if (frameNode) {
378             auto focusView = frameNode->GetPattern<FocusView>();
379             if (focusView) {
380                 if (focusView->neverShown_) {
381                     TAG_LOGI(AceLogTag::ACE_FOCUS, "Focus view: %{public}s/%{public}d is first shown.",
382                         focusView->GetFrameName().c_str(), focusView->GetFrameId());
383                     focusView->neverShown_ = false;
384                 } else {
385                     return;
386                 }
387             }
388         }
389         node = node->GetParent();
390     } while (node);
391 }
392 } // namespace OHOS::Ace::NG
393