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_manager.h"
17
18 #include "base/log/dump_log.h"
19 #include "base/log/log_wrapper.h"
20 #include "base/memory/ace_type.h"
21 #include "base/memory/referenced.h"
22 #include "base/utils/utils.h"
23 #include "core/components_ng/pattern/pattern.h"
24 #include "core/pipeline_ng/pipeline_context.h"
25
26 namespace OHOS::Ace::NG {
27
FocusManager(const RefPtr<PipelineContext> & pipeline)28 FocusManager::FocusManager(const RefPtr<PipelineContext>& pipeline) : pipeline_(pipeline)
29 {
30 if (pipeline && pipeline->GetRootElement()) {
31 currentFocus_ = pipeline->GetRootElement()->GetFocusHub();
32 }
33 }
34
FocusViewShow(const RefPtr<FocusView> & focusView,bool isTriggerByStep)35 void FocusManager::FocusViewShow(const RefPtr<FocusView>& focusView, bool isTriggerByStep)
36 {
37 CHECK_NULL_VOID(focusView);
38 if (!focusView->HasParentFocusHub()) {
39 TAG_LOGD(AceLogTag::ACE_FOCUS, "FocusView: %{public}s/%{public}d has no parent. Do not need show.",
40 focusView->GetFrameName().c_str(), focusView->GetFrameId());
41 return;
42 }
43 focusView->SetIsViewHasShow(true);
44 auto lastFocusView = lastFocusView_.Upgrade();
45 if (lastFocusView) {
46 if (lastFocusView == focusView || lastFocusView->IsChildFocusViewOf(focusView)) {
47 return;
48 }
49 if (!focusView->IsChildFocusViewOf(lastFocusView) && IsAutoFocusTransfer()) {
50 lastFocusView->LostViewFocus();
51 }
52 }
53
54 auto focusViewWeak = AceType::WeakClaim(AceType::RawPtr(focusView));
55 if (std::find(focusViewStack_.begin(), focusViewStack_.end(), focusViewWeak) != focusViewStack_.end()) {
56 focusViewStack_.remove(focusViewWeak);
57 }
58 focusViewStack_.emplace_back(focusViewWeak);
59 focusViewStackState_ = FocusViewStackState::SHOW;
60 lastFocusView_ = focusViewWeak;
61
62 // do not set LastWeakFocus to Previous node/scope in focusView when FocusViewShow trigger by FocusStep
63 if (!isTriggerByStep) {
64 lastFocusView = lastFocusView_.Upgrade();
65 if (!lastFocusView) {
66 return;
67 }
68 auto lastFocusViewHub = lastFocusView->GetFocusHub();
69 if (lastFocusViewHub) {
70 lastFocusViewHub->SetLastWeakFocusToPreviousInFocusView();
71 }
72 }
73 }
74
RearrangeViewStack()75 bool FocusManager::RearrangeViewStack()
76 {
77 auto curFocusView = FocusView::GetCurrentFocusView();
78 CHECK_NULL_RETURN(curFocusView, false);
79 auto curFocusViewHub = curFocusView->GetFocusHub();
80 CHECK_NULL_RETURN(curFocusViewHub, false);
81 auto curFocusViewWeak = AceType::WeakClaim(AceType::RawPtr(curFocusView));
82 if (!curFocusViewHub->IsCurrentFocus() && focusViewStackState_ == FocusViewStackState::SHOW) {
83 if (std::find(focusViewStack_.begin(), focusViewStack_.end(), curFocusViewWeak) != focusViewStack_.end()) {
84 focusViewStack_.remove(curFocusViewWeak);
85 }
86 lastFocusView_ = focusViewStack_.back();
87 return true;
88 }
89 if (focusViewStackState_ == FocusViewStackState::CLOSE) {
90 auto ret = SetFocusViewRootScope(curFocusView);
91 return ret;
92 }
93 return false;
94 }
95
FocusViewHide(const RefPtr<FocusView> & focusView)96 void FocusManager::FocusViewHide(const RefPtr<FocusView>& focusView)
97 {
98 CHECK_NULL_VOID(focusView);
99 if (IsAutoFocusTransfer()) {
100 focusView->LostViewFocus();
101 }
102 auto lastFocusView = lastFocusView_.Upgrade();
103 if (lastFocusView && (lastFocusView == focusView || lastFocusView->IsChildFocusViewOf(focusView))) {
104 lastFocusView_ = nullptr;
105 }
106 }
107
FocusViewClose(const RefPtr<FocusView> & focusView,bool isDetachFromTree)108 void FocusManager::FocusViewClose(const RefPtr<FocusView>& focusView, bool isDetachFromTree)
109 {
110 if (!IsAutoFocusTransfer() && !isDetachFromTree) {
111 return;
112 }
113 CHECK_NULL_VOID(focusView);
114 focusView->LostViewFocus();
115 focusView->SetIsViewHasShow(false);
116 for (auto iter = focusViewStack_.begin(); iter != focusViewStack_.end();) {
117 auto view = (*iter).Upgrade();
118 if (view && (view == focusView || view->IsChildFocusViewOf(focusView))) {
119 auto focusHub = view->GetFocusHub();
120 if (focusHub) {
121 focusHub->RemoveFocusScopeIdAndPriority();
122 }
123 iter = focusViewStack_.erase(iter);
124 focusViewStackState_ = FocusViewStackState::CLOSE;
125 } else {
126 ++iter;
127 }
128 }
129 if (focusViewStack_.empty()) {
130 lastFocusView_ = nullptr;
131 return;
132 }
133 if (focusViewStack_.back() != lastFocusView_) {
134 lastFocusView_ = focusViewStack_.back();
135 }
136 }
137
FlushFocusView()138 void FocusManager::FlushFocusView()
139 {
140 auto lastFocusView = lastFocusView_.Upgrade();
141 auto lastFocusViewHub = lastFocusView ? lastFocusView->GetFocusHub() : nullptr;
142 if (lastFocusViewHub && lastFocusViewHub->IsCurrentFocus()) {
143 return;
144 }
145 RefPtr<FocusView> currFocusView = nullptr;
146 for (const auto& weakView : focusViewStack_) {
147 auto view = weakView.Upgrade();
148 auto viewHub = view ? view->GetFocusHub() : nullptr;
149 if (!viewHub || !viewHub->IsCurrentFocus()) {
150 continue;
151 }
152 if (currFocusView && currFocusView->IsChildFocusViewOf(view)) {
153 continue;
154 }
155 currFocusView = view;
156 }
157 lastFocusView_ = currFocusView ? AceType::WeakClaim(AceType::RawPtr(currFocusView)) : nullptr;
158 }
159
GetFocusViewMap(FocusViewMap & focusViewMap)160 void FocusManager::GetFocusViewMap(FocusViewMap& focusViewMap)
161 {
162 for (const auto& focusViewWeak : focusViewStack_) {
163 auto focusView = focusViewWeak.Upgrade();
164 if (!focusView) {
165 continue;
166 }
167 auto focusViewId = focusView->GetFrameId();
168 auto entryFocusView = focusView->GetEntryFocusView();
169 if (entryFocusView && entryFocusView != focusView) {
170 auto entryFocusViewId = entryFocusView->GetFrameId();
171 auto entryFocusViewWeak = AceType::WeakClaim(AceType::RawPtr(entryFocusView));
172 auto iter = focusViewMap.find(entryFocusViewId);
173 if (iter == focusViewMap.end()) {
174 focusViewMap[entryFocusViewId] = { entryFocusViewWeak, { focusViewWeak } };
175 } else {
176 iter->second.second.emplace_back(focusViewWeak);
177 }
178 } else {
179 focusViewMap[focusViewId] = { focusViewWeak, {} };
180 }
181 }
182 }
183
PaintFocusState()184 void FocusManager::PaintFocusState()
185 {
186 auto pipeline = pipeline_.Upgrade();
187 CHECK_NULL_VOID(pipeline);
188 auto rootNode = pipeline->GetRootElement();
189 CHECK_NULL_VOID(rootNode);
190 auto rootFocusHub = rootNode->GetFocusHub();
191 CHECK_NULL_VOID(rootFocusHub);
192 if (!pipeline->GetIsFocusActive()) {
193 return;
194 }
195 rootFocusHub->ClearAllFocusState();
196 rootFocusHub->PaintAllFocusState();
197 }
198
199
DumpFocusManager()200 void FocusManager::DumpFocusManager()
201 {
202 if (!DumpLog::GetInstance().GetDumpFile()) {
203 return;
204 }
205 DumpLog::GetInstance().Print("Focus view:");
206 std::unordered_map<int32_t, std::pair<WeakPtr<FocusView>, std::list<WeakPtr<FocusView>>>> focusViewMap;
207 GetFocusViewMap(focusViewMap);
208 for (const auto& focusViewInfo : focusViewMap) {
209 auto focusView = focusViewInfo.second.first.Upgrade();
210 if (!focusView) {
211 continue;
212 }
213 auto childFocusViewWeakList = focusViewInfo.second.second;
214 bool isFocusedView = false;
215 auto lastFocusView = lastFocusView_.Upgrade();
216 auto lastEntryFocusView = lastFocusView ? lastFocusView->GetEntryFocusView() : nullptr;
217 if (focusView == lastEntryFocusView) {
218 isFocusedView = true;
219 }
220 std::string information = focusView->GetFrameName();
221 information += isFocusedView ? "(*)" : "";
222 information += " id:" + std::to_string(focusView->GetFrameId());
223 DumpLog::GetInstance().Print(0, information, static_cast<int32_t>(childFocusViewWeakList.size()));
224 for (const auto& childWeak : childFocusViewWeakList) {
225 auto child = childWeak.Upgrade();
226 if (!child) {
227 continue;
228 }
229 std::string childInformation = child->GetFrameName();
230 childInformation += child == lastFocusView ? "(*)" : "";
231 childInformation += " id:" + std::to_string(child->GetFrameId());
232 DumpLog::GetInstance().Print(1, childInformation, 0);
233 }
234 }
235 }
236
AddFocusScope(const std::string & focusScopeId,const RefPtr<FocusHub> & scopeFocusHub)237 bool FocusManager::AddFocusScope(const std::string& focusScopeId, const RefPtr<FocusHub>& scopeFocusHub)
238 {
239 auto iter = focusHubScopeMap_.find(focusScopeId);
240 if (iter != focusHubScopeMap_.end()) {
241 auto focusScope = iter->second.first.Upgrade();
242 if (!focusScope) {
243 iter->second.first = scopeFocusHub;
244 return true;
245 }
246 return false;
247 } else {
248 focusHubScopeMap_[focusScopeId] = { scopeFocusHub, {} };
249 }
250 return true;
251 }
252
RemoveFocusScope(const std::string & focusScopeId)253 void FocusManager::RemoveFocusScope(const std::string& focusScopeId)
254 {
255 auto iter = focusHubScopeMap_.find(focusScopeId);
256 if (iter != focusHubScopeMap_.end()) {
257 if (iter->second.second.empty()) {
258 focusHubScopeMap_.erase(iter);
259 } else {
260 iter->second.first = nullptr;
261 }
262 }
263 }
264
AddScopePriorityNode(const std::string & focusScopeId,const RefPtr<FocusHub> & priorFocusHub,bool pushFront)265 void FocusManager::AddScopePriorityNode(const std::string& focusScopeId, const RefPtr<FocusHub>& priorFocusHub,
266 bool pushFront)
267 {
268 auto iter = focusHubScopeMap_.find(focusScopeId);
269 if (iter != focusHubScopeMap_.end()) {
270 if (pushFront) {
271 iter->second.second.emplace_front(priorFocusHub);
272 } else {
273 iter->second.second.emplace_back(priorFocusHub);
274 }
275 } else {
276 focusHubScopeMap_[focusScopeId] = { nullptr, { priorFocusHub } };
277 }
278 }
279
RemoveScopePriorityNode(const std::string & focusScopeId,const RefPtr<FocusHub> & priorFocusHub)280 void FocusManager::RemoveScopePriorityNode(const std::string& focusScopeId, const RefPtr<FocusHub>& priorFocusHub)
281 {
282 auto iter = focusHubScopeMap_.find(focusScopeId);
283 if (iter != focusHubScopeMap_.end()) {
284 if (iter->second.second.empty()) {
285 return;
286 }
287 iter->second.second.remove(priorFocusHub);
288 auto focusScope = iter->second.first.Upgrade();
289 if (!focusScope && iter->second.second.empty()) {
290 focusHubScopeMap_.erase(iter);
291 }
292 }
293 }
294
GetFocusScopePriorityList(const std::string & focusScopeId)295 std::optional<std::list<WeakPtr<FocusHub>>*> FocusManager::GetFocusScopePriorityList(const std::string& focusScopeId)
296 {
297 auto iter = focusHubScopeMap_.find(focusScopeId);
298 if (iter != focusHubScopeMap_.end()) {
299 if (!iter->second.second.empty()) {
300 return &(iter->second.second);
301 }
302 }
303 return std::nullopt;
304 }
305
UpdateCurrentFocus(const RefPtr<FocusHub> & current,SwitchingUpdateReason reason)306 void FocusManager::UpdateCurrentFocus(const RefPtr<FocusHub>& current, SwitchingUpdateReason reason)
307 {
308 if (isSwitchingFocus_.value_or(false)) {
309 switchingFocus_ = current;
310 updateReason_ = reason;
311 }
312 }
313
GetCurrentFocus()314 RefPtr<FocusHub> FocusManager::GetCurrentFocus()
315 {
316 return currentFocus_.Upgrade();
317 }
318
AddFocusListener(FocusChangeCallback && callback)319 int32_t FocusManager::AddFocusListener(FocusChangeCallback&& callback)
320 {
321 // max callbacks count: INT32_MAX - 1
322 if (listeners_.size() == static_cast<size_t>(std::numeric_limits<int32_t>::max() - 1)) {
323 return -1;
324 }
325 int32_t handler = nextListenerHdl_;
326 listeners_.emplace(handler, std::move(callback));
327
328 do {
329 nextListenerHdl_ = (nextListenerHdl_ == std::numeric_limits<int32_t>::max()) ? 0 : ++nextListenerHdl_;
330 } while (listeners_.count(nextListenerHdl_) != 0);
331 return handler;
332 }
333
RemoveFocusListener(int32_t handler)334 void FocusManager::RemoveFocusListener(int32_t handler)
335 {
336 listeners_.erase(handler);
337 }
338
GetFocusManager(RefPtr<FrameNode> & node)339 RefPtr<FocusManager> FocusManager::GetFocusManager(RefPtr<FrameNode>& node)
340 {
341 auto context = node->GetContextRefPtr();
342 CHECK_NULL_RETURN(context, nullptr);
343 auto focusManager = context->GetFocusManager();
344 return focusManager;
345 }
346
FocusSwitchingStart(const RefPtr<FocusHub> & focusHub,SwitchingStartReason reason)347 void FocusManager::FocusSwitchingStart(const RefPtr<FocusHub>& focusHub,
348 SwitchingStartReason reason)
349 {
350 isSwitchingFocus_ = true;
351 switchingFocus_ = focusHub;
352 startReason_ = reason;
353 }
354
ReportFocusSwitching(FocusReason focusReason)355 void FocusManager::ReportFocusSwitching(FocusReason focusReason)
356 {
357 for (auto& [_, cb] : listeners_) {
358 cb(currentFocus_, switchingFocus_, focusReason);
359 }
360 currentFocus_ = switchingFocus_;
361 isSwitchingFocus_.reset();
362 startReason_.reset();
363 updateReason_.reset();
364 endReason_.reset();
365 }
366
FocusSwitchingEnd(SwitchingEndReason reason)367 void FocusManager::FocusSwitchingEnd(SwitchingEndReason reason)
368 {
369 // While switching window, focus may move by steps.(WindowFocus/FlushFocus)
370 // Merge all steps together as a single movement.
371 if (!isSwitchingFocus_.value_or(false)) {
372 return;
373 }
374 if (!isSwitchingWindow_) {
375 auto lastHub = currentFocus_.Upgrade();
376 TAG_LOGI(AceLogTag::ACE_FOCUS, "FocusSwitch end, %{public}s/" SEC_PLD(%{public}d) " onBlur, "
377 "%{public}s/" SEC_PLD(%{public}d) " onFocus, "
378 "start: %{public}d, end: %{public}d, update: %{public}d",
379 lastHub ? lastHub->GetFrameName().c_str() : "NULL",
380 SEC_PARAM(lastHub ? lastHub->GetFrameId() : -1),
381 switchingFocus_ ? switchingFocus_->GetFrameName().c_str() : "NULL",
382 SEC_PARAM(switchingFocus_ ? switchingFocus_->GetFrameId() : -1),
383 startReason_.value_or(SwitchingStartReason::DEFAULT),
384 reason, updateReason_.value_or(SwitchingUpdateReason::DEFAULT));
385 if (switchingFocus_ &&
386 startReason_.value_or(SwitchingStartReason::DEFAULT) != SwitchingStartReason::LOST_FOCUS_TO_VIEW_ROOT) {
387 switchingFocus_->ClearLastFocusNode();
388 }
389 ReportFocusSwitching(FocusReason::DEFAULT);
390 PaintFocusState();
391 } else {
392 isSwitchingFocus_ = false;
393 endReason_ = reason;
394 }
395 }
396
WindowFocusMoveStart()397 void FocusManager::WindowFocusMoveStart()
398 {
399 isSwitchingWindow_ = true;
400 }
401
WindowFocusMoveEnd()402 void FocusManager::WindowFocusMoveEnd()
403 {
404 isSwitchingWindow_ = false;
405 if (!isSwitchingFocus_.value_or(true)) {
406 auto lastHub = currentFocus_.Upgrade();
407 TAG_LOGI(AceLogTag::ACE_FOCUS, "WinFocusMove end, %{public}s/" SEC_PLD(%{public}d) " onBlur, "
408 "%{public}s/" SEC_PLD(%{public}d) " onFocus, "
409 "start: %{public}d, end: %{public}d, update: %{public}d",
410 lastHub ? lastHub->GetFrameName().c_str() : "NULL",
411 SEC_PARAM(lastHub ? lastHub->GetFrameId() : -1),
412 switchingFocus_ ? switchingFocus_->GetFrameName().c_str() : "NULL",
413 SEC_PARAM(switchingFocus_ ? switchingFocus_->GetFrameId() : -1),
414 startReason_.value_or(SwitchingStartReason::DEFAULT),
415 endReason_.value_or(SwitchingEndReason::DEFAULT),
416 updateReason_.value_or(SwitchingUpdateReason::DEFAULT));
417 ReportFocusSwitching(FocusReason::WINDOW_FOCUS);
418 PaintFocusState();
419 }
420 }
421
CreateFocusGuard(const RefPtr<FocusHub> & focusHub,const RefPtr<FocusManager> & focusManager,SwitchingStartReason reason)422 void FocusManager::FocusGuard::CreateFocusGuard(const RefPtr<FocusHub>& focusHub,
423 const RefPtr<FocusManager>& focusManager, SwitchingStartReason reason)
424 {
425 CHECK_NULL_VOID(focusHub);
426 CHECK_NULL_VOID(focusManager);
427 if (focusManager->isSwitchingFocus_.value_or(false)) {
428 return;
429 }
430 focusManager->FocusSwitchingStart(focusHub, reason);
431 focusMng_ = focusManager;
432 }
433
FocusGuard(const RefPtr<FocusHub> & focusHub,SwitchingStartReason reason)434 FocusManager::FocusGuard::FocusGuard(const RefPtr<FocusHub>& focusHub,
435 SwitchingStartReason reason)
436 {
437 RefPtr<FocusHub> hub = focusHub;
438 if (!focusHub ||!focusHub->GetFocusManager()) {
439 auto curFocusView = FocusView::GetCurrentFocusView();
440 CHECK_NULL_VOID(curFocusView);
441 auto curFocusViewHub = curFocusView->GetFocusHub();
442 CHECK_NULL_VOID(curFocusViewHub);
443 hub = curFocusViewHub;
444 }
445 auto mng = hub->GetFocusManager();
446 CreateFocusGuard(hub, mng, reason);
447 }
448
~FocusGuard()449 FocusManager::FocusGuard::~FocusGuard()
450 {
451 if (focusMng_) {
452 focusMng_->FocusSwitchingEnd();
453 }
454 }
455
SetFocusViewRootScope(const RefPtr<FocusView> & focusView)456 bool FocusManager::SetFocusViewRootScope(const RefPtr<FocusView>& focusView)
457 {
458 auto focusViewRootScope = focusView->GetViewRootScope();
459 focusView->SetIsViewRootScopeFocused(true);
460 return focusViewRootScope->RequestFocusImmediatelyInner();
461 }
462
WindowFocus(bool isFocus)463 void FocusManager::WindowFocus(bool isFocus)
464 {
465 if (!isFocus) {
466 return;
467 }
468 WindowFocusMoveStart();
469 FocusManager::FocusGuard guard(GetCurrentFocus(), SwitchingStartReason::WINDOW_FOCUS);
470 auto curFocusView = GetLastFocusView().Upgrade();
471 auto curFocusViewHub = curFocusView ? curFocusView->GetFocusHub() : nullptr;
472 if (!curFocusViewHub) {
473 TAG_LOGW(AceLogTag::ACE_FOCUS, "Current focus view can not found!");
474 } else if (curFocusView->GetIsViewHasFocused() && !curFocusViewHub->IsCurrentFocus()) {
475 TAG_LOGI(AceLogTag::ACE_FOCUS, "Request focus on current focus view: %{public}s/%{public}d",
476 curFocusView->GetFrameName().c_str(), curFocusView->GetFrameId());
477 if (!IsAutoFocusTransfer()) {
478 SetFocusViewRootScope(curFocusView);
479 } else {
480 auto lastViewFocusNode = curFocusViewHub->GetFocusLeaf();
481 lastViewFocusNode->RequestFocusImmediatelyInner();
482 }
483 } else {
484 auto container = Container::Current();
485 if (container && (container->IsUIExtensionWindow() || container->IsDynamicRender())) {
486 curFocusView->SetIsViewRootScopeFocused(false);
487 curFocusView->RequestDefaultFocus();
488 }
489 }
490
491 auto pipeline = pipeline_.Upgrade();
492 CHECK_NULL_VOID(pipeline);
493 auto root = pipeline->GetRootElement();
494 CHECK_NULL_VOID(root);
495 auto rootFocusHub = root->GetFocusHub();
496 CHECK_NULL_VOID(rootFocusHub);
497 if (!rootFocusHub->IsCurrentFocus()) {
498 auto focusDepend = rootFocusHub->GetFocusDependence();
499 rootFocusHub->SetFocusDependence(FocusDependence::SELF);
500 rootFocusHub->RequestFocusImmediately();
501 rootFocusHub->SetFocusDependence(focusDepend);
502 }
503 pipeline->RequestFrame();
504 }
505 } // namespace OHOS::Ace::NG
506