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 abilityTreeList_.push_back(newAbilityNode_);
164 currentAbilityNode_ = newAbilityNode_;
165 }
166 // clear current screen data when it is new ability.
167 if (isNewBundle || isNewAbility) {
168 currentComponentNode_ = nullptr;
169 currentPageNode_ = nullptr;
170 isNewAbility_ = true;
171 } else {
172 // set old screen to current screen data when it is old ability.
173 if (pageTreeList_.find(currentAbilityNode_->GetIndex()) == pageTreeList_.end()) {
174 ERROR_LOG_STR("ability index (%d) more than pageTreeList count (%d)", currentAbilityNode_->GetIndex(),
175 pageTreeList_.size());
176 return OHOS::ERR_INVALID_OPERATION;
177 }
178 currentPageNode_ = pageTreeList_[currentAbilityNode_->GetIndex()];
179 if (componentTreeList_.find(currentPageNode_->GetIndex()) == componentTreeList_.end()) {
180 ERROR_LOG_STR("page index (%d) more than componentTreeList count (%d)", currentPageNode_->GetIndex(),
181 componentTreeList_.size());
182 return OHOS::ERR_INVALID_OPERATION;
183 }
184 currentComponentNode_ = componentTreeList_[currentPageNode_->GetIndex()];
185 }
186 return OHOS::ERR_OK;
187 }
188
UpdateComponentInfo()189 ErrCode TreeManager::UpdateComponentInfo()
190 {
191 TRACK_LOG_STD();
192 ErrCode result = OHOS::ERR_OK;
193 // start update component tree.
194 isUpdateComponentFinished_ = false;
195 isNewAbility_ = false;
196 newElementInfoList_.clear();
197 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
198 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
199 newComponentNode_.use_count(), newComponentNode_.unique());
200 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
201 currentComponentNode_.use_count(), currentComponentNode_.unique());
202 }
203 // Generate Ability Node
204 MakeAndCheckNewAbility();
205
206 auto root = std::make_shared<OHOS::Accessibility::AccessibilityElementInfo>();
207 auto aacPtr = OHOS::Accessibility::AccessibilityUITestAbility::GetInstance();
208
209 // Get root AccessibilityElementInfo from Accessibility,
210 auto bResult = aacPtr->GetRoot(*(root.get()));
211 if (bResult != Accessibility::RET_OK) {
212 ERROR_LOG("Accessibility Ability get root element info failed!");
213 return OHOS::ERR_INVALID_OPERATION;
214 } else {
215 // save root AccessibilityElementInfo.
216 newElementInfoList_.push_back(root);
217 uint32_t count = newElementInfoList_.size();
218 DEBUG_LOG_STR("New Element Info count (%d), Type (%s)", root->GetChildCount(),
219 root->GetComponentType().c_str());
220
221 // Generate new ComponentTree.
222 newComponentNode_ = std::make_shared<ComponentTree>();
223 newComponentNode_->SetIndex(count - 1);
224
225 // Recurs get all children AccessibilityElementInfo.
226 auto cResult = RecursGetChildElementInfo(root, newComponentNode_);
227 if (!cResult) {
228 return OHOS::ERR_INVALID_OPERATION;
229 }
230 RecursComponent(newComponentNode_);
231 }
232 // Generate Page Node
233 newPageNode_ = std::make_shared<PageTree>();
234 newPageNode_->SetNodeId();
235
236 TRACK_LOG_END();
237 return result;
238 }
239
SetInputcomponentIndex(int actionType,uint32_t index)240 void TreeManager::SetInputcomponentIndex(int actionType, uint32_t index)
241 {
242 DEBUG_LOG_STR("Input: (%d), Input Type: (%d)", index, actionType);
243 if (currentPageNode_ == nullptr) {
244 ERROR_LOG("current page is null!");
245 return;
246 }
247
248 // component input count statistics
249 if (index != INVALIDED_INPUT_INDEX) {
250 if (inputComponentList_.size() <= 0) {
251 ERROR_LOG("input component list is null!");
252 return;
253 }
254 if (index >= inputComponentList_.size()) {
255 ERROR_LOG("index argument is invalided");
256 return;
257 }
258 inputComponentList_[index]->AddInputCount();
259 inputComponentList_[index]->AddTypeInputCount(actionType);
260 DEBUG_LOG_STR("inputComponent: GetNodeId (0x%016llX)", inputComponentList_[index]->GetNodeId());
261 } else {
262 if (inputComponent_ == nullptr) {
263 ERROR_LOG("inputComponent_ is nullptr");
264 return;
265 }
266 inputComponent_->AddInputCount();
267 inputComponent_->AddTypeInputCount(actionType);
268 DEBUG_LOG_STR("inputComponent: GetNodeId (0x%016llX)", inputComponent_->GetNodeId());
269 }
270 RecursComponent(currentComponentNode_);
271 // ability input count statistics
272 currentAbilityNode_->AddInputCount();
273
274 // page input count statistics
275 currentPageNode_->AddInputCount();
276 if (index != INVALIDED_INPUT_INDEX) {
277 currentPageNode_->SetCurrentComponentNode(inputComponentList_[index]);
278 } else {
279 currentPageNode_->SetCurrentComponentNode(inputComponent_);
280 }
281 }
282
SetActiveComponent(const std::vector<std::shared_ptr<ComponentTree>> & inputComponentList)283 void TreeManager::SetActiveComponent(const std::vector<std::shared_ptr<ComponentTree>>& inputComponentList)
284 {
285 DEBUG_LOG_STR("Active component list: size (%d)", inputComponentList.size());
286 // Clear old input data
287 inputElementInfoList_.clear();
288 inputComponentList_.clear();
289 uint32_t count = elementInfoList_.size();
290 for (auto componentNode : inputComponentList) {
291 if (count > componentNode->GetIndex()) {
292 // Save input pointer list
293 inputElementInfoList_.push_back(elementInfoList_[componentNode->GetIndex()]);
294 inputComponentList_.push_back(componentNode);
295 } else {
296 ERROR_LOG_STR("component index (%d) more than elementInfoList count (%d)", componentNode->GetIndex(),
297 count);
298 break;
299 }
300 }
301 }
302
SetActiveComponent(const std::shared_ptr<ComponentTree> & inputComponent)303 void TreeManager::SetActiveComponent(const std::shared_ptr<ComponentTree>& inputComponent)
304 {
305 // Save one input pointer.
306 if (inputComponent == nullptr) {
307 ERROR_LOG("argument failed inputComponent is nullptr");
308 return;
309 }
310 DEBUG_LOG_STR("Active component: GetNodeId (0x%016llX)", inputComponent->GetNodeId());
311 inputComponent_ = inputComponent;
312 if (elementInfoList_.size() > inputComponent->GetIndex()) {
313 inputElementInfo_ = elementInfoList_[inputComponent->GetIndex()];
314 } else {
315 ERROR_LOG_STR("component index (%d) more than elementInfoList count (%d)", inputComponent->GetIndex(),
316 elementInfoList_.size());
317 }
318 }
319
AddPage()320 bool TreeManager::AddPage()
321 {
322 TRACK_LOG_STD();
323 // save new component tree, and change current conmponent tree.
324 UpdateCurrentPage(true);
325
326 // page tree growth
327 if (newPageNode_ == nullptr) {
328 ERROR_LOG("the new Page Node is null");
329 return false;
330 }
331
332 uint32_t key = componentTreeList_.size();
333 componentTreeList_[key] = currentComponentNode_;
334 newPageNode_->SetIndex(key);
335 if (!isNewAbility_) {
336 if (currentPageNode_ != nullptr) {
337 newPageNode_->SetParent(currentPageNode_);
338 currentPageNode_->AddChild(newPageNode_);
339 }
340 } else {
341 // ability tree growth
342 key = pageTreeList_.size();
343 pageTreeList_[key] = newPageNode_;
344 currentAbilityNode_->SetIndex(key);
345 }
346 currentPageNode_ = newPageNode_;
347 currentAbilityNode_->AddAllComponentCount(currentPageNode_->GetAllComponentCount());
348
349 TRACK_LOG_END();
350 return SamePage();
351 }
352
SamePage()353 bool TreeManager::SamePage()
354 {
355 TRACK_LOG_STD();
356 isUpdateComponentFinished_ = true;
357 newElementInfoList_.clear();
358 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
359 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
360 newComponentNode_.use_count(), newComponentNode_.unique());
361 }
362 newComponentNode_.reset();
363 newPageNode_.reset();
364 newAbilityNode_.reset();
365 TRACK_LOG_END();
366 return true;
367 }
368
UpdatePage(int layer,uint32_t index)369 bool TreeManager::UpdatePage(int layer, uint32_t index)
370 {
371 TRACK_LOG_STD();
372 DEBUG_LOG_STR("UpdatePage: layer (%d), index (%u)", layer, index);
373 std::shared_ptr<WuKongTree> pageNode = currentPageNode_;
374 if (layer > 0) {
375 if (pageNode->GetChildren().size() <= index) {
376 ERROR_LOG_STR("UpdatePage child index (%d) more than elementInfoList_ GetChildren() size (%u)", index,
377 pageNode->GetChildren().size());
378 return false;
379 }
380 currentPageNode_ = std::static_pointer_cast<PageTree>(pageNode->GetChildren()[index]);
381 } else {
382 while (layer < 0) {
383 layer++;
384 pageNode = pageNode->GetParent();
385 if (pageNode == nullptr) {
386 ERROR_LOG_STR("UpdatePage back layer (%d) more than currentPageNode_ parent (%p)", layer,
387 pageNode.get());
388 return false;
389 }
390 }
391 currentPageNode_ = std::static_pointer_cast<PageTree>(pageNode);
392 }
393
394 if (componentTreeList_.find(currentPageNode_->GetIndex()) == componentTreeList_.end()) {
395 ERROR_LOG_STR("currentPageNode_ index (%u) more than componentTreeList_ size (%u)",
396 currentPageNode_->GetIndex(), componentTreeList_.size());
397 return false;
398 }
399
400 TRACK_LOG_STR("currentPageNode_->GetIndex(): %d", currentPageNode_->GetIndex());
401 currentComponentNode_ = componentTreeList_[currentPageNode_->GetIndex()];
402
403 if (!UpdateCurrentPage()) {
404 return false;
405 }
406 TRACK_LOG_END();
407 return SamePage();
408 }
409
RemovePage()410 bool TreeManager::RemovePage()
411 {
412 TRACK_LOG_STD();
413 uint32_t componentNodeIndex = currentPageNode_->GetIndex();
414 uint32_t componentTreeListCount = componentTreeList_.size();
415 if (componentNodeIndex >= componentTreeListCount) {
416 ERROR_LOG_STR("currentPageNode index (%u) more than componentTreeList_ size (%u)", componentNodeIndex,
417 componentTreeListCount);
418 return false;
419 }
420 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
421 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)",
422 componentTreeList_[componentNodeIndex].get(), componentTreeList_[componentNodeIndex].use_count(),
423 componentTreeList_[componentNodeIndex].unique());
424 }
425 auto componentNode = componentTreeList_[componentNodeIndex];
426 if (componentNode == nullptr) {
427 ERROR_LOG("componentNode point is nullptr of currentPageNode");
428 return false;
429 }
430 uint32_t startIndex = componentNode->GetIndex();
431 componentTreeList_[componentNodeIndex].reset();
432 uint32_t endIndex = startIndex + currentPageNode_->count_ - 1;
433 uint32_t elementInfoListCount = elementInfoList_.size();
434 DEBUG_LOG_STR(
435 "currentPageNode StartIndex (%u) EndIndex (%u) componentTreeList_ size (%u) elementInfoList_ size (%u)",
436 startIndex, endIndex, componentTreeListCount, elementInfoListCount);
437 if (startIndex >= elementInfoListCount || endIndex >= elementInfoListCount) {
438 ERROR_LOG_STR("currentPageNode StartIndex (%u) EndIndex (%u) more than elementInfoList_ size (%u)", startIndex,
439 endIndex, elementInfoListCount);
440 return false;
441 }
442 elementInfoList_.erase(elementInfoList_.begin() + startIndex, elementInfoList_.begin() + endIndex);
443 TRACK_LOG_END();
444 return true;
445 }
446
UpdateCurrentPage(bool isAdd)447 bool TreeManager::UpdateCurrentPage(bool isAdd)
448 {
449 TRACK_LOG_STD();
450 uint32_t count = elementInfoList_.size();
451 DEBUG_LOG_STR("elementInfoList_: %d", count);
452 for (auto elementInfo : newElementInfoList_) {
453 elementInfoList_.push_back(elementInfo);
454 }
455 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
456 DEBUG_LOG_STR("CompoentNode shared new (%p) count = (%ld) unique (%d)", newComponentNode_.get(),
457 newComponentNode_.use_count(), newComponentNode_.unique());
458 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
459 currentComponentNode_.use_count(), currentComponentNode_.unique());
460 }
461 // update component tree index
462 newComponentNode_->RecursUpdateNodeIndex(count);
463 if (!isAdd) {
464 newComponentNode_->RecursUpdateInfo(currentComponentNode_);
465 }
466 // set current sreen componentNode to new screen
467 currentComponentNode_ = newComponentNode_;
468 if (WuKongLogger::GetInstance()->GetLogLevel() == LOG_LEVEL_TRACK) {
469 DEBUG_LOG_STR("CompoentNode shared (%p) count = (%ld) unique (%d)", currentComponentNode_.get(),
470 currentComponentNode_.use_count(), currentComponentNode_.unique());
471 if (currentPageNode_ != nullptr) {
472 DEBUG_LOG_STR("CompoentNode shared (%p) index (%u) count = (%ld) unique (%d)",
473 componentTreeList_[currentPageNode_->GetIndex()].get(), currentPageNode_->GetIndex(),
474 componentTreeList_[currentPageNode_->GetIndex()].use_count(),
475 componentTreeList_[currentPageNode_->GetIndex()].unique());
476 }
477 }
478
479 if (!isAdd) {
480 componentTreeList_[currentPageNode_->GetIndex()] = currentComponentNode_;
481 currentAbilityNode_->allComponentCount_ -= currentPageNode_->GetAllComponentCount();
482 currentAbilityNode_->allComponentCount_ += newPageNode_->GetAllComponentCount();
483 currentPageNode_->nodeId_ = newPageNode_->nodeId_;
484 currentPageNode_->allComponentCount_ = newPageNode_->allComponentCount_;
485 }
486 TRACK_LOG_END();
487 return true;
488 }
489 } // namespace WuKong
490 } // namespace OHOS
491