/* * Copyright (C) 2016 Simon Fels * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License version 3, as published * by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . * */ #include "anbox/bridge/android_api_stub.h" #include "anbox/system_configuration.h" #include "anbox/logger.h" #include "anbox/rpc/channel.h" #include "anbox/utils.h" #include "anbox/wm/stack.h" #include "anbox_bridge.pb.h" #include "anbox_rpc.pb.h" #include #ifdef USE_PROTOBUF_CALLBACK_HEADER #include #endif namespace fs = boost::filesystem; namespace { constexpr const std::chrono::milliseconds default_rpc_call_timeout{30000}; } // namespace namespace anbox { namespace bridge { AndroidApiStub::AndroidApiStub() {} AndroidApiStub::~AndroidApiStub() {} void AndroidApiStub::set_rpc_channel( const std::shared_ptr &channel) { channel_ = channel; } void AndroidApiStub::reset_rpc_channel() { channel_.reset(); } void AndroidApiStub::ensure_rpc_channel() { if (!channel_) throw std::runtime_error("No remote client connected"); } void AndroidApiStub::launch(const android::Intent &intent, const graphics::Rect &launch_bounds, const wm::Stack::Id &stack) { ensure_rpc_channel(); auto c = std::make_shared>(); protobuf::bridge::LaunchApplication message; { std::lock_guard lock(mutex_); launch_wait_handle_.expect_result(); } switch (stack) { case wm::Stack::Id::Default: message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_DEFAULT); break; case wm::Stack::Id::Fullscreen: message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FULLSCREEN); break; case wm::Stack::Id::Freeform: message.set_stack(::anbox::protobuf::bridge::LaunchApplication_Stack_FREEFORM); break; default: break; } if (launch_bounds != graphics::Rect::Invalid) { auto rect = message.mutable_launch_bounds(); rect->set_left(launch_bounds_.left()); rect->set_top(launch_bounds_.top()); rect->set_right(launch_bounds_.right()); rect->set_bottom(launch_bounds_.bottom()); } auto launch_intent = message.mutable_intent(); if (!intent.action.empty()) launch_intent->set_action(intent.action); if (!intent.uri.empty()) launch_intent->set_uri(intent.uri); if (!intent.type.empty()) launch_intent->set_type(intent.type); if (!intent.package.empty()) launch_intent->set_package(intent.package); if (!intent.component.empty()) launch_intent->set_component(intent.component); for (const auto &category : intent.categories) { auto c = launch_intent->add_categories(); *c = category; } channel_->call_method( "launch_application", &message, c->response.get(), google::protobuf::NewCallback(this, &AndroidApiStub::application_launched, c.get())); launch_wait_handle_.wait_for_pending(default_rpc_call_timeout); if (!launch_wait_handle_.has_result()) throw std::runtime_error("RPC call timed out"); if (c->response->has_error()) throw std::runtime_error(c->response->error()); } core::Property& AndroidApiStub::ready() { return ready_; } void AndroidApiStub::application_launched( Request *request) { (void)request; launch_wait_handle_.result_received(); } void AndroidApiStub::set_focused_task(const std::int32_t &id) { ensure_rpc_channel(); auto c = std::make_shared>(); protobuf::bridge::SetFocusedTask message; message.set_id(id); { std::lock_guard lock(mutex_); set_focused_task_handle_.expect_result(); } channel_->call_method("set_focused_task", &message, c->response.get(), google::protobuf::NewCallback( this, &AndroidApiStub::focused_task_set, c.get())); set_focused_task_handle_.wait_for_pending(default_rpc_call_timeout); if (!set_focused_task_handle_.has_result()) throw std::runtime_error("RPC call timed out"); if (c->response->has_error()) throw std::runtime_error(c->response->error()); } void AndroidApiStub::focused_task_set(Request *request) { (void)request; set_focused_task_handle_.result_received(); } void AndroidApiStub::remove_task(const std::int32_t &id) { ensure_rpc_channel(); auto c = std::make_shared>(); protobuf::bridge::RemoveTask message; message.set_id(id); { std::lock_guard lock(mutex_); remove_task_handle_.expect_result(); } channel_->call_method("remove_task", &message, c->response.get(), google::protobuf::NewCallback( this, &AndroidApiStub::task_removed, c.get())); remove_task_handle_.wait_for_pending(default_rpc_call_timeout); if (!remove_task_handle_.has_result()) throw std::runtime_error("RPC call timed out"); if (c->response->has_error()) throw std::runtime_error(c->response->error()); } void AndroidApiStub::task_removed(Request *request) { (void)request; remove_task_handle_.result_received(); } void AndroidApiStub::resize_task(const std::int32_t &id, const anbox::graphics::Rect &rect, const std::int32_t &resize_mode) { ensure_rpc_channel(); auto c = std::make_shared>(); protobuf::bridge::ResizeTask message; message.set_id(id); message.set_resize_mode(resize_mode); auto r = message.mutable_rect(); r->set_left(rect.left()); r->set_top(rect.top()); r->set_right(rect.right()); r->set_bottom(rect.bottom()); { std::lock_guard lock(mutex_); resize_task_handle_.expect_result(); } channel_->call_method("resize_task", &message, c->response.get(), google::protobuf::NewCallback( this, &AndroidApiStub::task_resized, c.get())); resize_task_handle_.wait_for_pending(default_rpc_call_timeout); if (!resize_task_handle_.has_result()) throw std::runtime_error("RPC call timed out"); if (c->response->has_error()) throw std::runtime_error(c->response->error()); } void AndroidApiStub::task_resized(Request *request) { (void)request; resize_task_handle_.result_received(); } } // namespace bridge } // namespace anbox