Manual media scan trigger via JNI MediaScannerConnection
-
Hi,
I'm looking for a way to manually trigger a media scan after saving an image e.g. in the folder /DCIM or /Picture. Although the images are correctly saved they are only visible for other apps (gallery, facebook,...) after a refresh via e.g. google+/fotos.I tried it described like here https://developer.android.com/reference/android/media/MediaScannerConnection.html
but I only get an error.QAndroidJniObject jCtx("android.content.Context"); QAndroidJniObject jCtxD = jCtx.callMethod<QAndroidJniObject>("getApplicationContext"); QAndroidJniObject jCty("android.media.MediaScannerConnection.MediaScannerConnectionClient"); QAndroidJniObject jMsc("android.media.MediaScannerConnection", "(Landroid.content.Context; Landroid.media.MediaScannerConnection.MediaScannerConnectionClient)V", jCtxD, jCty);
Error: 313: error: cannot pass objects of non-trivially-copyable type 'class QAndroidJniObject' through '...' QAndroidJniObject jMsc("android.media.MediaScannerConnection", "(Landroid.content.Context; Landroid.media.MediaScannerConnection.MediaScannerConnectionClient)V", jCtxD, jCty);
Can maybe someone give me a hint what I'm doing wrong?
I already read Save Image to Android device , but I want to use only JNI without Java.
Thxs in andvance...
-
@PowerNow I have a media scan working on a camera application. So far I couldn't avoid the Java part, so this is C++ code in a class receiving the signal of an image already processed by the camera:
... connect(someObject, &SomeObject::imageProcessed, [this](QString fname) { QAndroidJniObject::callStaticMethod<void>("com/ path/application/MyActivity, "scanFile", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(fname).object<jstring>() ); });
Then on the Java side I have something like this:
... public class MyActivity extends QtActivity { ... public static void scanFile(String path) { MediaScannerConnection.scanFile(m_instance, new String[] { path }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { // No need to do anything on file actually scanned or not } } ); } ... }
-
@Pablo-J.-Rogina Thxs Pablo for your fast response! I'm just trying your proposal but my Android/Java knowledge is moderate. Please can you explain me how you get the current application context? How is your m_instance defined?
-
The following example shows how to auto-register an image for the Android Image Gallery app, tested on the Android kitcat.
First, append permission:
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGEJava Code:
android.content.Context.sendBroadcast(Intent intent)
To conversion C++/JNI
auto imagePath = QString(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/myImage.jpeg"); QAndroidJniEnvironment env; QAndroidJniObject activity = QtAndroid::androidActivity(); QAndroidJniObject context = activity.callObjectMethod("getApplicationContext", "()Landroid/content/Context;"); QAndroidJniObject intent("android/content/Intent"); QAndroidJniObject action = QAndroidJniObject::fromString("android.intent.action.MEDIA_SCANNER_SCAN_FILE"); QAndroidJniObject jpath = QAndroidJniObject::fromString(QUrl::fromLocalFile(imagePath).toString()); QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", jpath.object<jstring>()); intent = intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object()); intent = intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", action.object()); context.callMethod<void>("sendBroadcast", "(Landroid/content/Intent;)V", intent.object()); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); }
(*) A validation check on all JNI objects is required.
-
@PowerNow this is the whole Java code:
package com.yourname.yourproject; import org.qtproject.qt5.android.bindings.QtActivity; import org.qtproject.qt5.android.bindings.QtApplication; import android.os.Bundle; import android.media.MediaScannerConnection; import android.net.Uri; public class MyActivity extends QtActivity { private static MyActivity m_instance; public MyActivity() { m_instance = this; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); } public static void scanFile(String path) { MediaScannerConnection.scanFile(m_instance, new String[] { path }, null, new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { // No need to do anything on file actually scanned or not } } ); } }
-
Thxs a lot to @Pablo-J-Rogina and @Devopia53 !!!
@Devopia53 This was exactly I was looking for...
Afterwards only a littlebit simplified version.
QString ImgFilePath = "/.../Image.jpg"; QAndroidJniEnvironment env; QAndroidJniObject context = QtAndroid::androidContext(); QAndroidJniObject intent("android/content/Intent"); QAndroidJniObject action = QAndroidJniObject::fromString("android.intent.action.MEDIA_SCANNER_SCAN_FILE"); QAndroidJniObject jpath = QAndroidJniObject::fromString(QUrl::fromLocalFile(ImgFilePath).toString()); QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", jpath.object<jstring>()); intent = intent.callObjectMethod("setData", "(Landroid/net/Uri;)Landroid/content/Intent;", uri.object()); intent = intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", action.object()); context.callMethod<void>("sendBroadcast", "(Landroid/content/Intent;)V", intent.object()); if (env->ExceptionCheck()) { env->ExceptionDescribe(); env->ExceptionClear(); }