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