diff --git a/android/appmgr/src/org/anbox/appmgr/PlatformService.java b/android/appmgr/src/org/anbox/appmgr/PlatformService.java index 3602f0e..68581aa 100644 --- a/android/appmgr/src/org/anbox/appmgr/PlatformService.java +++ b/android/appmgr/src/org/anbox/appmgr/PlatformService.java @@ -116,7 +116,12 @@ public final class PlatformService { if (icon == null) continue; - data.writeString(appInfo.name); + String name = appInfo.name; + CharSequence label = appInfo.loadLabel(mPm); + if (label != null) + name = label.toString(); + + data.writeString(name); data.writeString(appInfo.packageName); data.writeString(launchIntent.getAction()); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c43be36..6f80342 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -60,7 +60,6 @@ set(SOURCES anbox/daemon.cpp anbox/config.cpp anbox/not_reachable.cpp - anbox/application_manager.h anbox/android/intent.cpp @@ -187,6 +186,7 @@ set(SOURCES anbox/dbus/stub/application_manager.cpp anbox/application/launcher_storage.cpp + anbox/application/database.cpp anbox/cmds/version.cpp anbox/cmds/session_manager.cpp diff --git a/src/anbox/application/database.cpp b/src/anbox/application/database.cpp new file mode 100644 index 0000000..6010cf5 --- /dev/null +++ b/src/anbox/application/database.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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/application/database.h" +#include "anbox/application/launcher_storage.h" +#include "anbox/config.h" +#include "anbox/logger.h" + +namespace anbox { +namespace application { +const Database::Item Database::Unknown{}; + +Database::Database() : + storage_(std::make_shared(SystemConfiguration::instance().application_item_dir())) { + storage_->reset(); +} + +Database::~Database() {} + +void Database::store_or_update(const Item &item) { + storage_->add_or_update(item); + items_[item.package] = item; + + // We don't need to store the icon data anymore at this point as the + // launcher is already stored it on the disk. + items_[item.package].icon.clear(); +} + +void Database::remove(const Item &item) { + auto iter = items_.find(item.package); + if (iter == items_.end()) + return; + storage_->remove(item); + items_.erase(iter); +} + +const Database::Item& Database::find_by_package(const std::string &package) const { + auto iter = items_.find(package); + if (iter == items_.end()) + return Unknown; + return iter->second; +} +} // namespace application +} // namespace anbox diff --git a/src/anbox/application/database.h b/src/anbox/application/database.h new file mode 100644 index 0000000..02aee1e --- /dev/null +++ b/src/anbox/application/database.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017 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 . + * + */ + +#ifndef ANBOX_APPLICATION_DATABASE_H_ +#define ANBOX_APPLICATION_DATABASE_H_ + +#include "anbox/android/intent.h" + +#include +#include +#include + +namespace anbox { +namespace application { +class LauncherStorage; +class Database { + public: + struct Item { + std::string name; + std::string package; + android::Intent launch_intent; + std::vector icon; + + bool valid() const { return package.length() > 0; } + }; + + static const Item Unknown; + + Database(); + ~Database(); + + void store_or_update(const Item &item); + void remove(const Item &item); + + const Item& find_by_package(const std::string &package) const; + + private: + std::shared_ptr storage_; + std::map items_; +}; +} // namespace application +} // namespace anbox + +#endif diff --git a/src/anbox/application/launcher_storage.cpp b/src/anbox/application/launcher_storage.cpp index a94602d..2d038dd 100644 --- a/src/anbox/application/launcher_storage.cpp +++ b/src/anbox/application/launcher_storage.cpp @@ -33,18 +33,14 @@ constexpr const char *snap_exe_path{"/snap/bin/anbox"}; namespace anbox { namespace application { -LauncherStorage::LauncherStorage(const fs::path &path, - const boost::filesystem::path &icon_path) : path_(path), icon_path_(icon_path) { -} +LauncherStorage::LauncherStorage(const fs::path &path) : + path_(path) {} LauncherStorage::~LauncherStorage() {} void LauncherStorage::reset() { if (fs::exists(path_)) fs::remove_all(path_); - - if (fs::exists(icon_path_)) - fs::remove_all(icon_path_); } std::string LauncherStorage::clean_package_name(const std::string &package_name) { @@ -58,12 +54,11 @@ fs::path LauncherStorage::path_for_item(const std::string &package_name) { } fs::path LauncherStorage::path_for_item_icon(const std::string &package_name) { - return icon_path_ / utils::string_format("anbox-%s.png", package_name); + return path_ / utils::string_format("anbox-%s.png", package_name); } -void LauncherStorage::add_or_update(const Item &item) { +void LauncherStorage::add_or_update(const Database::Item &item) { if (!fs::exists(path_)) fs::create_directories(path_); - if (!fs::exists(icon_path_)) fs::create_directories(icon_path_); auto package_name = item.package; std::replace(package_name.begin(), package_name.end(), '.', '-'); @@ -92,7 +87,7 @@ void LauncherStorage::add_or_update(const Item &item) { const auto item_icon_path = path_for_item_icon(package_name); if (auto desktop_item = std::ofstream(path_for_item(package_name).string())) { desktop_item << "[Desktop Entry]" << std::endl - << "Name=" << item.package << std::endl + << "Name=" << item.name << std::endl << "Exec=" << exec << std::endl << "Terminal=false" << std::endl << "Type=Application" << std::endl @@ -107,7 +102,7 @@ void LauncherStorage::add_or_update(const Item &item) { BOOST_THROW_EXCEPTION(std::runtime_error("Failed to write icon")); } -void LauncherStorage::remove(const Item &item) { +void LauncherStorage::remove(const Database::Item &item) { auto package_name = clean_package_name(item.package); const auto item_path = path_for_item(package_name); diff --git a/src/anbox/application/launcher_storage.h b/src/anbox/application/launcher_storage.h index e045ea2..d7c5e79 100644 --- a/src/anbox/application/launcher_storage.h +++ b/src/anbox/application/launcher_storage.h @@ -18,6 +18,7 @@ #ifndef ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ #define ANBOX_APPLICATION_LAUNCHER_STORAGE_H_ +#include "anbox/application/database.h" #include "anbox/android/intent.h" #include @@ -29,20 +30,12 @@ namespace anbox { namespace application { class LauncherStorage { public: - LauncherStorage(const boost::filesystem::path &path, - const boost::filesystem::path &icon_path); + LauncherStorage(const boost::filesystem::path &path); ~LauncherStorage(); - struct Item { - std::string name; - std::string package; - android::Intent launch_intent; - std::vector icon; - }; - void reset(); - void add_or_update(const Item &item); - void remove(const Item &item); + void add_or_update(const Database::Item &item); + void remove(const Database::Item &item); private: std::string clean_package_name(const std::string &package_name); @@ -50,7 +43,6 @@ class LauncherStorage { boost::filesystem::path path_for_item_icon(const std::string &package_name); boost::filesystem::path path_; - boost::filesystem::path icon_path_; }; } // namespace application } // namespace anbox diff --git a/src/anbox/bridge/platform_api_skeleton.cpp b/src/anbox/bridge/platform_api_skeleton.cpp index 221577d..c8eb9e2 100644 --- a/src/anbox/bridge/platform_api_skeleton.cpp +++ b/src/anbox/bridge/platform_api_skeleton.cpp @@ -16,7 +16,7 @@ */ #include "anbox/bridge/platform_api_skeleton.h" -#include "anbox/application/launcher_storage.h" +#include "anbox/application/database.h" #include "anbox/platform/policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" @@ -30,11 +30,11 @@ PlatformApiSkeleton::PlatformApiSkeleton( const std::shared_ptr &pending_calls, const std::shared_ptr &platform_policy, const std::shared_ptr &window_manager, - const std::shared_ptr &launcher_storage) + const std::shared_ptr &app_db) : pending_calls_(pending_calls), platform_policy_(platform_policy), window_manager_(window_manager), - launcher_storage_(launcher_storage) {} + app_db_(app_db) {} PlatformApiSkeleton::~PlatformApiSkeleton() {} @@ -62,10 +62,7 @@ void PlatformApiSkeleton::get_clipboard_data(anbox::protobuf::rpc::Void const *r done->Run(); } -void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent &event) { - if (event.first_boot_done()) - launcher_storage_->reset(); - +void PlatformApiSkeleton::handle_boot_finished_event(const anbox::protobuf::bridge::BootFinishedEvent&) { if (boot_finished_handler_) boot_finished_handler_(); } @@ -99,7 +96,7 @@ void PlatformApiSkeleton::handle_window_state_update_event(const anbox::protobuf void PlatformApiSkeleton::handle_application_list_update_event(const anbox::protobuf::bridge::ApplicationListUpdateEvent &event) { for (int n = 0; n < event.removed_applications_size(); n++) { - application::LauncherStorage::Item item; + application::Database::Item item; const auto app = event.removed_applications(n); item.package = app.package(); @@ -107,11 +104,11 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot if (item.package.empty()) continue; - launcher_storage_->remove(item); + app_db_->remove(item); } for (int n = 0; n < event.applications_size(); n++) { - application::LauncherStorage::Item item; + application::Database::Item item; const auto app = event.applications(n); item.name = app.name(); @@ -132,7 +129,7 @@ void PlatformApiSkeleton::handle_application_list_update_event(const anbox::prot if (item.package.empty()) continue; - launcher_storage_->add_or_update(item); + app_db_->store_or_update(item); } } diff --git a/src/anbox/bridge/platform_api_skeleton.h b/src/anbox/bridge/platform_api_skeleton.h index 6b4e25b..7a9891b 100644 --- a/src/anbox/bridge/platform_api_skeleton.h +++ b/src/anbox/bridge/platform_api_skeleton.h @@ -48,7 +48,7 @@ namespace wm { class Manager; } // namespace wm namespace application { -class LauncherStorage; +class Database; } // namespace application namespace bridge { class PlatformApiSkeleton { @@ -57,7 +57,7 @@ class PlatformApiSkeleton { const std::shared_ptr &pending_calls, const std::shared_ptr &platform_policy, const std::shared_ptr &window_manager, - const std::shared_ptr &launcher_storage); + const std::shared_ptr &app_db); virtual ~PlatformApiSkeleton(); void set_clipboard_data(anbox::protobuf::bridge::ClipboardData const *request, @@ -80,7 +80,7 @@ class PlatformApiSkeleton { std::shared_ptr pending_calls_; std::shared_ptr platform_policy_; std::shared_ptr window_manager_; - std::shared_ptr launcher_storage_; + std::shared_ptr app_db_; std::function boot_finished_handler_; }; } // namespace bridge diff --git a/src/anbox/cmds/session_manager.cpp b/src/anbox/cmds/session_manager.cpp index a408fdd..15de80c 100644 --- a/src/anbox/cmds/session_manager.cpp +++ b/src/anbox/cmds/session_manager.cpp @@ -22,6 +22,7 @@ #include "core/posix/signal.h" #include "anbox/application/launcher_storage.h" +#include "anbox/application/database.h" #include "anbox/audio/server.h" #include "anbox/bridge/android_api_stub.h" #include "anbox/bridge/platform_api_skeleton.h" @@ -139,11 +140,8 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) // FIXME this needs to be removed and solved differently behind the scenes registerDisplayManager(policy); - auto window_manager = std::make_shared(policy); - - auto launcher_storage = std::make_shared( - xdg::data().home() / "applications" / "anbox", - xdg::data().home() / "anbox" / "icons"); + auto app_db = std::make_shared(); + auto window_manager = std::make_shared(policy, app_db); auto gl_server = std::make_shared( graphics::GLRendererServer::Config{gles_driver_}, window_manager); @@ -175,7 +173,7 @@ anbox::cmds::SessionManager::SessionManager(const BusFactory &bus_factory) android_api_stub->set_rpc_channel(rpc_channel); auto server = std::make_shared( - pending_calls, policy, window_manager, launcher_storage); + pending_calls, policy, window_manager, app_db); server->register_boot_finished_handler([&]() { DEBUG("Android successfully booted"); android_api_stub->ready().set(true); diff --git a/src/anbox/config.cpp b/src/anbox/config.cpp index 134d10d..7c0961e 100644 --- a/src/anbox/config.cpp +++ b/src/anbox/config.cpp @@ -19,6 +19,7 @@ #include "anbox/config.h" #include "anbox/utils.h" +#include "external/xdg/xdg.h" #include @@ -70,6 +71,11 @@ std::string anbox::SystemConfiguration::input_device_dir() const { return dir; } +std::string anbox::SystemConfiguration::application_item_dir() const { + static auto dir = xdg::data().home() / "applications" / "anbox"; + return dir.string(); +} + anbox::SystemConfiguration& anbox::SystemConfiguration::instance() { static SystemConfiguration config; return config; diff --git a/src/anbox/config.h b/src/anbox/config.h index 6d1b19d..91f72c6 100644 --- a/src/anbox/config.h +++ b/src/anbox/config.h @@ -39,6 +39,7 @@ class SystemConfiguration { std::string container_config_dir() const; std::string container_socket_path() const; std::string input_device_dir() const; + std::string application_item_dir() const; protected: SystemConfiguration() = default; diff --git a/src/anbox/wm/manager.cpp b/src/anbox/wm/manager.cpp index f5b786c..779f257 100644 --- a/src/anbox/wm/manager.cpp +++ b/src/anbox/wm/manager.cpp @@ -16,6 +16,7 @@ */ #include "anbox/wm/manager.h" +#include "anbox/application/database.h" #include "anbox/platform/policy.h" #include "anbox/logger.h" @@ -23,8 +24,9 @@ namespace anbox { namespace wm { -Manager::Manager(const std::shared_ptr &policy) - : platform_policy_(policy) {} +Manager::Manager(const std::shared_ptr &policy, + const std::shared_ptr &app_db) + : platform_policy_(policy), app_db_(app_db) {} Manager::~Manager() {} @@ -60,7 +62,12 @@ void Manager::apply_window_state_update(const WindowState::List &updated, continue; } - auto platform_window = platform_policy_->create_window(window.task(), window.frame(), window.package_name()); + auto title = window.package_name(); + auto app = app_db_->find_by_package(window.package_name()); + if (app.valid()) + title = app.name; + + auto platform_window = platform_policy_->create_window(window.task(), window.frame(), title); platform_window->attach(); windows_.insert({window.task(), platform_window}); } diff --git a/src/anbox/wm/manager.h b/src/anbox/wm/manager.h index 5e81024..8fda1c9 100644 --- a/src/anbox/wm/manager.h +++ b/src/anbox/wm/manager.h @@ -26,13 +26,17 @@ #include namespace anbox { +namespace application { +class Database; +} // namespace application namespace platform { class Policy; } // namespace platform namespace wm { class Manager { public: - Manager(const std::shared_ptr &policy); + Manager(const std::shared_ptr &policy, + const std::shared_ptr &app_db); ~Manager(); void apply_window_state_update(const WindowState::List &updated, @@ -43,6 +47,7 @@ class Manager { private: std::mutex mutex_; std::shared_ptr platform_policy_; + std::shared_ptr app_db_; std::map> windows_; }; } // namespace wm diff --git a/tests/anbox/graphics/layer_composer_tests.cpp b/tests/anbox/graphics/layer_composer_tests.cpp index 2ed0394..b2ef1cc 100644 --- a/tests/anbox/graphics/layer_composer_tests.cpp +++ b/tests/anbox/graphics/layer_composer_tests.cpp @@ -20,6 +20,7 @@ #include #include +#include "anbox/application/database.h" #include "anbox/platform/default_policy.h" #include "anbox/wm/manager.h" #include "anbox/wm/window_state.h" @@ -44,7 +45,8 @@ TEST(LayerComposer, FindsNoSuitableWindowForLayer) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto single_window = wm::WindowState{ wm::Display::Id{1}, @@ -77,7 +79,8 @@ TEST(LayerComposer, MapsLayersToWindows) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto first_window = wm::WindowState{ wm::Display::Id{1}, @@ -136,7 +139,8 @@ TEST(LayerComposer, WindowPartiallyOffscreen) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto window = wm::WindowState{ wm::Display::Id{1}, @@ -180,7 +184,8 @@ TEST(LayerComposer, PopupShouldNotCauseWindowLayerOffset) { // The default policy will create a dumb window instance when requested // from the manager. auto platform_policy = std::make_shared(); - auto wm = std::make_shared(platform_policy); + auto app_db = std::make_shared(); + auto wm = std::make_shared(platform_policy, app_db); auto window = wm::WindowState{ wm::Display::Id{1},