2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include "TizenDeviceImpl.h"
23 #include "MockDeviceImpl.h"
24 #include "AtspiAccessibleWatcher.h"
33 #include <unordered_set>
35 using namespace Aurum;
36 using namespace AurumInternal;
38 #define WM_BUS_NAME "org.enlightenment.wm"
39 #define WM_OBJECT_PATH "/org/enlightenment/wm"
40 #define WM_INTERFACE_NAME "org.enlightenment.wm.proc"
41 #define WM_METHOD_NAME_INFO "GetVisibleWinInfo_v2"
43 std::vector<std::shared_ptr<TizenWindow>> UiDevice::mTizenWindows;
44 std::once_flag UiDevice::mOnceFlag;
45 static GDBusConnection *system_conn;
48 std::shared_ptr<ScreenAnalyzerWatcher> UiDevice::mSAWatcher;
51 UiDevice::UiDevice() : UiDevice(nullptr) {}
53 UiDevice::UiDevice(IDevice *impl)
54 : mDeviceImpl(impl), mWaiter(new Waiter{this})
56 LOGI("UiDevice constructor");
59 mSAWatcher = std::make_shared<ScreenAnalyzerWatcher>();
61 LOGI("UiDevice constructor finish");
70 std::shared_ptr<UiDevice> UiDevice::getInstance(IDevice *deviceImpl)
72 static std::shared_ptr<UiDevice> device{nullptr};
73 std::call_once(mOnceFlag, [deviceImpl] {
75 device.reset(new UiDevice(deviceImpl));
78 device.reset(new UiDevice(new TizenDeviceImpl()));
80 device.reset(new UiDevice(new MockDeviceImpl()));
88 std::vector<std::shared_ptr<TizenWindow>> UiDevice::getTizenWindowInfo() const
93 GDBusConnection *conn;
95 GVariantIter *iter = NULL;
102 gboolean transformed;
111 mTizenWindows.clear();
113 if (system_conn == NULL) {
114 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
116 LOGE("g_bus_get_sync() is failed. %s", err->message);
118 return mTizenWindows;
123 msg = g_dbus_message_new_method_call(WM_BUS_NAME,
126 WM_METHOD_NAME_INFO);
128 LOGE("g_dbus_message_new_method_call() is failed.");
129 return mTizenWindows;
132 reply = g_dbus_connection_send_message_with_reply_sync(system_conn, msg,
133 G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
137 LOGE("Failed to get info [%s]", err->message);
143 body = g_dbus_message_get_body(reply);
145 LOGE("Failed to get body");
149 g_variant_get(body, "(a(iiiiibbiibbis))", &iter);
151 LOGE("Failed to get iter");
155 LOGI("%-3s | %-6s | %-4s | %-4s | %-4s | %-4s | %-5s | %-5s | %-6s | %-3s | %-7s | %-6s | %-5s | %-20s", "No" ,"PID", "X", "Y", "W", "H", "Trans", "Alpha", "Opaque", "Vis", "Focused", "Mapped", "Layer", "Name");
156 while (g_variant_iter_loop(iter, "(iiiiibbiibbis)",
170 LOGI("%-3d | %-6d | %-4d | %-4d | %-4d | %-4d | %-5d | %-5d | %-6d | %-3d | %-7d | %-6d | %-5d | %-20s", idx++, pid, x,y,w,h, transformed, alpha, opaque, visibility, focused, mapped, layer, name);
171 if (visibility == 0 && pid > 0)
173 Rect<int> geometry = {x, y, w, h};
174 std::string winName(name);
175 mTizenWindows.push_back(std::make_shared<Aurum::TizenWindow>(pid, geometry, transformed, alpha, opaque, visibility, focused, mapped, layer, winName));
181 g_variant_iter_free(iter);
185 g_object_unref(reply);
187 return mTizenWindows;
190 std::vector<std::shared_ptr<AccessibleNode>> UiDevice::getWindowRoot() const
192 LOGI("Request window info");
193 getTizenWindowInfo();
195 std::vector<std::shared_ptr<AccessibleNode>> ret{};
196 std::unordered_map<int, std::shared_ptr<AccessibleApplication>> pidToAppNode{};
198 auto apps = AccessibleWatcher::getInstance()->getApplications();
199 for (auto app : apps)
201 app->getAccessibleNode()->updateName();
202 app->getAccessibleNode()->updatePid();
203 LOGI("App(%s) Pid(%d)", app->getPackageName().c_str(), app->getAccessibleNode()->getPid());
204 pidToAppNode[app->getAccessibleNode()->getPid()] = app;
207 for (auto tWin : mTizenWindows)
209 LOGI("Visible win (%d) (%d %d %d %d) (%s)", tWin->getPid(), tWin->getWindowGeometry().mTopLeft.x, tWin->getWindowGeometry().mTopLeft.y, tWin->getWindowGeometry().width(),
210 tWin->getWindowGeometry().height(), tWin->getName().c_str());
212 if (pidToAppNode.count(tWin->getPid()) == 0) continue;
214 LOGI("Active App : (%s) (%d)", tWin->getName().c_str(), tWin->getPid());
215 auto wins = pidToAppNode[tWin->getPid()]->getWindows();
216 std::transform(wins.begin(), wins.end(), std::back_inserter(ret),
217 [&](std::shared_ptr<AccessibleWindow> window) {
218 LOGI("Target window add pkg: (%s), name (%s)", window->getAccessibleNode()->getPkg().c_str(), window->getTitle().c_str());
219 return window->getAccessibleNode();
223 pidToAppNode.erase(tWin->getPid());
229 bool UiDevice::hasObject(const std::shared_ptr<UiSelector> selector) const
231 auto rootNodes = getWindowRoot();
232 for (const auto &node : rootNodes) {
233 const std::shared_ptr<AccessibleNode> foundNode =
234 Comparer::findObject(getInstance(), selector, node);
235 if (foundNode) return true;
241 std::shared_ptr<UiObject> UiDevice::findObject(const std::shared_ptr<UiSelector> selector) const
243 auto rootNodes = getWindowRoot();
244 for (const auto &node : rootNodes) {
245 const std::shared_ptr<AccessibleNode> foundNode =
246 Comparer::findObject(getInstance(), selector, node);
248 return std::make_shared<UiObject>(getInstance(), selector, foundNode);
250 return std::shared_ptr<UiObject>{nullptr};
254 std::vector<std::shared_ptr<UiObject>> UiDevice::findObjects(
255 const std::shared_ptr<UiSelector> selector) const
257 std::vector<std::shared_ptr<UiObject>> ret{};
258 auto rootNodes = getWindowRoot();
259 for (const auto &window : rootNodes) {
260 std::vector<std::shared_ptr<AccessibleNode>> nodes =
261 Comparer::findObjects(getInstance(), selector, window);
262 for (auto &node : nodes)
263 ret.push_back(std::make_shared<UiObject>(getInstance(), selector, node));
267 bool UiDevice::waitFor(
268 const std::function<bool(const ISearchable *)> condition) const
270 return mWaiter->waitFor(condition);
273 std::shared_ptr<UiObject> UiDevice::waitFor(
274 const std::function<std::shared_ptr<UiObject>(const ISearchable *)>
277 return mWaiter->waitFor(condition);
279 bool UiDevice::waitForIdle() const
281 std::this_thread::sleep_for(std::chrono::milliseconds{167});
285 bool UiDevice::waitForEvents(
286 const A11yEvent type, const int timeout) const
288 return executeAndWaitForEvents(NULL, type, timeout, std::string(), 0);
291 //FIXME: obj only need for idle event
292 bool UiDevice::executeAndWaitForEvents
293 (const Runnable *cmd, const A11yEvent type, const int timeout, const std::string packageName, const int count) const
295 //FIXME: Need to get top window
296 auto wins = this->getWindowRoot();
298 return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout, packageName, wins[0], count);
301 bool UiDevice::sendKeyAndWaitForEvents(
302 const std::string keycode, const A11yEvent type, const int timeout) const
304 std::unique_ptr<SendKeyRunnable> cmd = std::make_unique<SendKeyRunnable>(keycode);
305 return executeAndWaitForEvents(cmd.get(), type, timeout, std::string(), 0);
308 bool UiDevice::click(const int x, const int y)
310 bool result = mDeviceImpl->click(x, y);
315 bool UiDevice::click(const int x, const int y, const unsigned int durationMs)
317 bool result = mDeviceImpl->click(x, y, durationMs);
322 bool UiDevice::drag(const int sx, const int sy, const int ex, const int ey,
323 const int steps, const int durationMs)
325 bool result = mDeviceImpl->drag(sx, sy, ex, ey, steps, durationMs);
330 int UiDevice::touchDown(const int x, const int y)
332 int seq = mDeviceImpl->touchDown(x, y);
336 bool UiDevice::touchMove(const int x, const int y, const int seq)
338 bool result = mDeviceImpl->touchMove(x, y, seq);
342 bool UiDevice::touchUp(const int x, const int y, const int seq)
344 bool result = mDeviceImpl->touchUp(x, y, seq);
349 bool UiDevice::wheelUp(int amount, const int durationMs)
351 bool result = mDeviceImpl->wheelUp(amount, durationMs);
356 bool UiDevice::wheelDown(int amount, const int durationMs)
358 bool result = mDeviceImpl->wheelDown(amount, durationMs);
363 bool UiDevice::pressBack(KeyRequestType type)
365 bool result = mDeviceImpl->pressBack(type);
370 bool UiDevice::pressHome(KeyRequestType type)
372 bool result = mDeviceImpl->pressHome(type);
377 bool UiDevice::pressMenu(KeyRequestType type)
379 bool result = mDeviceImpl->pressMenu(type);
384 bool UiDevice::pressVolUp(KeyRequestType type)
386 bool result = mDeviceImpl->pressVolUp(type);
391 bool UiDevice::pressVolDown(KeyRequestType type)
393 bool result = mDeviceImpl->pressVolDown(type);
398 bool UiDevice::pressPower(KeyRequestType type)
400 bool result = mDeviceImpl->pressPower(type);
405 bool UiDevice::pressKeyCode(std::string keycode, KeyRequestType type)
407 bool result = mDeviceImpl->pressKeyCode(keycode, type);
411 bool UiDevice::repeatKeyCode(std::string keycode, int intervalMs, int durationMs)
413 bool result = mDeviceImpl->repeatKeyCode(keycode, intervalMs, durationMs);
417 bool UiDevice::takeScreenshot(std::string path, float scale, int quality)
419 return mDeviceImpl->takeScreenshot(path, scale, quality);
422 long long UiDevice::getSystemTime(TimeRequestType type)
424 return mDeviceImpl->getSystemTime(type);
427 const Size2D<int> UiDevice::getScreenSize()
429 return mDeviceImpl->getScreenSize();
433 std::vector<std::shared_ptr<SaObject>> UiDevice::getSaObject()
435 return mSAWatcher->GetSaObjects();
438 std::shared_ptr<ScreenAnalyzerWatcher> UiDevice::getSAWatcher()
444 void UiDevice::RequestScreenAnalyze()
447 mSAWatcher->PublishData();
451 bool UiDevice::getExternalAppLaunched()
453 auto ret = this->getWindowRoot();
454 return (ret.size() > 0) ? false : true;
457 void UiDevice::setWithScreenAnalyzer(bool withScreenAnalyzer)
459 mIsWithSA = withScreenAnalyzer;
462 bool UiDevice::getWithScreenAnalyzer()
467 bool UiDevice::registerCallback(const A11yEvent type, EventHandler cb, void *data) const
469 return AccessibleWatcher::getInstance()->registerCallback(type, cb, data);