169e6baa3d1bdde63a208e6bde263718924fdd4d
[platform/core/uifw/aurum.git] / libaurum / src / UiDevice.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 #ifdef TIZEN
21 #include "TizenDeviceImpl.h"
22 #endif
23 #include "MockDeviceImpl.h"
24 #include "AtspiAccessibleWatcher.h"
25 #include <unistd.h>
26 #include <utility>
27 #include <vector>
28 #include <chrono>
29 #include <thread>
30 #include <algorithm>
31 #include <iostream>
32 #include <gio/gio.h>
33 #include <unordered_set>
34
35 using namespace Aurum;
36 using namespace AurumInternal;
37
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"
42
43 std::vector<std::shared_ptr<TizenWindow>> UiDevice::mTizenWindows;
44 std::once_flag UiDevice::mOnceFlag;
45 static GDBusConnection *system_conn;
46
47 #ifdef MQTT_ENABLED
48 std::shared_ptr<ScreenAnalyzerWatcher> UiDevice::mSAWatcher;
49 #endif
50
51 UiDevice::UiDevice() : UiDevice(nullptr) {}
52
53 UiDevice::UiDevice(IDevice *impl)
54     : mDeviceImpl(impl), mWaiter(new Waiter{this})
55 {
56     LOGI("UiDevice constructor");
57     mIsWithSA = false;
58 #ifdef MQTT_ENABLED
59     mSAWatcher = std::make_shared<ScreenAnalyzerWatcher>();
60 #endif
61     LOGI("UiDevice constructor finish");
62 }
63
64 UiDevice::~UiDevice()
65 {
66     delete mDeviceImpl;
67     delete mWaiter;
68 }
69
70 std::shared_ptr<UiDevice> UiDevice::getInstance(IDevice *deviceImpl)
71 {
72     static std::shared_ptr<UiDevice> device{nullptr};
73     std::call_once(mOnceFlag, [deviceImpl] {
74         if (deviceImpl) {
75             device.reset(new UiDevice(deviceImpl));
76         } else {
77 #ifdef TIZEN
78             device.reset(new UiDevice(new TizenDeviceImpl()));
79 #else
80             device.reset(new UiDevice(new MockDeviceImpl()));
81 #endif
82         }
83     });
84
85     return device;
86 }
87
88 std::vector<std::shared_ptr<TizenWindow>> UiDevice::getTizenWindowInfo() const
89 {
90     GError *err = NULL;
91     GDBusMessage *msg;
92     GDBusMessage *reply;
93     GDBusConnection *conn;
94     GVariant *body;
95     GVariantIter *iter = NULL;
96     int idx = 0;
97     int pid;
98     int x;
99     int y;
100     int w;
101     int h;
102     gboolean transformed;
103     gboolean alpha;
104     int opaque;
105     int visibility;
106     gboolean focused;
107     gboolean mapped;
108     int layer;
109     char *name;
110
111     mTizenWindows.clear();
112
113     if (system_conn == NULL) {
114         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
115         if (conn == NULL) {
116             LOGE("g_bus_get_sync() is failed. %s", err->message);
117             g_error_free(err);
118             return mTizenWindows;
119         }
120         system_conn = conn;
121     }
122
123     msg = g_dbus_message_new_method_call(WM_BUS_NAME,
124             WM_OBJECT_PATH,
125             WM_INTERFACE_NAME,
126             WM_METHOD_NAME_INFO);
127     if (msg == NULL) {
128         LOGE("g_dbus_message_new_method_call() is failed.");
129         return mTizenWindows;
130     }
131
132     reply = g_dbus_connection_send_message_with_reply_sync(system_conn, msg,
133             G_DBUS_SEND_MESSAGE_FLAGS_NONE, -1, NULL, NULL, &err);
134
135     if (!reply) {
136         if (err != NULL) {
137             LOGE("Failed to get info [%s]", err->message);
138             g_error_free(err);
139         }
140         goto out;
141     }
142
143     body = g_dbus_message_get_body(reply);
144     if (!body) {
145         LOGE("Failed to get body");
146         goto out;
147     }
148
149     g_variant_get(body, "(a(iiiiibbiibbis))", &iter);
150     if (!iter) {
151         LOGE("Failed to get iter");
152         goto out;
153     }
154
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)",
157                 &pid,
158                 &x,
159                 &y,
160                 &w,
161                 &h,
162                 &transformed,
163                 &alpha,
164                 &opaque,
165                 &visibility,
166                 &focused,
167                 &mapped,
168                 &layer,
169                 &name)) {
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)
172         {
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));
176         }
177     }
178
179 out:
180     if (iter)
181         g_variant_iter_free(iter);
182     if (msg)
183         g_object_unref(msg);
184     if (reply)
185         g_object_unref(reply);
186
187     return mTizenWindows;
188 }
189
190 std::vector<std::shared_ptr<AccessibleNode>> UiDevice::getWindowRoot() const
191 {
192     LOGI("Request window info");
193     getTizenWindowInfo();
194
195     std::vector<std::shared_ptr<AccessibleNode>> ret{};
196     std::unordered_map<int, std::shared_ptr<AccessibleApplication>> pidToAppNode{};
197
198     auto apps = AccessibleWatcher::getInstance()->getApplications();
199     for (auto app : apps)
200     {
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;
205     }
206
207     for (auto tWin : mTizenWindows)
208     {
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());
211
212         if (pidToAppNode.count(tWin->getPid() == 0)) continue;
213
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();
220              }
221         );
222
223         pidToAppNode.erase(tWin->getPid());
224     }
225
226     return ret;
227 }
228
229 bool UiDevice::hasObject(const std::shared_ptr<UiSelector> selector) const
230 {
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;
236     }
237
238     return false;
239 }
240
241 std::shared_ptr<UiObject> UiDevice::findObject(const std::shared_ptr<UiSelector> selector) const
242 {
243     auto rootNodes = getWindowRoot();
244     for (const auto &node : rootNodes) {
245         const std::shared_ptr<AccessibleNode> foundNode =
246             Comparer::findObject(getInstance(), selector, node);
247         if (foundNode)
248             return std::make_shared<UiObject>(getInstance(), selector, foundNode);
249     }
250     return std::shared_ptr<UiObject>{nullptr};
251 }
252
253
254 std::vector<std::shared_ptr<UiObject>> UiDevice::findObjects(
255     const std::shared_ptr<UiSelector> selector) const
256 {
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));
264     }
265     return ret;
266 }
267 bool UiDevice::waitFor(
268     const std::function<bool(const ISearchable *)> condition) const
269 {
270     return mWaiter->waitFor(condition);
271 }
272
273 std::shared_ptr<UiObject> UiDevice::waitFor(
274     const std::function<std::shared_ptr<UiObject>(const ISearchable *)>
275         condition) const
276 {
277     return mWaiter->waitFor(condition);
278 }
279 bool UiDevice::waitForIdle() const
280 {
281     std::this_thread::sleep_for(std::chrono::milliseconds{167});
282     return true;
283 }
284
285 bool UiDevice::waitForEvents(
286     const A11yEvent type, const int timeout) const
287 {
288     return executeAndWaitForEvents(NULL, type, timeout, std::string(), 0);
289 }
290
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
294 {
295     //FIXME: Need to get top window
296     auto wins = this->getWindowRoot();
297
298     return AccessibleWatcher::getInstance()->executeAndWaitForEvents(cmd, type, timeout, packageName, wins[0], count);
299 }
300
301 bool UiDevice::sendKeyAndWaitForEvents(
302     const std::string keycode, const A11yEvent type, const int timeout) const
303 {
304     std::unique_ptr<SendKeyRunnable> cmd = std::make_unique<SendKeyRunnable>(keycode);
305     return executeAndWaitForEvents(cmd.get(), type, timeout, std::string(), 0);
306 }
307
308 bool UiDevice::click(const int x, const int y)
309 {
310     bool result =  mDeviceImpl->click(x, y);
311     waitForIdle();
312     return result;
313 }
314
315 bool UiDevice::click(const int x, const int y, const unsigned int durationMs)
316 {
317     bool result = mDeviceImpl->click(x, y, durationMs);
318     waitForIdle();
319     return result;
320 }
321
322 bool UiDevice::drag(const int sx, const int sy, const int ex, const int ey,
323                     const int steps, const int durationMs)
324 {
325     bool result =  mDeviceImpl->drag(sx, sy, ex, ey, steps, durationMs);
326     waitForIdle();
327     return result;
328 }
329
330 int UiDevice::touchDown(const int x, const int y)
331 {
332     int seq =  mDeviceImpl->touchDown(x, y);
333     return seq;
334 }
335
336 bool UiDevice::touchMove(const int x, const int y, const int seq)
337 {
338     bool result =  mDeviceImpl->touchMove(x, y, seq);
339     return result;
340 }
341
342 bool UiDevice::touchUp(const int x, const int y, const int seq)
343 {
344     bool result =  mDeviceImpl->touchUp(x, y, seq);
345     waitForIdle();
346     return result;
347 }
348
349 bool UiDevice::wheelUp(int amount, const int durationMs)
350 {
351     bool result =  mDeviceImpl->wheelUp(amount, durationMs);
352     waitForIdle();
353     return result;
354 }
355
356 bool UiDevice::wheelDown(int amount, const int durationMs)
357 {
358     bool result =  mDeviceImpl->wheelDown(amount, durationMs);
359     waitForIdle();
360     return result;
361 }
362
363 bool UiDevice::pressBack(KeyRequestType type)
364 {
365     bool result =  mDeviceImpl->pressBack(type);
366     waitForIdle();
367     return result;
368 }
369
370 bool UiDevice::pressHome(KeyRequestType type)
371 {
372     bool result =  mDeviceImpl->pressHome(type);
373     waitForIdle();
374     return result;
375 }
376
377 bool UiDevice::pressMenu(KeyRequestType type)
378 {
379     bool result =  mDeviceImpl->pressMenu(type);
380     waitForIdle();
381     return result;
382 }
383
384 bool UiDevice::pressVolUp(KeyRequestType type)
385 {
386     bool result =  mDeviceImpl->pressVolUp(type);
387     waitForIdle();
388     return result;
389 }
390
391 bool UiDevice::pressVolDown(KeyRequestType type)
392 {
393     bool result =  mDeviceImpl->pressVolDown(type);
394     waitForIdle();
395     return result;
396 }
397
398 bool UiDevice::pressPower(KeyRequestType type)
399 {
400     bool result =  mDeviceImpl->pressPower(type);
401     waitForIdle();
402     return result;
403 }
404
405 bool UiDevice::pressKeyCode(std::string keycode, KeyRequestType type)
406 {
407     bool result =  mDeviceImpl->pressKeyCode(keycode, type);
408     return result;
409 }
410
411 bool UiDevice::repeatKeyCode(std::string keycode, int intervalMs, int durationMs)
412 {
413     bool result =  mDeviceImpl->repeatKeyCode(keycode, intervalMs, durationMs);
414     return result;
415 }
416
417 bool UiDevice::takeScreenshot(std::string path, float scale, int quality)
418 {
419     return mDeviceImpl->takeScreenshot(path, scale, quality);
420 }
421
422 long long UiDevice::getSystemTime(TimeRequestType type)
423 {
424     return mDeviceImpl->getSystemTime(type);
425 }
426
427 const Size2D<int> UiDevice::getScreenSize()
428 {
429     return mDeviceImpl->getScreenSize();
430 }
431
432 #ifdef MQTT_ENABLED
433 std::vector<std::shared_ptr<SaObject>> UiDevice::getSaObject()
434 {
435     return mSAWatcher->GetSaObjects();
436 }
437
438 std::shared_ptr<ScreenAnalyzerWatcher> UiDevice::getSAWatcher()
439 {
440     return mSAWatcher;
441 }
442 #endif
443
444 void UiDevice::RequestScreenAnalyze()
445 {
446 #ifdef MQTT_ENABLED
447     mSAWatcher->PublishData();
448 #endif
449 }
450
451 bool UiDevice::getExternalAppLaunched()
452 {
453     auto ret = this->getWindowRoot();
454     return (ret.size() > 0) ? false : true;
455 }
456
457 void UiDevice::setWithScreenAnalyzer(bool withScreenAnalyzer)
458 {
459     mIsWithSA = withScreenAnalyzer;
460 }
461
462 bool UiDevice::getWithScreenAnalyzer()
463 {
464     return mIsWithSA;
465 }
466
467 bool UiDevice::registerCallback(const A11yEvent type, EventHandler cb, void *data) const
468 {
469     return AccessibleWatcher::getInstance()->registerCallback(type, cb, data);
470 }