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