You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
main-executable: handle drawable-based app icons by rendering them into SVG
This commit is contained in:
@@ -35,6 +35,7 @@
|
|||||||
#define _GET_FLOAT_FIELD(object, field) ((*env)->GetFloatField(env, object, _FIELD_ID(_CLASS(object), field, "F")))
|
#define _GET_FLOAT_FIELD(object, field) ((*env)->GetFloatField(env, object, _FIELD_ID(_CLASS(object), field, "F")))
|
||||||
#define _SET_FLOAT_FIELD(object, field, value) ((*env)->SetFloatField(env, object, _FIELD_ID(_CLASS(object), field, "F"), value))
|
#define _SET_FLOAT_FIELD(object, field, value) ((*env)->SetFloatField(env, object, _FIELD_ID(_CLASS(object), field, "F"), value))
|
||||||
#define _SET_STATIC_INT_FIELD(class, field, value) ((*env)->SetStaticIntField(env, class, _STATIC_FIELD_ID(class, field, "I"), value))
|
#define _SET_STATIC_INT_FIELD(class, field, value) ((*env)->SetStaticIntField(env, class, _STATIC_FIELD_ID(class, field, "I"), value))
|
||||||
|
#define _SET_STATIC_BOOL_FIELD(class, field, value) ((*env)->SetStaticBooleanField(env, class, _STATIC_FIELD_ID(class, field, "Z"), value))
|
||||||
#define _SET_STATIC_OBJ_FIELD(class, field, type, value) ((*env)->SetStaticObjectField(env, class, _STATIC_FIELD_ID(class, field, type), value))
|
#define _SET_STATIC_OBJ_FIELD(class, field, type, value) ((*env)->SetStaticObjectField(env, class, _STATIC_FIELD_ID(class, field, type), value))
|
||||||
#define _GET_STATIC_OBJ_FIELD(class, field, type) ((*env)->GetStaticObjectField(env, class, _STATIC_FIELD_ID(class, field, type)))
|
#define _GET_STATIC_OBJ_FIELD(class, field, type) ((*env)->GetStaticObjectField(env, class, _STATIC_FIELD_ID(class, field, type)))
|
||||||
#define _GET_BYTE_ARRAY_ELEMENTS(b_array) ((*env)->GetByteArrayElements(env, b_array, NULL))
|
#define _GET_BYTE_ARRAY_ELEMENTS(b_array) ((*env)->GetByteArrayElements(env, b_array, NULL))
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ void set_up_handle_cache(JNIEnv *env)
|
|||||||
|
|
||||||
handle_cache.application.class = _REF((*env)->FindClass(env, "android/app/Application"));
|
handle_cache.application.class = _REF((*env)->FindClass(env, "android/app/Application"));
|
||||||
handle_cache.application.get_app_icon_path = _METHOD(handle_cache.application.class, "get_app_icon_path", "()Ljava/lang/String;");
|
handle_cache.application.get_app_icon_path = _METHOD(handle_cache.application.class, "get_app_icon_path", "()Ljava/lang/String;");
|
||||||
|
handle_cache.application.get_app_icon_paintable = _METHOD(handle_cache.application.class, "get_app_icon_paintable", "()J");
|
||||||
|
|
||||||
handle_cache.looper.class = _REF((*env)->FindClass(env, "android/os/Looper"));
|
handle_cache.looper.class = _REF((*env)->FindClass(env, "android/os/Looper"));
|
||||||
handle_cache.looper.loop = _STATIC_METHOD(handle_cache.looper.class, "loop", "()V");
|
handle_cache.looper.loop = _STATIC_METHOD(handle_cache.looper.class, "loop", "()V");
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ struct handle_cache {
|
|||||||
struct {
|
struct {
|
||||||
jclass class;
|
jclass class;
|
||||||
jmethodID get_app_icon_path;
|
jmethodID get_app_icon_path;
|
||||||
|
jmethodID get_app_icon_paintable;
|
||||||
} application;
|
} application;
|
||||||
struct {
|
struct {
|
||||||
jclass class;
|
jclass class;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package android.app;
|
|||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
|
import android.R;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.ContextWrapper;
|
import android.content.ContextWrapper;
|
||||||
import android.content.pm.PackageParser;
|
import android.content.pm.PackageParser;
|
||||||
@@ -10,7 +11,22 @@ public class Application extends ContextWrapper {
|
|||||||
public long native_window;
|
public long native_window;
|
||||||
|
|
||||||
private String get_app_icon_path() {
|
private String get_app_icon_path() {
|
||||||
return getString(pkg.applicationInfo.icon);
|
String icon_path = null;
|
||||||
|
try {
|
||||||
|
icon_path = getString(pkg.applicationInfo.icon);
|
||||||
|
} catch (android.content.res.Resources.NotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (icon_path == null) {
|
||||||
|
icon_path = getString(R.mipmap.sym_def_app_icon);
|
||||||
|
} else if (icon_path.endsWith(".xml")) {
|
||||||
|
icon_path = null;
|
||||||
|
}
|
||||||
|
return icon_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long get_app_icon_paintable() {
|
||||||
|
return getPackageManager().getApplicationIcon(pkg.applicationInfo).paintable;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get_app_label() {
|
String get_app_label() {
|
||||||
|
|||||||
@@ -2613,7 +2613,7 @@ public class PackageManager {
|
|||||||
* @see #getApplicationIcon(String)
|
* @see #getApplicationIcon(String)
|
||||||
*/
|
*/
|
||||||
public Drawable getApplicationIcon(ApplicationInfo info) {
|
public Drawable getApplicationIcon(ApplicationInfo info) {
|
||||||
return null;
|
return Context.this_application.getDrawable(info.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// for dladdr
|
// for dladdr
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <cairo-svg.h>
|
||||||
#include <gdk/wayland/gdkwayland.h>
|
#include <gdk/wayland/gdkwayland.h>
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include <libportal/portal.h>
|
#include <libportal/portal.h>
|
||||||
@@ -176,6 +177,13 @@ static void dynamic_launcher_ready_callback(GObject *portal, GAsyncResult *res,
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cairo_status_t cairo_write_func_gstring(void *closure, const unsigned char *data, unsigned int length)
|
||||||
|
{
|
||||||
|
GString *str = closure;
|
||||||
|
g_string_append_len(str, (gchar *)data, length);
|
||||||
|
return CAIRO_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
// this is exported by the shim bionic linker
|
// this is exported by the shim bionic linker
|
||||||
void dl_parse_library_path(const char *path, char *delim);
|
void dl_parse_library_path(const char *path, char *delim);
|
||||||
|
|
||||||
@@ -561,17 +569,40 @@ static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *h
|
|||||||
(*env)->ExceptionDescribe(env);
|
(*env)->ExceptionDescribe(env);
|
||||||
|
|
||||||
GVariant *icon_serialized = NULL;
|
GVariant *icon_serialized = NULL;
|
||||||
if (app_icon_path && !d->install_internal) {
|
if (!d->install_internal) {
|
||||||
extract_from_apk(app_icon_path, app_icon_path);
|
if (app_icon_path) {
|
||||||
char *app_icon_path_full = g_strdup_printf("%s/%s", app_data_dir, app_icon_path);
|
/* we can import the icon as-is */
|
||||||
GMappedFile *icon_file = g_mapped_file_new(app_icon_path_full, FALSE, NULL);
|
extract_from_apk(app_icon_path, app_icon_path);
|
||||||
GBytes *icon_bytes = g_mapped_file_get_bytes(icon_file);
|
char *app_icon_path_full = g_strdup_printf("%s/%s", app_data_dir, app_icon_path);
|
||||||
GIcon *icon = g_bytes_icon_new(icon_bytes);
|
GMappedFile *icon_file = g_mapped_file_new(app_icon_path_full, FALSE, NULL);
|
||||||
icon_serialized = g_icon_serialize(icon);
|
GBytes *icon_bytes = g_mapped_file_get_bytes(icon_file);
|
||||||
g_object_unref(icon);
|
GIcon *icon = g_bytes_icon_new(icon_bytes);
|
||||||
g_bytes_unref(icon_bytes);
|
icon_serialized = g_icon_serialize(icon);
|
||||||
g_mapped_file_unref(icon_file);
|
g_object_unref(icon);
|
||||||
g_free(app_icon_path_full);
|
g_bytes_unref(icon_bytes);
|
||||||
|
g_mapped_file_unref(icon_file);
|
||||||
|
g_free(app_icon_path_full);
|
||||||
|
} else {
|
||||||
|
/* the icon is a generalized Drawable, let's render it into an SVG */
|
||||||
|
_SET_STATIC_BOOL_FIELD((*env)->FindClass(env, "android/graphics/drawable/VectorDrawable"), "direct_draw_override", true);
|
||||||
|
GdkPaintable *icon_paintable = _PTR((*env)->CallLongMethod(env, application_object, handle_cache.application.get_app_icon_paintable));
|
||||||
|
GString *svg_string = g_string_new("");
|
||||||
|
cairo_surface_t *svg_surface = cairo_svg_surface_create_for_stream(cairo_write_func_gstring, svg_string, 108, 108);
|
||||||
|
cairo_t *cr = cairo_create(svg_surface);
|
||||||
|
GdkSnapshot *snapshot = gtk_snapshot_new();
|
||||||
|
gdk_paintable_snapshot(icon_paintable, snapshot, 108, 108);
|
||||||
|
GskRenderNode *node = gtk_snapshot_to_node(snapshot);
|
||||||
|
gsk_render_node_draw(node, cr);
|
||||||
|
gsk_render_node_unref(node);
|
||||||
|
g_object_unref(snapshot);
|
||||||
|
cairo_destroy(cr);
|
||||||
|
cairo_surface_destroy(svg_surface);
|
||||||
|
GBytes *icon_bytes = g_string_free_to_bytes(svg_string);
|
||||||
|
GIcon *icon = g_bytes_icon_new(icon_bytes);
|
||||||
|
icon_serialized = g_icon_serialize(icon);
|
||||||
|
g_object_unref(icon);
|
||||||
|
g_bytes_unref(icon_bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *dest_name = g_strdup_printf("%s.apk", package_name);
|
gchar *dest_name = g_strdup_printf("%s.apk", package_name);
|
||||||
|
|||||||
Reference in New Issue
Block a user