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