Aurum: Improve performance of findElements command
[platform/core/uifw/aurum.git] / libaurum / src / Comparer.cc
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *               http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  */
17
18 #include "Aurum.h"
19
20 using namespace Aurum;
21
22 Comparer::Comparer(const std::shared_ptr<UiDevice>& device, const std::shared_ptr<UiSelector>& selector,
23                    const bool &earlyReturn)
24     : mDevice(device), mSelector(selector), mEarlyReturn(earlyReturn)
25 {
26 }
27
28 Comparer::~Comparer() {}
29
30 std::shared_ptr<AccessibleNode> Comparer::findObject(const std::shared_ptr<UiDevice>& device,
31                                      const std::shared_ptr<UiSelector>& selector,
32                                      const std::shared_ptr<AccessibleNode>& root)
33 {
34     std::vector<std::shared_ptr<AccessibleNode>> ret;
35     findObjects(ret, device, selector, root, true);
36     if (ret.size() > 0)
37         return std::move(ret[0]);
38     else
39         return nullptr;
40 }
41
42 void Comparer::findObjects(std::vector<std::shared_ptr<AccessibleNode>> &ret,
43                                                     const std::shared_ptr<UiDevice>& device,
44                                                     const std::shared_ptr<UiSelector>& selector,
45                                                     const std::shared_ptr<AccessibleNode>& root, bool earlyReturn)
46 {
47     Comparer comparer(device, selector, earlyReturn);
48
49     LOGI("findObjects selector(%s) from (type:%s style:%s, role:%s, text:%s) earlyReturn:%d", selector->description().c_str(), root->getType().c_str(),  root->getStyle().c_str(),  root->getRole().c_str(),  root->getText().c_str(), earlyReturn);
50     if (selector->mParent) {
51
52         // TODO: Optimize findObjects() when selector has a parent
53         std::vector<std::shared_ptr<AccessibleNode>> ret;
54         Comparer::findObjects(ret, device, selector->mParent, root);
55
56         for (const auto &node : ret) {
57             comparer.findObjects(ret, node);
58         }
59
60         return;
61     }
62
63     if (selector->mMatchXPath) {
64         std::string pkg = root->getPkg();
65         auto XMLDoc = AccessibleWatcher::getInstance()->getXMLDoc(pkg);
66
67         if (XMLDoc.get() == nullptr) return;
68
69         XMLDoc->findObjects(ret, selector->mXPath, earlyReturn);
70
71         return;
72     }
73
74     comparer.findObjects(ret, root);
75 }
76
77 void Comparer::findObjects(std::vector<std::shared_ptr<AccessibleNode>> &ret,
78                                                             const std::shared_ptr<AccessibleNode>& root)
79 {
80     std::list<std::shared_ptr<PartialMatch>> partialList{};
81     findObjects(ret, root, 0, 1, partialList);
82     LOGI("%d object(s) found", (int)ret.size());
83 }
84
85 void Comparer::findObjects(std::vector<std::shared_ptr<AccessibleNode>> &ret,
86     const std::shared_ptr<AccessibleNode>& root, const int &index, const int &depth,
87     std::list<std::shared_ptr<PartialMatch>> &partialMatches)
88 {
89
90     if (mSelector->mMatchShowing && !root->isShowing()) return;
91
92     for (auto &match : partialMatches)
93         match->update(root, index, depth, partialMatches);
94
95     std::shared_ptr<PartialMatch> currentMatch =
96         PartialMatch::accept(root, mSelector, index, depth);
97     if (currentMatch) partialMatches.push_front(currentMatch);
98
99     if (!(mSelector->mMaxDepth && (depth+1 > mSelector->mMaxDepth))) {
100         auto children = root->getChildren();
101         for (int i = 0; i < (int)children.size(); i++) {
102             auto child = children[i];
103             if (child->getRawHandler() == nullptr) continue;
104
105             findObjects(ret, child, i, depth + 1, partialMatches);
106             if (!ret.empty() && mEarlyReturn) {
107                 LOGI("Object found and earlyReturn");
108                 return;
109             }
110         }
111     } else {
112         LOGI("Abort searching! No need to search children(maxDepth limit overflow, %d < %d < %d)", mSelector->mMinDepth? mSelector->mMinDepth: -1, depth, mSelector->mMaxDepth?(mSelector->mMaxDepth):9999999);
113     }
114
115     if (currentMatch && currentMatch->finalizeMatch()){
116         LOGI("Found matched = %s with criteria %s", root->description().c_str(), currentMatch->debugPrint().c_str());
117         ret.push_back(root);
118     }
119 }