Synchronize application icons with the host
This commit is contained in:
parent
8caaa1f35c
commit
5c7b0adf8c
11 changed files with 103 additions and 41 deletions
|
|
@ -27,8 +27,14 @@ import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.ApplicationInfo;
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Bitmap.Config;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
public final class PlatformService {
|
public final class PlatformService {
|
||||||
private static final String TAG = "AnboxAppMgr";
|
private static final String TAG = "AnboxAppMgr";
|
||||||
|
|
@ -69,28 +75,41 @@ public final class PlatformService {
|
||||||
data.writeInt(apps.size());
|
data.writeInt(apps.size());
|
||||||
for (int n = 0; n < apps.size(); n++) {
|
for (int n = 0; n < apps.size(); n++) {
|
||||||
ApplicationInfo appInfo = apps.get(n);
|
ApplicationInfo appInfo = apps.get(n);
|
||||||
|
|
||||||
|
Intent launchIntent = mPm.getLaunchIntentForPackage(appInfo.packageName);
|
||||||
|
if (launchIntent == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Drawable icon = null;
|
||||||
|
try {
|
||||||
|
icon = mPm.getApplicationIcon(appInfo.packageName);
|
||||||
|
}
|
||||||
|
catch (PackageManager.NameNotFoundException ex) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
data.writeString(appInfo.name);
|
data.writeString(appInfo.name);
|
||||||
data.writeString(appInfo.packageName);
|
data.writeString(appInfo.packageName);
|
||||||
|
|
||||||
Intent launchIntent = mPm.getLaunchIntentForPackage(appInfo.packageName);
|
data.writeString(launchIntent.getAction());
|
||||||
if (launchIntent != null) {
|
if (launchIntent.getData() != null)
|
||||||
data.writeInt(1);
|
data.writeString(launchIntent.getData().toString());
|
||||||
data.writeString(launchIntent.getAction());
|
else
|
||||||
if (launchIntent.getData() != null)
|
data.writeString("");
|
||||||
data.writeString(launchIntent.getData().toString());
|
data.writeString(launchIntent.getType());
|
||||||
else
|
data.writeString(launchIntent.getComponent().getPackageName());
|
||||||
data.writeString("");
|
data.writeString(launchIntent.getComponent().getClassName());
|
||||||
data.writeString(launchIntent.getType());
|
data.writeInt(launchIntent.getCategories().size());
|
||||||
data.writeString(launchIntent.getComponent().getPackageName());
|
for (String category : launchIntent.getCategories())
|
||||||
data.writeString(launchIntent.getComponent().getClassName());
|
data.writeString(category);
|
||||||
data.writeInt(launchIntent.getCategories().size());
|
|
||||||
for (String category : launchIntent.getCategories())
|
|
||||||
data.writeString(category);
|
|
||||||
} else {
|
|
||||||
data.writeInt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME add icon, flags, ...
|
Bitmap iconBitmap = drawableToBitmap(icon);
|
||||||
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||||
|
iconBitmap.compress(Bitmap.CompressFormat.PNG, 90, outStream);
|
||||||
|
data.writeByteArray(outStream.toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
Parcel reply = Parcel.obtain();
|
Parcel reply = Parcel.obtain();
|
||||||
|
|
@ -107,4 +126,16 @@ public final class PlatformService {
|
||||||
|
|
||||||
public void notifyPackageRemoved(Intent intent) {
|
public void notifyPackageRemoved(Intent intent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Bitmap drawableToBitmap(Drawable drawable) {
|
||||||
|
if (drawable instanceof BitmapDrawable)
|
||||||
|
return ((BitmapDrawable)drawable).getBitmap();
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Config.ARGB_8888);
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||||
|
drawable.draw(canvas);
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,8 @@ void PlatformApiStub::update_application_list(const ApplicationListUpdate &updat
|
||||||
auto c = launch_intent->add_categories();
|
auto c = launch_intent->add_categories();
|
||||||
*c = category;
|
*c = category;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app->set_icon(a.icon.data(), a.icon.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
rpc_channel_->send_event(seq);
|
rpc_channel_->send_event(seq);
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ public:
|
||||||
std::vector<std::string> categories;
|
std::vector<std::string> categories;
|
||||||
};
|
};
|
||||||
Intent launch_intent;
|
Intent launch_intent;
|
||||||
|
std::vector<int8_t> icon;
|
||||||
};
|
};
|
||||||
std::vector<Application> applications;
|
std::vector<Application> applications;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -97,27 +97,27 @@ status_t PlatformService::update_application_list(const Parcel &data) {
|
||||||
package_name.string(),
|
package_name.string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (data.readInt32() == 1) {
|
String8 action(data.readString16());
|
||||||
String8 action(data.readString16());
|
String8 uri(data.readString16());
|
||||||
String8 uri(data.readString16());
|
String8 type(data.readString16());
|
||||||
String8 type(data.readString16());
|
String8 component_package(data.readString16());
|
||||||
String8 component_package(data.readString16());
|
String8 component_class(data.readString16());
|
||||||
String8 component_class(data.readString16());
|
|
||||||
|
|
||||||
std::vector<std::string> categories;
|
std::vector<std::string> categories;
|
||||||
unsigned int num_categories = data.readInt32();
|
unsigned int num_categories = data.readInt32();
|
||||||
for (int m = 0; m < num_categories; m++)
|
for (int m = 0; m < num_categories; m++)
|
||||||
categories.push_back(String8(data.readString16()).string());
|
categories.push_back(String8(data.readString16()).string());
|
||||||
|
|
||||||
p.launch_intent.action = action;
|
p.launch_intent.action = action;
|
||||||
p.launch_intent.uri = uri;
|
p.launch_intent.uri = uri;
|
||||||
p.launch_intent.type = type;
|
p.launch_intent.type = type;
|
||||||
p.launch_intent.package = component_package;
|
p.launch_intent.package = component_package;
|
||||||
p.launch_intent.component = component_class;
|
p.launch_intent.component = component_class;
|
||||||
p.launch_intent.categories = categories;
|
p.launch_intent.categories = categories;
|
||||||
|
|
||||||
update.applications.push_back(p);
|
data.readByteVector(&p.icon);
|
||||||
};
|
|
||||||
|
update.applications.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
platform_api_stub_->update_application_list(update);
|
platform_api_stub_->update_application_list(update);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include "anbox/application/launcher_storage.h"
|
#include "anbox/application/launcher_storage.h"
|
||||||
#include "anbox/utils.h"
|
#include "anbox/utils.h"
|
||||||
|
#include "anbox/logger.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
@ -26,19 +27,25 @@ namespace fs = boost::filesystem;
|
||||||
|
|
||||||
namespace anbox {
|
namespace anbox {
|
||||||
namespace application {
|
namespace application {
|
||||||
LauncherStorage::LauncherStorage(const fs::path &path) : path_(path) {}
|
LauncherStorage::LauncherStorage(const fs::path &path,
|
||||||
|
const boost::filesystem::path &icon_path) : path_(path), icon_path_(icon_path) {
|
||||||
|
}
|
||||||
|
|
||||||
LauncherStorage::~LauncherStorage() {}
|
LauncherStorage::~LauncherStorage() {}
|
||||||
|
|
||||||
void LauncherStorage::add(const Item &item) {
|
void LauncherStorage::add(const Item &item) {
|
||||||
if (!fs::exists(path_)) fs::create_directories(path_);
|
if (!fs::exists(path_)) fs::create_directories(path_);
|
||||||
|
if (!fs::exists(icon_path_)) fs::create_directories(icon_path_);
|
||||||
|
|
||||||
auto package_name = item.package;
|
auto package_name = item.package;
|
||||||
std::replace(package_name.begin(), package_name.end(), '.', '-');
|
std::replace(package_name.begin(), package_name.end(), '.', '-');
|
||||||
|
|
||||||
const auto item_path =
|
const auto item_path =
|
||||||
path_ / utils::string_format("anbox-%s.desktop", package_name);
|
path_ / utils::string_format("anbox-%s.desktop", package_name);
|
||||||
std::string exec = "anbox launch ";
|
const auto item_icon_path =
|
||||||
|
icon_path_ / utils::string_format("anbox-%s.png", package_name);
|
||||||
|
|
||||||
|
std::string exec = utils::string_format("%s launch ", utils::process_get_exe_path(getpid()));
|
||||||
|
|
||||||
if (!item.launch_intent.action.empty())
|
if (!item.launch_intent.action.empty())
|
||||||
exec += utils::string_format("--action=%s ", item.launch_intent.action);
|
exec += utils::string_format("--action=%s ", item.launch_intent.action);
|
||||||
|
|
@ -62,7 +69,11 @@ void LauncherStorage::add(const Item &item) {
|
||||||
<< "Exec=" << exec << std::endl
|
<< "Exec=" << exec << std::endl
|
||||||
<< "Terminal=false" << std::endl
|
<< "Terminal=false" << std::endl
|
||||||
<< "Type=Application" << std::endl
|
<< "Type=Application" << std::endl
|
||||||
<< "Encoding=UTF-8" << std::endl;
|
<< "Icon=" << item_icon_path.string() << std::endl;
|
||||||
|
f.close();
|
||||||
|
|
||||||
|
f = std::ofstream(item_icon_path.string());
|
||||||
|
f.write(item.icon.data(), item.icon.size());
|
||||||
f.close();
|
f.close();
|
||||||
}
|
}
|
||||||
} // namespace application
|
} // namespace application
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,22 @@ namespace anbox {
|
||||||
namespace application {
|
namespace application {
|
||||||
class LauncherStorage {
|
class LauncherStorage {
|
||||||
public:
|
public:
|
||||||
LauncherStorage(const boost::filesystem::path &path);
|
LauncherStorage(const boost::filesystem::path &path,
|
||||||
|
const boost::filesystem::path &icon_path);
|
||||||
~LauncherStorage();
|
~LauncherStorage();
|
||||||
|
|
||||||
struct Item {
|
struct Item {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string package;
|
std::string package;
|
||||||
android::Intent launch_intent;
|
android::Intent launch_intent;
|
||||||
|
std::vector<char> icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
void add(const Item &item);
|
void add(const Item &item);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::filesystem::path path_;
|
boost::filesystem::path path_;
|
||||||
|
boost::filesystem::path icon_path_;
|
||||||
};
|
};
|
||||||
} // namespace application
|
} // namespace application
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,11 @@ void PlatformApiSkeleton::handle_application_list_update_event(
|
||||||
for (int m = 0; m < li.categories_size(); m++)
|
for (int m = 0; m < li.categories_size(); m++)
|
||||||
item.launch_intent.categories.push_back(li.categories(m));
|
item.launch_intent.categories.push_back(li.categories(m));
|
||||||
|
|
||||||
|
item.icon = std::vector<char>(app.icon().begin(), app.icon().end());
|
||||||
|
|
||||||
|
if (item.package.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
// If the item is already stored it will be updated
|
// If the item is already stored it will be updated
|
||||||
launcher_storage_->add(item);
|
launcher_storage_->add(item);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,8 @@ anbox::cmds::Run::Run(const BusFactory &bus_factory)
|
||||||
auto window_manager = std::make_shared<wm::Manager>(policy);
|
auto window_manager = std::make_shared<wm::Manager>(policy);
|
||||||
|
|
||||||
auto launcher_storage = std::make_shared<application::LauncherStorage>(
|
auto launcher_storage = std::make_shared<application::LauncherStorage>(
|
||||||
xdg::data().home() / "applications");
|
xdg::data().home() / "applications" / "anbox",
|
||||||
|
xdg::data().home() / "anbox" / "icons");
|
||||||
|
|
||||||
auto gl_server =
|
auto gl_server =
|
||||||
std::make_shared<graphics::GLRendererServer>(window_manager);
|
std::make_shared<graphics::GLRendererServer>(window_manager);
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@ message ApplicationListUpdateEvent {
|
||||||
required string name = 1;
|
required string name = 1;
|
||||||
required string package = 2;
|
required string package = 2;
|
||||||
optional Intent launch_intent = 3;
|
optional Intent launch_intent = 3;
|
||||||
|
optional bytes icon = 4;
|
||||||
}
|
}
|
||||||
repeated Application applications = 1;
|
repeated Application applications = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,5 +158,10 @@ std::string prefix_dir_from_env(const std::string &path,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string process_get_exe_path(const pid_t &pid) {
|
||||||
|
auto exe_path = string_format("/proc/%d/exe", pid);
|
||||||
|
return boost::filesystem::read_symlink(exe_path).string();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
} // namespace anbox
|
} // namespace anbox
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ void ensure_paths(const std::vector<std::string> &paths);
|
||||||
std::string prefix_dir_from_env(const std::string &path,
|
std::string prefix_dir_from_env(const std::string &path,
|
||||||
const std::string &env_var);
|
const std::string &env_var);
|
||||||
|
|
||||||
|
std::string process_get_exe_path(const pid_t &pid);
|
||||||
|
|
||||||
template <typename... Types>
|
template <typename... Types>
|
||||||
static std::string string_format(const std::string &fmt_str, Types &&... args);
|
static std::string string_format(const std::string &fmt_str, Types &&... args);
|
||||||
} // namespace utils
|
} // namespace utils
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue