1 /*
2 * Copyright (c) 2022-2025 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/base/simplified_inspector.h"
17
18 #include <memory>
19
20 #include "core/components/scroll/scroll_controller_base.h"
21 #if !defined(CROSS_PLATFORM) && defined(WEB_SUPPORTED)
22 #include "core/components_ng/pattern/web/web_pattern.h"
23 #endif
24 #include "core/common/recorder/inspector_tree_collector.h"
25 #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
26 #include "core/components_ng/pattern/stage/page_pattern.h"
27 #include "core/components_ng/pattern/text/span_node.h"
28 #include "core/components_v2/inspector/inspector_constants.h"
29 #include "interfaces/inner_api/ace/ui_event_observer.h"
30
31 namespace OHOS::Ace::NG {
32 namespace {
33 const char INSPECTOR_TYPE[] = "$type";
34 const char INSPECTOR_ID[] = "$ID";
35 const char INSPECTOR_RECT[] = "$rect";
36 const char INSPECTOR_ATTRS[] = "$attrs";
37 const char INSPECTOR_ROOT[] = "root";
38 const char INSPECTOR_WIDTH[] = "width";
39 const char INSPECTOR_HEIGHT[] = "height";
40 const char INSPECTOR_RESOLUTION[] = "$resolution";
41 const char INSPECTOR_CHILDREN[] = "$children";
42 const char INSPECTOR_BUNDLE[] = "bundleName";
43 const char INSPECTOR_ABILITY[] = "ability";
44 const char INSPECTOR_PAGE_URL[] = "pageUrl";
45 const char INSPECTOR_NAV_DST_NAME[] = "navDstName";
46 const char INSPECTOR_ATTR_ID[] = "id";
47 const char INSPECTOR_LABEL[] = "label";
48 const char INSPECTOR_CONTENT[] = "content";
49 const char INSPECTOR_ENABLED[] = "enabled";
50 const char INSPECTOR_OPACITY[] = "opacity";
51 const char INSPECTOR_ZINDEX[] = "zindex";
52 const char INSPECTOR_VISIBILITY[] = "visibility";
53 const char INSPECTOR_CHILDREN_COUNT[] = "$childrenCount";
54
55 constexpr char KEY_CODE[] = "code";
56 constexpr int32_t ERR_OK = 0;
57 constexpr int32_t ERR_INVALID_PARAM = 101;
58 constexpr int32_t ERR_NOT_FOUND_TARGET_NODE = 102;
59 constexpr int32_t ERR_NOT_FOUND_SCROLLABLE_NODE = 103;
60
61 enum class TargetType {
62 UNKNOWN = 0,
63 NODE,
64 WEB,
65 ENUM_END,
66 };
67
68 struct ScrollCommand {
69 TargetType type { TargetType::UNKNOWN };
70 int32_t nodeId { 0 };
71 float scrollOffset { 0.0 };
72 ScrollAlign scrollAlign { ScrollAlign::NONE };
73 std::string webContentJs;
74 };
75
ParseCommandParam(const std::string & commandParams,ScrollCommand & command)76 bool ParseCommandParam(const std::string& commandParams, ScrollCommand& command)
77 {
78 auto jsonObj = JsonUtil::ParseJsonString(commandParams);
79 if (!jsonObj || !jsonObj->IsValid() || !jsonObj->IsObject()) {
80 return false;
81 }
82 auto action = jsonObj->GetString("action");
83 if (action != "scroll") {
84 return false;
85 }
86 auto type = jsonObj->GetInt("targetType", 0);
87 if (type >= static_cast<int32_t>(TargetType::UNKNOWN) && type < static_cast<int32_t>(TargetType::ENUM_END)) {
88 command.type = static_cast<TargetType>(type);
89 }
90 command.nodeId = jsonObj->GetInt("targetId", 0);
91 command.scrollOffset = static_cast<float>(jsonObj->GetDouble("scrollOffset", 0.0));
92 auto align = jsonObj->GetInt("scrollAlign", 0);
93 if (type >= static_cast<int32_t>(ScrollAlign::START) && type <= static_cast<int32_t>(ScrollAlign::NONE)) {
94 command.scrollAlign = static_cast<ScrollAlign>(align);
95 }
96 command.webContentJs = jsonObj->GetString("webContentJs");
97 return true;
98 }
99
GetNodeById(const RefPtr<FrameNode> & root,int32_t id)100 RefPtr<UINode> GetNodeById(const RefPtr<FrameNode>& root, int32_t id)
101 {
102 std::queue<RefPtr<UINode>> elements;
103 elements.push(root);
104 RefPtr<UINode> inspectorElement;
105 while (!elements.empty()) {
106 auto current = elements.front();
107 elements.pop();
108 if (current == nullptr) {
109 continue;
110 }
111 if (id == current->GetId()) {
112 return current;
113 }
114
115 const auto& children = current->GetChildrenForInspector(true);
116 for (const auto& child : children) {
117 elements.push(child);
118 }
119 }
120 return nullptr;
121 }
122
IsScrollable(const RefPtr<NG::FrameNode> & frameNode)123 bool IsScrollable(const RefPtr<NG::FrameNode>& frameNode)
124 {
125 CHECK_NULL_RETURN(frameNode, false);
126 auto tag = frameNode->GetTag();
127 if (tag == V2::LIST_ETS_TAG || tag == V2::SCROLL_ETS_TAG || tag == V2::WATERFLOW_ETS_TAG ||
128 tag == V2::GRID_ETS_TAG) {
129 auto pattern = frameNode->GetPattern<ScrollablePattern>();
130 CHECK_NULL_RETURN(pattern, false);
131 return pattern->IsScrollable();
132 }
133 return false;
134 }
135
FindParentScrollable(const RefPtr<FrameNode> & child)136 RefPtr<FrameNode> FindParentScrollable(const RefPtr<FrameNode>& child)
137 {
138 auto parentFrameNode = child->GetAncestorNodeOfFrame(true);
139 while (parentFrameNode) {
140 if (IsScrollable(parentFrameNode)) {
141 return parentFrameNode;
142 }
143 parentFrameNode = parentFrameNode->GetAncestorNodeOfFrame(true);
144 }
145 return nullptr;
146 }
147
ScrollToTarget(const ScrollCommand & command,const RefPtr<NG::FrameNode> & pageRootNode)148 int32_t ScrollToTarget(const ScrollCommand& command, const RefPtr<NG::FrameNode>& pageRootNode)
149 {
150 CHECK_NULL_RETURN(pageRootNode, ERR_NOT_FOUND_TARGET_NODE);
151 auto targetNode = GetNodeById(pageRootNode, command.nodeId);
152 CHECK_NULL_RETURN(targetNode, ERR_NOT_FOUND_TARGET_NODE);
153 auto target = AceType::DynamicCast<FrameNode>(targetNode);
154 CHECK_NULL_RETURN(target, ERR_NOT_FOUND_TARGET_NODE);
155 auto scrollable = FindParentScrollable(target);
156 CHECK_NULL_RETURN(scrollable, ERR_NOT_FOUND_SCROLLABLE_NODE);
157 ScrollablePattern::ScrollToTarget(scrollable, target, command.scrollOffset, command.scrollAlign);
158 return ERR_OK;
159 }
160 } // namespace
161
TestScrollToTarget(const std::vector<std::string> & params,const RefPtr<FrameNode> & pageRootNode)162 void SimplifiedInspector::TestScrollToTarget(
163 const std::vector<std::string>& params, const RefPtr<FrameNode>& pageRootNode)
164 {
165 CHECK_NULL_VOID(pageRootNode);
166 // -element -lastpage ${nodeid} ${offset} ${align}
167 const int32_t PARAM_NODE_ID = 2;
168 const int32_t PARAM_OFFSET = 3;
169 const int32_t PARAM_ALIGN = 4;
170 auto id = StringUtils::StringToInt(params[PARAM_NODE_ID]);
171 auto offset = StringUtils::StringToFloat(params[PARAM_OFFSET]);
172 auto align = StringUtils::StringToInt(params[PARAM_ALIGN]);
173 ScrollCommand command { TargetType::NODE, id, offset, static_cast<ScrollAlign>(align) };
174 ScrollToTarget(command, pageRootNode);
175 }
176
SimplifiedInspector(int32_t containerId,const TreeParams & params)177 SimplifiedInspector::SimplifiedInspector(int32_t containerId, const TreeParams& params)
178 : containerId_(containerId), params_(params), inspectorCfg_({ params.isContentOnly, !params.enableBackground }),
179 isBackground_(params.enableBackground)
180 {}
181
SimplifiedInspector(int32_t containerId,const UICommandParams & params)182 SimplifiedInspector::SimplifiedInspector(int32_t containerId, const UICommandParams& params)
183 : containerId_(containerId), commandParams_(params)
184 {}
185
GetOverlayNode(const RefPtr<NG::UINode> & pageNode)186 RefPtr<NG::UINode> GetOverlayNode(const RefPtr<NG::UINode>& pageNode)
187 {
188 CHECK_NULL_RETURN(pageNode, nullptr);
189 auto stageNode = pageNode->GetParent();
190 CHECK_NULL_RETURN(stageNode, nullptr);
191 auto stageParent = stageNode->GetParent();
192 CHECK_NULL_RETURN(stageParent, nullptr);
193 auto overlayNode = stageParent->GetChildren().back();
194 if (overlayNode->GetTag() == "stage") {
195 return nullptr;
196 }
197 return overlayNode;
198 }
199
GetInspector()200 std::string SimplifiedInspector::GetInspector()
201 {
202 TAG_LOGD(AceLogTag::ACE_UIEVENT, "Inspector1:container %{public}d", containerId_);
203 auto jsonRoot = JsonUtil::Create(true);
204 RefPtr<FrameNode> pageRootNode;
205 auto success = GetInspectorStep1(jsonRoot, pageRootNode);
206 if (!success) {
207 return jsonRoot->ToString();
208 }
209 GetInspectorStep2(jsonRoot, pageRootNode);
210 return jsonRoot->ToString();
211 }
212
GetInspectorStep1(const std::unique_ptr<JsonValue> & jsonRoot,RefPtr<FrameNode> & pageRootNode)213 bool SimplifiedInspector::GetInspectorStep1(const std::unique_ptr<JsonValue>& jsonRoot, RefPtr<FrameNode>& pageRootNode)
214 {
215 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
216 auto context = NG::PipelineContext::GetContextByContainerId(containerId_);
217 CHECK_NULL_RETURN(context, false);
218 auto scale = context->GetViewScale();
219 auto rootHeight = context->GetRootHeight();
220 auto rootWidth = context->GetRootWidth();
221 deviceRect_.SetRect(0, 0, rootWidth * scale, rootHeight * scale);
222 jsonRoot->Put(INSPECTOR_WIDTH, std::to_string(rootWidth * scale).c_str());
223 jsonRoot->Put(INSPECTOR_HEIGHT, std::to_string(rootHeight * scale).c_str());
224 jsonRoot->Put(INSPECTOR_RESOLUTION, std::to_string(SystemProperties::GetResolution()).c_str());
225 jsonRoot->Put(INSPECTOR_NAV_DST_NAME, context->GetCurrentPageNameCallback().c_str());
226
227 CHECK_NULL_RETURN(context->GetStageManager(), false);
228 pageRootNode = context->GetStageManager()->GetLastPage();
229 return pageRootNode != nullptr;
230 }
231
GetInspectorStep2(const std::unique_ptr<JsonValue> & jsonRoot,const RefPtr<FrameNode> & pageRootNode)232 bool SimplifiedInspector::GetInspectorStep2(
233 const std::unique_ptr<JsonValue>& jsonRoot, const RefPtr<FrameNode>& pageRootNode)
234 {
235 auto pagePattern = pageRootNode->GetPattern<PagePattern>();
236 CHECK_NULL_RETURN(pagePattern, false);
237 auto pageInfo = pagePattern->GetPageInfo();
238 CHECK_NULL_RETURN(pageInfo, false);
239 jsonRoot->Put(INSPECTOR_BUNDLE, AceApplicationInfo::GetInstance().GetPackageName().c_str());
240 jsonRoot->Put(INSPECTOR_ABILITY, AceApplicationInfo::GetInstance().GetAbilityName().c_str());
241 jsonRoot->Put(INSPECTOR_PAGE_URL, pageInfo->GetPageUrl().c_str());
242
243 pageId_ = pageRootNode->GetPageId();
244 std::list<RefPtr<NG::UINode>> children;
245 for (const auto& item : pageRootNode->GetChildrenForInspector(params_.enableCacheNode)) {
246 GetFrameNodeChildren(item, children);
247 }
248 auto overlayNode = GetOverlayNode(pageRootNode);
249 if (overlayNode) {
250 GetFrameNodeChildren(overlayNode, children);
251 }
252 auto jsonNodeArray = JsonUtil::CreateArray(true);
253 size_ = children.size();
254 for (auto& uiNode : children) {
255 GetInspectorChildren(uiNode, jsonNodeArray, true);
256 }
257 if (jsonNodeArray->GetArraySize()) {
258 jsonRoot->PutRef(INSPECTOR_CHILDREN, std::move(jsonNodeArray));
259 }
260 jsonRoot->Put(INSPECTOR_CHILDREN_COUNT, size_);
261 return true;
262 }
263
GetFrameNodeChildren(const RefPtr<UINode> & uiNode,std::list<RefPtr<UINode>> & children)264 void SimplifiedInspector::GetFrameNodeChildren(const RefPtr<UINode>& uiNode, std::list<RefPtr<UINode>>& children)
265 {
266 CHECK_NULL_VOID(uiNode);
267 if (isBackground_) {
268 collector_->RetainNode(uiNode);
269 }
270 if (AceType::InstanceOf<NG::FrameNode>(uiNode) || AceType::InstanceOf<SpanNode>(uiNode) ||
271 AceType::InstanceOf<CustomNode>(uiNode)) {
272 if (uiNode->GetTag() == "page") {
273 if (uiNode->GetPageId() != pageId_) {
274 return;
275 }
276 } else if (uiNode->GetTag() != "stage") {
277 auto frameNode = AceType::DynamicCast<NG::FrameNode>(uiNode);
278 auto spanNode = AceType::DynamicCast<NG::SpanNode>(uiNode);
279 if ((frameNode && !frameNode->IsInternal()) || spanNode) {
280 children.emplace_back(uiNode);
281 return;
282 }
283 }
284 }
285 for (const auto& frameChild : uiNode->GetChildrenForInspector(params_.enableCacheNode)) {
286 GetFrameNodeChildren(frameChild, children);
287 }
288 }
289
GetInspectorChildren(const RefPtr<NG::UINode> & parent,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray,bool isActive)290 void SimplifiedInspector::GetInspectorChildren(
291 const RefPtr<NG::UINode>& parent, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray, bool isActive)
292 {
293 // Span is a special case in Inspector since span inherits from UINode
294 if (AceType::InstanceOf<SpanNode>(parent)) {
295 size_ += 1;
296 GetSpanInspector(parent, jsonNodeArray);
297 return;
298 }
299 auto jsonNode = JsonUtil::Create(true);
300 auto node = AceType::DynamicCast<FrameNode>(parent);
301 CHECK_NULL_VOID(node);
302 auto active = isActive && node->IsActive();
303 if (!isActive && !params_.enableAllNodes) {
304 return;
305 }
306 auto lp = node->GetLayoutProperty();
307 CHECK_NULL_VOID(lp);
308 bool isVisible = lp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE;
309 if (!isVisible && !params_.enableAllNodes) {
310 return;
311 }
312 jsonNode->Put(INSPECTOR_ID, node->GetId());
313 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
314 RectF rect;
315 if (!CheckNodeRect(node, rect, params_.isVisibleOnly)) {
316 return;
317 }
318 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
319 size_ += 1;
320 GetWebContentIfNeed(node);
321 FillInspectorAttrs(parent, jsonNode);
322 std::list<RefPtr<NG::UINode>> children;
323 for (const auto& item : parent->GetChildrenForInspector(params_.enableCacheNode)) {
324 GetFrameNodeChildren(item, children);
325 }
326 auto jsonChildrenArray = JsonUtil::CreateArray(true);
327 for (auto uiNode : children) {
328 GetInspectorChildren(uiNode, jsonChildrenArray, active);
329 }
330 if (jsonChildrenArray->GetArraySize()) {
331 jsonNode->PutRef(INSPECTOR_CHILDREN, std::move(jsonChildrenArray));
332 }
333 jsonNodeArray->PutRef(std::move(jsonNode));
334 }
335
GetSpanInspector(const RefPtr<UINode> & parent,std::unique_ptr<JsonValue> & jsonNodeArray)336 void SimplifiedInspector::GetSpanInspector(const RefPtr<UINode>& parent, std::unique_ptr<JsonValue>& jsonNodeArray)
337 {
338 // span rect follows parent text size
339 auto spanParentNode = parent->GetParent();
340 CHECK_NULL_VOID(spanParentNode);
341 auto node = AceType::DynamicCast<FrameNode>(spanParentNode);
342 CHECK_NULL_VOID(node);
343 auto jsonNode = JsonUtil::Create(true);
344
345 FillInspectorAttrs(parent, jsonNode);
346
347 jsonNode->Put(INSPECTOR_ID, parent->GetId());
348 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
349 RectF rect = node->GetTransformRectRelativeToWindow();
350 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
351 jsonNodeArray->PutRef(std::move(jsonNode));
352 }
353
FillInspectorAttrs(const RefPtr<UINode> & parent,std::unique_ptr<JsonValue> & jsonNode)354 void SimplifiedInspector::FillInspectorAttrs(const RefPtr<UINode>& parent, std::unique_ptr<JsonValue>& jsonNode)
355 {
356 if (params_.isNewVersion) {
357 auto tmpJson = JsonUtil::Create(true);
358 parent->ToTreeJson(tmpJson, inspectorCfg_);
359 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(tmpJson));
360 return;
361 }
362 auto tmpJson = JsonUtil::Create(true);
363 InspectorFilter filter;
364 parent->ToJsonValue(tmpJson, filter);
365 if (params_.enableFullAttrs) {
366 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(tmpJson));
367 return;
368 }
369 jsonNode->Put(INSPECTOR_ATTR_ID, tmpJson->GetString(INSPECTOR_ATTR_ID).c_str());
370
371 auto jsonObject = JsonUtil::Create(true);
372 if (tmpJson->Contains(INSPECTOR_LABEL)) {
373 jsonObject->Put(INSPECTOR_LABEL, tmpJson->GetString(INSPECTOR_LABEL).c_str());
374 }
375 if (tmpJson->Contains(INSPECTOR_CONTENT)) {
376 jsonObject->Put(INSPECTOR_CONTENT, tmpJson->GetString(INSPECTOR_CONTENT).c_str());
377 }
378 jsonObject->Put(INSPECTOR_ENABLED, tmpJson->GetBool(INSPECTOR_ENABLED));
379 jsonObject->Put(INSPECTOR_OPACITY, tmpJson->GetDouble(INSPECTOR_OPACITY));
380 jsonObject->Put(INSPECTOR_ZINDEX, tmpJson->GetInt(INSPECTOR_ZINDEX));
381 jsonObject->Put(INSPECTOR_VISIBILITY, tmpJson->GetString(INSPECTOR_VISIBILITY).c_str());
382 jsonNode->PutRef(INSPECTOR_ATTRS, std::move(jsonObject));
383 }
384
CheckNodeRect(const RefPtr<FrameNode> & node,RectF & rect,bool isVisibleOnly)385 bool SimplifiedInspector::CheckNodeRect(const RefPtr<FrameNode>& node, RectF& rect, bool isVisibleOnly)
386 {
387 auto renderContext = node->GetRenderContext();
388 CHECK_NULL_RETURN(renderContext, false);
389 auto paintRect = renderContext->GetPaintRectWithoutTransform();
390 if (paintRect.IsEmpty()) {
391 return false;
392 }
393 rect = node->GetTransformRectRelativeToWindow();
394 if (isVisibleOnly && !deviceRect_.IsIntersectWith(rect)) {
395 return false;
396 }
397 return true;
398 }
399
GetWebContentIfNeed(const RefPtr<FrameNode> & node)400 void SimplifiedInspector::GetWebContentIfNeed(const RefPtr<FrameNode>& node)
401 {
402 if (!isAsync_ || !collector_) {
403 return;
404 }
405 if (node->GetTag() != V2::WEB_ETS_TAG) {
406 return;
407 }
408 #if !defined(CROSS_PLATFORM) && defined(WEB_SUPPORTED)
409 if (params_.enableWeb && params_.webAccessibility && !params_.enableBackground) {
410 auto pattern = node->GetPattern<WebPattern>();
411 CHECK_NULL_VOID(pattern);
412 if (!pattern->GetActiveStatus()) {
413 return;
414 }
415 auto lambda = [collector = collector_](std::shared_ptr<JsonValue>& jsonValue, int32_t webId) {
416 std::string key = "Web_" + std::to_string(webId);
417 collector->GetJson()->Put(key.c_str(), jsonValue->ToString().c_str());
418 collector->DecreaseTaskNum();
419 };
420 collector_->IncreaseTaskNum();
421 pattern->GetAllWebAccessibilityNodeInfos(std::move(lambda), node->GetId(), false);
422 return;
423 }
424 if (params_.enableWeb && !params_.webContentJs.empty()) {
425 auto pattern = node->GetPattern<WebPattern>();
426 CHECK_NULL_VOID(pattern);
427 if (!pattern->GetActiveStatus()) {
428 return;
429 }
430 auto lambda = [webId = node->GetId(), collector = collector_](const std::string& result) {
431 std::string key = "Web_" + std::to_string(webId);
432 collector->GetJson()->Put(key.c_str(), result.c_str());
433 collector->DecreaseTaskNum();
434 };
435 collector_->IncreaseTaskNum();
436 if (!pattern->RunJavascriptAsync(params_.webContentJs, std::move(lambda))) {
437 collector_->DecreaseTaskNum();
438 }
439 }
440 #endif
441 }
442
GetInspectorAsync(const std::shared_ptr<Recorder::InspectorTreeCollector> & collector)443 void SimplifiedInspector::GetInspectorAsync(const std::shared_ptr<Recorder::InspectorTreeCollector>& collector)
444 {
445 #if !defined(PREVIEW) && !defined(ACE_UNITTEST)
446 ContainerScope scope(Container::CurrentIdSafely());
447 CHECK_NULL_VOID(collector);
448 collector->CreateJson();
449 collector_ = collector;
450 isAsync_ = true;
451 TAG_LOGD(AceLogTag::ACE_UIEVENT, "Inspector2:container %{public}d", containerId_);
452 collector->IncreaseTaskNum();
453 auto& jsonRoot = collector->GetJson();
454 RefPtr<FrameNode> pageRootNode;
455 auto success = GetInspectorStep1(jsonRoot, pageRootNode);
456 if (!success) {
457 collector->DecreaseTaskNum();
458 return;
459 }
460 GetInspectorStep2(jsonRoot, pageRootNode);
461 collector->DecreaseTaskNum();
462 #endif
463 }
464
GetInspectorBackgroundAsync(const std::shared_ptr<Recorder::InspectorTreeCollector> & collector)465 void SimplifiedInspector::GetInspectorBackgroundAsync(
466 const std::shared_ptr<Recorder::InspectorTreeCollector>& collector)
467 {
468 ContainerScope scope(Container::CurrentIdSafely());
469 CHECK_NULL_VOID(collector);
470 collector->CreateJson();
471 collector_ = collector;
472 isAsync_ = true;
473 auto context = NG::PipelineContext::GetContextByContainerId(containerId_);
474 CHECK_NULL_VOID(context);
475 CHECK_NULL_VOID(context->GetStageManager());
476 auto pageRootNode = context->GetStageManager()->GetLastPage();
477 CHECK_NULL_VOID(pageRootNode);
478 pageId_ = pageRootNode->GetPageId();
479 auto pagePattern = pageRootNode->GetPattern<PagePattern>();
480 CHECK_NULL_VOID(pagePattern);
481 auto pageInfo = pagePattern->GetPageInfo();
482 CHECK_NULL_VOID(pageInfo);
483 auto pageUrl = pageInfo->GetPageUrl();
484 auto pageName = context->GetCurrentPageNameCallback();
485
486 auto treeNode = std::make_shared<SimplifiedInspectorTree>();
487 GetInspectorTreeNode(pageRootNode, treeNode);
488
489 CHECK_NULL_VOID(context->GetTaskExecutor());
490 collector->SetTaskExecutor(context->GetTaskExecutor());
491 collector->IncreaseTaskNum();
492 context->GetTaskExecutor()->PostTask(
493 [inspector = shared_from_this(), context, pageUrl, pageName, treeNode]() {
494 auto& jsonRoot = inspector->collector_->GetJson();
495 jsonRoot->Put(INSPECTOR_TYPE, INSPECTOR_ROOT);
496 auto scale = context->GetViewScale();
497 auto rootHeight = context->GetRootHeight();
498 auto rootWidth = context->GetRootWidth();
499 inspector->deviceRect_.SetRect(0, 0, rootWidth * scale, rootHeight * scale);
500 jsonRoot->Put(INSPECTOR_WIDTH, std::to_string(rootWidth * scale).c_str());
501 jsonRoot->Put(INSPECTOR_HEIGHT, std::to_string(rootHeight * scale).c_str());
502 jsonRoot->Put(INSPECTOR_RESOLUTION, std::to_string(SystemProperties::GetResolution()).c_str());
503 jsonRoot->Put(INSPECTOR_ABILITY, AceApplicationInfo::GetInstance().GetAbilityName().c_str());
504 jsonRoot->Put(INSPECTOR_BUNDLE, AceApplicationInfo::GetInstance().GetPackageName().c_str());
505 jsonRoot->Put(INSPECTOR_PAGE_URL, pageUrl.c_str());
506 jsonRoot->Put(INSPECTOR_NAV_DST_NAME, pageName.c_str());
507 auto jsonNodeArray = JsonUtil::CreateArray(true);
508 inspector->size_ = 1;
509 for (auto& subTreeNode : treeNode->children) {
510 inspector->GetInspectorChildrenBackground(subTreeNode, jsonNodeArray);
511 }
512 if (jsonNodeArray->GetArraySize()) {
513 jsonRoot->PutRef(INSPECTOR_CHILDREN, std::move(jsonNodeArray));
514 }
515 jsonRoot->Put(INSPECTOR_CHILDREN_COUNT, inspector->size_);
516 inspector->collector_->DecreaseTaskNum();
517 }, TaskExecutor::TaskType::BACKGROUND, "GetSimplifiedInspector");
518 }
519
GetInspectorTreeNode(const RefPtr<NG::UINode> & pageRootNode,std::shared_ptr<SimplifiedInspectorTree> & root)520 void SimplifiedInspector::GetInspectorTreeNode(
521 const RefPtr<NG::UINode>& pageRootNode, std::shared_ptr<SimplifiedInspectorTree>& root)
522 {
523 collector_->RetainNode(pageRootNode);
524 std::list<RefPtr<NG::UINode>> children;
525 for (const auto& item : pageRootNode->GetChildrenForInspector(params_.enableCacheNode)) {
526 GetFrameNodeChildren(item, children);
527 }
528 auto overlayNode2 = GetOverlayNode(pageRootNode);
529 if (overlayNode2) {
530 GetFrameNodeChildren(overlayNode2, children);
531 }
532 root->node = pageRootNode;
533 std::list<std::shared_ptr<SimplifiedInspectorTree>> childNodes;
534 for (const auto& uiNode : children) {
535 auto treeNode = std::make_shared<SimplifiedInspectorTree>();
536 GetInspectorTreeNodeChildren(uiNode, treeNode, true);
537 if (treeNode->node.Upgrade()) {
538 childNodes.emplace_back(treeNode);
539 }
540 }
541 root->children = std::move(childNodes);
542 }
543
GetInspectorTreeNodeChildren(const RefPtr<NG::UINode> & parent,std::shared_ptr<SimplifiedInspectorTree> & treeNode,bool isActive)544 void SimplifiedInspector::GetInspectorTreeNodeChildren(
545 const RefPtr<NG::UINode>& parent, std::shared_ptr<SimplifiedInspectorTree>& treeNode, bool isActive)
546 {
547 if (AceType::InstanceOf<SpanNode>(parent)) {
548 treeNode->node = parent;
549 return;
550 }
551 auto node = AceType::DynamicCast<FrameNode>(parent);
552 if (!node) {
553 return;
554 }
555 auto active = isActive && node->IsActive();
556 if (!isActive && !params_.enableAllNodes) {
557 return;
558 }
559 treeNode->node = parent;
560 std::list<RefPtr<NG::UINode>> children;
561 for (const auto& item : parent->GetChildrenForInspector(params_.enableCacheNode)) {
562 GetFrameNodeChildren(item, children);
563 }
564 for (auto uiNode : children) {
565 auto subTreeNode = std::make_shared<SimplifiedInspectorTree>();
566 GetInspectorTreeNodeChildren(uiNode, subTreeNode, active);
567 if (subTreeNode->node.Upgrade()) {
568 treeNode->children.emplace_back(subTreeNode);
569 }
570 }
571 }
572
GetInspectorChildrenBackground(const std::shared_ptr<SimplifiedInspectorTree> & treeNode,std::unique_ptr<OHOS::Ace::JsonValue> & jsonNodeArray)573 void SimplifiedInspector::GetInspectorChildrenBackground(
574 const std::shared_ptr<SimplifiedInspectorTree>& treeNode, std::unique_ptr<OHOS::Ace::JsonValue>& jsonNodeArray)
575 {
576 auto parent = treeNode->node.Upgrade();
577 CHECK_NULL_VOID(parent);
578 // Span is a special case in Inspector since span inherits from UINode
579 if (AceType::InstanceOf<SpanNode>(parent)) {
580 size_ += 1;
581 GetSpanInspector(parent, jsonNodeArray);
582 return;
583 }
584 auto jsonNode = JsonUtil::Create(true);
585 auto node = AceType::DynamicCast<FrameNode>(parent);
586 CHECK_NULL_VOID(node);
587 auto lp = node->GetLayoutProperty();
588 CHECK_NULL_VOID(lp);
589 bool isVisible = lp->GetVisibilityValue(VisibleType::VISIBLE) == VisibleType::VISIBLE;
590 if (!isVisible && !params_.enableAllNodes) {
591 return;
592 }
593 jsonNode->Put(INSPECTOR_ID, node->GetId());
594 jsonNode->Put(INSPECTOR_TYPE, parent->GetTag().c_str());
595 RectF rect;
596 if (!CheckNodeRect(node, rect, params_.isVisibleOnly)) {
597 return;
598 }
599 jsonNode->Put(INSPECTOR_RECT, rect.ToBounds().c_str());
600 size_ += 1;
601 GetWebContentIfNeed(node);
602 FillInspectorAttrs(parent, jsonNode);
603 std::list<RefPtr<NG::UINode>> children;
604 for (const auto& item : parent->GetChildrenForInspector(params_.enableCacheNode)) {
605 GetFrameNodeChildren(item, children);
606 }
607 auto jsonChildrenArray = JsonUtil::CreateArray(true);
608 for (auto subTreeNode : treeNode->children) {
609 GetInspectorChildrenBackground(subTreeNode, jsonChildrenArray);
610 }
611 if (jsonChildrenArray->GetArraySize()) {
612 jsonNode->PutRef(INSPECTOR_CHILDREN, std::move(jsonChildrenArray));
613 }
614 jsonNodeArray->PutRef(std::move(jsonNode));
615 }
616
ExecuteUICommand(const std::shared_ptr<Recorder::InspectorTreeCollector> & collector)617 void SimplifiedInspector::ExecuteUICommand(const std::shared_ptr<Recorder::InspectorTreeCollector>& collector)
618 {
619 CHECK_NULL_VOID(collector);
620 collector_ = collector;
621 ContainerScope scope(Container::CurrentIdSafely());
622 collector->CreateJson();
623 collector->IncreaseTaskNum();
624 ScrollCommand command;
625 if (!ParseCommandParam(commandParams_.params, command)) {
626 collector->GetJson()->Put(KEY_CODE, ERR_INVALID_PARAM);
627 collector->DecreaseTaskNum();
628 return;
629 }
630 auto context = PipelineContext::GetCurrentContext();
631 CHECK_NULL_VOID(context);
632 CHECK_NULL_VOID(context->GetStageManager());
633 auto pageRootNode = context->GetStageManager()->GetLastPage();
634 CHECK_NULL_VOID(pageRootNode);
635 if (command.type == TargetType::NODE) {
636 TAG_LOGD(AceLogTag::ACE_UIEVENT, "ExecuteUICommand node");
637 auto ret = ScrollToTarget(command, pageRootNode);
638 collector->GetJson()->Put(KEY_CODE, ret);
639 collector->DecreaseTaskNum();
640 } else if (command.type == TargetType::WEB) {
641 TAG_LOGD(AceLogTag::ACE_UIEVENT, "ExecuteUICommand web");
642 auto ret = ExecuteWebScrollCommand(pageRootNode, command.nodeId, command.webContentJs);
643 if (ret != ERR_OK) {
644 collector->GetJson()->Put(KEY_CODE, ret);
645 collector->DecreaseTaskNum();
646 }
647 }
648 }
649
ExecuteWebScrollCommand(const RefPtr<FrameNode> & rootNode,int32_t nodeId,const std::string & jsCode)650 int32_t SimplifiedInspector::ExecuteWebScrollCommand(
651 const RefPtr<FrameNode>& rootNode, int32_t nodeId, const std::string& jsCode)
652 {
653 #if !defined(CROSS_PLATFORM) && defined(WEB_SUPPORTED)
654 if (jsCode.empty()) {
655 return ERR_INVALID_PARAM;
656 }
657 auto targetNode = GetNodeById(rootNode, nodeId);
658 CHECK_NULL_RETURN(targetNode, ERR_NOT_FOUND_TARGET_NODE);
659 if (targetNode->GetTag() != V2::WEB_ETS_TAG) {
660 return ERR_NOT_FOUND_TARGET_NODE;
661 }
662 auto frameNode = AceType::DynamicCast<NG::FrameNode>(targetNode);
663 CHECK_NULL_RETURN(frameNode, ERR_NOT_FOUND_TARGET_NODE);
664 auto pattern = frameNode->GetPattern<WebPattern>();
665 CHECK_NULL_RETURN(pattern, ERR_NOT_FOUND_TARGET_NODE);
666 pattern->RunJavascriptAsync(jsCode, [collector = collector_](const std::string& result) {
667 collector->GetJson()->Put(KEY_CODE, ERR_OK);
668 collector->GetJson()->Put("ret", result.c_str());
669 collector->DecreaseTaskNum();
670 });
671 return ERR_OK;
672 #else
673 return ERR_NOT_FOUND_TARGET_NODE;
674 #endif
675 }
676 } // namespace OHOS::Ace::NG
677