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