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
separate Intent serialization and action handling out of the NotificationManager
This way, the mechanism can in the future also be used to send Intents from one app to another.
This commit is contained in:
@@ -193,6 +193,7 @@ resources = gnome.compile_resources('com.gitlab.android_translation_layer.androi
|
||||
|
||||
executable('android-translation-layer', [
|
||||
'src/main-executable/main.c',
|
||||
'src/main-executable/actions.c',
|
||||
'src/main-executable/back_button.c',
|
||||
'src/main-executable/bionic_compat.c',
|
||||
'src/main-executable/libc_bio_path_overrides.c',
|
||||
|
||||
@@ -16,14 +16,15 @@ static GHashTable *ongoing_notifications = NULL;
|
||||
|
||||
/* We queue up notification updates in pending_notifications to make sure that there is at least 200ms
|
||||
delay between consecutive updates. This prevents dynamic notification updated from arriving in wrong
|
||||
order at the desktop environment */
|
||||
order at the desktop environment.
|
||||
Normally 20ms should be enough to prevent notification update order issues, but we use a 10x larger value
|
||||
to be safe and 200ms should be more than enough as notification update interval. */
|
||||
static GHashTable *pending_notifications = NULL;
|
||||
static GMutex pending_notifications_mutex = {0};
|
||||
static GSource *send_notifcation_timer = NULL;
|
||||
|
||||
static gboolean send_notifcation_func(GSource *send_notifcation_timer, GSourceFunc callback, gpointer user_data)
|
||||
{
|
||||
printf("Sending notifications\n");
|
||||
GApplication *app = g_application_get_default();
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
@@ -58,20 +59,6 @@ static void unref_nullsafe(void *data) {
|
||||
g_object_unref(data);
|
||||
}
|
||||
|
||||
static void notification_action(GSimpleAction *action, GVariant* parameter, gpointer user_data)
|
||||
{
|
||||
printf("notification_action\n");
|
||||
int type;
|
||||
const char *actionName;
|
||||
const char *className;
|
||||
const char *data;
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
g_variant_get(parameter, "(isss)", &type, &actionName, &className, &data);
|
||||
jmethodID notificationActionCallback = _STATIC_METHOD((*env)->FindClass(env, "android/app/NotificationManager"), "notificationActionCallback", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
(*env)->CallStaticVoidMethod(env, (*env)->FindClass(env, "android/app/NotificationManager"), notificationActionCallback, type, _JSTRING(actionName), _JSTRING(className), _JSTRING(data));
|
||||
}
|
||||
|
||||
static void queue_notification(int id, GNotification *notification) {
|
||||
g_mutex_lock(&pending_notifications_mutex);
|
||||
if (!pending_notifications) {
|
||||
@@ -81,22 +68,21 @@ static void queue_notification(int id, GNotification *notification) {
|
||||
GApplication *app = g_application_get_default();
|
||||
gchar *desktop_id = g_strdup_printf("%s.desktop", g_application_get_application_id(app));
|
||||
GDesktopAppInfo *info = g_desktop_app_info_new(desktop_id);
|
||||
if (!info) // some desktop environments don't allow XDG-portal notifications without a desktop file
|
||||
/* Some desktop environments don't allow XDG-portal notifications without a desktop file.
|
||||
There is no public API to force a specific backend, so we have to set the environment variable.
|
||||
The GNOTIFICATION_BACKEND variable will be read by GIO the first time the notification backend is used.
|
||||
This method should be future proof unless the freedesktop backend is removed. */
|
||||
if (!info)
|
||||
setenv("GNOTIFICATION_BACKEND", "freedesktop", 0);
|
||||
else
|
||||
g_object_unref(info);
|
||||
g_free(desktop_id);
|
||||
GSimpleAction *action = g_simple_action_new("notificationaction", g_variant_type_new("(isss)"));
|
||||
g_signal_connect(action, "activate", G_CALLBACK(notification_action), app);
|
||||
g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(action));
|
||||
g_object_unref(action);
|
||||
ongoing_notifications = g_hash_table_new(NULL, NULL);
|
||||
}
|
||||
g_hash_table_insert(pending_notifications, GINT_TO_POINTER(id), notification);
|
||||
g_mutex_unlock(&pending_notifications_mutex);
|
||||
if (g_source_get_ready_time(send_notifcation_timer) == -1) {
|
||||
if (g_source_get_ready_time(send_notifcation_timer) == -1)
|
||||
g_source_set_ready_time(send_notifcation_timer, 0); // immediately
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_android_app_NotificationManager_nativeInitBuilder(JNIEnv *env, jobject this)
|
||||
@@ -104,32 +90,18 @@ JNIEXPORT jlong JNICALL Java_android_app_NotificationManager_nativeInitBuilder(J
|
||||
return _INTPTR(g_notification_new(""));
|
||||
}
|
||||
|
||||
static GVariant *serialize_intent(JNIEnv *env, jint type, jstring action_jstr, jstring className_jstr, jstring data_jstr)
|
||||
{
|
||||
const char *action = action_jstr ? (*env)->GetStringUTFChars(env, action_jstr, NULL) : NULL;
|
||||
const char *className = className_jstr ? (*env)->GetStringUTFChars(env, className_jstr, NULL) : NULL;
|
||||
const char *data = data_jstr ? (*env)->GetStringUTFChars(env, data_jstr, NULL) : NULL;
|
||||
GVariant *intent = g_variant_new("(isss)", type, action ?: "", className ?: "", data ?: "");
|
||||
if (action_jstr) (*env)->ReleaseStringUTFChars(env, action_jstr, action);
|
||||
if (className_jstr) (*env)->ReleaseStringUTFChars(env, className_jstr, className);
|
||||
if (data_jstr) (*env)->ReleaseStringUTFChars(env, data_jstr, data);
|
||||
return intent;
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeAddAction(JNIEnv *env, jobject this, jlong builder_ptr, jstring name_jstr, jint type, jstring action, jstring className, jstring data)
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeAddAction(JNIEnv *env, jobject this, jlong builder_ptr, jstring name_jstr, jint type, jobject intent)
|
||||
{
|
||||
GNotification *notification = _PTR(builder_ptr);
|
||||
const char *name = "";
|
||||
if (name_jstr) {
|
||||
if (name_jstr)
|
||||
name = (*env)->GetStringUTFChars(env, name_jstr, NULL);
|
||||
}
|
||||
g_notification_add_button_with_target_value(notification, name, "app.notificationaction", serialize_intent(env, type, action, className, data));
|
||||
if (name_jstr) {
|
||||
g_notification_add_button_with_target_value(notification, name, intent_actionname_from_type(type), intent_serialize(env, intent));
|
||||
if (name_jstr)
|
||||
(*env)->ReleaseStringUTFChars(env, name_jstr, name);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeShowNotification(JNIEnv *env, jobject this, jlong builder_ptr, jint id, jstring title_jstr, jstring text_jstr, jstring icon_jstr, jboolean ongoing, jint type, jstring action, jstring className, jstring data)
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeShowNotification(JNIEnv *env, jobject this, jlong builder_ptr, jint id, jstring title_jstr, jstring text_jstr, jstring icon_jstr, jboolean ongoing, jint type, jobject intent)
|
||||
{
|
||||
GNotification *notification = _PTR(builder_ptr);
|
||||
|
||||
@@ -157,7 +129,7 @@ JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeShowNotificati
|
||||
g_free(icon_path_full);
|
||||
(*env)->ReleaseStringUTFChars(env, icon_jstr, icon_path);
|
||||
}
|
||||
g_notification_set_default_action_and_target_value(notification, "app.notificationaction", serialize_intent(env, type, action, className, data));
|
||||
g_notification_set_default_action_and_target_value(notification, intent_actionname_from_type(type), intent_serialize(env, intent));
|
||||
queue_notification(id, notification);
|
||||
if (ongoing)
|
||||
g_hash_table_add(ongoing_notifications, GINT_TO_POINTER(id));
|
||||
|
||||
@@ -18,18 +18,18 @@ JNIEXPORT jlong JNICALL Java_android_app_NotificationManager_nativeInitBuilder
|
||||
/*
|
||||
* Class: android_app_NotificationManager
|
||||
* Method: nativeAddAction
|
||||
* Signature: (JLjava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
* Signature: (JLjava/lang/String;ILandroid/content/Intent;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeAddAction
|
||||
(JNIEnv *, jobject, jlong, jstring, jint, jstring, jstring, jstring);
|
||||
(JNIEnv *, jobject, jlong, jstring, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: android_app_NotificationManager
|
||||
* Method: nativeShowNotification
|
||||
* Signature: (JILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
* Signature: (JILjava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILandroid/content/Intent;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_android_app_NotificationManager_nativeShowNotification
|
||||
(JNIEnv *, jobject, jlong, jint, jstring, jstring, jstring, jboolean, jint, jstring, jstring, jstring);
|
||||
(JNIEnv *, jobject, jlong, jint, jstring, jstring, jstring, jboolean, jint, jobject);
|
||||
|
||||
/*
|
||||
* Class: android_app_NotificationManager
|
||||
|
||||
@@ -159,6 +159,8 @@ void set_up_handle_cache(JNIEnv *env)
|
||||
if((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
handle_cache.context.sendBroadcast = _METHOD(handle_cache.context.class, "sendBroadcast", "(Landroid/content/Intent;)V");
|
||||
handle_cache.context.startActivity = _METHOD(handle_cache.context.class, "startActivity", "(Landroid/content/Intent;)V");
|
||||
handle_cache.context.startService = _METHOD(handle_cache.context.class, "startService", "(Landroid/content/Intent;)Landroid/content/ComponentName;");
|
||||
|
||||
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;");
|
||||
@@ -179,6 +181,8 @@ void set_up_handle_cache(JNIEnv *env)
|
||||
handle_cache.intent.constructor = _METHOD(handle_cache.intent.class, "<init>", "()V");
|
||||
handle_cache.intent.putExtraCharSequence = _METHOD(handle_cache.intent.class, "putExtra", "(Ljava/lang/String;Ljava/lang/CharSequence;)Landroid/content/Intent;");
|
||||
handle_cache.intent.putExtraByteArray = _METHOD(handle_cache.intent.class, "putExtra", "(Ljava/lang/String;[B)Landroid/content/Intent;");
|
||||
handle_cache.intent.getDataString = _METHOD(handle_cache.intent.class, "getDataString", "()Ljava/lang/String;");
|
||||
handle_cache.intent.setClassName = _METHOD(handle_cache.intent.class, "setClassName", "(Landroid/content/Context;Ljava/lang/String;)Landroid/content/Intent;");
|
||||
|
||||
handle_cache.instrumentation.class = _REF((*env)->FindClass(env, "android/app/Instrumentation"));
|
||||
|
||||
@@ -188,6 +192,9 @@ void set_up_handle_cache(JNIEnv *env)
|
||||
|
||||
handle_cache.canvas.class = _REF((*env)->FindClass(env, "android/graphics/Canvas"));
|
||||
handle_cache.canvas.drawText = _METHOD(handle_cache.canvas.class, "drawText", "(Ljava/lang/CharSequence;IIFFLandroid/graphics/Paint;)V");
|
||||
|
||||
handle_cache.uri.class = _REF((*env)->FindClass(env, "android/net/Uri"));
|
||||
handle_cache.uri.parse = _STATIC_METHOD(handle_cache.uri.class, "parse", "(Ljava/lang/String;)Landroid/net/Uri;");
|
||||
}
|
||||
|
||||
void extract_from_apk(const char *path, const char *target) {
|
||||
@@ -371,3 +378,56 @@ void atl_safe_gtk_widget_queue_resize(GtkWidget *widget)
|
||||
gtk_widget_add_tick_callback(widget, queue_queue_resize, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
GVariant *intent_serialize(JNIEnv *env, jobject intent) {
|
||||
jstring action_jstr = _GET_OBJ_FIELD(intent, "action", "Ljava/lang/String;");
|
||||
jobject component = _GET_OBJ_FIELD(intent, "component", "Landroid/content/ComponentName;");
|
||||
jstring className_jstr = component ? _GET_OBJ_FIELD(component, "mClass", "Ljava/lang/String;") : NULL;
|
||||
jstring data_jstr = (*env)->CallObjectMethod(env, intent, handle_cache.intent.getDataString);
|
||||
|
||||
const char *action = action_jstr ? (*env)->GetStringUTFChars(env, action_jstr, NULL) : NULL;
|
||||
const char *className = className_jstr ? (*env)->GetStringUTFChars(env, className_jstr, NULL) : NULL;
|
||||
const char *data = data_jstr ? (*env)->GetStringUTFChars(env, data_jstr, NULL) : NULL;
|
||||
GVariant *variant = g_variant_new(INTENT_G_VARIANT_TYPE_STRING, action ?: "", className ?: "", data ?: "");
|
||||
if (action_jstr)
|
||||
(*env)->ReleaseStringUTFChars(env, action_jstr, action);
|
||||
if (className_jstr)
|
||||
(*env)->ReleaseStringUTFChars(env, className_jstr, className);
|
||||
if (data_jstr)
|
||||
(*env)->ReleaseStringUTFChars(env, data_jstr, data);
|
||||
return variant;
|
||||
}
|
||||
|
||||
jobject intent_deserialize(JNIEnv *env, GVariant *variant) {
|
||||
const char *action;
|
||||
const char *className;
|
||||
const char *data;
|
||||
g_variant_get(variant, INTENT_G_VARIANT_TYPE_STRING, &action, &className, &data);
|
||||
if (action && action[0] == '\0')
|
||||
action = NULL;
|
||||
if (className && className[0] == '\0')
|
||||
className = NULL;
|
||||
if (data && data[0] == '\0')
|
||||
data = NULL;
|
||||
|
||||
jobject intent = (*env)->NewObject(env, handle_cache.intent.class, handle_cache.intent.constructor);
|
||||
_SET_OBJ_FIELD(intent, "action", "Ljava/lang/String;", _JSTRING(action));
|
||||
if (className)
|
||||
(*env)->CallObjectMethod(env, intent, handle_cache.intent.setClassName, _GET_STATIC_OBJ_FIELD(handle_cache.context.class, "this_application", "Landroid/app/Application;"), _JSTRING(className));
|
||||
if (data)
|
||||
_SET_OBJ_FIELD(intent, "data", "Landroid/net/Uri;", (*env)->CallStaticObjectMethod(env, handle_cache.uri.class, handle_cache.uri.parse, _JSTRING(data)));
|
||||
return intent;
|
||||
}
|
||||
|
||||
const char *intent_actionname_from_type(int type) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
return "app.startActivity";
|
||||
case 1:
|
||||
return "app.startService";
|
||||
case 2:
|
||||
return "app.sendBroadcast";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ struct handle_cache {
|
||||
jclass class;
|
||||
jmethodID get_package_name;
|
||||
jmethodID sendBroadcast;
|
||||
jmethodID startActivity;
|
||||
jmethodID startService;
|
||||
} context;
|
||||
struct {
|
||||
jclass class;
|
||||
@@ -128,6 +130,8 @@ struct handle_cache {
|
||||
jmethodID constructor;
|
||||
jmethodID putExtraCharSequence;
|
||||
jmethodID putExtraByteArray;
|
||||
jmethodID getDataString;
|
||||
jmethodID setClassName;
|
||||
} intent;
|
||||
struct {
|
||||
jclass class;
|
||||
@@ -143,6 +147,10 @@ struct handle_cache {
|
||||
jclass class;
|
||||
jmethodID drawText;
|
||||
} canvas;
|
||||
struct {
|
||||
jclass class;
|
||||
jmethodID parse;
|
||||
} uri;
|
||||
};
|
||||
|
||||
extern struct handle_cache handle_cache;
|
||||
@@ -195,4 +203,9 @@ void atl_safe_gtk_widget_set_visible(GtkWidget *widget, gboolean visible);
|
||||
void atl_safe_gtk_widget_queue_allocate(GtkWidget *widget);
|
||||
void atl_safe_gtk_widget_queue_resize(GtkWidget *widget);
|
||||
|
||||
#define INTENT_G_VARIANT_TYPE_STRING "(sss)" // (action, className, data)
|
||||
GVariant *intent_serialize(JNIEnv *env, jobject intent);
|
||||
jobject intent_deserialize(JNIEnv *env, GVariant *variant);
|
||||
const char *intent_actionname_from_type(int type);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,10 +4,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import android.app.Notification.MediaStyle;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
@@ -30,28 +28,20 @@ public class NotificationManager {
|
||||
long builder = nativeInitBuilder();
|
||||
for (Notification.Action action : notification.actions) {
|
||||
int intentType = -1;
|
||||
String actionName = null;
|
||||
String className = null;
|
||||
String data = null;
|
||||
Intent intent = null;
|
||||
if (action.intent != null) {
|
||||
intentType = action.intent.type;
|
||||
actionName = action.intent.intent.getAction();
|
||||
className = action.intent.intent.getComponent() != null ? action.intent.intent.getComponent().getClassName() : null;
|
||||
data = action.intent.intent.getData() != null ? action.intent.intent.getData().toString() : null;
|
||||
intent = action.intent.intent;
|
||||
}
|
||||
nativeAddAction(builder, action.title, intentType, actionName, className, data);
|
||||
nativeAddAction(builder, action.title, intentType, intent);
|
||||
}
|
||||
int intentType = -1;
|
||||
String actionName = null;
|
||||
String className = null;
|
||||
String data = null;
|
||||
Intent intent = null;
|
||||
if (notification.intent != null) {
|
||||
intentType = notification.intent.type;
|
||||
actionName = notification.intent.intent.getAction();
|
||||
className = notification.intent.intent.getComponent() != null ? notification.intent.intent.getComponent().getClassName() : null;
|
||||
data = notification.intent.intent.getData() != null ? notification.intent.intent.getData().toString() : null;
|
||||
intent = notification.intent.intent;
|
||||
}
|
||||
nativeShowNotification(builder, id, notification.title, notification.text, notification.iconPath, notification.ongoing, intentType, actionName, className, data);
|
||||
nativeShowNotification(builder, id, notification.title, notification.text, notification.iconPath, notification.ongoing, intentType, intent);
|
||||
}
|
||||
|
||||
public void notify(int id, Notification notification) {
|
||||
@@ -78,29 +68,11 @@ public class NotificationManager {
|
||||
cancel(null, id);
|
||||
}
|
||||
|
||||
protected static void notificationActionCallback(int intentType, String action, String className, String data) {
|
||||
Context context = Context.this_application;
|
||||
action = "".equals(action) ? null : action;
|
||||
className = "".equals(className) ? null : className;
|
||||
data = "".equals(data) ? null : data;
|
||||
Intent intent = new Intent(action, data != null ? Uri.parse(data) : null);
|
||||
if (className != null) {
|
||||
intent.setComponent(new ComponentName(context, className));
|
||||
}
|
||||
if (intentType == 0) { // type Activity
|
||||
context.startActivity(intent);
|
||||
} else if (intentType == 1) { // type Service
|
||||
context.startService(intent);
|
||||
} else if (intentType == 2) { // type Broadcast
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
public void createNotificationChannel(NotificationChannel channel) {}
|
||||
|
||||
protected native long nativeInitBuilder();
|
||||
protected native void nativeAddAction(long builder, String title, int intentType, String action, String className, String data);
|
||||
protected native void nativeShowNotification(long builder, int id, String title, String text, String iconPath, boolean ongoing, int intentType, String action, String className, String data);
|
||||
protected native void nativeAddAction(long builder, String title, int intentType, Intent intent);
|
||||
protected native void nativeShowNotification(long builder, int id, String title, String text, String iconPath, boolean ongoing, int intentType, Intent intent);
|
||||
protected native void nativeShowMPRIS(String packageName, String identiy);
|
||||
protected native void nativeCancel(int id);
|
||||
protected native void nativeCancelMPRIS();
|
||||
|
||||
49
src/main-executable/actions.c
Normal file
49
src/main-executable/actions.c
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <gio/gio.h>
|
||||
#include <jni.h>
|
||||
|
||||
#include "../api-impl-jni/defines.h"
|
||||
#include "../api-impl-jni/util.h"
|
||||
|
||||
static void action_start_activity(GSimpleAction *action, GVariant* parameter, gpointer user_data)
|
||||
{
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
jobject intent = intent_deserialize(env, parameter);
|
||||
jobject context = _GET_STATIC_OBJ_FIELD(handle_cache.context.class, "this_application", "Landroid/app/Application;");
|
||||
(*env)->CallVoidMethod(env, context, handle_cache.context.startActivity, intent);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void action_start_service(GSimpleAction *action, GVariant* parameter, gpointer user_data)
|
||||
{
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
jobject intent = intent_deserialize(env, parameter);
|
||||
jobject context = _GET_STATIC_OBJ_FIELD(handle_cache.context.class, "this_application", "Landroid/app/Application;");
|
||||
(*env)->CallObjectMethod(env, context, handle_cache.context.startService, intent);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
}
|
||||
|
||||
static void action_send_broadcast(GSimpleAction *action, GVariant* parameter, gpointer user_data)
|
||||
{
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
||||
jobject intent = intent_deserialize(env, parameter);
|
||||
jobject context = _GET_STATIC_OBJ_FIELD(handle_cache.context.class, "this_application", "Landroid/app/Application;");
|
||||
(*env)->CallVoidMethod(env, context, handle_cache.context.sendBroadcast, intent);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
}
|
||||
|
||||
const GActionEntry action_entries[] = {
|
||||
{ "startActivity", action_start_activity, INTENT_G_VARIANT_TYPE_STRING},
|
||||
{ "startService", action_start_service, INTENT_G_VARIANT_TYPE_STRING},
|
||||
{ "sendBroadcast", action_send_broadcast, INTENT_G_VARIANT_TYPE_STRING},
|
||||
};
|
||||
|
||||
const int action_entries_count = ARRAY_SIZE(action_entries);
|
||||
4
src/main-executable/actions.h
Normal file
4
src/main-executable/actions.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <gio/gio.h>
|
||||
|
||||
extern const GActionEntry action_entries[];
|
||||
extern const int action_entries_count;
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "back_button.h"
|
||||
#include "libc_bio_path_overrides.h"
|
||||
#include "actions.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
@@ -714,6 +715,19 @@ static void open(GtkApplication *app, GFile **files, gint nfiles, const gchar *h
|
||||
if ((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionDescribe(env);
|
||||
}
|
||||
|
||||
const char *app_id = g_application_get_application_id(G_APPLICATION(app));
|
||||
if (strcmp(app_id, "com.example.demo_application")) {
|
||||
// This would normally happen automatically, if the GApplication is not contructed with G_APPLICATION_NON_UNIQUE
|
||||
g_dbus_connection_call(g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL),
|
||||
"org.freedesktop.DBus",
|
||||
"/org/freedesktop/DBus",
|
||||
"org.freedesktop.DBus",
|
||||
"RequestName",
|
||||
g_variant_new("(su)", app_id, G_BUS_NAME_OWNER_FLAGS_NONE),
|
||||
G_VARIANT_TYPE("(u)"),
|
||||
0, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void activate(GtkApplication *app, struct jni_callback_data *d)
|
||||
@@ -780,12 +794,7 @@ int main(int argc, char **argv)
|
||||
callback_data->extra_jvm_options = NULL;
|
||||
callback_data->extra_string_keys = NULL;
|
||||
|
||||
bool has_app_id = false;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strncmp(argv[i], "--gapplication-app-id", sizeof("--gapplication-app-id")-1) == 0)
|
||||
has_app_id = true;
|
||||
}
|
||||
app = gtk_application_new("com.example.demo_application", (has_app_id ? 0 : G_APPLICATION_NON_UNIQUE) | G_APPLICATION_HANDLES_OPEN | G_APPLICATION_CAN_OVERRIDE_APP_ID);
|
||||
app = gtk_application_new("com.example.demo_application", G_APPLICATION_NON_UNIQUE | G_APPLICATION_HANDLES_OPEN | G_APPLICATION_CAN_OVERRIDE_APP_ID);
|
||||
|
||||
// cmdline related setup
|
||||
init_cmd_parameters(G_APPLICATION(app), callback_data);
|
||||
@@ -793,6 +802,7 @@ int main(int argc, char **argv)
|
||||
|
||||
g_signal_connect(app, "activate", G_CALLBACK(activate), callback_data);
|
||||
g_signal_connect(app, "open", G_CALLBACK(open), callback_data);
|
||||
g_action_map_add_action_entries(G_ACTION_MAP(app), action_entries, action_entries_count, NULL);
|
||||
status = g_application_run(G_APPLICATION(app), argc, argv);
|
||||
remove_ongoing_notifications();
|
||||
g_object_unref(app);
|
||||
|
||||
Reference in New Issue
Block a user