Introduce new getMatches API. 90/302290/4
authorHosang Kim <hosang12.kim@samsung.com>
Tue, 5 Dec 2023 06:17:04 +0000 (15:17 +0900)
committerHosang Kim <hosang12.kim@samsung.com>
Tue, 19 Dec 2023 05:11:43 +0000 (14:11 +0900)
the getMatches can find objects under specific conditions.
It runs quickly because the search happens in the app.
Internally, this API uses atspi_collection_get_matches and includes a new class, AtspiMatchRuleConvertor, to convert UiSelector to AtspiMatchRule.

Change-Id: I2856a81aa5e70d8290e33faa0df231c95749eb35

15 files changed:
libaurum/inc/Accessibility/AccessibleNode.h
libaurum/inc/Impl/Accessibility/AtspiAccessibleNode.h
libaurum/inc/Impl/Accessibility/AtspiMatchRuleConvertor.h [new file with mode: 0644]
libaurum/inc/Impl/Accessibility/AtspiWrapper.h
libaurum/inc/Impl/Accessibility/MockAccessibleNode.h
libaurum/inc/UiDevice.h
libaurum/inc/UiObject.h
libaurum/inc/UiSelector.h
libaurum/src/Impl/Accessibility/AtspiAccessibleNode.cc
libaurum/src/Impl/Accessibility/AtspiMatchRuleConvertor.cc [new file with mode: 0644]
libaurum/src/Impl/Accessibility/AtspiWrapper.cc
libaurum/src/Impl/Accessibility/MockAccessibleNode.cc
libaurum/src/Impl/Accessibility/meson.build
libaurum/src/UiDevice.cc
libaurum/src/UiObject.cc

index 8c3e555..b65f316 100644 (file)
@@ -27,6 +27,7 @@
 #include "IEventConsumer.h"
 #include "IObject.h"
 #include "Rect.h"
+#include "UiSelector.h"
 #include "config.h"
 
 namespace Aurum {
@@ -132,6 +133,11 @@ public:
     virtual std::shared_ptr<AccessibleNode> getParent() const = 0;
 
     /**
+     * @copydoc UiObject::getMatches()
+     */
+    virtual std::vector<std::shared_ptr<AccessibleNode>> getMatches(const std::shared_ptr<UiSelector> selector, const bool ealryReturn) const = 0;
+
+    /**
      * @brief Called by @AccessibleWatcher::notifyAll.
      *        Changes Node property If it's @EventType, @ObjectEventType are matches.
      *
index b4572b8..54d091a 100644 (file)
@@ -71,6 +71,11 @@ public:
     std::shared_ptr<AccessibleNode> getParent() const override;
 
     /**
+     * @copydoc UiObject::getMatches()
+     */
+    std::vector<std::shared_ptr<AccessibleNode>> getMatches(const std::shared_ptr<UiSelector> selector, const bool ealryReturn) const override;
+
+    /**
      * @copydoc AccessibleNode::isValid()
      */
     bool isValid() const override;
diff --git a/libaurum/inc/Impl/Accessibility/AtspiMatchRuleConvertor.h b/libaurum/inc/Impl/Accessibility/AtspiMatchRuleConvertor.h
new file mode 100644 (file)
index 0000000..1b3a57b
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *               http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+#ifndef _ATSPI_MATCH_RULE_CONVERTOR_H_
+#define _ATSPI_MATCH_RULE_CONVERTOR_H_
+
+#include <memory>
+
+#include <atspi/atspi.h>
+
+#include "UiSelector.h"
+
+using namespace Aurum;
+
+namespace AurumInternal {
+
+class AtspiMatchRuleConvertor {
+public:
+    AtspiMatchRuleConvertor(const std::shared_ptr<UiSelector> selector);
+    ~AtspiMatchRuleConvertor();
+
+    operator AtspiMatchRule*();
+
+private:
+    std::shared_ptr<UiSelector>  mSelector;
+};
+
+}
+
+#endif
index 6f3ebeb..fbca138 100644 (file)
@@ -71,6 +71,8 @@ public:
     static gchar *Atspi_accessible_get_toolkit_name(AtspiAccessible *node, GError **error);
     static AtspiRect *Atspi_text_get_minimum_bounding_rectangles(AtspiText* obj, gint start_offset, gint end_offset, AtspiCoordType type, GError** error);
     static void Atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error);
+    static AtspiCollection *Atspi_accessible_get_collection_iface(AtspiAccessible *node);
+    static GArray *Atspi_collection_get_matches(AtspiCollection *obj, AtspiMatchRule *rule, AtspiCollectionSortOrder sortby, gint count, gboolean traverse, GError **error);
 
 private:
     static std::recursive_mutex mMutex;
index abb23c4..77f9ce3 100644 (file)
@@ -68,6 +68,12 @@ public:
      */
     std::shared_ptr<AccessibleNode> getParent() const override;
 
+    /**
+     * @brief TBD
+     * @since_tizen 8.0
+     */
+    std::vector<std::shared_ptr<AccessibleNode>> getMatches(const std::shared_ptr<UiSelector> selector, const bool ealryReturn) const override;
+
 public:
     /**
      * @brief TBD
index e9d519c..7315f7b 100644 (file)
@@ -314,6 +314,20 @@ public:
         const std::shared_ptr<UiSelector> selector) const override;
 
     /**
+     * @brief Get the Matches object that satisfied with the selector condition in the object tree.
+     *        This method is similar to findObjects, but getMatches is more faster than findObjects.
+     *
+     * @param[in] selector @UiSelector
+     * @param[in] earlyReturn boolean
+     *
+     * @return the list of found UiObject pointer vector
+     *
+     * @since_tizen 8.0
+     */
+    std::vector<std::shared_ptr<UiObject>> getMatches(
+        const std::shared_ptr<UiSelector> selector, const bool earlyReturn) const;
+
+    /**
      * TODO
      */
     bool waitFor(
index 52d4a9c..3f7911b 100644 (file)
@@ -139,6 +139,20 @@ public:
         const std::shared_ptr<UiSelector> selector) const override;
 
     /**
+     * @brief Get the Matches object that satisfied with the selector condition in the object tree.
+     *        This method is similar to findObjects, but getMatches is more faster than findObjects.
+     *
+     * @param[in] selector @UiSelector
+     * @param[in] earlyReturn boolean
+     *
+     * @return the list of found UiObject pointer vector
+     *
+     * @since_tizen 8.0
+     */
+    std::vector<std::shared_ptr<UiObject>> getMatches(
+        const std::shared_ptr<UiSelector> selector, const bool earlyReturn) const;
+
+    /**
      * TODO
      */
     bool waitFor(
index 2eca30d..4d2a129 100644 (file)
@@ -24,6 +24,8 @@
 #include <vector>
 #include <memory>
 
+#include "Rect.h"
+
 namespace Aurum {
 
 /**
index 1301c8b..e4572d4 100644 (file)
@@ -18,6 +18,7 @@
 #include "Aurum.h"
 
 #include "AtspiAccessibleNode.h"
+#include "AtspiMatchRuleConvertor.h"
 #include "AtspiWrapper.h"
 
 #include <gio/gio.h>
@@ -612,3 +613,31 @@ void AtspiAccessibleNode::setFeatureProperty(AtspiStateType type)
         break;
     }
 }
+
+std::vector<std::shared_ptr<AccessibleNode>> AtspiAccessibleNode::getMatches(const std::shared_ptr<UiSelector> selector, const bool ealryReturn) const
+{
+    std::vector<std::shared_ptr<AccessibleNode>> ret{};
+
+    AtspiCollection *collection = AtspiWrapper::Atspi_accessible_get_collection_iface(mNode);
+    if (collection) {
+        AtspiMatchRule *rule = AtspiMatchRuleConvertor(selector);
+        if (!rule) return ret;
+
+        int count = ealryReturn ? 1 : 0;
+        GArray *matches = AtspiWrapper::Atspi_collection_get_matches(collection, rule, ATSPI_Collection_SORT_ORDER_CANONICAL, count, false, NULL);
+        if (matches) {
+            ret.reserve(matches->len);
+            AtspiAccessible *match = nullptr;
+            for (unsigned int i = 0; i < matches->len; i++) {
+                match = g_array_index(matches, AtspiAccessible *, i);
+               if (match) {
+                   ret.push_back(std::make_shared<AtspiAccessibleNode>(match));
+               }
+            }
+            g_array_free(matches, true);
+        }
+        g_object_unref(rule);
+    }
+
+    return ret;
+}
diff --git a/libaurum/src/Impl/Accessibility/AtspiMatchRuleConvertor.cc b/libaurum/src/Impl/Accessibility/AtspiMatchRuleConvertor.cc
new file mode 100644 (file)
index 0000000..d5c9294
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *               http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+
+#include <atspi/atspi.h>
+
+#include "Aurum.h"
+#include "AtspiMatchRuleConvertor.h"
+
+using namespace Aurum;
+using namespace AurumInternal;
+
+AtspiMatchRuleConvertor::AtspiMatchRuleConvertor(const std::shared_ptr<UiSelector> selector)
+: mSelector(selector)
+{
+}
+
+AtspiMatchRuleConvertor::~AtspiMatchRuleConvertor()
+{
+}
+
+AtspiMatchRuleConvertor::operator AtspiMatchRule *()
+{
+    if (!mSelector) return nullptr;
+
+    AtspiCollectionMatchType stateMatchType = ATSPI_Collection_MATCH_INVALID;
+    AtspiCollectionMatchType attributeMatchType = ATSPI_Collection_MATCH_INVALID;
+
+    // Add rule of states
+    AtspiStateSet *ss = atspi_state_set_new(nullptr);
+    if (mSelector->mIschecked) atspi_state_set_add(ss, ATSPI_STATE_CHECKED);
+    if (mSelector->mIscheckable) atspi_state_set_add(ss, ATSPI_STATE_CHECKABLE);
+    if (mSelector->mIsclickable) atspi_state_set_add(ss, ATSPI_STATE_SENSITIVE);
+    if (mSelector->mIsenabled) atspi_state_set_add(ss, ATSPI_STATE_ENABLED);
+    if (mSelector->mIsfocused) atspi_state_set_add(ss, ATSPI_STATE_FOCUSED);
+    if (mSelector->mIsfocusable) atspi_state_set_add(ss, ATSPI_STATE_FOCUSABLE);
+    if (mSelector->mIsselected) atspi_state_set_add(ss, ATSPI_STATE_SELECTED);
+    if (mSelector->mIsshowing) atspi_state_set_add(ss, ATSPI_STATE_SHOWING);
+    if (mSelector->mIsactive) atspi_state_set_add(ss, ATSPI_STATE_ACTIVE);
+    if (mSelector->mIsvisible) atspi_state_set_add(ss, ATSPI_STATE_VISIBLE);
+    if (mSelector->mIsselectable) atspi_state_set_add(ss, ATSPI_STATE_SELECTABLE);
+    if (mSelector->mIshighlightable) atspi_state_set_add(ss, ATSPI_STATE_HIGHLIGHTABLE);
+
+    if (atspi_state_set_is_empty(ss))
+    {
+        g_object_unref(ss);
+        ss = nullptr;
+    }
+    else
+    {
+        stateMatchType = ATSPI_Collection_MATCH_ALL;
+    }
+
+    // Add rule of attributes
+    GHashTable *attributes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+    if (mSelector->mMatchType)
+    {
+        g_hash_table_insert(attributes, g_strdup("class"), g_strdup(mSelector->mType.c_str()));
+    }
+
+    if (mSelector->mMatchAutomationId)
+    {
+        g_hash_table_insert(attributes, g_strdup("automationId"), g_strdup(mSelector->mAutomationId.c_str()));
+    }
+
+    if (g_hash_table_size(attributes) == 0)
+    {
+        g_hash_table_unref (attributes);
+        attributes = nullptr;
+    }
+    else
+    {
+        attributeMatchType = ATSPI_Collection_MATCH_ALL;
+    }
+
+    AtspiMatchRule* rule = atspi_match_rule_new(ss, stateMatchType,
+                                                attributes, attributeMatchType,
+                                                nullptr, ATSPI_Collection_MATCH_INVALID,
+                                                nullptr, ATSPI_Collection_MATCH_INVALID,
+                                                false);
+
+    if (ss) g_object_unref(ss);
+    if (attributes) g_hash_table_unref (attributes);
+
+    return rule;
+}
index e9b8228..4d78d75 100644 (file)
@@ -235,4 +235,16 @@ void AtspiWrapper::Atspi_accessible_set_listen_post_render(AtspiAccessible *obj,
 {
     std::unique_lock<std::recursive_mutex> lock(mMutex);
     atspi_accessible_set_listen_post_render(obj, enabled, error);
+}
+
+AtspiCollection *AtspiWrapper::Atspi_accessible_get_collection_iface(AtspiAccessible *node)
+{
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    return atspi_accessible_get_collection_iface(node);
+}
+
+GArray *AtspiWrapper::Atspi_collection_get_matches(AtspiCollection *obj, AtspiMatchRule *rule, AtspiCollectionSortOrder sortby, gint count, gboolean traverse, GError **error)
+{
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    return atspi_collection_get_matches(obj, rule, sortby, count, traverse, error);
 }
\ No newline at end of file
index a397f37..860a089 100644 (file)
@@ -61,6 +61,13 @@ std::shared_ptr<AccessibleNode> MockAccessibleNode::getParent() const
     return mParentNode;
 }
 
+std::vector<std::shared_ptr<AccessibleNode>> MockAccessibleNode::getMatches(const std::shared_ptr<UiSelector> selector, const bool ealryReturn) const
+{
+    std::vector<std::shared_ptr<AccessibleNode>> ret{};
+
+    return ret;
+}
+
 void* MockAccessibleNode::getRawHandler(void) const
 {
     printf("%s:%d / %s\n",__FILE__, __LINE__, __PRETTY_FUNCTION__);
index fd535cc..f7b23b4 100644 (file)
@@ -4,6 +4,7 @@
         files('AtspiAccessibleNode.cc'),
         files('AtspiAccessibleWatcher.cc'),
         files('AtspiWrapper.cc'),
+        files('AtspiMatchRuleConvertor.cc'),
     ]
 
     libaurum_src += [
@@ -11,4 +12,4 @@
         files('MockAccessibleWindow.cc'),
         files('MockAccessibleNode.cc'),
         files('MockAccessibleWatcher.cc'),
-    ]
\ No newline at end of file
+    ]
index 60f9ab2..9bb7e42 100644 (file)
@@ -113,6 +113,21 @@ std::vector<std::shared_ptr<UiObject>> UiDevice::findObjects(
     }
     return ret;
 }
+
+std::vector<std::shared_ptr<UiObject>> UiDevice::getMatches(
+    const std::shared_ptr<UiSelector> selector, const bool earlyReturn) const
+{
+    std::vector<std::shared_ptr<UiObject>> ret{};
+
+    auto rootNodes = getWindowRoot();
+    for (const auto &window : rootNodes) {
+        auto nodes = window->getMatches(selector, earlyReturn);
+        for (auto &node : nodes)
+            ret.push_back(std::make_shared<UiObject>(getInstance(), nullptr, node));
+    }
+    return ret;
+}
+
 bool UiDevice::waitFor(
     const std::function<bool(const ISearchable *)> condition) const
 {
index 411cd4d..ca0946b 100644 (file)
@@ -105,6 +105,18 @@ std::vector<std::shared_ptr<UiObject>> UiObject::findObjects(
     return result;
 }
 
+std::vector<std::shared_ptr<UiObject>> UiObject::getMatches(
+    const std::shared_ptr<UiSelector> selector, const bool earlyReturn) const
+{
+    std::vector<std::shared_ptr<UiObject>> result{};
+
+    auto nodes = getAccessibleNode()->getMatches(selector, earlyReturn);
+    for (auto &node : nodes) {
+        result.push_back(std::make_shared<UiObject>(mDevice, selector, std::move(node)));
+    }
+    return result;
+}
+
 bool UiObject::waitFor(
     const std::function<bool(const ISearchable *)> condition) const
 {