It support device idle point to user.
user can use this event instead of waiting ramdom time for ui update.
Change-Id: I72b24ff39b7613484c75280583ce2c41dceddc9b
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,
* @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.
/**
* @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
*/
/**
* @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()
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);
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;
};
}
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;
* @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;
* @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.
{"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},
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)
{
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)
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)
{
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();
mEventQueue.clear();
mMutex.unlock();
+ if (isIdle == IdleEventState::IDLE_LISTEN_DONE)
+ break;
+
if (!localEvents.empty())
{
for (const auto &event : localEvents) {
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;
}
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
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;
}
bool MockAccessibleWatcher::registerCallback(const A11yEvent type, EventHandler cb, void *data)
{
return true;
-}
\ No newline at end of file
+}
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)
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;
}
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);
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
EVENT_WINDOW_ACTIVATE = 0;
EVENT_WINDOW_DEACTIVATE = 1;
EVENT_STATE_CHANGED_FOCUSED = 2;
+ EVENT_WINDOW_IDLE = 3;
}
ActionType type = 1;
oneof params {
EventType eventType = 4;
int32 timeoutMs = 5;
string packageName = 6;
+ int32 count = 7;
}
message RspActionAndWaitEvent {