diff --git a/meson.build b/meson.build
index f36ed95c..7247681d 100644
--- a/meson.build
+++ b/meson.build
@@ -47,6 +47,12 @@ mpris = gnome.gdbus_codegen('mpris-dbus',
portal_openuri = gnome.gdbus_codegen('portal-openuri',
'src/api-impl-jni/content/org.freedesktop.portal.OpenURI.xml',
interface_prefix: 'org.freedesktop.portal')
+unifiedpush_distributor = gnome.gdbus_codegen('unifiedpush-distributor',
+ 'src/api-impl-jni/content/org.unifiedpush.Distributor1.xml',
+ interface_prefix: 'org.unifiedpush')
+unifiedpush_connector = gnome.gdbus_codegen('unifiedpush-connector',
+ 'src/api-impl-jni/content/org.unifiedpush.Connector1.xml',
+ interface_prefix: 'org.unifiedpush')
extra_deps = []
extra_jni_srcs = []
@@ -157,6 +163,8 @@ libtranslationlayer_so = shared_library('translation_layer_main', [
'src/api-impl-jni/widgets/android_widget_TextView.c',
mpris,
portal_openuri,
+ unifiedpush_distributor,
+ unifiedpush_connector,
wl_proto_headers,
wl_proto_sources,
extra_jni_srcs,
diff --git a/src/api-impl-jni/content/android_content_Context.c b/src/api-impl-jni/content/android_content_Context.c
index ea569ba9..bb95cd82 100644
--- a/src/api-impl-jni/content/android_content_Context.c
+++ b/src/api-impl-jni/content/android_content_Context.c
@@ -8,6 +8,8 @@
#endif
#include "portal-openuri.h"
+#include "unifiedpush-distributor.h"
+#include "unifiedpush-connector.h"
#include "../defines.h"
#include "../util.h"
@@ -86,3 +88,90 @@ JNIEXPORT void JNICALL Java_android_content_Context_nativeOpenFile(JNIEnv *env,
g_object_unref(openuri);
g_object_unref(connection);
}
+
+static void on_bus_acquired(GDBusConnection *connection, const char *name, gpointer user_data)
+{
+ Connector1 *connector1 = user_data;
+ g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(connector1),
+ connection, "/org/unifiedpush/Connector", NULL);
+}
+
+static gboolean on_new_endpoint(Connector1 *connector, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ GVariant *parameters = g_dbus_method_invocation_get_parameters(invocation);
+ const char *token;
+ g_variant_get_child(parameters, 0, "s", &token);
+ const char *endpoint;
+ g_variant_get_child(parameters, 1, "s", &endpoint);
+ connector1_complete_new_endpoint(connector, invocation);
+
+ JNIEnv *env = get_jni_env();
+ jobject intent = (*env)->NewObject(env, handle_cache.intent.class, handle_cache.intent.constructor);
+ _SET_OBJ_FIELD(intent, "action", "Ljava/lang/String;", _JSTRING("org.unifiedpush.android.connector.NEW_ENDPOINT"));
+ (*env)->CallObjectMethod(env, intent, handle_cache.intent.putExtraCharSequence, _JSTRING("token"), _JSTRING(token));
+ (*env)->CallObjectMethod(env, intent, handle_cache.intent.putExtraCharSequence, _JSTRING("endpoint"), _JSTRING(endpoint));
+
+ 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);
+ }
+ return TRUE;
+}
+
+static gboolean on_message(Connector1 *connector, GDBusMethodInvocation *invocation, gpointer user_data)
+{
+ GVariant *parameters = g_dbus_method_invocation_get_parameters(invocation);
+ const char *token;
+ g_variant_get_child(parameters, 0, "s", &token);
+ gsize size;
+ const int8_t *message = g_variant_get_fixed_array(g_variant_get_child_value(parameters, 1), &size, 1);
+ connector1_complete_message(connector, invocation);
+
+ JNIEnv *env = get_jni_env();
+ jobject intent = (*env)->NewObject(env, handle_cache.intent.class, handle_cache.intent.constructor);
+ _SET_OBJ_FIELD(intent, "action", "Ljava/lang/String;", _JSTRING("org.unifiedpush.android.connector.MESSAGE"));
+ (*env)->CallObjectMethod(env, intent, handle_cache.intent.putExtraCharSequence, _JSTRING("token"), _JSTRING(token));
+ jbyteArray bytesMessage = (*env)->NewByteArray(env, size);
+ (*env)->SetByteArrayRegion(env, bytesMessage, 0, size, message);
+ (*env)->CallObjectMethod(env, intent, handle_cache.intent.putExtraByteArray, _JSTRING("bytesMessage"), bytesMessage);
+
+ 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);
+ }
+ return TRUE;
+}
+
+JNIEXPORT void JNICALL Java_android_content_Context_nativeExportUnifiedPush(JNIEnv *env, jclass this, jstring application_jstr)
+{
+ const char *application = (*env)->GetStringUTFChars(env, application_jstr, NULL);
+
+ Connector1 *connector1 = connector1_skeleton_new();
+ g_signal_connect(connector1, "handle-new-endpoint", G_CALLBACK(on_new_endpoint), NULL);
+ g_signal_connect(connector1, "handle-message", G_CALLBACK(on_message), NULL);
+ g_bus_own_name(G_BUS_TYPE_SESSION, application, G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired, NULL, NULL, connector1, NULL);
+ (*env)->ReleaseStringUTFChars(env, application_jstr, application);
+}
+
+JNIEXPORT void JNICALL Java_android_content_Context_nativeRegisterUnifiedPush(JNIEnv *env, jclass this, jstring token_jstr, jstring application_jstr)
+{
+ const char *token = (*env)->GetStringUTFChars(env, token_jstr, NULL);
+ const char *application = (*env)->GetStringUTFChars(env, application_jstr, NULL);
+
+ GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
+ Distributor1 *distributor1 = distributor1_proxy_new_sync(connection, 0, "org.unifiedpush.Distributor.kde", "/org/unifiedpush/Distributor", NULL, NULL);
+ GError *error = NULL;
+ distributor1_call_register(distributor1, application, token, "", NULL, NULL, &error);
+ if (error) {
+ printf("nativeRegisterUnifiedPush: error=%s\n", error->message);
+ g_error_free(error);
+ }
+ g_object_unref(distributor1);
+ g_object_unref(connection);
+
+ (*env)->ReleaseStringUTFChars(env, token_jstr, token);
+ (*env)->ReleaseStringUTFChars(env, application_jstr, application);
+}
diff --git a/src/api-impl-jni/content/org.unifiedpush.Connector1.xml b/src/api-impl-jni/content/org.unifiedpush.Connector1.xml
new file mode 100644
index 00000000..6609ca78
--- /dev/null
+++ b/src/api-impl-jni/content/org.unifiedpush.Connector1.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/api-impl-jni/content/org.unifiedpush.Distributor1.xml b/src/api-impl-jni/content/org.unifiedpush.Distributor1.xml
new file mode 100644
index 00000000..d983fde5
--- /dev/null
+++ b/src/api-impl-jni/content/org.unifiedpush.Distributor1.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/api-impl-jni/generated_headers/android_content_Context.h b/src/api-impl-jni/generated_headers/android_content_Context.h
index b3609de5..bef33831 100644
--- a/src/api-impl-jni/generated_headers/android_content_Context.h
+++ b/src/api-impl-jni/generated_headers/android_content_Context.h
@@ -33,6 +33,22 @@ JNIEXPORT void JNICALL Java_android_content_Context_native_1updateConfig
JNIEXPORT void JNICALL Java_android_content_Context_nativeOpenFile
(JNIEnv *, jclass, jint);
+/*
+ * Class: android_content_Context
+ * Method: nativeExportUnifiedPush
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_android_content_Context_nativeExportUnifiedPush
+ (JNIEnv *, jclass, jstring);
+
+/*
+ * Class: android_content_Context
+ * Method: nativeRegisterUnifiedPush
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_android_content_Context_nativeRegisterUnifiedPush
+ (JNIEnv *, jclass, jstring, jstring);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/api-impl-jni/util.c b/src/api-impl-jni/util.c
index 523ff2db..c950ee8b 100644
--- a/src/api-impl-jni/util.c
+++ b/src/api-impl-jni/util.c
@@ -156,6 +156,7 @@ void set_up_handle_cache(JNIEnv *env)
handle_cache.context.get_package_name = _METHOD(handle_cache.context.class, "getPackageName", "()Ljava/lang/String;");
if((*env)->ExceptionCheck(env))
(*env)->ExceptionDescribe(env);
+ handle_cache.context.sendBroadcast = _METHOD(handle_cache.context.class, "sendBroadcast", "(Landroid/content/Intent;)V");
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;");
@@ -174,6 +175,7 @@ void set_up_handle_cache(JNIEnv *env)
handle_cache.intent.class = _REF((*env)->FindClass(env, "android/content/Intent"));
handle_cache.intent.constructor = _METHOD(handle_cache.intent.class, "", "()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.instrumentation.class = _REF((*env)->FindClass(env, "android/app/Instrumentation"));
diff --git a/src/api-impl-jni/util.h b/src/api-impl-jni/util.h
index 5d343344..bd9a5365 100644
--- a/src/api-impl-jni/util.h
+++ b/src/api-impl-jni/util.h
@@ -100,6 +100,7 @@ struct handle_cache {
struct {
jclass class;
jmethodID get_package_name;
+ jmethodID sendBroadcast;
} context;
struct {
jclass class;
@@ -123,6 +124,7 @@ struct handle_cache {
jclass class;
jmethodID constructor;
jmethodID putExtraCharSequence;
+ jmethodID putExtraByteArray;
} intent;
struct {
jclass class;
diff --git a/src/api-impl/android/app/Notification.java b/src/api-impl/android/app/Notification.java
index 2a527344..030d9871 100644
--- a/src/api-impl/android/app/Notification.java
+++ b/src/api-impl/android/app/Notification.java
@@ -188,6 +188,10 @@ public class Notification implements Parcelable {
public Builder setSound(Uri sound) {return this;}
+ public Builder setSmallIcon(int icon) {return this;}
+
+ public Builder setTicker(CharSequence tickerText) {return this;}
+
public Notification build() {
return notification;
}
diff --git a/src/api-impl/android/content/Context.java b/src/api-impl/android/content/Context.java
index de6484c1..93f04601 100644
--- a/src/api-impl/android/content/Context.java
+++ b/src/api-impl/android/content/Context.java
@@ -133,11 +133,22 @@ public class Context extends Object {
Security.addProvider(provider);
r.applyPackageQuirks(application_info.packageName);
+
+ for (PackageParser.Activity receiver : pkg.receivers) {
+ for (PackageParser.ActivityIntentInfo intent : receiver.intents) {
+ if (intent.matchAction("org.unifiedpush.android.connector.MESSAGE")) {
+ nativeExportUnifiedPush(application_info.packageName);
+ break;
+ }
+ }
+ }
}
private static native String native_get_apk_path();
protected static native void native_updateConfig(Configuration config);
private static native void nativeOpenFile(int fd);
+ private static native void nativeExportUnifiedPush(String packageName);
+ private static native void nativeRegisterUnifiedPush(String token, String application);
static Application createApplication(long native_window) throws Exception {
Application application;
@@ -502,6 +513,16 @@ public class Context extends Object {
public void unregisterComponentCallbacks(ComponentCallbacks callbacks) {}
public boolean bindService(final Intent intent, final ServiceConnection serviceConnection, int dummy3) {
+ if (intent.getComponent() == null) {
+ for (PackageParser.Service s : pkg.services) {
+ for (PackageParser.IntentInfo ii : s.intents) {
+ if (ii.matchAction(intent.getAction())) {
+ intent.setComponent(new ComponentName(pkg.packageName, s.className));
+ break;
+ }
+ }
+ }
+ }
if (intent.getComponent() == null) {
Slog.w(TAG, "Context.bindService: intent.getComponent() is null");
return false;
@@ -629,11 +650,27 @@ public class Context extends Object {
}
public void sendBroadcast(Intent intent) {
+ if ("org.unifiedpush.android.distributor.REGISTER".equals(intent.getAction())) {
+ nativeRegisterUnifiedPush(intent.getStringExtra("token"), intent.getStringExtra("application"));
+ }
for (IntentFilter filter : receiverMap.keySet()) {
if (filter.matchAction(intent.getAction())) {
receiverMap.get(filter).onReceive(this, intent);
}
}
+ for (PackageParser.Activity receiver : pkg.receivers) {
+ for (PackageParser.IntentInfo intentInfo : receiver.intents) {
+ if (intentInfo.matchAction(intent.getAction())) {
+ try {
+ Class extends BroadcastReceiver> cls = Class.forName(receiver.className).asSubclass(BroadcastReceiver.class);
+ BroadcastReceiver receiverInstance = cls.newInstance();
+ receiverInstance.onReceive(this, intent);
+ } catch (ReflectiveOperationException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
}
public boolean stopService(Intent intent) throws ClassNotFoundException {
diff --git a/src/api-impl/android/content/pm/PackageManager.java b/src/api-impl/android/content/pm/PackageManager.java
index c90cc541..80575d46 100644
--- a/src/api-impl/android/content/pm/PackageManager.java
+++ b/src/api-impl/android/content/pm/PackageManager.java
@@ -2318,6 +2318,11 @@ public class PackageManager {
*/
public List queryBroadcastReceivers(Intent intent,
int flags) {
+ if ("org.unifiedpush.android.distributor.REGISTER".equals(intent.getAction())) {
+ ResolveInfo ri = new ResolveInfo();
+ ri.activityInfo.exported = true;
+ return Arrays.asList(ri);
+ }
return new ArrayList();
}
diff --git a/src/api-impl/android/content/pm/ResolveInfo.java b/src/api-impl/android/content/pm/ResolveInfo.java
index a7def7a6..2d13224d 100644
--- a/src/api-impl/android/content/pm/ResolveInfo.java
+++ b/src/api-impl/android/content/pm/ResolveInfo.java
@@ -6,6 +6,7 @@ public class ResolveInfo {
public ActivityInfo activityInfo = new ActivityInfo();
public ServiceInfo serviceInfo = new ServiceInfo();
public IntentFilter filter = new IntentFilter();
+ public int priority = -500;
public static class DisplayNameComparator {
diff --git a/src/api-impl/android/os/Binder.java b/src/api-impl/android/os/Binder.java
index 2450a29a..db660d22 100644
--- a/src/api-impl/android/os/Binder.java
+++ b/src/api-impl/android/os/Binder.java
@@ -1,5 +1,7 @@
package android.os;
+import android.content.Context;
+
public class Binder implements IBinder {
public void attachInterface(IInterface owner, String descriptor) {}
@@ -16,7 +18,7 @@ public class Binder implements IBinder {
@Override
public boolean transact(int code, Parcel data, Parcel reply, int flags) { return false; }
- public static int getCallingUid() { return 0; }
+ public static int getCallingUid() { return Context.this_application.getApplicationInfo().uid; }
public static int getCallingPid() { return 0; }
}