bootstrap: introduce a new command for dumping object tree
authorWonki Kim <wonki_.kim@samsung.com>
Thu, 13 Aug 2020 05:41:48 +0000 (14:41 +0900)
committerJongmin Lee <jm105.lee@samsung.com>
Thu, 27 Aug 2020 05:00:13 +0000 (14:00 +0900)
this patch introduces a new command for dumping object tree
by this patch, user can retreive tree dump without composition of findElement commands

Change-Id: I4a360fe11ac9df02bbdda8c65cc7275c47e1466c

libaurum/inc/UiObject.h
libaurum/src/Comparer.cc
libaurum/src/UiObject.cc
org.tizen.aurum-bootstrap/inc/Commands/Commands.h
org.tizen.aurum-bootstrap/inc/Commands/DumpObjectTreeCommand.h [new file with mode: 0644]
org.tizen.aurum-bootstrap/meson.build
org.tizen.aurum-bootstrap/src/AurumServiceImpl.cc
org.tizen.aurum-bootstrap/src/Commands/DumpObjectTreeCommand.cc [new file with mode: 0644]
protocol/aurum.proto
protocol/examples/python/testInternal.py

index 6735242da26cda6cb289c98b69e9b6810b213471..b9ff14a2942a91702e5e71b3c4a32222266ab031 100644 (file)
@@ -299,4 +299,4 @@ private:
     static const unsigned int LOGNCLICK_INTERVAL = 50;
 };
 
-#endif
\ No newline at end of file
+#endif
index 1b743348a68dceec528f397bbb05085e5c761105..ccf61384ffa60eb56646b85b1df1d4b8a81936a3 100644 (file)
@@ -75,4 +75,4 @@ std::vector<std::shared_ptr<AccessibleNode>> Comparer::findObjects(
     }
 
     return ret;
-}
\ No newline at end of file
+}
index 2a4cb7652beb12eff480fb95bd914c5f95df00b2..6b5b987d5f8eba86d17f3ac9818f18d659a5dbf5 100644 (file)
@@ -132,10 +132,7 @@ int UiObject::getChildCount() const
 
 std::vector<std::shared_ptr<UiObject>> UiObject::getChildren() const
 {
-    auto sel = std::make_shared<UiSelector>();
-    sel->depth(1);
-    sel->isShowing(true);
-    return this->findObjects(sel);
+    return this->findObjects(Sel::depth(1));
 }
 
 std::string UiObject::getApplicationPackage() const
@@ -280,4 +277,4 @@ std::shared_ptr<AccessibleNode> UiObject::getAccessibleNode() const
     // mDevice->waitForIdle();
     mNode->refresh();
     return mNode;
-}
\ No newline at end of file
+}
index 1999f95d4d68a89b7a4c3ae27955aff84386c486..cb21e7f182b273917ed6ec7bae9ed2f20fca0894 100644 (file)
@@ -32,4 +32,5 @@
 #include "Commands/SendKeyCommand.h"
 
 #include "Commands/TakeScreenshotCommand.h"
-#endif
\ No newline at end of file
+#include "Commands/DumpObjectTreeCommand.h"
+#endif
diff --git a/org.tizen.aurum-bootstrap/inc/Commands/DumpObjectTreeCommand.h b/org.tizen.aurum-bootstrap/inc/Commands/DumpObjectTreeCommand.h
new file mode 100644 (file)
index 0000000..4efd687
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include <aurum.grpc.pb.h>
+#include "config.h"
+
+class DumpObjectTreeCommand: public Command {
+protected:
+    const ::aurum::ReqDumpObjectTree* mRequest;
+    ::aurum::RspDumpObjectTree*       mResponse;
+
+protected:
+    ObjectMapper* mObjMap;
+
+public:
+    DumpObjectTreeCommand(const ::aurum::ReqDumpObjectTree* request,
+                       ::aurum::RspDumpObjectTree*       response);
+    ::grpc::Status execute() override;
+protected:
+    void traverse(::aurum::Element *el, std::string key, int depth);
+};
index 2661436eb5b64856c2996da6821fd0153a934510..8d414a6577fa970f7c88655c1fe587b3432d137a 100644 (file)
@@ -39,6 +39,7 @@ bootstrap_svr_src += [
    files('src/Commands/Command.cc'),
    files('src/Commands/PreCommand.cc'),
    files('src/Commands/PostCommand.cc'),
+   files('src/Commands/DumpObjectTreeCommand.cc'),
 ]
 
 bootstrap_svr_dep = [
@@ -70,4 +71,4 @@ bootstrap_svr_bin = executable(
    pie:true,
 )
 
-install_data('org.tizen.aurum-bootstrap.xml', install_dir: get_option('tzpackage_path'))
\ No newline at end of file
+install_data('org.tizen.aurum-bootstrap.xml', install_dir: get_option('tzpackage_path'))
index 4d177eaa4ddfdd2813a073badf25b656240f1c76..0c05327e5aa34a528e83d129387afa832b047982 100644 (file)
@@ -187,4 +187,12 @@ aurumServiceImpl::~aurumServiceImpl() {}
 {
     std::unique_ptr<TakeScreenshotCommand> cmd = std::make_unique<TakeScreenshotCommand>(request, writer);
     return execute(cmd.get());
-}
\ No newline at end of file
+}
+
+::grpc::Status aurumServiceImpl::dumpObjectTree(::grpc::ServerContext *context,
+                           const ::aurum::ReqDumpObjectTree *request,
+                           ::aurum::RspDumpObjectTree *      response)
+{
+    std::unique_ptr<DumpObjectTreeCommand> cmd = std::make_unique<DumpObjectTreeCommand>(request, response);
+    return execute(cmd.get());
+}
diff --git a/org.tizen.aurum-bootstrap/src/Commands/DumpObjectTreeCommand.cc b/org.tizen.aurum-bootstrap/src/Commands/DumpObjectTreeCommand.cc
new file mode 100644 (file)
index 0000000..ce371d0
--- /dev/null
@@ -0,0 +1,69 @@
+#include "DumpObjectTreeCommand.h"
+
+#include "ISearchable.h"
+
+#include "Sel.h"
+#include "UiDevice.h"
+#include "UiObject.h"
+#include "UiSelector.h"
+
+#include <loguru.hpp>
+
+
+DumpObjectTreeCommand::DumpObjectTreeCommand(const ::aurum::ReqDumpObjectTree* request,
+                                                   ::aurum::RspDumpObjectTree* response)
+    : mRequest{request}, mResponse{response}
+{
+    mObjMap = ObjectMapper::getInstance();
+}
+
+void populateElement(::aurum::Element *el, std::shared_ptr<UiObject> obj)
+{
+}
+
+void DumpObjectTreeCommand::traverse(::aurum::Element *el, std::string key, int depth)
+{
+    LOG_SCOPE_F(INFO, "traverse depth:%d el:%p key:%s", depth, el, key.c_str());
+
+    auto obj = mObjMap->getElement(key);
+    auto children = obj->getChildren();
+
+    ::aurum::Rect *rect = el->mutable_geometry();
+    const Rect<int> &size = obj->getBoundingBox();
+    rect->set_x(size.mTopLeft.x);
+    rect->set_y(size.mTopLeft.y);
+    rect->set_width(size.width());
+    rect->set_height(size.height());
+
+    el->set_widget_type(obj->getElementType());
+    el->set_widget_style(obj->getElementStyle());
+    el->set_value(obj->getText());
+
+    el->set_isshowing(obj->isShowing());
+    el->set_isvisible(obj->isVisible());
+    el->set_isenabled(obj->isEnabled());
+    el->set_isselected(obj->isSelected());
+    el->set_ischecked(obj->isChecked());
+
+    for (auto&& child : children) {
+        if (!(child->isShowing() && child->isVisible())) continue;
+        ::aurum::Element *childEl = el->add_child();
+        std::string key2 = mObjMap->addElement(std::move(child));
+        childEl->set_elementid(key2);
+        traverse(childEl, key2, depth+1);
+    }
+}
+
+::grpc::Status DumpObjectTreeCommand::execute()
+{
+    LOG_SCOPE_F(INFO, "DumpObjectTree --------------- ");
+    LOG_F(INFO, "elementid : %s", mRequest->elementid().c_str());
+    if (mRequest->elementid().length()) {
+        ::aurum::Element* root = mResponse->add_roots();
+        root->set_elementid(mRequest->elementid());
+        traverse(root, mRequest->elementid(), 0);
+    } else {
+        ;
+    }
+    return grpc::Status::OK;
+}
\ No newline at end of file
index 2eed21d07c4175b67e41ee90ab52bf6c94a2e763..a7cbad9e3213e4e858f1a2bf6668f97094fae49b 100644 (file)
@@ -29,6 +29,7 @@ service Bootstrap {
    rpc getLocation(ReqGetLocation) returns (RspGetLocation) {}
    rpc sendKey(ReqKey) returns (RspKey) {}
    rpc takeScreenshot(ReqTakeScreenshot) returns (stream RspTakeScreenshot) {}
+   rpc dumpObjectTree(ReqDumpObjectTree) returns (RspDumpObjectTree) {}
 }
 
 // ------------------------------------ //
@@ -48,6 +49,16 @@ enum ParamType {
 
 message Element {
    string elementId = 1;
+   repeated Element child = 2;
+   Rect geometry = 3;
+   string widget_type = 4;
+   string widget_style = 5;
+   string value = 6;
+   bool isShowing = 7;
+   bool isEnabled = 8;
+   bool isSelected = 9;
+   bool isChecked = 10;
+   bool isVisible = 11;
 }
 
 message Point {
@@ -370,3 +381,14 @@ message ReqEmpty {
 }
 message RspEmpty {
 }
+
+// ------------------------------------ //
+
+message ReqDumpObjectTree {
+   string elementId = 1;
+}
+
+message RspDumpObjectTree {
+   RspStatus status = 1;
+   repeated Element roots = 2;
+}
\ No newline at end of file
index 6c9f28dd08e09c75f0ce308b71ab929a4af0cf00..3ad24c35834d0a8afbd3275b6674ad7b6f5277da 100644 (file)
@@ -4,6 +4,9 @@ import aurum_pb2_grpc
 import logging
 import grpc
 import time
+from tkinter import *
+from PIL import ImageTk,Image
+
 def touchTest(stub):
     stub.touchUp(ReqTouchUp(coordination=Point(x=160,y=30), seqId=0))
     stub.touchUp(ReqTouchUp(coordination=Point(x=160,y=30), seqId=1))
@@ -19,11 +22,53 @@ def touchTest(stub):
 
     return True
 
+global img
+
+def traverse(node, canvas, depth):
+    print('traverse', depth)
+    print('size:',node.geometry)
+
+    #//canvas.pack()
+    rect = canvas.create_rectangle(node.geometry.x, node.geometry.y, node.geometry.x+node.geometry.width, node.geometry.y+node.geometry.height,  outline='red')
+    for child in node.child:
+        traverse(child, canvas, depth+1)
+
+def dumpTest(stub, tkroot):
+    response = stub.findElement(ReqFindElement(maxDepth=1, minDepth=1, isShowing=True))
+    print(response)
+    for i in response.elements:
+       response = stub.dumpObjectTree(ReqDumpObjectTree(elementId=i.elementId))
+    print(response.roots)
+
+    responses = stub.takeScreenshot(ReqTakeScreenshot())
+    image = open("screenshot.png", "wb")
+    for res in responses:
+        image.write(res.image)
+    image.close()
+
+    canvas = Canvas(tkroot, width=360, height=360)
+    canvas.pack()
+
+    img = ImageTk.PhotoImage(Image.open("./screenshot.png"))
+    print(img)
+    canvas.create_image(0, 0, anchor=NW, image=img)
+    canvas.img = img
+    traverse(response.roots[0], canvas, 0)
+
+def test(arg=None):
+    print(test, arg)
 
 def run():
     with grpc.insecure_channel('127.0.0.1:50051') as channel:
         stub = aurum_pb2_grpc.BootstrapStub(channel)
-        touchTest(stub)
+        root = Tk()
+        root.geometry('360x360')
+
+        dumpTest(stub, root)
+
+        root.mainloop()
+
+#        touchTest(stub)
 
 #        print(stub.getLocation(ReqGetLocation()).status)
 #        print(stub.sync(ReqEmpty()))