• 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/common/stylus/stylus_detector_mgr.h"
17 
18 #include "core/common/stylus/stylus_detector_default.h"
19 #include "core/common/stylus/stylus_detector_callback.h"
20 #include "core/components_ng/pattern/text_field/text_field_pattern.h"
21 
22 namespace OHOS::Ace {
23 const static std::unordered_set<std::string> TEXT_FIELD_COMPONENT_TAGS = {
24     V2::TEXTINPUT_ETS_TAG,
25     V2::TEXTAREA_ETS_TAG,
26     V2::RICH_EDITOR_ETS_TAG,
27     V2::SEARCH_Field_ETS_TAG,
28 };
29 
GetInstance()30 StylusDetectorMgr* StylusDetectorMgr::GetInstance()
31 {
32     static StylusDetectorMgr instance;
33     return &instance;
34 }
35 
IsEnable()36 bool StylusDetectorMgr::IsEnable()
37 {
38     CHECK_NULL_RETURN(engine_, false);
39     auto isEnable = engine_->IsEnable();
40     CHECK_NULL_RETURN(isEnable, false);
41     return isEnable;
42 }
RegisterStylusInteractionListener(const std::string & bundleName,const std::shared_ptr<IStylusDetectorCallback> & callback)43 bool StylusDetectorMgr::RegisterStylusInteractionListener(
44     const std::string& bundleName, const std::shared_ptr<IStylusDetectorCallback>& callback)
45 {
46     CHECK_NULL_RETURN(engine_, false);
47     return engine_->RegisterStylusInteractionListener(bundleName, callback);
48 }
UnRegisterStylusInteractionListener(const std::string & bundleName)49 void StylusDetectorMgr::UnRegisterStylusInteractionListener(const std::string& bundleName)
50 {
51     CHECK_NULL_VOID(engine_);
52     return engine_->UnRegisterStylusInteractionListener(bundleName);
53 }
Notify(const NotifyInfo & notifyInfo)54 bool StylusDetectorMgr::Notify(const NotifyInfo& notifyInfo)
55 {
56     CHECK_NULL_RETURN(engine_, false);
57     return engine_->Notify(notifyInfo);
58 }
59 
FindHitFrameNode(const TouchEvent & touchEvent,const TouchTestResult & touchTestResult)60 RefPtr<NG::FrameNode> StylusDetectorMgr::FindHitFrameNode(
61     const TouchEvent& touchEvent, const TouchTestResult& touchTestResult)
62 {
63     RefPtr<NG::FrameNode> frameNode;
64     // TextField, textInput, search and richEditor has default touchEventTarget.
65     for (const auto& entry : touchTestResult) {
66         auto recognizer = AceType::DynamicCast<NG::NGGestureRecognizer>(entry);
67         if (recognizer) {
68             continue;
69         }
70         auto nodeId = entry->GetNodeId();
71         auto UiNode = ElementRegister::GetInstance()->GetUINodeById(nodeId);
72         frameNode = AceType::DynamicCast<NG::FrameNode>(UiNode);
73         if (frameNode) {
74             break;
75         }
76     }
77     CHECK_NULL_RETURN(frameNode, nullptr);
78 
79     auto pipeline = frameNode->GetContextRefPtr();
80     if (!pipeline) {
81         TAG_LOGI(AceLogTag::ACE_STYLUS, "Can't find pipeline for find hit node.");
82         return nullptr;
83     }
84     auto nanoTimestamp = pipeline->GetVsyncTime();
85     auto textBasePattern = frameNode->GetPattern<NG::TextBase>();
86     CHECK_NULL_RETURN(textBasePattern, nullptr);
87     if (!textBasePattern->IsTextEditableForStylus() ||
88         IsHitCleanNodeResponseArea({ touchEvent.x, touchEvent.y }, frameNode, nanoTimestamp)) {
89         return nullptr;
90     }
91     return frameNode;
92 }
93 
IsNeedInterceptedTouchEvent(const TouchEvent & touchEvent,std::unordered_map<size_t,TouchTestResult> touchTestResults)94 bool StylusDetectorMgr::IsNeedInterceptedTouchEvent(
95     const TouchEvent& touchEvent, std::unordered_map<size_t, TouchTestResult> touchTestResults)
96 {
97     if (!IsStylusTouchEvent(touchEvent)) {
98         return false;
99     }
100 
101     const auto iter = touchTestResults.find(touchEvent.id);
102     if (iter == touchTestResults.end() || iter->second.empty()) {
103         TAG_LOGI(AceLogTag::ACE_STYLUS, "TouchTestResult is empty");
104         return false;
105     }
106 
107     auto frameNode = FindHitFrameNode(touchEvent, iter->second);
108     if (!frameNode) {
109         TAG_LOGI(AceLogTag::ACE_STYLUS,
110             "Stylus hit position is (" SEC_PLD(%{public}f) "," SEC_PLD(%{public}f) "). TargetNode is None",
111             SEC_PARAM(touchEvent.x), SEC_PARAM(touchEvent.y));
112         return false;
113     }
114 
115     TAG_LOGI(AceLogTag::ACE_STYLUS,
116         "Stylus hit position is (" SEC_PLD(%{public}f) "," SEC_PLD(%{public}f) ")."
117         "TargetNode is %{public}s, id is " SEC_PLD(%{public}s) ".",
118         SEC_PARAM(touchEvent.x), SEC_PARAM(touchEvent.y), frameNode->GetTag().c_str(),
119         SEC_PARAM(frameNode->GetInspectorId()->c_str()));
120 
121     if (!IsEnable()) {
122         TAG_LOGI(AceLogTag::ACE_STYLUS, "Stylus service is not enable");
123         return false;
124     }
125 
126     auto container = Container::Current();
127     CHECK_NULL_RETURN(container, false);
128     auto bundleName = container->GetBundleName();
129     NotifyInfo info;
130     info.componentId = frameNode->GetId();
131     nodeId_ = info.componentId;
132     const auto layoutIter = textFieldLayoutInfos_.find(nodeId_);
133     if (layoutIter != textFieldLayoutInfos_.end()) {
134         layoutInfo_ = layoutIter->second;
135     }
136     info.x = touchEvent.screenX;
137     info.y = touchEvent.screenY;
138     info.bundleName = bundleName;
139     auto stylusDetectorCallback = std::make_shared<StylusDetectorCallBack>();
140     isRegistered_ = RegisterStylusInteractionListener(bundleName, stylusDetectorCallback);
141     sInd_ = -1;
142     eInd_ = -1;
143     showMenu_ = false;
144     return Notify(info);
145 }
146 
AddTextFieldFrameNode(const RefPtr<NG::FrameNode> & frameNode,const WeakPtr<NG::LayoutInfoInterface> & layoutInfo)147 void StylusDetectorMgr::AddTextFieldFrameNode(const RefPtr<NG::FrameNode>& frameNode,
148     const WeakPtr<NG::LayoutInfoInterface>& layoutInfo)
149 {
150     CHECK_NULL_VOID(frameNode);
151     auto tag = frameNode->GetTag();
152     auto iter = TEXT_FIELD_COMPONENT_TAGS.find(tag);
153     if (iter == TEXT_FIELD_COMPONENT_TAGS.end()) {
154         return;
155     }
156     auto id = frameNode->GetId();
157     auto destructor = [id]() { StylusDetectorMgr::GetInstance()->RemoveTextFieldFrameNode(id); };
158     frameNode->PushDestroyCallbackWithTag(std::move(destructor), "DestroyCallbackForStylus");
159     textFieldNodes_[id] = AceType::WeakClaim(AceType::RawPtr(frameNode));
160     textFieldLayoutInfos_[id] = layoutInfo;
161 }
162 
RemoveTextFieldFrameNode(const int32_t id)163 void StylusDetectorMgr::RemoveTextFieldFrameNode(const int32_t id)
164 {
165     textFieldNodes_.erase(id);
166     textFieldLayoutInfos_.erase(id);
167     if (textFieldNodes_.empty()) {
168         auto container = Container::Current();
169         CHECK_NULL_VOID(container);
170         auto bundleName = container->GetBundleName();
171         isRegistered_ = false;
172         UnRegisterStylusInteractionListener(bundleName);
173     }
174 }
175 
StylusDetectorMgr()176 StylusDetectorMgr::StylusDetectorMgr() : engine_(nullptr), isRegistered_(false)
177 {
178     auto lib = StylusDetectorLoader::Load();
179     if (!lib || !(engine_ = lib->CreateStylusDetector())) {
180         engine_ = StylusDetectorInstance(StylusDetectorDefault::GetInstance(), [](StylusDetectorInterface* e) {});
181     }
182 }
183 
IsStylusTouchEvent(const TouchEvent & touchEvent) const184 bool StylusDetectorMgr::IsStylusTouchEvent(const TouchEvent& touchEvent) const
185 {
186     return touchEvent.sourceTool == SourceTool::PEN && touchEvent.type == TouchType::DOWN;
187 }
188 
IsHitCleanNodeResponseArea(const NG::PointF & point,const RefPtr<NG::FrameNode> & frameNode,uint64_t nanoTimestamp)189 bool StylusDetectorMgr::IsHitCleanNodeResponseArea(
190     const NG::PointF& point, const RefPtr<NG::FrameNode>& frameNode, uint64_t nanoTimestamp)
191 {
192     CHECK_NULL_RETURN(frameNode, false);
193     if (frameNode->GetTag() != V2::TEXTINPUT_ETS_TAG) {
194         return false;
195     }
196 
197     auto textFieldPattern = frameNode->GetPattern<NG::TextFieldPattern>();
198     CHECK_NULL_RETURN(textFieldPattern, false);
199     auto responseArea = textFieldPattern->GetCleanNodeResponseArea();
200     CHECK_NULL_RETURN(responseArea, false);
201     auto cleanNodeResponseArea = AceType::DynamicCast<NG::CleanNodeResponseArea>(responseArea);
202     if (!cleanNodeResponseArea->IsShow()) {
203         return false;
204     }
205 
206     auto cleanNodeFrameNode = cleanNodeResponseArea->GetFrameNode();
207     CHECK_NULL_RETURN(cleanNodeFrameNode, false);
208     auto cleanNodeGeometryNode = cleanNodeFrameNode->GetGeometryNode();
209     CHECK_NULL_RETURN(cleanNodeGeometryNode, false);
210     auto globalFrameRect = cleanNodeGeometryNode->GetFrameRect();
211     globalFrameRect.SetOffset(cleanNodeFrameNode->CalculateCachedTransformRelativeOffset(nanoTimestamp));
212     return globalFrameRect.IsInRegion(point);
213 }
214 
IsNeedInterceptedTouchEventForWeb(float x,float y)215 bool StylusDetectorMgr::IsNeedInterceptedTouchEventForWeb(float x, float y)
216 {
217     if (!IsEnable()) {
218         TAG_LOGI(AceLogTag::ACE_STYLUS, "IsNeedInterceptedTouchEventForWeb Stylus service is not enable");
219         return false;
220     }
221 
222     auto container = Container::Current();
223     CHECK_NULL_RETURN(container, false);
224     auto bundleName = container->GetBundleName();
225     NotifyInfo info;
226     info.componentId = -1;
227     info.x = x;
228     info.y = y;
229     info.bundleName = bundleName;
230     auto stylusDetectorCallback = std::make_shared<StylusDetectorCallBack>();
231     nodeId_ = 0;
232     sInd_ = -1;
233     eInd_ = -1;
234     showMenu_ = false;
235     isRegistered_ = RegisterStylusInteractionListener(bundleName, stylusDetectorCallback);
236     return Notify(info);
237 }
238 } // namespace OHOS::Ace