mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-04-28 12:17:57 +03:00
add a media ContentProvider
Every time the ContentProvider is accessed, a file chooser opens and the selected file is then provided as media file.
This commit is contained in:
parent
cff51b230b
commit
49fa854c93
7 changed files with 238 additions and 0 deletions
|
@ -113,6 +113,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [
|
||||||
'src/api-impl-jni/AssetInputStream.c',
|
'src/api-impl-jni/AssetInputStream.c',
|
||||||
'src/api-impl-jni/audio/android_media_AudioTrack.c',
|
'src/api-impl-jni/audio/android_media_AudioTrack.c',
|
||||||
'src/api-impl-jni/audio/android_media_SoundPool.c',
|
'src/api-impl-jni/audio/android_media_SoundPool.c',
|
||||||
|
'src/api-impl-jni/content/android_content_ATLMediaContentProvider.c',
|
||||||
'src/api-impl-jni/content/android_content_ClipboardManager.c',
|
'src/api-impl-jni/content/android_content_ClipboardManager.c',
|
||||||
'src/api-impl-jni/content/android_content_ContentResolver.c',
|
'src/api-impl-jni/content/android_content_ContentResolver.c',
|
||||||
'src/api-impl-jni/content/android_content_Context.c',
|
'src/api-impl-jni/content/android_content_Context.c',
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "../generated_headers/android_content_ATLMediaContentProvider.h"
|
||||||
|
#include "../defines.h"
|
||||||
|
#include "../util.h"
|
||||||
|
|
||||||
|
extern GtkWindow *window;
|
||||||
|
|
||||||
|
static void file_dialog_callback(GObject *dialog, GAsyncResult *res, gpointer user_data) {
|
||||||
|
GFile *file = gtk_file_dialog_open_finish(GTK_FILE_DIALOG(dialog), res, NULL);
|
||||||
|
JNIEnv *env = get_jni_env();
|
||||||
|
jobject this = (jobject) user_data;
|
||||||
|
(*env)->CallVoidMethod(env, this, _METHOD(_CLASS(this), "setSelectedFile", "(Ljava/lang/String;)V"), _JSTRING(g_file_get_path(file)));
|
||||||
|
g_object_unref(file);
|
||||||
|
_UNREF(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_android_content_ATLMediaContentProvider_native_1open_1media_1folder(JNIEnv *env, jobject this)
|
||||||
|
{
|
||||||
|
GtkFileDialog *dialog = gtk_file_dialog_new();
|
||||||
|
gtk_file_dialog_set_title(GTK_FILE_DIALOG(dialog), "Open Media Folder");
|
||||||
|
gtk_file_dialog_set_modal(GTK_FILE_DIALOG(dialog), TRUE);
|
||||||
|
gtk_file_dialog_open(dialog, window, NULL, file_dialog_callback, _REF(this));
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
/* DO NOT EDIT THIS FILE - it is machine generated */
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class android_content_ATLMediaContentProvider */
|
||||||
|
|
||||||
|
#ifndef _Included_android_content_ATLMediaContentProvider
|
||||||
|
#define _Included_android_content_ATLMediaContentProvider
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: android_content_ATLMediaContentProvider
|
||||||
|
* Method: native_open_media_folder
|
||||||
|
* Signature: ()V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_android_content_ATLMediaContentProvider_native_1open_1media_1folder
|
||||||
|
(JNIEnv *, jobject);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
145
src/api-impl/android/content/ATLMediaContentProvider.java
Normal file
145
src/api-impl/android/content/ATLMediaContentProvider.java
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package android.content;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.database.MatrixCursor;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
|
public class ATLMediaContentProvider extends ContentProvider {
|
||||||
|
|
||||||
|
boolean waitingForFileChooser = false;
|
||||||
|
File selectedFile = null;
|
||||||
|
long timestamp = 0;
|
||||||
|
|
||||||
|
// called from native
|
||||||
|
void setSelectedFile(String selectedFile) {
|
||||||
|
this.selectedFile = new File(selectedFile);
|
||||||
|
this.waitingForFileChooser = false;
|
||||||
|
this.timestamp = System.currentTimeMillis();
|
||||||
|
synchronized(this) {
|
||||||
|
notifyAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void openFileChooser() {
|
||||||
|
if (!waitingForFileChooser) {
|
||||||
|
waitingForFileChooser = true;
|
||||||
|
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
native_open_media_folder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
synchronized(this) {
|
||||||
|
try {
|
||||||
|
while (waitingForFileChooser) {
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
|
||||||
|
// if we haven't selected a file, open the file chooser
|
||||||
|
if (!"0".equals(uri.getLastPathSegment()) && timestamp + 1000 < System.currentTimeMillis()) {
|
||||||
|
openFileChooser();
|
||||||
|
}
|
||||||
|
MatrixCursor cursor = new MatrixCursor(projection);
|
||||||
|
Object[] row = new Object[projection.length];
|
||||||
|
if (uri.getQueryParameter("distinct") != null) {
|
||||||
|
for (int i = 0; i < projection.length; i++) {
|
||||||
|
switch (projection[i]) {
|
||||||
|
case "bucket_display_name":
|
||||||
|
row[i] = "files";
|
||||||
|
break;
|
||||||
|
case "bucket_id":
|
||||||
|
row[i] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < projection.length; i++) {
|
||||||
|
switch (projection[i]) {
|
||||||
|
case "_id":
|
||||||
|
row[i] = 0;
|
||||||
|
break;
|
||||||
|
case "_data":
|
||||||
|
case "title":
|
||||||
|
row[i] = selectedFile;
|
||||||
|
break;
|
||||||
|
case "mime_type":
|
||||||
|
row[i] = getType(uri);
|
||||||
|
break;
|
||||||
|
case "media_type":
|
||||||
|
if (getType(uri).startsWith("image/"))
|
||||||
|
row[i] = 1;
|
||||||
|
else if (getType(uri).startsWith("audio/"))
|
||||||
|
row[i] = 2;
|
||||||
|
else if (getType(uri).startsWith("video/"))
|
||||||
|
row[i] = 3;
|
||||||
|
else
|
||||||
|
row[i] = 0;
|
||||||
|
break;
|
||||||
|
case "date_modified":
|
||||||
|
case "datetaken":
|
||||||
|
row[i] = selectedFile.lastModified();
|
||||||
|
break;
|
||||||
|
case "orientation":
|
||||||
|
row[i] = 0;
|
||||||
|
break;
|
||||||
|
case "_size":
|
||||||
|
row[i] = selectedFile.length();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor.addRow(row);
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getType(Uri uri) {
|
||||||
|
try {
|
||||||
|
return Files.probeContentType(selectedFile.toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return "application/octet-stream";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||||
|
return ParcelFileDescriptor.open(selectedFile, ParcelFileDescriptor.parseMode(mode));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri insert(Uri uri, ContentValues values) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'insert'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'update'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int delete(Uri uri, String selection, String[] selectionArgs) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'delete'");
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void native_open_media_folder();
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ public abstract class ContentProvider {
|
||||||
providers.put(provider_parsed.info.authority, provider);
|
providers.put(provider_parsed.info.authority, provider);
|
||||||
} catch(Exception e) { e.printStackTrace(); }
|
} catch(Exception e) { e.printStackTrace(); }
|
||||||
}
|
}
|
||||||
|
providers.put("media", new ATLMediaContentProvider());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onCreate() {return false;}
|
public boolean onCreate() {return false;}
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
package android.provider;
|
package android.provider;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
||||||
public class MediaStore {
|
public class MediaStore {
|
||||||
|
|
||||||
|
@ -9,6 +16,43 @@ public class MediaStore {
|
||||||
public static class Media {
|
public static class Media {
|
||||||
|
|
||||||
public static final Uri EXTERNAL_CONTENT_URI = Uri.parse("content://media/external/images/media");
|
public static final Uri EXTERNAL_CONTENT_URI = Uri.parse("content://media/external/images/media");
|
||||||
|
public static final Uri INTERNAL_CONTENT_URI = Uri.parse("content://media/internal/images/media");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Thumbnails {
|
||||||
|
|
||||||
|
public static Cursor queryMiniThumbnail(ContentResolver contentResolver, long id, int kind, String[] projection) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap getThumbnail(ContentResolver contentResolver, long imageId, long groupId, int kind, BitmapFactory.Options options) throws FileNotFoundException {
|
||||||
|
ParcelFileDescriptor fd = contentResolver.openFileDescriptor(Media.EXTERNAL_CONTENT_URI.buildUpon().appendPath(String.valueOf(imageId)).build(), "r");
|
||||||
|
return BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor(), null, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Video {
|
||||||
|
|
||||||
|
public static class Media {
|
||||||
|
|
||||||
|
public static final Uri EXTERNAL_CONTENT_URI = Uri.parse("content://media/external/video/media");
|
||||||
|
public static final Uri INTERNAL_CONTENT_URI = Uri.parse("content://media/internal/video/media");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Audio {
|
||||||
|
|
||||||
|
public static class Media {
|
||||||
|
|
||||||
|
public static final Uri EXTERNAL_CONTENT_URI = Uri.parse("content://media/external/audio/media");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Files {
|
||||||
|
|
||||||
|
public static Uri getContentUri(String type) {
|
||||||
|
return Uri.parse("content://media/files/" + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ srcs = [
|
||||||
'android/bluetooth/le/ScanCallback.java',
|
'android/bluetooth/le/ScanCallback.java',
|
||||||
'android/content/ActivityNotFoundException.java',
|
'android/content/ActivityNotFoundException.java',
|
||||||
'android/content/AsyncQueryHandler.java',
|
'android/content/AsyncQueryHandler.java',
|
||||||
|
'android/content/ATLMediaContentProvider.java',
|
||||||
'android/content/BroadcastReceiver.java',
|
'android/content/BroadcastReceiver.java',
|
||||||
'android/content/ClipboardManager.java',
|
'android/content/ClipboardManager.java',
|
||||||
'android/content/ClipData.java',
|
'android/content/ClipData.java',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue