• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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/pattern/text_field/text_field_manager.h"
17 
18 #include "base/geometry/dimension.h"
19 #include "base/memory/ace_type.h"
20 #include "base/utils/utils.h"
21 #include "core/common/ime/text_input_type.h"
22 #include "core/components_ng/event/focus_hub.h"
23 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
24 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
25 #include "core/components_ng/pattern/text/text_base.h"
26 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
27 
28 namespace OHOS::Ace::NG {
29 namespace {
30 constexpr Dimension RESERVE_BOTTOM_HEIGHT = 24.0_vp;
31 constexpr int32_t MAX_FILL_CONTENT_SIZE = 5;
32 } // namespace
33 
ClearOnFocusTextField()34 void TextFieldManagerNG::ClearOnFocusTextField()
35 {
36     onFocusTextField_ = nullptr;
37 }
38 
ClearOnFocusTextField(int32_t id)39 void TextFieldManagerNG::ClearOnFocusTextField(int32_t id)
40 {
41     if (onFocusTextFieldId_ == id) {
42         onFocusTextField_ = nullptr;
43         focusFieldIsInline_ = false;
44         optionalPosition_ = std::nullopt;
45         usingCustomKeyboardAvoid_ = false;
46         isScrollableChild_ = false;
47     }
48 }
49 
OnBackPressed()50 bool TextFieldManagerNG::OnBackPressed()
51 {
52     auto pattern = onFocusTextField_.Upgrade();
53     CHECK_NULL_RETURN(pattern, false);
54     auto textBasePattern = AceType::DynamicCast<TextBase>(pattern);
55     CHECK_NULL_RETURN(textBasePattern, false);
56     return textBasePattern->OnBackPressed();
57 }
58 
SetClickPosition(const Offset & position)59 void TextFieldManagerNG::SetClickPosition(const Offset& position)
60 {
61     auto pipeline = PipelineContext::GetCurrentContextSafelyWithCheck();
62     CHECK_NULL_VOID(pipeline);
63     auto rootHeight = pipeline->GetRootHeight();
64     if (GreatOrEqual(position.GetY(), rootHeight) || LessOrEqual(position.GetY(), 0.0f)) {
65         auto pattern = onFocusTextField_.Upgrade();
66         CHECK_NULL_VOID(pattern);
67         auto host = pattern->GetHost();
68         CHECK_NULL_VOID(host);
69         auto parent = host->GetAncestorNodeOfFrame(true);
70         while (parent) {
71             // when Panel and SheetPage is out of screen, no need to update position_ for keyboard avoidance
72             if (parent->GetTag() == V2::PANEL_ETS_TAG || parent->GetTag() == V2::SHEET_PAGE_TAG) {
73                 return;
74             }
75             parent = parent->GetAncestorNodeOfFrame(true);
76         }
77     }
78     auto rootWidth = pipeline->GetRootWidth();
79     if (GreatOrEqual(position.GetX(), rootWidth) || LessNotEqual(position.GetX(), 0.0f)) {
80         return;
81     }
82     TAG_LOGD(AceLogTag::ACE_KEYBOARD, "SetClickPosition from %{public}s to %{public}s",
83         position_.ToString().c_str(), position.ToString().c_str());
84     position_ = position;
85     optionalPosition_ = position;
86 }
87 
FindScrollableOfFocusedTextField(const RefPtr<FrameNode> & textField)88 RefPtr<FrameNode> TextFieldManagerNG::FindScrollableOfFocusedTextField(const RefPtr<FrameNode>& textField)
89 {
90     CHECK_NULL_RETURN(textField, {});
91     auto parent = textField->GetAncestorNodeOfFrame(true);
92     while (parent) {
93         auto pattern = parent->GetPattern<ScrollablePattern>();
94         if (pattern) {
95             return parent;
96         }
97         parent = parent->GetAncestorNodeOfFrame(true);
98     }
99     return {};
100 }
101 
GetFocusedNodeCaretRect()102 RectF TextFieldManagerNG::GetFocusedNodeCaretRect()
103 {
104     auto node = onFocusTextField_.Upgrade();
105     CHECK_NULL_RETURN(node, RectF());
106     auto frameNode = node->GetHost();
107     CHECK_NULL_RETURN(frameNode, RectF());
108     auto textBase = DynamicCast<TextBase>(node);
109     CHECK_NULL_RETURN(textBase, RectF());
110     auto caretRect = textBase->GetCaretRect() + frameNode->GetTransformRectRelativeToWindow();
111     return caretRect;
112 }
113 
TriggerCustomKeyboardAvoid()114 void TextFieldManagerNG::TriggerCustomKeyboardAvoid()
115 {
116     CHECK_NULL_VOID(UsingCustomKeyboardAvoid());
117     auto pattern = onFocusTextField_.Upgrade();
118     CHECK_NULL_VOID(pattern);
119     auto curPattern = DynamicCast<TextFieldPattern>(pattern);
120     CHECK_NULL_VOID(curPattern);
121     if (!curPattern->GetIsCustomKeyboardAttached()) {
122         return;
123     }
124     auto caretHeight = curPattern->GetCaretRect().Height();
125     auto safeHeight = caretHeight + curPattern->GetCaretRect().GetY();
126     if (curPattern->GetCaretRect().GetY() > caretHeight) {
127         safeHeight = caretHeight;
128     }
129     auto keyboardOverLay = curPattern->GetKeyboardOverLay();
130     CHECK_NULL_VOID(keyboardOverLay);
131     auto host = curPattern->GetHost();
132     CHECK_NULL_VOID(host);
133     auto nodeId = host->GetId();
134     keyboardOverLay->TriggerCustomKeyboardAvoid(nodeId, safeHeight);
135 }
136 
TriggerAvoidOnCaretChange()137 void TextFieldManagerNG::TriggerAvoidOnCaretChange()
138 {
139     auto pattern = onFocusTextField_.Upgrade();
140     CHECK_NULL_VOID(pattern);
141     auto host = pattern->GetHost();
142     CHECK_NULL_VOID(host);
143     auto pipeline = host->GetContext();
144     CHECK_NULL_VOID(pipeline);
145     auto safeAreaManager = pipeline->GetSafeAreaManager();
146     CHECK_NULL_VOID(safeAreaManager);
147     if (!pipeline->UsingCaretAvoidMode() || NearEqual(safeAreaManager->GetKeyboardInset().Length(), 0)) {
148         return;
149     }
150     ScrollTextFieldToSafeArea();
151     if (UsingCustomKeyboardAvoid()) {
152         TriggerCustomKeyboardAvoid();
153     } else {
154         auto keyboardInset = safeAreaManager->GetKeyboardInset();
155         lastKeyboardOffset_ = safeAreaManager->GetKeyboardOffset(true);
156         Rect keyboardRect;
157         keyboardRect.SetRect(0, 0, 0, keyboardInset.Length());
158         pipeline->OnVirtualKeyboardAreaChange(keyboardRect,
159             GetFocusedNodeCaretRect().Top(), GetHeight());
160     }
161     auto currentKeyboardOffset = safeAreaManager->GetKeyboardOffset(true);
162     if (currentKeyboardOffset != lastKeyboardOffset_) {
163         AvoidKeyboardInSheet(host);
164     }
165 }
166 
GetOnFocusTextFieldInfo(const WeakPtr<Pattern> & onFocusTextField)167 void TextFieldManagerNG::GetOnFocusTextFieldInfo(const WeakPtr<Pattern>& onFocusTextField)
168 {
169     auto node = onFocusTextField.Upgrade();
170     CHECK_NULL_VOID(node);
171     auto frameNode = node->GetHost();
172     CHECK_NULL_VOID(frameNode);
173     auto scrollableNode = FindScrollableOfFocusedTextField(frameNode);
174     CHECK_NULL_VOID(scrollableNode);
175     auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
176     CHECK_NULL_VOID(scrollPattern);
177     isScrollableChild_ = scrollPattern->IsScrollToSafeAreaHelper();
178     TAG_LOGI(ACE_KEYBOARD, "isScrollableChild_: %{public}d", isScrollableChild_);
179 }
180 
FindCorrectScrollNode(const SafeAreaInsets::Inset & bottomInset,bool isShowKeyboard)181 RefPtr<FrameNode> TextFieldManagerNG::FindCorrectScrollNode(const SafeAreaInsets::Inset& bottomInset,
182     bool isShowKeyboard)
183 {
184     auto node = onFocusTextField_.Upgrade();
185     CHECK_NULL_RETURN(node, nullptr);
186     auto frameNode = node->GetHost();
187     CHECK_NULL_RETURN(frameNode, nullptr);
188     auto parent = frameNode->GetAncestorNodeOfFrame(true);
189     while (parent) {
190         auto pattern = parent->GetPattern<ScrollablePattern>();
191         if (!pattern) {
192             parent = parent->GetAncestorNodeOfFrame(true);
193             continue;
194         }
195         if (!pattern->IsScrollToSafeAreaHelper() || pattern->GetAxis() == Axis::HORIZONTAL) {
196             return nullptr;
197         }
198         auto scrollableRect = parent->GetTransformRectRelativeToWindow();
199         if (!isShowKeyboard || LessNotEqual(scrollableRect.Top(), bottomInset.start)) {
200             return parent;
201         }
202         parent = parent->GetAncestorNodeOfFrame(true);
203     }
204     return nullptr;
205 }
206 
ScrollToSafeAreaHelper(const SafeAreaInsets::Inset & bottomInset,bool isShowKeyboard)207 bool TextFieldManagerNG::ScrollToSafeAreaHelper(
208     const SafeAreaInsets::Inset& bottomInset, bool isShowKeyboard)
209 {
210     auto node = onFocusTextField_.Upgrade();
211     CHECK_NULL_RETURN(node, false);
212     auto frameNode = node->GetHost();
213     CHECK_NULL_RETURN(frameNode, false);
214     auto textBase = DynamicCast<TextBase>(node);
215     CHECK_NULL_RETURN(textBase, false);
216     textBase->OnVirtualKeyboardAreaChanged();
217 
218     auto scrollableNode = FindCorrectScrollNode(bottomInset, isShowKeyboard);
219     CHECK_NULL_RETURN(scrollableNode, false);
220     auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
221     CHECK_NULL_RETURN(scrollPattern && scrollPattern->IsScrollToSafeAreaHelper(), false);
222     CHECK_NULL_RETURN(scrollPattern->GetAxis() != Axis::HORIZONTAL, false);
223 
224     auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
225     if (isShowKeyboard) {
226         CHECK_NULL_RETURN(LessNotEqual(scrollableRect.Top(), bottomInset.start), false);
227     }
228 
229     auto caretRect = textBase->GetCaretRect() + frameNode->GetPositionToWindowWithTransform();
230     auto diffTop = caretRect.Top() - scrollableRect.Top();
231     // caret height larger scroll's content region
232     if (isShowKeyboard && LessOrEqual(diffTop, 0) && LessNotEqual(bottomInset.start,
233         (caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()))) {
234         return false;
235     }
236 
237     // caret above scroll's content region
238     if (LessNotEqual(diffTop, 0)) {
239         TAG_LOGI(ACE_KEYBOARD, "scrollRect:%{public}s caretRect:%{public}s totalOffset()=%{public}f diffTop=%{public}f",
240             scrollableRect.ToString().c_str(), caretRect.ToString().c_str(), scrollPattern->GetTotalOffset(), diffTop);
241         scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() + diffTop);
242         return true;
243     }
244 
245     // caret inner scroll's content region
246     if (isShowKeyboard && LessNotEqual((caretRect.Bottom() + RESERVE_BOTTOM_HEIGHT.ConvertToPx()), bottomInset.start)) {
247         return false;
248     }
249 
250     // caret below safeArea
251     float diffBot = 0.0f;
252 
253     auto scrollBottom = isShowKeyboard && GreatOrEqual(scrollableRect.Bottom(), bottomInset.start) ?
254         bottomInset.start : scrollableRect.Bottom();
255     diffBot = scrollBottom - caretRect.Bottom() - RESERVE_BOTTOM_HEIGHT.ConvertToPx();
256     CHECK_NULL_RETURN(diffBot < 0, false);
257     TAG_LOGI(ACE_KEYBOARD, "scrollRect:%{public}s caretRect:%{public}s totalOffset()=%{public}f diffBot=%{public}f",
258         scrollableRect.ToString().c_str(), caretRect.ToString().c_str(), scrollPattern->GetTotalOffset(), diffBot);
259     scrollPattern->ScrollTo(scrollPattern->GetTotalOffset() - diffBot);
260     return true;
261 }
262 
ScrollTextFieldToSafeArea()263 bool TextFieldManagerNG::ScrollTextFieldToSafeArea()
264 {
265     auto pipeline = PipelineContext::GetCurrentContext();
266     CHECK_NULL_RETURN(pipeline, false);
267     auto manager = pipeline->GetSafeAreaManager();
268     CHECK_NULL_RETURN(manager, false);
269     auto systemSafeArea = manager->GetSystemSafeArea();
270     uint32_t bottom = systemSafeArea.bottom_.IsValid()? systemSafeArea.bottom_.start : pipeline->GetCurrentRootHeight();
271     auto keyboardHeight = manager->GetRawKeyboardHeight();
272     SafeAreaInsets::Inset keyboardInset = { .start = bottom - keyboardHeight, .end = bottom };
273     bool isShowKeyboard = manager->GetKeyboardInset().IsValid();
274     int32_t keyboardOrientation = manager->GetKeyboardOrientation();
275     auto container = Container::Current();
276     if (keyboardOrientation != -1 && container && container->GetDisplayInfo()) {
277         auto nowOrientation = static_cast<int32_t>(container->GetDisplayInfo()->GetRotation());
278         if (nowOrientation != keyboardOrientation) {
279             // When rotating the screen, sometimes we might get a keyboard height that in wrong
280             // orientation due to timeing issue. In this case, we assume there is no keyboard.
281             TAG_LOGI(ACE_KEYBOARD, "Current Orientation can't match keyboard orientation");
282             keyboardInset = { .start = bottom, .end = bottom };
283         }
284     }
285     if (isShowKeyboard) {
286         auto bottomInset = pipeline->GetSafeArea().bottom_.Combine(keyboardInset);
287         CHECK_NULL_RETURN(bottomInset.IsValid(), false);
288         return ScrollToSafeAreaHelper(bottomInset, isShowKeyboard);
289     } else if (manager->KeyboardSafeAreaEnabled()) {
290         // hide keyboard only scroll when keyboard avoid mode is resize
291         return ScrollToSafeAreaHelper({0, 0}, isShowKeyboard);
292     }
293     return false;
294 }
295 
SetHeight(float height)296 void TextFieldManagerNG::SetHeight(float height)
297 {
298     height_ = height + RESERVE_BOTTOM_HEIGHT.ConvertToPx();
299 }
300 
UpdateScrollableParentViewPort(const RefPtr<FrameNode> & node)301 void TextFieldManagerNG::UpdateScrollableParentViewPort(const RefPtr<FrameNode>& node)
302 {
303     CHECK_NULL_VOID(node);
304     auto scrollableNode = FindScrollableOfFocusedTextField(node);
305     CHECK_NULL_VOID(scrollableNode);
306     auto scrollPattern = scrollableNode->GetPattern<ScrollablePattern>();
307     CHECK_NULL_VOID(scrollPattern);
308     if (scrollPattern->GetAxis() == Axis::HORIZONTAL) {
309         return;
310     }
311     auto scrollableRect = scrollableNode->GetTransformRectRelativeToWindow();
312     scrollableNode->SetViewPort(scrollableRect);
313 }
314 
AvoidKeyBoardInNavigation()315 void TextFieldManagerNG::AvoidKeyBoardInNavigation()
316 {
317     auto node = onFocusTextField_.Upgrade();
318     auto pipeline = PipelineContext::GetCurrentContext();
319     CHECK_NULL_VOID(pipeline);
320     auto manager = pipeline->GetSafeAreaManager();
321     auto avoidKeyboardOffset =  manager ? manager->GetKeyboardOffset() : 0.0f;
322     if (!node) {
323         auto navNode = weakNavNode_.Upgrade();
324         CHECK_NULL_VOID(navNode);
325         SetNavContentAvoidKeyboardOffset(navNode, avoidKeyboardOffset);
326         return;
327     }
328     auto frameNode = node->GetHost();
329     CHECK_NULL_VOID(frameNode);
330     auto preNavNode = weakNavNode_.Upgrade();
331     if (preNavNode) {
332         SetNavContentAvoidKeyboardOffset(preNavNode, 0.0f);
333     }
334     auto navNode = FindNavNode(frameNode);
335     CHECK_NULL_VOID(navNode);
336     weakNavNode_ = navNode;
337     SetNavContentAvoidKeyboardOffset(navNode, avoidKeyboardOffset);
338 }
339 
AvoidKeyboardInSheet(const RefPtr<FrameNode> & textField)340 void TextFieldManagerNG::AvoidKeyboardInSheet(const RefPtr<FrameNode>& textField)
341 {
342     CHECK_NULL_VOID(textField);
343     auto parent = textField->GetAncestorNodeOfFrame(true);
344     while (parent) {
345         if (parent->GetHostTag() == V2::SHEET_PAGE_TAG) {
346             break;
347         }
348         parent = parent->GetAncestorNodeOfFrame(true);
349     }
350     CHECK_NULL_VOID(parent);
351     auto sheetNodePattern = parent->GetPattern<SheetPresentationPattern>();
352     CHECK_NULL_VOID(sheetNodePattern);
353     TAG_LOGI(ACE_KEYBOARD, "Force AvoidKeyboard in sheet");
354     sheetNodePattern->AvoidSafeArea(true);
355 }
356 
FindNavNode(const RefPtr<FrameNode> & textField)357 RefPtr<FrameNode> TextFieldManagerNG::FindNavNode(const RefPtr<FrameNode>& textField)
358 {
359     CHECK_NULL_RETURN(textField, nullptr);
360     auto parent = textField->GetAncestorNodeOfFrame(true);
361     RefPtr<FrameNode> ret = nullptr;
362     while (parent) {
363         // when the sheet showed in navdestination, sheet replaced navdestination to do avoid keyboard.
364         if (parent->GetHostTag() == V2::SHEET_WRAPPER_TAG) {
365             auto sheetNode = parent->GetChildAtIndex(0);
366             CHECK_NULL_RETURN(sheetNode, nullptr);
367             return AceType::DynamicCast<FrameNode>(sheetNode);
368         }
369         if (parent->GetHostTag() == V2::DIALOG_ETS_TAG) {
370             return AceType::DynamicCast<FrameNode>(parent);
371         }
372         if (parent->GetHostTag() == V2::NAVDESTINATION_VIEW_ETS_TAG ||
373             parent->GetHostTag() == V2::NAVBAR_ETS_TAG) {
374                 ret = parent;
375                 break;
376             }
377         parent = parent->GetAncestorNodeOfFrame(true);
378     }
379     CHECK_NULL_RETURN(ret, nullptr);
380 
381     // return navdestination or navBar if the closest ancestor navigation can expandKeyboard
382     // if can't, recursively find the ancestor navigation can expandKeyboard.
383     auto navigationNode = ret->GetAncestorNodeOfFrame(true);
384     while (navigationNode) {
385         if (navigationNode->GetHostTag() == V2::NAVIGATION_VIEW_ETS_TAG) {
386             break;
387         }
388         navigationNode = navigationNode->GetAncestorNodeOfFrame(true);
389     }
390     CHECK_NULL_RETURN(navigationNode, nullptr);
391     auto layoutProperty = navigationNode->GetLayoutProperty<NavigationLayoutProperty>();
392     CHECK_NULL_RETURN(layoutProperty, nullptr);
393     auto& opts = layoutProperty->GetSafeAreaExpandOpts();
394 
395     // if the extended keyboard area is set for the navigation, top navdestination or navbar need to avoid keyboard,
396     // otherwise don't aovid, following parent navigation.
397     bool isExpandKeyboard = opts && (opts->type & SAFE_AREA_TYPE_KEYBOARD) && (opts->edges & SAFE_AREA_EDGE_BOTTOM);
398     if (isExpandKeyboard) {
399         return ret;
400     }
401     auto mayAvoidNavContentNode = FindNavNode(navigationNode);
402     if (mayAvoidNavContentNode) {
403         return mayAvoidNavContentNode;
404     }
405     SetNavContentAvoidKeyboardOffset(ret, 0.0f);
406     return nullptr;
407 }
408 
SetNavContentAvoidKeyboardOffset(const RefPtr<FrameNode> & navNode,float avoidKeyboardOffset)409 void TextFieldManagerNG::SetNavContentAvoidKeyboardOffset(const RefPtr<FrameNode>& navNode, float avoidKeyboardOffset)
410 {
411     auto navDestinationNode = AceType::DynamicCast<NavDestinationGroupNode>(navNode);
412     if (navDestinationNode) {
413         TAG_LOGI(ACE_KEYBOARD, "navNode id:%{public}d, avoidKeyboardOffset:%{public}f", navNode->GetId(),
414             avoidKeyboardOffset);
415         auto pattern = navDestinationNode->GetPattern<NavDestinationPattern>();
416         if (pattern) {
417             avoidKeyboardOffset = pattern->NeedIgnoreKeyboard() ? 0.0f : avoidKeyboardOffset;
418             pattern->SetAvoidKeyboardOffset(avoidKeyboardOffset);
419         }
420     }
421     auto navBarNode = AceType::DynamicCast<NavBarNode>(navNode);
422     if (navBarNode) {
423         auto pattern = navBarNode->GetPattern<NavBarPattern>();
424         if (pattern) {
425             pattern->SetAvoidKeyboardOffset(avoidKeyboardOffset);
426         }
427     }
428     navNode->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
429 }
430 
AddTextFieldInfo(const TextFieldInfo & textFieldInfo)431 void TextFieldManagerNG::AddTextFieldInfo(const TextFieldInfo& textFieldInfo)
432 {
433     if (textFieldInfo.nodeId == -1 || textFieldInfo.autoFillContainerNodeId == -1) {
434         return;
435     }
436 
437     auto containerNodeIter = textFieldInfoMap_.find(textFieldInfo.autoFillContainerNodeId);
438     if (containerNodeIter != textFieldInfoMap_.end()) {
439         auto& innerTextFieldMap = containerNodeIter->second;
440         innerTextFieldMap[textFieldInfo.nodeId] = textFieldInfo;
441     } else {
442         std::unordered_map<int32_t, TextFieldInfo> innerTextFieldInfoMap;
443         innerTextFieldInfoMap[textFieldInfo.nodeId] = textFieldInfo;
444         textFieldInfoMap_[textFieldInfo.autoFillContainerNodeId] = innerTextFieldInfoMap;
445     }
446 }
447 
RemoveTextFieldInfo(const int32_t & autoFillContainerNodeId,const int32_t & nodeId)448 void TextFieldManagerNG::RemoveTextFieldInfo(const int32_t& autoFillContainerNodeId, const int32_t& nodeId)
449 {
450     auto containerNodeIter = textFieldInfoMap_.find(autoFillContainerNodeId);
451     if (containerNodeIter != textFieldInfoMap_.end()) {
452         auto& innerTextFieldInfoMap = containerNodeIter->second;
453         auto textFieldNodeIter = innerTextFieldInfoMap.find(nodeId);
454         if (textFieldNodeIter != innerTextFieldInfoMap.end()) {
455             innerTextFieldInfoMap.erase(textFieldNodeIter);
456         }
457     }
458 }
459 
UpdateTextFieldInfo(const TextFieldInfo & textFieldInfo)460 void TextFieldManagerNG::UpdateTextFieldInfo(const TextFieldInfo& textFieldInfo)
461 {
462     if (textFieldInfo.nodeId == -1 || textFieldInfo.autoFillContainerNodeId == -1) {
463         return;
464     }
465     auto containerNodeIter = textFieldInfoMap_.find(textFieldInfo.autoFillContainerNodeId);
466     if (containerNodeIter != textFieldInfoMap_.end()) {
467         auto& innerTextFieldInfoMap = containerNodeIter->second;
468         auto textFieldNodeIter = innerTextFieldInfoMap.find(textFieldInfo.nodeId);
469         if (textFieldNodeIter != innerTextFieldInfoMap.end()) {
470             innerTextFieldInfoMap.erase(textFieldNodeIter);
471         }
472         innerTextFieldInfoMap[textFieldInfo.nodeId] = textFieldInfo;
473     } else {
474         AddTextFieldInfo(textFieldInfo);
475     }
476 }
477 
HasAutoFillPasswordNodeInContainer(const int32_t & autoFillContainerNodeId,const int32_t & nodeId)478 bool TextFieldManagerNG::HasAutoFillPasswordNodeInContainer(
479     const int32_t& autoFillContainerNodeId, const int32_t& nodeId)
480 {
481     auto containerNodeIter = textFieldInfoMap_.find(autoFillContainerNodeId);
482     if (containerNodeIter == textFieldInfoMap_.end()) {
483         return false;
484     }
485 
486     auto& innerTextFieldInfoMap = containerNodeIter->second;
487     auto textFieldNodeIter = innerTextFieldInfoMap.find(nodeId);
488     if (textFieldNodeIter == innerTextFieldInfoMap.end()) {
489         return false;
490     }
491 
492     for (const auto& textField : innerTextFieldInfoMap) {
493         auto textFieldId = textField.first;
494         auto textFieldInfo = textField.second;
495         if (textFieldId == nodeId) {
496             continue;
497         }
498 
499         auto isPasswordType = IsAutoFillPasswordType(textFieldInfo);
500         if (isPasswordType && textFieldInfo.enableAutoFill) {
501             return true;
502         }
503     }
504 
505     return false;
506 }
507 
IsAutoFillPasswordType(const TextFieldInfo & textFieldInfo)508 bool TextFieldManagerNG::IsAutoFillPasswordType(const TextFieldInfo& textFieldInfo)
509 {
510     return textFieldInfo.inputType == TextInputType::VISIBLE_PASSWORD ||
511            textFieldInfo.inputType == TextInputType::NEW_PASSWORD ||
512            textFieldInfo.inputType == TextInputType::NUMBER_PASSWORD ||
513            textFieldInfo.contentType == TextContentType::VISIBLE_PASSWORD ||
514            textFieldInfo.contentType == TextContentType::NEW_PASSWORD;
515 }
516 
SetOnFocusTextField(const WeakPtr<Pattern> & onFocusTextField)517 void TextFieldManagerNG::SetOnFocusTextField(const WeakPtr<Pattern>& onFocusTextField)
518 {
519     const auto& pattern = onFocusTextField.Upgrade();
520     if (pattern && pattern->GetHost()) {
521         onFocusTextFieldId_ = pattern->GetHost()->GetId();
522     }
523     if (onFocusTextField_ != onFocusTextField) {
524         SetImeAttached(false);
525         GetOnFocusTextFieldInfo(onFocusTextField);
526     }
527     onFocusTextField_ = onFocusTextField;
528 }
529 
GetImeShow() const530 bool TextFieldManagerNG::GetImeShow() const
531 {
532     if (!imeShow_ && imeAttachCalled_) {
533         TAG_LOGI(ACE_KEYBOARD, "imeNotShown but attach called, still consider that as shown");
534     }
535     return imeShow_ || imeAttachCalled_;
536 }
537 
AddAvoidKeyboardCallback(int32_t id,bool isCustomKeyboard,const std::function<void ()> && callback)538 void TextFieldManagerNG::AddAvoidKeyboardCallback(
539     int32_t id, bool isCustomKeyboard, const std::function<void()>&& callback)
540 {
541     if (isCustomKeyboard) {
542         avoidCustomKeyboardCallbacks_.insert({ id, std::move(callback) });
543     } else {
544         avoidSystemKeyboardCallbacks_.insert({ id, std::move(callback) });
545     }
546 }
547 
OnAfterAvoidKeyboard(bool isCustomKeyboard)548 void TextFieldManagerNG::OnAfterAvoidKeyboard(bool isCustomKeyboard)
549 {
550     auto callbacks =
551         isCustomKeyboard ? std::move(avoidCustomKeyboardCallbacks_) : std::move(avoidSystemKeyboardCallbacks_);
552     for (const auto& pair : callbacks) {
553         if (pair.second) {
554             pair.second();
555         }
556     }
557 }
558 
~TextFieldManagerNG()559 TextFieldManagerNG::~TextFieldManagerNG()
560 {
561     textFieldInfoMap_.clear();
562     textFieldFillContentMaps_.clear();
563 }
564 
ParseFillContentJsonValue(const std::unique_ptr<JsonValue> & jsonObject)565 bool TextFieldManagerNG::ParseFillContentJsonValue(const std::unique_ptr<JsonValue>& jsonObject)
566 {
567     if (!jsonObject->IsValid() || !jsonObject->IsArray()) {
568         TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "fillContent list format is invalid");
569         return false;
570     }
571 
572     for (int32_t i = 0; i < jsonObject->GetArraySize(); ++i) {
573         auto item = jsonObject->GetArrayItem(i);
574         if (!item) {
575             continue;
576         }
577         auto nodeId = item->GetInt("id", -1);
578         if (nodeId == -1) {
579             continue;
580         }
581         FillContentMap fillContentMap;
582         auto fillContent = item->GetValue("fillContent");
583         if (!fillContent) {
584             continue;
585         }
586         GenerateFillContentMap(fillContent->GetString(), fillContentMap);
587         if (!fillContentMap.empty()) {
588             textFieldFillContentMaps_[nodeId] = fillContentMap;
589         }
590     }
591     return true;
592 }
593 
GenerateFillContentMap(const std::string & fillContent,FillContentMap & map)594 void TextFieldManagerNG::GenerateFillContentMap(const std::string& fillContent, FillContentMap& map)
595 {
596     auto jsonObject = JsonUtil::ParseJsonString(fillContent);
597     CHECK_NULL_VOID(jsonObject);
598     if (!jsonObject->IsValid() || jsonObject->IsArray() || !jsonObject->IsObject()) {
599         TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "fillContent format is invalid");
600         return;
601     }
602     auto child = jsonObject->GetChild();
603     while (child && child->IsValid()) {
604         if (!child->IsObject() && child->IsString()) {
605             std::string strKey = child->GetKey();
606             std::string strVal = child->GetString();
607             if (strKey.empty()) {
608                 child = child->GetNext();
609                 continue;
610             }
611             if (map.size() < MAX_FILL_CONTENT_SIZE) {
612                 map.insert(std::pair<std::string, std::variant<std::string, bool, int32_t>>(strKey, strVal));
613             } else {
614                 TAG_LOGW(AceLogTag::ACE_AUTO_FILL, "fillContent is more than 5");
615                 break;
616             }
617         }
618         child = child->GetNext();
619     }
620 }
621 
GetFillContentMap(int32_t id)622 FillContentMap TextFieldManagerNG::GetFillContentMap(int32_t id)
623 {
624     std::unordered_map<std::string, std::variant<std::string, bool, int32_t>> fillContentMap;
625     auto fillContentMapIter = textFieldFillContentMaps_.find(id);
626     if (fillContentMapIter != textFieldFillContentMaps_.end()) {
627         fillContentMap = fillContentMapIter->second;
628     }
629     return fillContentMap;
630 }
631 
RemoveFillContentMap(int32_t id)632 void TextFieldManagerNG::RemoveFillContentMap(int32_t id)
633 {
634     auto fillContentMapIter = textFieldFillContentMaps_.find(id);
635     if (fillContentMapIter != textFieldFillContentMaps_.end()) {
636         textFieldFillContentMaps_.erase(fillContentMapIter);
637     }
638 }
639 } // namespace OHOS::Ace::NG
640