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