QT ImagePicker using JNI
-
I have been working on creating a image picker for a couple of days now and i am stuck. I have been able to get the activity to start and get the results back to the handleActivityResult() function. At this point i get a Reference to data. The data is a const QAndroidJniObject &data. I then use the getData method to turn this into a URI. I then need to the absolute path of this file so i can make a q image and display it to the screen. I have googled methods for creating a file path string from the URI. Everyone uses the Cursor cursor = getContextResolver() method to do this. The program will crash when i run this. I will past the code below so you can look at it and tell me what i am doing wrong.
notificationclient.cpp
/*
bool NotificationClient::SelectPhotoTest(bool started)
{
QAndroidJniObject intent = QAndroidJniObject::callStaticObjectMethod(
"org/qtproject/example/notification/NotificationClient",
"photoPicker",
"()Landroid/content/Intent;" );
qDebug() << "STARTING INTENT FOR SELECTING A PHOTO";
ImagePicker* aarr = new ImagePicker();QtAndroid::startActivity( intent, 12051978, aarr); return started;
}
*/
this is called when a person clicks a button. Works fine.imagepicker.cpp
/*void ImagePicker::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
{qDebug() << "TOTAPE RETURNING FROM SELECT PHOTO - " << resultCode << " - " << receiverRequestCode; if ( resultCode == -1 ) { // OK ! //this will get us the data for the image or bit map //need to pass data to the java and convert it to uri QString dataQString = data.toString(); qDebug() << "This is the data to string befor sent to getData() - " << dataQString; QAndroidJniObject imageUri = data.callObjectMethod( "getData", "()Landroid/net/Uri;"); QAndroidJniObject imageFile = QAndroidJniObject::callStaticObjectMethod( "org/qtproject/example/notification/NotificationClient", "getRealPathFromURI", "(Landroid/net/Uri;)Ljava/lang/String;", imageUri.object<jobject>()); QString path = imageFile.toString(); qDebug() << "the real path is - " << path; }
}
*/
This is the handler and the program that makes the calls to the java file. I get results from the activity. Data is not null, imageURI = ontent://com.android.providers.media.documents/document/image%3A2433". After the getData call.
NotificationClient.java
/*public static Intent photoPicker()
{Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); return Intent.createChooser(intent,"Select Photo"); } public String _getRealPathFromURI(Uri contentURI) { String result = "Internal getPathFromURI function call"; Context test = getApplicationContext(); Cursor cursor = test.getContentResolver().query(contentURI, null, null, null, null); if (cursor == null) { // Source is Dropbox or other similar local file path result = contentURI.getPath(); } else { cursor.moveToFirst(); int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA); result = cursor.getString(idx); cursor.close(); } return result; } public static String getRealPathFromURI(Uri contentURI) { NotificationClient me = new NotificationClient(); String result = me._getRealPathFromURI(contentURI); return result; }
*/
I then get this error that is caused by the getContentResolver() i believe.
W/System.err(15426): java.lang.reflect.InvocationTargetException
W/System.err(15426): at java.lang.reflect.Method.invoke(Native Method)
W/System.err(15426): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err(15426): at org.qtproject.qt5.android.bindings.QtApplication.invokeDelegateMethod(QtApplication.java:153)
W/System.err(15426): at org.qtproject.qt5.android.bindings.QtActivity.onActivityResult(QtActivity.java:753)
W/System.err(15426): at android.app.Activity.dispatchActivityResult(Activity.java:6192)
W/System.err(15426): at android.app.ActivityThread.deliverResults(ActivityThread.java:3570)
W/System.err(15426): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3617)
W/System.err(15426): at android.app.ActivityThread.access$1300(ActivityThread.java:151)
W/System.err(15426): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1352)
W/System.err(15426): at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err(15426): at android.os.Looper.loop(Looper.java:135)
W/System.err(15426): at android.app.ActivityThread.main(ActivityThread.java:5254)
W/System.err(15426): at java.lang.reflect.Method.invoke(Native Method)
W/System.err(15426): at java.lang.reflect.Method.invoke(Method.java:372)
W/System.err(15426): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
W/System.err(15426): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
W/System.err(15426): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.Context android.content.Context.getApplicationContext()' on a null object reference
W/System.err(15426): at android.content.ContextWrapper.getApplicationContext(ContextWrapper.java:106)
W/System.err(15426): at org.qtproject.example.notification.NotificationClient._getRealPathFromURI(NotificationClient.java:111)
W/System.err(15426): at org.qtproject.example.notification.NotificationClient.getRealPathFromURI(NotificationClient.java:134)
W/System.err(15426): at org.qtproject.qt5.android.QtNative.onActivityResult(Native Method)
W/System.err(15426): at org.qtproject.qt5.android.QtActivityDelegate.onActivityResult(QtActivityDelegate.java:894)
W/System.err(15426): ... 16 moreSorry for the long post but i could really use some help.
-
I think you have to do this in Java, i.e. call the intent with action ACTION_GET_CONTENT and wait for the activity result (onActivityResult).
Then you set up a callback to Qt when the result is ready. You might return the file-path as a string to Qt and convert to QString using android extras library. To set up the callback, look here.To get the filepath from file, look here or search the stackoverflow.com. To get the filepath from sdcard with all api versions (before kitkat, kitkat, lollipop), it could be hard. Maybe the easiest is to use inputstream to make a copy into the application area and return that file path when the user has chosen the file.
-
The next version of QuickAndroid will come with a Image Picker using native code. You may use it directly or just check learn how its handle image picking. In fact, it is a bit troublesome to do it in Android. There has several way of passing image data. (e.g clip data, content url , file url). It depends on the photo application.
quickandroid/ImagePicker.java at DEV · benlau/quickandroid
quickandroid/ImagePicker.qml at DEV · benlau/quickandroid
p.s Daily build of apk with image picker is available at :