TYPE3
[iec.git] / src / type3_AndroidCloud / anbox-master / src / anbox / bridge / android_api_stub.cpp
1 /*
2  * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 3, as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranties of
10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11  * PURPOSE.  See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program.  If not, see <http://www.gnu.org/licenses/>.
15  *
16  */
17
18 #include "anbox/bridge/android_api_stub.h"
19 #include "anbox/system_configuration.h"
20 #include "anbox/logger.h"
21 #include "anbox/rpc/channel.h"
22 #include "anbox/utils.h"
23 #include "anbox/wm/stack.h"
24
25 #include "anbox_bridge.pb.h"
26 #include "anbox_rpc.pb.h"
27
28 #include <boost/filesystem.hpp>
29 #ifdef USE_PROTOBUF_CALLBACK_HEADER
30 #include <google/protobuf/stubs/callback.h>
31 #endif
32
33
34 namespace fs = boost::filesystem;
35
36 namespace {
37 constexpr const std::chrono::milliseconds default_rpc_call_timeout{30000};
38 } // namespace
39
40 namespace anbox {
41 namespace bridge {
42 AndroidApiStub::AndroidApiStub() {}
43
44 AndroidApiStub::~AndroidApiStub() {}
45
46 void AndroidApiStub::set_rpc_channel(
47     const std::shared_ptr<rpc::Channel> &channel) {
48   channel_ = channel;
49 }
50
51 void AndroidApiStub::reset_rpc_channel() { channel_.reset(); }
52
53 void AndroidApiStub::ensure_rpc_channel() {
54   if (!channel_) throw std::runtime_error("No remote client connected");
55 }
56
57 void AndroidApiStub::launch(const android::Intent &intent,
58                             const graphics::Rect &launch_bounds,
59                             const wm::Stack::Id &stack) {
60   ensure_rpc_channel();
61
62   auto c = std::make_shared<Request<protobuf::rpc::Void>>();
63   protobuf::bridge::LaunchApplication message;
64
65   {
66     std::lock_guard<decltype(mutex_)> lock(mutex_);
67     launch_wait_handle_.expect_result();
68   }
69
70   switch (stack) {
71   case wm::Stack::Id::Default:
72     message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_DEFAULT);
73     break;
74   case wm::Stack::Id::Fullscreen:
75     message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FULLSCREEN);
76     break;
77   case wm::Stack::Id::Freeform:
78     message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FREEFORM);
79     break;
80   default:
81     break;
82   }
83
84   if (launch_bounds != graphics::Rect::Invalid) {
85     auto rect = message.mutable_launch_bounds();
86     rect->set_left(launch_bounds_.left());
87     rect->set_top(launch_bounds_.top());
88     rect->set_right(launch_bounds_.right());
89     rect->set_bottom(launch_bounds_.bottom());
90   }
91
92   auto launch_intent = message.mutable_intent();
93
94   if (!intent.action.empty()) launch_intent->set_action(intent.action);
95
96   if (!intent.uri.empty()) launch_intent->set_uri(intent.uri);
97
98   if (!intent.type.empty()) launch_intent->set_type(intent.type);
99
100   if (!intent.package.empty()) launch_intent->set_package(intent.package);
101
102   if (!intent.component.empty()) launch_intent->set_component(intent.component);
103
104   for (const auto &category : intent.categories) {
105     auto c = launch_intent->add_categories();
106     *c = category;
107   }
108
109   channel_->call_method(
110       "launch_application", &message, c->response.get(),
111       google::protobuf::NewCallback(this, &AndroidApiStub::application_launched,
112                                     c.get()));
113
114   launch_wait_handle_.wait_for_pending(default_rpc_call_timeout);
115   if (!launch_wait_handle_.has_result())
116     throw std::runtime_error("RPC call timed out");
117
118   if (c->response->has_error()) throw std::runtime_error(c->response->error());
119 }
120
121 core::Property<bool>& AndroidApiStub::ready() {
122   return ready_;
123 }
124
125 void AndroidApiStub::application_launched(
126     Request<protobuf::rpc::Void> *request) {
127   (void)request;
128   launch_wait_handle_.result_received();
129 }
130
131 void AndroidApiStub::set_focused_task(const std::int32_t &id) {
132   ensure_rpc_channel();
133
134   auto c = std::make_shared<Request<protobuf::rpc::Void>>();
135
136   protobuf::bridge::SetFocusedTask message;
137   message.set_id(id);
138
139   {
140     std::lock_guard<decltype(mutex_)> lock(mutex_);
141     set_focused_task_handle_.expect_result();
142   }
143
144   channel_->call_method("set_focused_task", &message, c->response.get(),
145                         google::protobuf::NewCallback(
146                             this, &AndroidApiStub::focused_task_set, c.get()));
147
148   set_focused_task_handle_.wait_for_pending(default_rpc_call_timeout);
149   if (!set_focused_task_handle_.has_result())
150     throw std::runtime_error("RPC call timed out");
151
152   if (c->response->has_error()) throw std::runtime_error(c->response->error());
153 }
154
155 void AndroidApiStub::focused_task_set(Request<protobuf::rpc::Void> *request) {
156   (void)request;
157   set_focused_task_handle_.result_received();
158 }
159
160 void AndroidApiStub::remove_task(const std::int32_t &id) {
161   ensure_rpc_channel();
162
163   auto c = std::make_shared<Request<protobuf::rpc::Void>>();
164
165   protobuf::bridge::RemoveTask message;
166   message.set_id(id);
167
168   {
169     std::lock_guard<decltype(mutex_)> lock(mutex_);
170     remove_task_handle_.expect_result();
171   }
172
173   channel_->call_method("remove_task", &message, c->response.get(),
174                         google::protobuf::NewCallback(
175                             this, &AndroidApiStub::task_removed, c.get()));
176
177   remove_task_handle_.wait_for_pending(default_rpc_call_timeout);
178   if (!remove_task_handle_.has_result())
179     throw std::runtime_error("RPC call timed out");
180
181   if (c->response->has_error()) throw std::runtime_error(c->response->error());
182 }
183
184 void AndroidApiStub::task_removed(Request<protobuf::rpc::Void> *request) {
185   (void)request;
186   remove_task_handle_.result_received();
187 }
188
189 void AndroidApiStub::resize_task(const std::int32_t &id,
190                                  const anbox::graphics::Rect &rect,
191                                  const std::int32_t &resize_mode) {
192   ensure_rpc_channel();
193
194   auto c = std::make_shared<Request<protobuf::rpc::Void>>();
195
196   protobuf::bridge::ResizeTask message;
197   message.set_id(id);
198   message.set_resize_mode(resize_mode);
199
200   auto r = message.mutable_rect();
201   r->set_left(rect.left());
202   r->set_top(rect.top());
203   r->set_right(rect.right());
204   r->set_bottom(rect.bottom());
205
206   {
207     std::lock_guard<decltype(mutex_)> lock(mutex_);
208     resize_task_handle_.expect_result();
209   }
210
211   channel_->call_method("resize_task", &message, c->response.get(),
212                         google::protobuf::NewCallback(
213                             this, &AndroidApiStub::task_resized, c.get()));
214
215   resize_task_handle_.wait_for_pending(default_rpc_call_timeout);
216   if (!resize_task_handle_.has_result())
217     throw std::runtime_error("RPC call timed out");
218
219   if (c->response->has_error()) throw std::runtime_error(c->response->error());
220 }
221
222 void AndroidApiStub::task_resized(Request<protobuf::rpc::Void> *request) {
223   (void)request;
224   resize_task_handle_.result_received();
225 }
226 }  // namespace bridge
227 }  // namespace anbox