2 * Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
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.
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.
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/>.
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"
25 #include "anbox_bridge.pb.h"
26 #include "anbox_rpc.pb.h"
28 #include <boost/filesystem.hpp>
29 #ifdef USE_PROTOBUF_CALLBACK_HEADER
30 #include <google/protobuf/stubs/callback.h>
34 namespace fs = boost::filesystem;
37 constexpr const std::chrono::milliseconds default_rpc_call_timeout{30000};
42 AndroidApiStub::AndroidApiStub() {}
44 AndroidApiStub::~AndroidApiStub() {}
46 void AndroidApiStub::set_rpc_channel(
47 const std::shared_ptr<rpc::Channel> &channel) {
51 void AndroidApiStub::reset_rpc_channel() { channel_.reset(); }
53 void AndroidApiStub::ensure_rpc_channel() {
54 if (!channel_) throw std::runtime_error("No remote client connected");
57 void AndroidApiStub::launch(const android::Intent &intent,
58 const graphics::Rect &launch_bounds,
59 const wm::Stack::Id &stack) {
62 auto c = std::make_shared<Request<protobuf::rpc::Void>>();
63 protobuf::bridge::LaunchApplication message;
66 std::lock_guard<decltype(mutex_)> lock(mutex_);
67 launch_wait_handle_.expect_result();
71 case wm::Stack::Id::Default:
72 message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_DEFAULT);
74 case wm::Stack::Id::Fullscreen:
75 message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FULLSCREEN);
77 case wm::Stack::Id::Freeform:
78 message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FREEFORM);
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());
92 auto launch_intent = message.mutable_intent();
94 if (!intent.action.empty()) launch_intent->set_action(intent.action);
96 if (!intent.uri.empty()) launch_intent->set_uri(intent.uri);
98 if (!intent.type.empty()) launch_intent->set_type(intent.type);
100 if (!intent.package.empty()) launch_intent->set_package(intent.package);
102 if (!intent.component.empty()) launch_intent->set_component(intent.component);
104 for (const auto &category : intent.categories) {
105 auto c = launch_intent->add_categories();
109 channel_->call_method(
110 "launch_application", &message, c->response.get(),
111 google::protobuf::NewCallback(this, &AndroidApiStub::application_launched,
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");
118 if (c->response->has_error()) throw std::runtime_error(c->response->error());
121 core::Property<bool>& AndroidApiStub::ready() {
125 void AndroidApiStub::application_launched(
126 Request<protobuf::rpc::Void> *request) {
128 launch_wait_handle_.result_received();
131 void AndroidApiStub::set_focused_task(const std::int32_t &id) {
132 ensure_rpc_channel();
134 auto c = std::make_shared<Request<protobuf::rpc::Void>>();
136 protobuf::bridge::SetFocusedTask message;
140 std::lock_guard<decltype(mutex_)> lock(mutex_);
141 set_focused_task_handle_.expect_result();
144 channel_->call_method("set_focused_task", &message, c->response.get(),
145 google::protobuf::NewCallback(
146 this, &AndroidApiStub::focused_task_set, c.get()));
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");
152 if (c->response->has_error()) throw std::runtime_error(c->response->error());
155 void AndroidApiStub::focused_task_set(Request<protobuf::rpc::Void> *request) {
157 set_focused_task_handle_.result_received();
160 void AndroidApiStub::remove_task(const std::int32_t &id) {
161 ensure_rpc_channel();
163 auto c = std::make_shared<Request<protobuf::rpc::Void>>();
165 protobuf::bridge::RemoveTask message;
169 std::lock_guard<decltype(mutex_)> lock(mutex_);
170 remove_task_handle_.expect_result();
173 channel_->call_method("remove_task", &message, c->response.get(),
174 google::protobuf::NewCallback(
175 this, &AndroidApiStub::task_removed, c.get()));
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");
181 if (c->response->has_error()) throw std::runtime_error(c->response->error());
184 void AndroidApiStub::task_removed(Request<protobuf::rpc::Void> *request) {
186 remove_task_handle_.result_received();
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();
194 auto c = std::make_shared<Request<protobuf::rpc::Void>>();
196 protobuf::bridge::ResizeTask message;
198 message.set_resize_mode(resize_mode);
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());
207 std::lock_guard<decltype(mutex_)> lock(mutex_);
208 resize_task_handle_.expect_result();
211 channel_->call_method("resize_task", &message, c->response.get(),
212 google::protobuf::NewCallback(
213 this, &AndroidApiStub::task_resized, c.get()));
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");
219 if (c->response->has_error()) throw std::runtime_error(c->response->error());
222 void AndroidApiStub::task_resized(Request<protobuf::rpc::Void> *request) {
224 resize_task_handle_.result_received();
226 } // namespace bridge