diff --git a/meson.build b/meson.build index c7917a3c..4be7a5eb 100644 --- a/meson.build +++ b/meson.build @@ -50,6 +50,9 @@ viewporter = wl_mod.scan_xml(xml) mpris = gnome.gdbus_codegen('mpris-dbus', 'src/api-impl-jni/media/org.mpris.MediaPlayer2.xml', interface_prefix: 'org.mpris') +portal_openuri = gnome.gdbus_codegen('portal-openuri', + 'src/api-impl-jni/content/org.freedesktop.portal.OpenURI.xml', + interface_prefix: 'org.freedesktop.portal') # libandroid libandroid_so = shared_library('android', [ @@ -139,6 +142,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ linux_dmabuf, viewporter, mpris, + portal_openuri, ] + marshal_files, include_directories: ['src/sk_area/'], install: true, diff --git a/src/api-impl-jni/app/android_app_Activity.c b/src/api-impl-jni/app/android_app_Activity.c index 9599517c..40bad027 100644 --- a/src/api-impl-jni/app/android_app_Activity.c +++ b/src/api-impl-jni/app/android_app_Activity.c @@ -2,6 +2,7 @@ #include #include +#include #include "../defines.h" #include "../util.h" @@ -261,7 +262,7 @@ JNIEXPORT void JNICALL Java_android_app_Activity_nativeFileChooser(JNIEnv *env, #endif const char *type = type_jstring ? (*env)->GetStringUTFChars(env, type_jstring, NULL) : NULL; - if (type) { + if (type && !strchr(type, '*')) { GtkFileFilter *filter = gtk_file_filter_new(); gtk_file_filter_add_mime_type(filter, type); gtk_file_filter_set_name(filter, type); diff --git a/src/api-impl-jni/content/android_content_Context.c b/src/api-impl-jni/content/android_content_Context.c index 03018b6a..717573c3 100644 --- a/src/api-impl-jni/content/android_content_Context.c +++ b/src/api-impl-jni/content/android_content_Context.c @@ -3,6 +3,8 @@ #include #include +#include "portal-openuri.h" + #include "../defines.h" #include "../util.h" @@ -32,3 +34,16 @@ JNIEXPORT void JNICALL Java_android_content_Context_native_1updateConfig(JNIEnv if (!theme_name_from_env) g_free(theme_name); } + +JNIEXPORT void JNICALL Java_android_content_Context_nativeOpenFile(JNIEnv *env, jclass class, jint fd) +{ + GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); + OpenURI *openuri = open_uri_proxy_new_sync(connection, 0, "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", NULL, NULL); + GVariantBuilder opt_builder; + g_variant_builder_init(&opt_builder, G_VARIANT_TYPE_VARDICT); + GUnixFDList *fd_list = g_unix_fd_list_new_from_array(&fd, 1); + open_uri_call_open_file_sync(openuri, "", g_variant_new("h", 0), g_variant_builder_end(&opt_builder), fd_list, NULL, NULL, NULL, NULL); + g_object_unref(fd_list); + g_object_unref(openuri); + g_object_unref(connection); +} diff --git a/src/api-impl-jni/content/org.freedesktop.portal.OpenURI.xml b/src/api-impl-jni/content/org.freedesktop.portal.OpenURI.xml new file mode 100644 index 00000000..5ed054cf --- /dev/null +++ b/src/api-impl-jni/content/org.freedesktop.portal.OpenURI.xml @@ -0,0 +1,167 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 bb1f0add..b3609de5 100644 --- a/src/api-impl-jni/generated_headers/android_content_Context.h +++ b/src/api-impl-jni/generated_headers/android_content_Context.h @@ -25,6 +25,14 @@ JNIEXPORT jstring JNICALL Java_android_content_Context_native_1get_1apk_1path JNIEXPORT void JNICALL Java_android_content_Context_native_1updateConfig (JNIEnv *, jclass, jobject); +/* + * Class: android_content_Context + * Method: nativeOpenFile + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_android_content_Context_nativeOpenFile + (JNIEnv *, jclass, jint); + #ifdef __cplusplus } #endif diff --git a/src/api-impl/android/content/ContentProvider.java b/src/api-impl/android/content/ContentProvider.java index 05b85fab..2b3ba8d8 100644 --- a/src/api-impl/android/content/ContentProvider.java +++ b/src/api-impl/android/content/ContentProvider.java @@ -6,6 +6,7 @@ import java.util.Map; import android.content.pm.PackageParser; import android.database.Cursor; import android.net.Uri; +import android.os.ParcelFileDescriptor; public abstract class ContentProvider { @@ -34,4 +35,8 @@ public abstract class ContentProvider { public abstract int delete(Uri uri, String selection, String[] selectionArgs); + public abstract String getType(Uri uri); + + public abstract ParcelFileDescriptor openFile(Uri uri, String mode); + } diff --git a/src/api-impl/android/content/ContentResolver.java b/src/api-impl/android/content/ContentResolver.java index 9fdc96dd..dab0496c 100644 --- a/src/api-impl/android/content/ContentResolver.java +++ b/src/api-impl/android/content/ContentResolver.java @@ -23,7 +23,15 @@ public class ContentResolver { } public ParcelFileDescriptor openFileDescriptor(Uri uri, String mode) throws FileNotFoundException { - return ParcelFileDescriptor.open(new File(uri.toString()), ParcelFileDescriptor.parseMode(mode)); + if ("file".equals(uri.getScheme())) { + return ParcelFileDescriptor.open(new File(uri.toString()), ParcelFileDescriptor.parseMode(mode)); + } else { + ContentProvider provider = ContentProvider.providers.get(uri.getAuthority()); + if (provider != null) + return provider.openFile(uri, mode); + else + return null; + } } public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { @@ -53,4 +61,12 @@ public class ContentResolver { else return null; } + + public String getType(Uri uri) { + ContentProvider provider = ContentProvider.providers.get(uri.getAuthority()); + if (provider != null) + return provider.getType(uri); + else + return null; + } } diff --git a/src/api-impl/android/content/Context.java b/src/api-impl/android/content/Context.java index 2d5d8263..7081079c 100644 --- a/src/api-impl/android/content/Context.java +++ b/src/api-impl/android/content/Context.java @@ -35,6 +35,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Looper; +import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Vibrator; import android.telephony.TelephonyManager; @@ -116,6 +117,7 @@ public class Context extends Object { private static native String native_get_apk_path(); protected static native void native_updateConfig(Configuration config); + private static native void nativeOpenFile(int fd); static Application createApplication(long native_window) throws Exception { Application application; @@ -494,6 +496,15 @@ public class Context extends Object { ClipboardManager.native_set_clipboard(text); } else if (intent.getData() != null) { Slog.i(TAG, "starting extern activity with intent: " + intent); + if (intent.getData().getScheme().equals("content")) { + try { + ParcelFileDescriptor fd = getContentResolver().openFileDescriptor(intent.getData(), "r"); + nativeOpenFile(fd.getFd()); + return; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } Activity.nativeOpenURI(String.valueOf(intent.getData())); } return; diff --git a/src/api-impl/android/content/SearchRecentSuggestionsProvider.java b/src/api-impl/android/content/SearchRecentSuggestionsProvider.java index 6bb77003..65b1d5d3 100644 --- a/src/api-impl/android/content/SearchRecentSuggestionsProvider.java +++ b/src/api-impl/android/content/SearchRecentSuggestionsProvider.java @@ -2,6 +2,7 @@ package android.content; import android.database.Cursor; import android.net.Uri; +import android.os.ParcelFileDescriptor; public class SearchRecentSuggestionsProvider extends ContentProvider { public void setupSuggestions(String s, int i) {} @@ -20,4 +21,14 @@ public class SearchRecentSuggestionsProvider extends ContentProvider { public int delete(Uri uri, String selection, String[] selectionArgs) { throw new UnsupportedOperationException("Unimplemented method 'delete'"); } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException("Unimplemented method 'getType'"); + } + + @Override + public ParcelFileDescriptor openFile(Uri uri, String mode) { + throw new UnsupportedOperationException("Unimplemented method 'openFile'"); + } }