1 /*
2 * Copyright (c) 2022 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 #include "tree_manager.h"
16
17 #include "accessibility_ui_test_ability.h"
18 #include "component_manager.h"
19 #include "touch_input.h"
20
21 namespace OHOS {
22 namespace WuKong {
23 namespace {
24 class ComponentManagerMonitor : public ComponentManagerListener {
OnStatusUpdated(ComponentStatus status)25 void OnStatusUpdated(ComponentStatus status) override
26 {
27 }
OnScreenUpdated()28 void OnScreenUpdated() override
29 {
30 }
OnPermissionScreenShown()31 void OnPermissionScreenShown() override
32 {
33 }
34 };
35 } // namespace
36
TreeManager()37 TreeManager::TreeManager() : isUpdateComponentFinished_(false), isNewAbility_(false)
38 {
39 }
~TreeManager()40 TreeManager::~TreeManager()
41 {
42 TRACK_LOG_STD();
43 }
44
RecursGetChildElementInfo(const std::shared_ptr<OHOS::Accessibility::AccessibilityElementInfo> & parent,const std::shared_ptr<ComponentTree> & componentParent)45 bool TreeManager::RecursGetChildElementInfo(
46 const std::shared_ptr<OHOS::Accessibility::AccessibilityElementInfo>& parent,
47 const std::shared_ptr<ComponentTree>& componentParent)
48 {
49 auto res = Accessibility::RET_OK;
50 if (componentParent == nullptr) {
51 ERROR_LOG("tree parent is null!");
52 return false;
53 }
54 for (int32_t i = 0; i < parent->GetChildCount(); i++) {
55 auto elementChild = std::make_shared<OHOS::Accessibility::AccessibilityElementInfo>();
56 // Get child AccessibilityElementInfo from Accessibility.
57 res = OHOS::Accessibility::AccessibilityUITestAbility::GetInstance()->GetChildElementInfo(
58 i, *(parent.get()), *(elementChild.get()));
59 if (res != Accessibility::RET_OK) {
60 ERROR_LOG("GetChildElementInfo failed!");
61 return false;
62 }
63 TRACK_LOG_STR("GetChildElementInfo child ID (%d), child count (%d), Type (%s)",
64 elementChild->GetAccessibilityId(), elementChild->GetChildCount(),
65 elementChild->GetComponentType().c_str());
66
67 // save child AccessibilityElementInfo.
68 newElementInfoList_.push_back(elementChild);
69
70 // Generate ComponentTree.
71 std::shared_ptr<ComponentTree> componentChild = std::make_shared<ComponentTree>();
72 componentChild->SetIndex(newElementInfoList_.size() - 1);
73 // set ComponentTree parent
74 componentChild->SetParent(componentParent);
75 componentParent->AddChild(componentChild);
76 // Recurs get child AccessibilityElementInfo.
77 auto result = RecursGetChildElementInfo(elementChild, componentChild);
78 if (!result) {
79 return false;
80 }
81 }
82
83 componentParent->SetNodeId();
84 return res == Accessibility::RET_OK ? true : false;
85 }
RecursComponent(const std::shared_ptr<ComponentTree> & componentTree)86 bool TreeManager::RecursComponent(const std::shared_ptr<ComponentTree>& componentTree)
87 {
88 if (LOG_LEVEL_TRACK < WuKongLogger::GetInstance()->GetLogLevel()) {
89 return false;
90 }
91 if (componentTree == nullptr) {
92 return false;
93 }
94 auto children = componentTree->GetChildren();
95
96 auto elementInfo = GetNewElementInfoList(componentTree->GetIndex());
97 if (elementInfo != nullptr) {
98 TRACK_LOG_STR("Component Node Indxe:(%d), NodeId:(0x%016llX), input count:(%u), Element ID(%d), Type(%s)",
99 componentTree->GetIndex(), componentTree->GetNodeId(), componentTree->GetInputCount(),
100 elementInfo->GetAccessibilityId(), elementInfo->GetComponentType().c_str());
101 } else {
102 TRACK_LOG_STR("Component Node Indxe:(%d), NodeId:(0x%016llX), input count:(%u)", componentTree->GetIndex(),
103 componentTree->GetNodeId(), componentTree->GetInputCount());
104 }
105
106 for (auto tree : children) {
107 RecursComponent(std::static_pointer_cast<ComponentTree>(tree));
108 }
109 return true;
110 }
111
FindAbility(const std::shared_ptr<AbilityTree> & abilityNode)112 bool TreeManager::FindAbility(const std::shared_ptr<AbilityTree>& abilityNode)
113 {
114 if (newAbilityNode_->IsEqual(abilityNode)) {
115 DEBUG_LOG("Found same old ability");
116 currentAbilityNode_ = abilityNode;
117 return true;
118 } else {
119 for (auto child : abilityNode->GetChildren()) {
120 if (FindAbility(std::static_pointer_cast<AbilityTree>(child))) {
121 return true;
122 }
123 }
124 return false;
125 }
126 }
127
MakeAndCheckNewAbility()128 ErrCode TreeManager::MakeAndCheckNewAbility()
129 {
130 // Check ability state
131 newAbilityNode_ = std::make_shared<AbilityTree>();
132 newAbilityNode_->SetNodeId();
133 // check same abiliby as current ability
134 if (currentAbilityNode_ != nullptr) {
135 if (newAbilityNode_->IsEqual(currentAbilityNode_)) {
136 DEBUG_LOG("Ability not change");
137 return OHOS::ERR_OK;
138 }
139 } else if (currentAbilityNode_ == nullptr) {
140 return OHOS::ERR_INVALID_OPERATION;
141 }
142
143 DEBUG_LOG("Ability changed");
144 bool isNewBundle = true;
145 bool isNewAbility = false;
146 for (auto abilityTree : abilityTreeList_) {
147 TRACK_LOG_STR("NewAbility Bundle: (%s), Bundle List Name: (%s)", newAbilityNode_->bundleName_.c_str(),
148 abilityTree->bundleName_.c_str());
149 // check is new bundle.
150 if (abilityTree->bundleName_ == newAbilityNode_->bundleName_) {
151 isNewBundle = false;
152 // find new ability in ability tree.
153 if (!FindAbility(abilityTree)) {
154 currentAbilityNode_->AddChild(newAbilityNode_);
155 newAbilityNode_->SetParent(currentAbilityNode_);
156 currentAbilityNode_ = newAbilityNode_;
157 isNewAbility = true;
158 }
159 }
160 }
161 // save new bundle for launch multi-application
162 if (isNewBundle) {
163 InitContainer();
164 abilityTreeList_.push_back(newAbilityNode_);
165 currentAbilityNode_ = newAbilityNode_;
166 }
167 // clear current screen data when it is new ability.
168 if (isNewBundle || isNewAbility) {
169 currentComponentNode_ = nullptr;
170 currentPageNode_ = nullptr;
171 isNewAbility_ = true;
172 } else {
173 // set old screen to current screen data when it is old ability.
174 if (pageTreeList_.find(currentAbilityNode_->GetIndex()) == pageTreeList_.end()) {
175 ERROR_LOG_STR("ability index (%d) more than pageTreeList count (%d)", currentAbilityNode_->GetIndex(),
176 pageTreeList_.size());
177 return OHOS::ERR_INVALID_OPERATION;
178 }
179 currentPageNode_ = pageTreeList_[currentAbilityNode_->GetIndex()];
180 if (componentTreeList_.find(currentPageNode_->GetIndex()) == componentTreeList_.end()) {
181 ERROR_LOG_STR("page index (%d) more than componentTreeList count (%d)", currentPageNode_->GetIndex(),
182 componentTreeList_.size());
183 return OHOS::ERR_INVALID_OPERATION;
184 }
185 currentComponentNode_ = componentTreeList_[currentPageNode_->GetIndex()];
186 }
187 return OHOS::ERR_OK;
188 }
189
UpdateComponentInfo()190 ErrCode TreeManager::UpdateComponentInfo()
191 {
192 TRACK_LOG_STD();
193 ErrCode result = OHOS::ERR_OK;
194 // start update component tree.
195 isUpdateComponentFinished_ = false;
196 isNewAbility_ = false;
197 newElementInfoList_.clear();
198 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
199 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
200 newComponentNode_.use_count(), newComponentNode_.unique());
201 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
202 currentComponentNode_.use_count(), currentComponentNode_.unique());
203 }
204 // Generate Ability Node
205 MakeAndCheckNewAbility();
206
207 auto root = std::make_shared<OHOS::Accessibility::AccessibilityElementInfo>();
208 auto aacPtr = OHOS::Accessibility::AccessibilityUITestAbility::GetInstance();
209
210 // Get root AccessibilityElementInfo from Accessibility,
211 auto bResult = aacPtr->GetRoot(*(root.get()));
212 if (bResult != Accessibility::RET_OK) {
213 ERROR_LOG("Accessibility Ability get root element info failed!");
214 return OHOS::ERR_INVALID_OPERATION;
215 } else {
216 // save root AccessibilityElementInfo.
217 newElementInfoList_.push_back(root);
218 uint32_t count = newElementInfoList_.size();
219 DEBUG_LOG_STR("New Element Info count (%d), Type (%s)", root->GetChildCount(),
220 root->GetComponentType().c_str());
221
222 // Generate new ComponentTree.
223 newComponentNode_ = std::make_shared<ComponentTree>();
224 newComponentNode_->SetIndex(count - 1);
225
226 // Recurs get all children AccessibilityElementInfo.
227 auto cResult = RecursGetChildElementInfo(root, newComponentNode_);
228 if (!cResult) {
229 return OHOS::ERR_INVALID_OPERATION;
230 }
231 RecursComponent(newComponentNode_);
232 }
233 // Generate Page Node
234 newPageNode_ = std::make_shared<PageTree>();
235 newPageNode_->SetNodeId();
236
237 TRACK_LOG_END();
238 return result;
239 }
240
SetInputcomponentIndex(int actionType,uint32_t index)241 void TreeManager::SetInputcomponentIndex(int actionType, uint32_t index)
242 {
243 DEBUG_LOG_STR("Input: (%d), Input Type: (%d)", index, actionType);
244 if (currentPageNode_ == nullptr) {
245 ERROR_LOG("current page is null!");
246 return;
247 }
248
249 // component input count statistics
250 if (index != INVALIDED_INPUT_INDEX) {
251 if (inputComponentList_.size() <= 0) {
252 ERROR_LOG("input component list is null!");
253 return;
254 }
255 if (index >= inputComponentList_.size()) {
256 ERROR_LOG("index argument is invalided");
257 return;
258 }
259 inputComponentList_[index]->AddInputCount();
260 inputComponentList_[index]->AddTypeInputCount(actionType);
261 DEBUG_LOG_STR("inputComponent: GetNodeId (0x%016llX)", inputComponentList_[index]->GetNodeId());
262 } else {
263 if (inputComponent_ == nullptr) {
264 ERROR_LOG("inputComponent_ is nullptr");
265 return;
266 }
267 inputComponent_->AddInputCount();
268 inputComponent_->AddTypeInputCount(actionType);
269 DEBUG_LOG_STR("inputComponent: GetNodeId (0x%016llX)", inputComponent_->GetNodeId());
270 }
271 RecursComponent(currentComponentNode_);
272 // ability input count statistics
273 currentAbilityNode_->AddInputCount();
274
275 // page input count statistics
276 currentPageNode_->AddInputCount();
277 if (index != INVALIDED_INPUT_INDEX) {
278 currentPageNode_->SetCurrentComponentNode(inputComponentList_[index]);
279 } else {
280 currentPageNode_->SetCurrentComponentNode(inputComponent_);
281 }
282 }
283
SetActiveComponent(const std::vector<std::shared_ptr<ComponentTree>> & inputComponentList)284 void TreeManager::SetActiveComponent(const std::vector<std::shared_ptr<ComponentTree>>& inputComponentList)
285 {
286 DEBUG_LOG_STR("Active component list: size (%d)", inputComponentList.size());
287 // Clear old input data
288 inputElementInfoList_.clear();
289 inputComponentList_.clear();
290 uint32_t count = elementInfoList_.size();
291 for (auto componentNode : inputComponentList) {
292 if (count > componentNode->GetIndex()) {
293 // Save input pointer list
294 inputElementInfoList_.push_back(elementInfoList_[componentNode->GetIndex()]);
295 inputComponentList_.push_back(componentNode);
296 } else {
297 ERROR_LOG_STR("component index (%d) more than elementInfoList count (%d)", componentNode->GetIndex(),
298 count);
299 break;
300 }
301 }
302 }
303
SetActiveComponent(const std::shared_ptr<ComponentTree> & inputComponent)304 void TreeManager::SetActiveComponent(const std::shared_ptr<ComponentTree>& inputComponent)
305 {
306 // Save one input pointer.
307 if (inputComponent == nullptr) {
308 ERROR_LOG("argument failed inputComponent is nullptr");
309 return;
310 }
311 DEBUG_LOG_STR("Active component: GetNodeId (0x%016llX)", inputComponent->GetNodeId());
312 inputComponent_ = inputComponent;
313 if (elementInfoList_.size() > inputComponent->GetIndex()) {
314 inputElementInfo_ = elementInfoList_[inputComponent->GetIndex()];
315 } else {
316 ERROR_LOG_STR("component index (%d) more than elementInfoList count (%d)", inputComponent->GetIndex(),
317 elementInfoList_.size());
318 }
319 }
320
AddPage()321 bool TreeManager::AddPage()
322 {
323 TRACK_LOG_STD();
324 // save new component tree, and change current conmponent tree.
325 UpdateCurrentPage(true);
326
327 // page tree growth
328 if (newPageNode_ == nullptr) {
329 ERROR_LOG("the new Page Node is null");
330 return false;
331 }
332
333 uint32_t key = componentTreeList_.size();
334 componentTreeList_[key] = currentComponentNode_;
335 newPageNode_->SetIndex(key);
336 if (!isNewAbility_) {
337 if (currentPageNode_ != nullptr) {
338 newPageNode_->SetParent(currentPageNode_);
339 currentPageNode_->AddChild(newPageNode_);
340 }
341 } else {
342 // ability tree growth
343 key = pageTreeList_.size();
344 pageTreeList_[key] = newPageNode_;
345 currentAbilityNode_->SetIndex(key);
346 }
347 currentPageNode_ = newPageNode_;
348 currentAbilityNode_->AddAllComponentCount(currentPageNode_->GetAllComponentCount());
349
350 TRACK_LOG_END();
351 return SamePage();
352 }
353
SamePage()354 bool TreeManager::SamePage()
355 {
356 TRACK_LOG_STD();
357 isUpdateComponentFinished_ = true;
358 newElementInfoList_.clear();
359 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
360 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
361 newComponentNode_.use_count(), newComponentNode_.unique());
362 }
363 newComponentNode_.reset();
364 newPageNode_.reset();
365 newAbilityNode_.reset();
366 TRACK_LOG_END();
367 return true;
368 }
369
UpdatePage(int layer,uint32_t index)370 bool TreeManager::UpdatePage(int layer, uint32_t index)
371 {
372 TRACK_LOG_STD();
373 DEBUG_LOG_STR("UpdatePage: layer (%d), index (%u)", layer, index);
374 std::shared_ptr<WuKongTree> pageNode = currentPageNode_;
375 if (layer > 0) {
376 if (pageNode->GetChildren().size() <= index) {
377 ERROR_LOG_STR("UpdatePage child index (%d) more than elementInfoList_ GetChildren() size (%u)", index,
378 pageNode->GetChildren().size());
379 return false;
380 }
381 currentPageNode_ = std::static_pointer_cast<PageTree>(pageNode->GetChildren()[index]);
382 } else {
383 while (layer < 0) {
384 layer++;
385 pageNode = pageNode->GetParent();
386 if (pageNode == nullptr) {
387 ERROR_LOG_STR("UpdatePage back layer (%d) more than currentPageNode_ parent (%p)", layer,
388 pageNode.get());
389 return false;
390 }
391 }
392 currentPageNode_ = std::static_pointer_cast<PageTree>(pageNode);
393 }
394
395 if (componentTreeList_.find(currentPageNode_->GetIndex()) == componentTreeList_.end()) {
396 ERROR_LOG_STR("currentPageNode_ index (%u) more than componentTreeList_ size (%u)",
397 currentPageNode_->GetIndex(), componentTreeList_.size());
398 return false;
399 }
400
401 TRACK_LOG_STR("currentPageNode_->GetIndex(): %d", currentPageNode_->GetIndex());
402 currentComponentNode_ = componentTreeList_[currentPageNode_->GetIndex()];
403
404 if (!UpdateCurrentPage()) {
405 return false;
406 }
407 TRACK_LOG_END();
408 return SamePage();
409 }
410
RemovePage()411 bool TreeManager::RemovePage()
412 {
413 TRACK_LOG_STD();
414 uint32_t componentNodeIndex = currentPageNode_->GetIndex();
415 uint32_t componentTreeListCount = componentTreeList_.size();
416 if (componentNodeIndex >= componentTreeListCount) {
417 ERROR_LOG_STR("currentPageNode index (%u) more than componentTreeList_ size (%u)", componentNodeIndex,
418 componentTreeListCount);
419 return false;
420 }
421 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
422 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)",
423 componentTreeList_[componentNodeIndex].get(), componentTreeList_[componentNodeIndex].use_count(),
424 componentTreeList_[componentNodeIndex].unique());
425 }
426 auto componentNode = componentTreeList_[componentNodeIndex];
427 if (componentNode == nullptr) {
428 ERROR_LOG("componentNode point is nullptr of currentPageNode");
429 return false;
430 }
431 uint32_t startIndex = componentNode->GetIndex();
432 componentTreeList_[componentNodeIndex].reset();
433 uint32_t endIndex = startIndex + currentPageNode_->count_ - 1;
434 uint32_t elementInfoListCount = elementInfoList_.size();
435 DEBUG_LOG_STR(
436 "currentPageNode StartIndex (%u) EndIndex (%u) componentTreeList_ size (%u) elementInfoList_ size (%u)",
437 startIndex, endIndex, componentTreeListCount, elementInfoListCount);
438 if (startIndex >= elementInfoListCount || endIndex >= elementInfoListCount) {
439 ERROR_LOG_STR("currentPageNode StartIndex (%u) EndIndex (%u) more than elementInfoList_ size (%u)", startIndex,
440 endIndex, elementInfoListCount);
441 return false;
442 }
443 elementInfoList_.erase(elementInfoList_.begin() + startIndex, elementInfoList_.begin() + endIndex);
444 TRACK_LOG_END();
445 return true;
446 }
447
UpdateCurrentPage(bool isAdd)448 bool TreeManager::UpdateCurrentPage(bool isAdd)
449 {
450 TRACK_LOG_STD();
451 uint32_t count = elementInfoList_.size();
452 DEBUG_LOG_STR("elementInfoList_: %d", count);
453 for (auto elementInfo : newElementInfoList_) {
454 elementInfoList_.push_back(elementInfo);
455 }
456 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
457 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
458 newComponentNode_.use_count(), newComponentNode_.unique());
459 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
460 currentComponentNode_.use_count(), currentComponentNode_.unique());
461 }
462 // update component tree index
463 newComponentNode_->RecursUpdateNodeIndex(count);
464 if (!isAdd) {
465 newComponentNode_->RecursUpdateInfo(currentComponentNode_);
466 }
467 // set current sreen componentNode to new screen
468 currentComponentNode_ = newComponentNode_;
469 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
470 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
471 currentComponentNode_.use_count(), currentComponentNode_.unique());
472 if (currentPageNode_ != nullptr) {
473 DEBUG_LOG_STR("CompoentNode shared (%p) index (%u) count = (%ld) unique (%d)",
474 componentTreeList_[currentPageNode_->GetIndex()].get(), currentPageNode_->GetIndex(),
475 componentTreeList_[currentPageNode_->GetIndex()].use_count(),
476 componentTreeList_[currentPageNode_->GetIndex()].unique());
477 }
478 }
479
480 if (!isAdd) {
481 componentTreeList_[currentPageNode_->GetIndex()] = currentComponentNode_;
482 currentAbilityNode_->allComponentCount_ -= currentPageNode_->GetAllComponentCount();
483 currentAbilityNode_->allComponentCount_ += newPageNode_->GetAllComponentCount();
484 currentPageNode_->nodeId_ = newPageNode_->nodeId_;
485 currentPageNode_->allComponentCount_ = newPageNode_->allComponentCount_;
486 }
487 TRACK_LOG_END();
488 return true;
489 }
490 } // namespace WuKong
491 } // namespace OHOS
492