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