Introduce EVENT_WINDOW_IDLE event 75/288475/12 accepted/tizen/unified/20230310.062704
authorWoochan Lee <wc0917.lee@samsung.com>
Fri, 17 Feb 2023 04:15:45 +0000 (13:15 +0900)
committerwoochan lee <wc0917.lee@samsung.com>
Thu, 9 Mar 2023 08:24:16 +0000 (08:24 +0000)
It support device idle point to user.
user can use this event instead of waiting ramdom time for ui update.

Change-Id: I72b24ff39b7613484c75280583ce2c41dceddc9b

14 files changed:
libaurum/inc/A11yEvent.h
libaurum/inc/Accessibility/AccessibleWatcher.h
libaurum/inc/Impl/Accessibility/AtspiAccessibleWatcher.h
libaurum/inc/Impl/Accessibility/AtspiWrapper.h
libaurum/inc/Impl/Accessibility/MockAccessibleWatcher.h
libaurum/inc/UiDevice.h
libaurum/src/A11yEvent.cc
libaurum/src/Impl/Accessibility/AtspiAccessibleWatcher.cc
libaurum/src/Impl/Accessibility/AtspiWrapper.cc
libaurum/src/Impl/Accessibility/MockAccessibleWatcher.cc
libaurum/src/UiDevice.cc
org.tizen.aurum-bootstrap/src/Commands/ActionAndWaitEventCommand.cc
org.tizen.aurum-bootstrap/src/Commands/LaunchAppCommand.cc
protocol/aurum.proto

index d891e88..beb1ab7 100644 (file)
@@ -43,6 +43,7 @@ enum class A11yEvent {
      EVENT_WINDOW_LOWER = 0x00100,
      EVENT_WINDOW_MOVE = 0x00200,
      EVENT_WINDOW_RESIZE = 0x00400,
+     EVENT_WINDOW_RENDER_POST = 0x00800,
 
      EVENT_TEXT_CHANGED_INSERT = 0x00800,
      EVENT_TEXT_CHANGED_DELETE = 0x01000,
index c3b9308..df6a0a4 100644 (file)
@@ -104,12 +104,14 @@ public:
      * @param[in] cmd @Runnable
      * @param[in] type @A11yEvent
      * @param[in] timeout time(millisecond) to wait event occur
+     * @param[in] obj @AccessibleNode
+     * @param[in] count count of render post evnet
      *
      * @return true if event occur in time, else false
      *
      * @since_tizen 6.5
      */
-    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName) = 0;
+    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, std::shared_ptr<AccessibleNode> obj, const int count) = 0;
 
     /**
      * @brief Gets active application map.
index 967b010..fb9968a 100644 (file)
@@ -53,6 +53,19 @@ enum class WindowActivateInfoType {
 /**
  * @internal
  *
+ * @brief Idle event state enum class.
+ *
+ * @since_tizen 7.5
+ */
+enum class IdleEventState {
+    IDLE_LISTEN_START = 0x00,
+    IDLE_LISTEN_READY = 0x01,
+    IDLE_LISTEN_DONE = 0x02,
+};
+
+/**
+ * @internal
+ *
  * @brief IAtspiEvents Interface
  * @since_tizen 6.5
  */
@@ -105,7 +118,7 @@ public:
     /**
      * @copydoc @AccessibleWatcher::executeAndWaitForEvents()
      */
-    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName) override;
+    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, std::shared_ptr<AccessibleNode> obj, const int count)  override;
 
     /**
      * @copydoc @AccessibleWatcher::getActiveAppMap()
@@ -149,6 +162,7 @@ private:
     bool removeFromWindowSet(AtspiAccessible *node);
     bool addToWindowSet(AtspiAccessible *node);
     static gpointer eventThreadLoop(gpointer data);
+    static gpointer timerThread(gpointer data);
     void appendApp(AtspiAccessibleWatcher *instance, AtspiAccessible *app, char *pkg);
     void removeApp(AtspiAccessibleWatcher *instance, AtspiAccessible *app, char *pkg);
 
@@ -166,6 +180,10 @@ private:
     bool isTv;
     std::mutex XMLMutex;
     std::map<const A11yEvent, std::list<std::shared_ptr<A11yEventHandler>>> mHandlers;
+    static GThread *mTimerThread;
+    static gint64 mStartTime;
+    static IdleEventState isIdle;
+    static int mRenderCount;
 };
 
 }
index 0389c30..1cdd2a8 100644 (file)
@@ -69,6 +69,7 @@ public:
     static guint Atspi_accessible_get_process_id(AtspiAccessible *node, GError **error);
     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);
 
 private:
     static std::recursive_mutex mMutex;
index 80209bf..622e26d 100644 (file)
@@ -71,7 +71,7 @@ public:
      * @brief TBD
      * @since_tizen 6.5
      */
-    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName) override;
+    virtual bool executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, std::shared_ptr<AccessibleNode> obj, const int count)  override;
 
     virtual bool registerCallback(const A11yEvent type, EventHandler cb, void *data) override;
 
index b79fbe6..1bc1f31 100644 (file)
@@ -365,13 +365,14 @@ public:
      * @param[in] type one of @A11yEvent
      * @param[in] timeout time(millisecond) to wait event occur
      * @param[in] packageName package name that event occurs
+     * @param[in] count count of render post evnet
      *
      * @return true if event happened in time, otherwise false
      *
      * @since_tizen 6.5
      */
     bool executeAndWaitForEvents(
-        const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName) const;
+        const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, const int count) const;
 
 /**
      * @brief Register atspi event callback.
index e91ed94..6505dc5 100644 (file)
@@ -51,6 +51,7 @@ static std::unordered_map<std::string,A11yEvent> const table = { {"window:create
                                                                                                                                 {"window:lower", A11yEvent::EVENT_WINDOW_LOWER},
                                                                                                                                 {"window:resize", A11yEvent::EVENT_WINDOW_RESIZE},
                                                                                                                                 {"window:move", A11yEvent::EVENT_WINDOW_MOVE},
+                                                                                                                                {"window:renderpost", A11yEvent::EVENT_WINDOW_RENDER_POST},
                                                                                                                                 {"object:text-changed:insert", A11yEvent::EVENT_TEXT_CHANGED_INSERT},
                                                                                                                                 {"object:text-changed:delete", A11yEvent::EVENT_TEXT_CHANGED_DELETE},
                                                                                                                                 {"object:state-changed:VISIBLE", A11yEvent::EVENT_STATE_CHANGED_VISIBLE},
index 27f332e..c3400c0 100644 (file)
@@ -39,6 +39,11 @@ std::vector<std::shared_ptr<A11yEventInfo>> AtspiAccessibleWatcher::mEventQueue;
 GThread *AtspiAccessibleWatcher::mEventThread = nullptr;
 std::mutex AtspiAccessibleWatcher::mMutex = std::mutex{};
 GMainLoop *AtspiAccessibleWatcher::mLoop = nullptr;
+GThread *AtspiAccessibleWatcher::mTimerThread = nullptr;
+gint64 AtspiAccessibleWatcher::mStartTime = 0;
+IdleEventState AtspiAccessibleWatcher::isIdle = IdleEventState::IDLE_LISTEN_READY;
+static const unsigned int WAIT_FOR_IDLE_MICRO_SEC = 100000; // 0.1 sec
+int AtspiAccessibleWatcher::mRenderCount = 10;
 
 static bool iShowingNode(AtspiAccessible *node)
 {
@@ -222,6 +227,28 @@ void AtspiAccessibleWatcher::removeApp(AtspiAccessibleWatcher *instance, AtspiAc
     g_object_unref(app);
 }
 
+gpointer AtspiAccessibleWatcher::timerThread(gpointer data)
+{
+    mStartTime = g_get_monotonic_time();
+    for (;;)
+    {
+        //FIXME: User can change waiting time and count of render post
+        //       instead of waiting spelcific time
+        if ((g_get_monotonic_time() - mStartTime) > WAIT_FOR_IDLE_MICRO_SEC)
+        {
+            break;
+        }
+
+        usleep(100);
+    }
+
+    mTimerThread = nullptr;
+    isIdle = IdleEventState::IDLE_LISTEN_DONE;
+    g_thread_exit(NULL);
+
+    return NULL;
+}
+
 void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *watcher)
 {
     if (!event->source)
@@ -232,6 +259,30 @@ void AtspiAccessibleWatcher::onAtspiEvents(AtspiEvent *event, void *watcher)
     AtspiAccessibleWatcher *instance = (AtspiAccessibleWatcher *)watcher;
     name = AtspiWrapper::Atspi_accessible_get_name(event->source, NULL);
 
+    LOGE("WCC event = %s", event->type);
+    if (isIdle == IdleEventState::IDLE_LISTEN_START && !strncmp(event->type, "window:post-render", 18))
+    {
+        if (mTimerThread == nullptr)
+        {
+            LOGI("Timer Thread Start");
+            mTimerThread = g_thread_new("TimerThread", timerThread, instance);
+        }
+        else
+        {
+            mStartTime = g_get_monotonic_time();
+        }
+
+        mRenderCount--;
+        if (mRenderCount == 0)
+        {
+          LOGI("RenderCount is 0. Stop to listen RenderPost");
+          mStartTime = g_get_monotonic_time() + WAIT_FOR_IDLE_MICRO_SEC;
+        }
+
+        if (name) free(name);
+        return;
+    }
+
     AtspiAccessible *app = AtspiWrapper::Atspi_accessible_get_application(event->source, NULL);
     if (name && app)
     {
@@ -321,11 +372,24 @@ std::vector<std::shared_ptr<AccessibleApplication>> AtspiAccessibleWatcher::getA
     return ret;
 }
 
-bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName)
+bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, std::shared_ptr<AccessibleNode> obj, const int count)
 {
     mMutex.lock();
     mEventQueue.clear();
     mMutex.unlock();
+
+    // Call atspi method for start to listen atspi event.
+    if (type == A11yEvent::EVENT_WINDOW_RENDER_POST)
+    {
+        LOGI("RenderPost listen start with pkg (%s) timeout (%d) count (%d)", obj->getPkg().c_str(), timeout, count);
+        isIdle = IdleEventState::IDLE_LISTEN_START;
+        if (count == 0 || count < 0)
+          mRenderCount = 10;
+        else
+          mRenderCount = count;
+        AtspiWrapper::Atspi_accessible_set_listen_post_render((AtspiAccessible *)(obj->getRawHandler()), true, NULL);
+    }
+
     if (cmd)
         cmd->run();
 
@@ -339,6 +403,9 @@ bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const
         mEventQueue.clear();
         mMutex.unlock();
 
+        if (isIdle == IdleEventState::IDLE_LISTEN_DONE)
+            break;
+
         if (!localEvents.empty())
         {
             for (const auto &event : localEvents) {
@@ -356,6 +423,15 @@ bool AtspiAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const
             std::chrono::milliseconds{100});
     }
 
+    if (isIdle != IdleEventState::IDLE_LISTEN_READY)
+    {
+        LOGI("RenderPost listen finish");
+        isIdle = IdleEventState::IDLE_LISTEN_READY;
+        AtspiWrapper::Atspi_accessible_set_listen_post_render((AtspiAccessible *)(obj->getRawHandler()), false, NULL);
+
+        return true;
+    }
+
     return false;
 }
 
index b923969..02fa126 100644 (file)
@@ -225,3 +225,8 @@ AtspiRect *AtspiWrapper::Atspi_text_get_minimum_bounding_rectangles(AtspiText* o
     return atspi_text_get_range_extents(obj, start_offset, end_offset, type, error);
 }
 
+void AtspiWrapper::Atspi_accessible_set_listen_post_render(AtspiAccessible *obj, gboolean enabled, GError **error)
+{
+    std::unique_lock<std::recursive_mutex> lock(mMutex);
+    atspi_accessible_set_listen_post_render(obj, enabled, error);
+}
\ No newline at end of file
index ac44651..e054ced 100644 (file)
@@ -68,7 +68,7 @@ std::shared_ptr<MockAccessibleApplication> MockAccessibleWatcher::addApplication
     return app;
 }
 
-bool MockAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName)
+bool MockAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, std::shared_ptr<AccessibleNode> obj, const int count)
 {
     return true;
 }
@@ -76,4 +76,4 @@ bool MockAccessibleWatcher::executeAndWaitForEvents(const Runnable *cmd, const A
 bool MockAccessibleWatcher::registerCallback(const A11yEvent type, EventHandler cb, void *data)
 {
     return true;
-}
\ No newline at end of file
+}
index 0d710c8..328c5bb 100644 (file)
@@ -285,20 +285,24 @@ bool UiDevice::waitForIdle() const
 bool UiDevice::waitForEvents(
     const A11yEvent type, const int timeout) const
 {
-    return executeAndWaitForEvents(NULL, type, timeout, std::string());
+    return executeAndWaitForEvents(NULL, type, timeout, std::string(), 0);
 }
 
-bool UiDevice::executeAndWaitForEvents(
-    const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName) const
+//FIXME: obj only need for idle event
+bool UiDevice::executeAndWaitForEvents
+    (const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, const int count)  const
 {
-    return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout, packageName);
+    //FIXME: Need to get top window
+    auto wins = this->getWindowRoot();
+
+    return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout, packageName, wins[0], count);
 }
 
 bool UiDevice::sendKeyAndWaitForEvents(
     const std::string keycode, const A11yEvent type, const int timeout) const
 {
     std::unique_ptr<SendKeyRunnable> cmd = std::make_unique<SendKeyRunnable>(keycode);
-    return executeAndWaitForEvents(cmd.get(), type, timeout, std::string());
+    return executeAndWaitForEvents(cmd.get(), type, timeout, std::string(), 0);
 }
 
 bool UiDevice::click(const int x, const int y)
index 4449c2f..3439879 100644 (file)
@@ -34,6 +34,8 @@ A11yEvent convertEventType(const ::aurum::ReqActionAndWaitEvent_EventType type)
         return A11yEvent::EVENT_WINDOW_ACTIVATE;
     else if (type == ::aurum::ReqActionAndWaitEvent_EventType::ReqActionAndWaitEvent_EventType_EVENT_WINDOW_DEACTIVATE)
         return A11yEvent::EVENT_WINDOW_DEACTIVATE;
+    else if (type == ::aurum::ReqActionAndWaitEvent_EventType::ReqActionAndWaitEvent_EventType_EVENT_WINDOW_IDLE)
+        return A11yEvent::EVENT_WINDOW_RENDER_POST;
     else
         return A11yEvent::EVENT_STATE_CHANGED_FOCUSED;
 }
@@ -44,7 +46,8 @@ A11yEvent convertEventType(const ::aurum::ReqActionAndWaitEvent_EventType type)
     std::unique_ptr<ActionAndWaitEventRunnable> cmd = std::make_unique<ActionAndWaitEventRunnable>(
                                                       mRequest->type(), mRequest->elementid(), mRequest->xf86keycode());
     std::shared_ptr<UiDevice> obj = UiDevice::getInstance();
-    bool ret = obj->executeAndWaitForEvents(cmd.get(), convertEventType(mRequest->eventtype()), mRequest->timeoutms(), mRequest->packagename());
+    //FIXME: Separation of params according to event type
+    bool ret = obj->executeAndWaitForEvents(cmd.get(), convertEventType(mRequest->eventtype()), mRequest->timeoutms(), mRequest->packagename(), mRequest->count());
 
     if (ret) mResponse->set_status(::aurum::RspStatus::OK);
     else mResponse->set_status(::aurum::RspStatus::ERROR);
index 401ac0a..64dd8cc 100644 (file)
@@ -35,7 +35,7 @@ LaunchAppCommand::LaunchAppCommand(const ::aurum::ReqLaunchApp *request,
     LOGI("LaunchApp --------------- ");
     std::unique_ptr<LaunchAppRunnable> cmd = std::make_unique<LaunchAppRunnable>(mRequest->packagename(), mRequest->data());
     std::shared_ptr<UiDevice> obj = UiDevice::getInstance();
-    obj->executeAndWaitForEvents(cmd.get(), A11yEvent::EVENT_WINDOW_ACTIVATE, WAIT_APP_LAUNCH, mRequest->packagename());
+    obj->executeAndWaitForEvents(cmd.get(), A11yEvent::EVENT_WINDOW_ACTIVATE, WAIT_APP_LAUNCH, mRequest->packagename(), 0);
 
     return grpc::Status::OK;
 }
\ No newline at end of file
index 9e4a42a..2f087d5 100644 (file)
@@ -590,6 +590,7 @@ message ReqActionAndWaitEvent {
       EVENT_WINDOW_ACTIVATE = 0;
       EVENT_WINDOW_DEACTIVATE = 1;
       EVENT_STATE_CHANGED_FOCUSED = 2;
+      EVENT_WINDOW_IDLE = 3;
    }
    ActionType type = 1;
    oneof params {
@@ -599,6 +600,7 @@ message ReqActionAndWaitEvent {
    EventType eventType = 4;
    int32 timeoutMs = 5;
    string packageName = 6;
+   int32 count = 7;
 }
 
 message RspActionAndWaitEvent {