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?



  • @PowerNow

    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_STORAGE

    Java 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();
    }
    

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.