Improve application manangement and create desktop entries for available app

This commit is contained in:
Simon Fels 2016-12-02 16:11:38 +01:00
commit 00aadb5467
45 changed files with 1435 additions and 249 deletions

View file

@ -60,6 +60,8 @@ set(SOURCES
anbox/not_reachable.cpp
anbox/application_manager.h
anbox/android/intent.cpp
anbox/common/fd.cpp
anbox/common/fd_sets.h
anbox/common/variable_length_array.h
@ -168,9 +170,10 @@ set(SOURCES
anbox/dbus/skeleton/application_manager.cpp
anbox/dbus/stub/application_manager.cpp
anbox/application/launcher_storage.cpp
anbox/cmds/version.cpp
anbox/cmds/run.cpp
anbox/cmds/install.cpp
anbox/cmds/launch.cpp
anbox/cmds/container_manager.cpp
@ -193,7 +196,8 @@ target_link_libraries(anbox-core
renderControl_dec
OpenGLESDispatch
OpenglCodecCommon
anbox-protobuf)
anbox-protobuf
xdg)
add_executable(anbox main.cpp)
target_link_libraries(anbox

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/android/intent.h"
#include <ostream>
namespace anbox {
namespace android {
std::ostream& operator<<(std::ostream &out, const Intent &intent)
{
out << "["
<< "action=" << intent.action << " "
<< "uri=" << intent.uri << " "
<< "type=" << intent.type << " "
<< "flags=" << intent.flags << " "
<< "package=" << intent.package << " "
<< "component=" << intent.component << " "
<< "categories=[ ";
for (const auto &category : intent.categories)
out << category << " ";
out << "]]";
return out;
}
} // namespace android
} // namespace anbox

View file

@ -0,0 +1,41 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_ANDROID_INTENT_H_
#define ANBOX_ANDROID_INTENT_H_
#include <string>
#include <vector>
namespace anbox {
namespace android {
struct Intent {
std::string action;
std::string uri;
std::string type;
int flags = 0;
std::string package;
std::string component;
std::vector<std::string> categories;
};
std::ostream& operator<<(std::ostream &out, const Intent &intent);
} // namespace android
} // namespace anbox
#endif

View file

@ -0,0 +1,71 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#include "anbox/application/launcher_storage.h"
#include "anbox/utils.h"
#include <algorithm>
#include <iostream>
#include <fstream>
namespace fs = boost::filesystem;
namespace anbox {
namespace application {
LauncherStorage::LauncherStorage(const fs::path &path) :
path_(path) {
}
LauncherStorage::~LauncherStorage() {
}
void LauncherStorage::add(const Item &item) {
if (!fs::exists(path_))
fs::create_directories(path_);
auto package_name = item.package;
std::replace(package_name.begin(), package_name.end(), '.', '-');
const auto item_path = path_ / utils::string_format("anbox-%s.desktop", package_name);
std::string exec = "anbox launch ";
if (!item.launch_intent.action.empty())
exec += utils::string_format("--action=%s ", item.launch_intent.action);
if (!item.launch_intent.type.empty())
exec += utils::string_format("--type=%s ", item.launch_intent.type);
if (!item.launch_intent.uri.empty())
exec += utils::string_format("--uri=%s ", item.launch_intent.uri);
if (!item.launch_intent.package.empty())
exec += utils::string_format("--package=%s ", item.launch_intent.package);
if (!item.launch_intent.component.empty())
exec += utils::string_format("--component=%s ", item.launch_intent.component);
std::ofstream f(item_path.string());
f << "[Desktop Entry]" << std::endl
<< "Name=" << item.package << std::endl
<< "Exec=" << exec << std::endl
<< "Terminal=false" << std::endl
<< "Type=Application" << std::endl
<< "Encoding=UTF-8" << std::endl;
f.close();
}
} // namespace application
} // namespace anbox

View file

@ -0,0 +1,49 @@
/*
* Copyright (C) 2016 Simon Fels <morphis@gravedo.de>
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef ANBOX_APPLICATION_LAUNCHER_STORAGE_H_
#define ANBOX_APPLICATION_LAUNCHER_STORAGE_H_
#include "anbox/android/intent.h"
#include <string>
#include <vector>
#include <boost/filesystem.hpp>
namespace anbox {
namespace application {
class LauncherStorage {
public:
LauncherStorage(const boost::filesystem::path &path);
~LauncherStorage();
struct Item {
std::string name;
std::string package;
android::Intent launch_intent;
};
void add(const Item &item);
private:
boost::filesystem::path path_;
};
} // namespace application
} // namespace anbox
#endif

View file

@ -19,14 +19,14 @@
#define ANBOX_APPLICATION_MANAGER_H_
#include "anbox/do_not_copy_or_move.h"
#include "anbox/android/intent.h"
#include <string>
namespace anbox {
class ApplicationManager : public DoNotCopyOrMove {
public:
virtual void install(const std::string &path) = 0;
virtual void launch(const std::string &package, const std::string &activity) = 0;
virtual void launch(const android::Intent &intent) = 0;
};
} // namespace anbox

View file

@ -49,57 +49,39 @@ void AndroidApiStub::ensure_rpc_channel() {
throw std::runtime_error("No remote client connected");
}
void AndroidApiStub::install(const std::string &path) {
ensure_rpc_channel();
const auto target_path = utils::string_format("/data/anbox-share/%s", fs::path(path).filename().string());
if (fs::exists(target_path))
fs::remove(target_path);
fs::copy(path, target_path);
const auto container_path = utils::string_format("/data/anbox-share/%s", fs::path(path).filename().string());
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::InstallApplication message;
message.set_path(container_path);
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
install_wait_handle_.expect_result();
}
channel_->call_method("install_application",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &AndroidApiStub::application_installed, c.get()));
install_wait_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
}
void AndroidApiStub::application_installed(Request<protobuf::rpc::Void> *request) {
(void) request;
install_wait_handle_.result_received();
}
void AndroidApiStub::launch(const std::string &package, const std::string &activity) {
void AndroidApiStub::launch(const android::Intent &intent) {
ensure_rpc_channel();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::LaunchApplication message;
message.set_package_name(package);
if (activity.length() > 0)
message.set_activity(activity);
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
launch_wait_handle_.expect_result();
}
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(),
@ -116,40 +98,6 @@ void AndroidApiStub::application_launched(Request<protobuf::rpc::Void> *request)
launch_wait_handle_.result_received();
}
void AndroidApiStub::set_dns_servers(const std::string &domain, const std::vector<std::string> &servers) {
ensure_rpc_channel();
auto c = std::make_shared<Request<protobuf::rpc::Void>>();
protobuf::bridge::SetDnsServers message;
message.set_domain(domain);
for (const auto &server : servers) {
auto server_message = message.add_servers();
server_message->set_address(server);
}
{
std::lock_guard<decltype(mutex_)> lock(mutex_);
set_dns_servers_wait_handle_.expect_result();
}
channel_->call_method("set_dns_servers",
&message,
c->response.get(),
google::protobuf::NewCallback(this, &AndroidApiStub::dns_servers_set, c.get()));
set_dns_servers_wait_handle_.wait_for_all();
if (c->response->has_error())
throw std::runtime_error(c->response->error());
}
void AndroidApiStub::dns_servers_set(Request<protobuf::rpc::Void> *request) {
(void) request;
set_dns_servers_wait_handle_.result_received();
}
void AndroidApiStub::set_focused_task(const std::int32_t &id) {
ensure_rpc_channel();

View file

@ -42,10 +42,8 @@ public:
void set_rpc_channel(const std::shared_ptr<rpc::Channel> &channel);
void reset_rpc_channel();
void install(const std::string &path) override;
void launch(const std::string &package, const std::string &activity) override;
void launch(const android::Intent &intent) override;
void set_dns_servers(const std::string &domain, const std::vector<std::string> &servers);
void set_focused_task(const std::int32_t &id);
private:
@ -58,16 +56,12 @@ private:
bool success;
};
void application_installed(Request<protobuf::rpc::Void> *request);
void application_launched(Request<protobuf::rpc::Void> *request);
void dns_servers_set(Request<protobuf::rpc::Void> *request);
void focused_task_set(Request<protobuf::rpc::Void> *request);
mutable std::mutex mutex_;
std::shared_ptr<rpc::Channel> channel_;
common::WaitHandle install_wait_handle_;
common::WaitHandle launch_wait_handle_;
common::WaitHandle set_dns_servers_wait_handle_;
common::WaitHandle set_focused_task_handle_;
};
} // namespace bridge

View file

@ -16,6 +16,7 @@
*/
#include "anbox/bridge/platform_api_skeleton.h"
#include "anbox/application/launcher_storage.h"
#include "anbox/wm/manager.h"
#include "anbox/wm/window_state.h"
#include "anbox/logger.h"
@ -25,9 +26,11 @@
namespace anbox {
namespace bridge {
PlatformApiSkeleton::PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager) :
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage) :
pending_calls_(pending_calls),
window_manager_(window_manager) {
window_manager_(window_manager),
launcher_storage_(launcher_storage) {
}
PlatformApiSkeleton::~PlatformApiSkeleton() {
@ -66,6 +69,29 @@ void PlatformApiSkeleton::handle_window_state_update_event(const anbox::protobuf
window_manager_->apply_window_state_update(updated, removed);
}
void PlatformApiSkeleton::handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) {
for (int n = 0; n < event.applications_size(); n++) {
application::LauncherStorage::Item item;
const auto app = event.applications(n);
item.name = app.name();
item.package = app.package();
const auto li = app.launch_intent();
item.launch_intent.action = li.action();
item.launch_intent.uri = li.uri();
item.launch_intent.type = li.uri();
item.launch_intent.package = li.package();
item.launch_intent.component = li.component();
for (int m = 0; m < li.categories_size(); m++)
item.launch_intent.categories.push_back(li.categories(m));
// If the item is already stored it will be updated
launcher_storage_->add(item);
}
}
void PlatformApiSkeleton::register_boot_finished_handler(const std::function<void()> &action) {
boot_finished_handler_ = action;
}

View file

@ -34,6 +34,7 @@ class Void;
namespace bridge {
class BootFinishedEvent;
class WindowStateUpdateEvent;
class ApplicationListUpdateEvent;
} // namespace bridge
} // namespace protobuf
namespace rpc {
@ -42,21 +43,27 @@ class PendingCallCache;
namespace wm {
class Manager;
} // namespace wm
namespace application {
class LauncherStorage;
} // namespace application
namespace bridge {
class PlatformApiSkeleton {
public:
PlatformApiSkeleton(const std::shared_ptr<rpc::PendingCallCache> &pending_calls,
const std::shared_ptr<wm::Manager> &window_manager);
const std::shared_ptr<wm::Manager> &window_manager,
const std::shared_ptr<application::LauncherStorage> &launcher_storage);
virtual ~PlatformApiSkeleton();
void handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event);
void handle_window_state_update_event(const anbox::protobuf::bridge::WindowStateUpdateEvent &event);
void handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event);
void register_boot_finished_handler(const std::function<void()> &action);
private:
std::shared_ptr<rpc::PendingCallCache> pending_calls_;
std::shared_ptr<wm::Manager> window_manager_;
std::shared_ptr<application::LauncherStorage> launcher_storage_;
std::function<void()> boot_finished_handler_;
};
} // namespace bridge

View file

@ -44,11 +44,14 @@ void PlatformMessageProcessor::process_event_sequence(const std::string &raw_eve
return;
}
if (seq.has_boot_finished())
server_->handle_boot_finished_event(seq.boot_finished());
if (seq.has_window_state_update())
server_->handle_window_state_update_event(seq.window_state_update());
if (seq.has_boot_finished())
server_->handle_boot_finished_event(seq.boot_finished());
if (seq.has_application_list_update())
server_->handle_application_list_update_event(seq.application_list_update());
}
} // namespace anbox
} // namespace network

View file

@ -25,19 +25,20 @@
namespace fs = boost::filesystem;
anbox::cmds::Launch::Launch()
: CommandWithFlagsAndAction{cli::Name{"launch"}, cli::Usage{"launch"}, cli::Description{"Launch specified application in the Android container"}}
: CommandWithFlagsAndAction{cli::Name{"launch"}, cli::Usage{"launch"}, cli::Description{"Launch an Activity by sending an intent"}}
{
flag(cli::make_flag(cli::Name{"package"}, cli::Description{"Package the application is part of"}, package_));
flag(cli::make_flag(cli::Name{"activity"}, cli::Description{"Activity of the application to start"}, activity_));
action([this](const cli::Command::Context&) {
if (package_.empty() && activity_.empty())
BOOST_THROW_EXCEPTION(std::runtime_error("Package or activity name not specified"));
flag(cli::make_flag(cli::Name{"action"}, cli::Description{"Action of the intent"}, intent_.action));
flag(cli::make_flag(cli::Name{"type"}, cli::Description{"MIME type for the intent"}, intent_.type));
flag(cli::make_flag(cli::Name{"uri"}, cli::Description{"URI used as data within the intent"}, intent_.uri));
flag(cli::make_flag(cli::Name{"package"}, cli::Description{"Package the intent should go to"}, intent_.package));
flag(cli::make_flag(cli::Name{"component"}, cli::Description{"Component of a package the intent should go"}, intent_.component));
action([this](const cli::Command::Context&) {
auto bus = std::make_shared<core::dbus::Bus>(core::dbus::WellKnownBus::session);
bus->install_executor(core::dbus::asio::make_executor(bus));
auto stub = dbus::stub::ApplicationManager::create_for_bus(bus);
stub->launch(package_, activity_);
stub->launch(intent_);
return EXIT_SUCCESS;
});

View file

@ -23,6 +23,7 @@
#include <memory>
#include "anbox/cli.h"
#include "anbox/android/intent.h"
namespace anbox {
namespace cmds {
@ -31,8 +32,7 @@ public:
Launch();
private:
std::string package_;
std::string activity_;
android::Intent intent_;
};
} // namespace cmds
} // namespace anbox

View file

@ -37,6 +37,9 @@
#include "anbox/container/client.h"
#include "anbox/wm/manager.h"
#include "anbox/ubuntu/platform_policy.h"
#include "anbox/application/launcher_storage.h"
#include "external/xdg/xdg.h"
#include <sys/prctl.h>
@ -97,6 +100,9 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
auto window_manager = std::make_shared<wm::Manager>(policy);
auto launcher_storage = std::make_shared<application::LauncherStorage>(
xdg::data().home() / "applications");
auto renderer = std::make_shared<graphics::GLRendererServer>(window_manager);
renderer->start();
@ -130,14 +136,11 @@ anbox::cmds::Run::Run(const BusFactory& bus_factory)
// more than one one day we need proper dispatching to the right one.
android_api_stub->set_rpc_channel(rpc_channel);
auto server = std::make_shared<bridge::PlatformApiSkeleton>(pending_calls, window_manager);
auto server = std::make_shared<bridge::PlatformApiSkeleton>(pending_calls,
window_manager,
launcher_storage);
server->register_boot_finished_handler([&]() {
DEBUG("Android successfully booted");
dispatcher->dispatch([&]() {
// FIXME make this configurable or once we have a bridge let the host
// act as a DNS proxy.
android_api_stub->set_dns_servers("anbox", std::vector<std::string>{ "8.8.8.8" });
});
});
return std::make_shared<bridge::PlatformMessageProcessor>(sender, server, pending_calls);
}));

View file

@ -24,7 +24,6 @@
#include "anbox/cmds/version.h"
#include "anbox/cmds/run.h"
#include "anbox/cmds/install.h"
#include "anbox/cmds/launch.h"
#include "anbox/cmds/container_manager.h"
@ -38,7 +37,6 @@ Daemon::Daemon() :
cmd.command(std::make_shared<cmds::Version>())
.command(std::make_shared<cmds::Run>())
.command(std::make_shared<cmds::Install>())
.command(std::make_shared<cmds::Launch>())
.command(std::make_shared<cmds::ContainerManager>());
}

View file

@ -33,12 +33,6 @@ struct Service {
struct ApplicationManager {
static inline std::string name() { return "org.anbox.ApplicationManager"; }
struct Methods {
struct Install {
static inline std::string name() { return "Install"; }
typedef anbox::dbus::interface::ApplicationManager Interface;
typedef void ResultType;
static inline std::chrono::milliseconds default_timeout() { return std::chrono::seconds{240}; }
};
struct Launch {
static inline std::string name() { return "Launch"; }
typedef anbox::dbus::interface::ApplicationManager Interface;

View file

@ -17,6 +17,7 @@
#include "anbox/dbus/skeleton/application_manager.h"
#include "anbox/dbus/interface.h"
#include "anbox/android/intent.h"
#include "anbox/logger.h"
namespace anbox {
@ -29,41 +30,22 @@ ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
object_(object),
impl_(impl) {
object_->install_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Install>(
[this](const core::dbus::Message::Ptr &msg) {
std::string path;
auto reader = msg->reader();
reader >> path;
core::dbus::Message::Ptr reply;
try {
install(path);
DEBUG("install done");
reply = core::dbus::Message::make_method_return(msg);
DEBUG("Successfully installed application");
}
catch (std::exception const &err) {
DEBUG("Failed to install application: %s", err.what());
reply = core::dbus::Message::make_error(msg,
"org.anbox.Error.Failed",
err.what());
}
bus_->send(reply);
});
object_->install_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Launch>(
[this](const core::dbus::Message::Ptr &msg) {
std::string package, activity;
auto reader = msg->reader();
reader >> package;
reader >> activity;
android::Intent intent;
reader >> intent.action;
reader >> intent.uri;
reader >> intent.type;
reader >> intent.flags;
reader >> intent.package;
reader >> intent.component;
core::dbus::Message::Ptr reply;
try {
launch(package, activity);
launch(intent);
reply = core::dbus::Message::make_method_return(msg);
}
catch (std::exception const &err) {
@ -77,15 +59,10 @@ ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
}
ApplicationManager::~ApplicationManager() {
object_->uninstall_method_handler<anbox::dbus::interface::ApplicationManager::Methods::Install>();
}
void ApplicationManager::install(const std::string &path) {
impl_->install(path);
}
void ApplicationManager::launch(const std::string &package, const std::string &activity) {
impl_->launch(package, activity);
void ApplicationManager::launch(const android::Intent &intent) {
impl_->launch(intent);
}
} // namespace skeleton
} // namespace dbus

View file

@ -34,8 +34,7 @@ public:
const std::shared_ptr<anbox::ApplicationManager> &impl);
~ApplicationManager();
void install(const std::string &path) override;
void launch(const std::string &package, const std::string &activity) override;
void launch(const android::Intent &intent) override;
private:
core::dbus::Bus::Ptr bus_;

View file

@ -39,23 +39,16 @@ ApplicationManager::ApplicationManager(const core::dbus::Bus::Ptr &bus,
ApplicationManager::~ApplicationManager() {
}
void ApplicationManager::install(const std::string &path) {
DEBUG("path %s", path);
auto result = object_->invoke_method_synchronously<
anbox::dbus::interface::ApplicationManager::Methods::Install,
anbox::dbus::interface::ApplicationManager::Methods::Install::ResultType>(path);
if (result.is_error())
throw std::runtime_error(result.error().print());
}
void ApplicationManager::launch(const std::string &package, const std::string &activity) {
DEBUG("package %s activity %s", package, activity);
void ApplicationManager::launch(const android::Intent &intent) {
auto result = object_->invoke_method_synchronously<
anbox::dbus::interface::ApplicationManager::Methods::Launch,
anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>(package, activity);
anbox::dbus::interface::ApplicationManager::Methods::Launch::ResultType>(
intent.action,
intent.uri,
intent.type,
intent.flags,
intent.package,
intent.component);
if (result.is_error())
throw std::runtime_error(result.error().print());

View file

@ -36,8 +36,7 @@ public:
const core::dbus::Object::Ptr& object);
~ApplicationManager();
void install(const std::string &path) override;
void launch(const std::string &package, const std::string &activity) override;
void launch(const android::Intent &intent) override;
private:
core::dbus::Bus::Ptr bus_;

View file

@ -7,6 +7,15 @@ message StructuredError {
optional uint32 code = 2;
}
message Intent {
optional string action = 1;
optional string uri = 2;
optional string type = 3;
optional string package = 4;
optional string component = 5;
repeated string categories = 6;
}
message Notification {
required string package_name = 1;
required string category = 2;
@ -15,21 +24,8 @@ message Notification {
optional string text = 5;
}
message InstallApplication {
required string path = 1;
}
message LaunchApplication {
required string package_name = 1;
optional string activity = 2;
}
message SetDnsServers {
required string domain = 1;
message Server {
required string address = 1;
}
repeated Server servers = 2;
required Intent intent = 1;
}
message SetFocusedTask {
@ -55,9 +51,19 @@ message WindowStateUpdateEvent {
repeated WindowState removed_windows = 2;
}
message ApplicationListUpdateEvent {
message Application {
required string name = 1;
required string package = 2;
optional Intent launch_intent = 3;
}
repeated Application applications = 1;
}
message EventSequence {
optional BootFinishedEvent boot_finished = 1;
optional WindowStateUpdateEvent window_state_update = 2;
optional ApplicationListUpdateEvent application_list_update = 3;
optional string error = 127;
optional StructuredError structured_error = 128;