Save Image to Android device
-
@eiriham said:
Thanks! But I cant really get that to work. The pictures dont show in the photo album.
Now the search begins.
-
on Android you need to trigger the Media scanner to add it to the systems media database so other apps can access it. If it's working after a device restart, then thats the cause.
-
you should make sure that your app has the correct permission to write to the filesystem. Change your code to the following and check the error (in console):
QBuffer buffer; buffer.open(QIODevice::WriteOnly); img.save(&buffer, "PNG"); buffer.close(); QString path = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + "/image.png"; QFile f( path ); if( file.open( QIODevice::WriteOnly ) ) { file.write( buffer.buffer() ); file.close(); } if( file.error() != QFileDevice::NoError ) qFatal() << QString("Error writing file '%1':").arg(path) << file.errorString();
-
-
@eiriham said:
I found my pictures after a device restart. Since it did, do I still need step 2?
if you want to have it in the media database immediately, then yes.
If you can live with it being available after a device restart, then noBecause I get the following error:
OpenOnly is not a member of QIODevice.my mistake. should be "ReadOnly". (Changed it already in my code)
-
@eiriham
seems i need some sleep :P
Should be "WriteOnly" instead of "ReadOnly" unlike i said before... -
Thanks!
Well, I have not fixed step 1 yet, but I did exactly as in step 2. Again, the picture was showing only after a restart. What is the difference between the code in step 2 that you presented and the code I wrote in the original post?
They both seem to do the same thing? Or would your code work with the mediascanner, and mine wont?
-
@eiriham
i just added my code, so we can check the error messageAre you triggering the media scanner already?!
-
@eiriham
because you were wondering why it still shows up after a device restart.
There is no way around using the media scanner if you want to have it immediately listed in the media db. -
Any help would be appreciated. I am looking at this post now, but it is not solved: http://lists.qt-project.org/pipermail/interest/2015-April/016263.html.
Also, I saw your post about the Android Extra JNI, but how do I call the scanFile from there?
This is the start of the code I am trying to write:
@
void SnapshotController::trigMediaScanner(QString path)
{
QAndroidJniObject string = QAndroidJniObject::fromString(path);QAndroidJniEnvironment test2;
}
@ -
This is a funny issue. People claim that calling scanFile should work, but I have seen no sign that anyone has actually managed to make it work from Qt...
Yes, I am trying the same thing, but currently, on a personal app, just use Android app media.re.Scan: as needed.
-
I had the same issue to show a picture taken by my app immediatly after saving it. And scanFile works for me.
I wrote a java class extending org.qtproject.qt5.android.bindings.QtActivity and declared it in the manifest file.
public class AndroidAccess extends org.qtproject.qt5.android.bindings.QtActivity { public static MediaScannerConnection s_mMs; @Override public void onCreate(Bundle savedInstanceState) { ... s_mMs = new MediaScannerConnection(getApplicationContext(), null); s_mMs.connect(); } public static void scanForPicture(String name) { s_mMs.scanFile(name, null); } }
and then in my Qt class i simply call:
QAndroidJniObject::callStaticMethod<void>("org/tud/qpcam/AndroidAccess", "scanForPicture", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(this->getSavePicturesDir().absolutePath()).object<jstring>());
whereas getSavePicturesDir() returns the directory where the pictures were saved to.
Works like charm with Qt 5.6 and android 4.4 - 6.0. -
Thanks! I am trying to get this to work now.
How did you register it in the manifest file?
And how do I know the path? I mean, how did you know you had to put in "org/tud/qpcam/AndroidAccess"?I try this but the isAvailable returns false:
qDebug()<< "Is available: " << QAndroidJniObject::isClassAvailable("MediaScanner"); QAndroidJniObject::callStaticMethod<void>("MediaScanner", "scanForPicture", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(this->getSavePicturesDir().absolutePath()).object<jstring>());
-
Well, i tried a lot of ways and sendBroadcast() did not work for me. So maybe my way isnt the shortest one, but it works and thats what matters, doesnt it?
-
Create the android files "create Android APK"
-
set the package name, e.g. "aha.androscanner" in manifest
-
open manifest in text mode and replace android:name="org.qtproject.qt5.android.bindings.QtActivity" with android:name="aha.androscanner.AndroScannerInJava"
-
Create a subdirectory below the android folder, e.g. ...android/src/aha/androscanner
-
Put in a java file, named exactly like in point 3, e.g. AndroScannerInJava.java and add it to project
-
add "android: QT += androidextras" to your .pro file
-
Fill in the code
AndroScannerInJava.java
package aha.androscanner; import android.media.MediaScannerConnection; import android.os.Bundle; public class AndroScannerInJava extends org.qtproject.qt5.android.bindings.QtActivity { public static MediaScannerConnection s_mMs; @Override public void onCreate(Bundle savedInstanceState) { System.out.println("in the activity"); super.onCreate(savedInstanceState); s_mMs = new MediaScannerConnection(getApplicationContext(), null); s_mMs.connect(); } public static void scanForPicture(String name) { System.out.print("scan for picture -> "); System.out.println(name); s_mMs.scanFile(name, null); } }
Within Qt code you call:
void MainWindow::saveThatPicture() { qDebug() << "saveThatPicture!"; QPixmap pix(700,700); pix.fill(Qt::red); QDir picDir = QDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); QDir saveDir = QDir(picDir.filePath("aha")); if(!saveDir.exists()) picDir.mkdir("aha"); QString filePath = saveDir.filePath("test.jpg"); pix.save(filePath); QAndroidJniObject::callStaticMethod<void>("aha/androscanner/AndroScannerInJava", "scanForPicture", "(Ljava/lang/String;)V", QAndroidJniObject::fromString(filePath).object<jstring>()); }
Manifest.xml
<?xml version='1.0' encoding='utf-8'?> <manifest package="aha.androscanner" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto"> <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="-- %%INSERT_APP_NAME%% --"> <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation" android:name="aha.androscanner.AndroScannerInJava" android:label="-- %%INSERT_APP_NAME%% --" android:screenOrientation="unspecified" android:launchMode="singleTop"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/> <meta-data android:name="android.app.repository" android:value="default"/> <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/> <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/> <!-- Deploy Qt libs as part of package --> <meta-data android:name="android.app.bundle_local_qt_libs" android:value="-- %%BUNDLE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.bundled_in_lib_resource_id" android:resource="@array/bundled_in_lib"/> <meta-data android:name="android.app.bundled_in_assets_resource_id" android:resource="@array/bundled_in_assets"/> <!-- Run with local libs --> <meta-data android:name="android.app.use_local_qt_libs" android:value="-- %%USE_LOCAL_QT_LIBS%% --"/> <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/> <meta-data android:name="android.app.load_local_libs" android:value="-- %%INSERT_LOCAL_LIBS%% --"/> <meta-data android:name="android.app.load_local_jars" android:value="-- %%INSERT_LOCAL_JARS%% --"/> <meta-data android:name="android.app.static_init_classes" android:value="-- %%INSERT_INIT_CLASSES%% --"/> <!-- Messages maps --> <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/> <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/> <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/> <!-- Messages maps --> <!-- Splash screen --> <!-- <meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/> --> <!-- Splash screen --> <!-- Background running --> <!-- Warning: changing this value to true may cause unexpected crashes if the application still try to draw after "applicationStateChanged(Qt::ApplicationSuspended)" signal is sent! --> <meta-data android:name="android.app.background_running" android:value="false"/> <!-- Background running --> <!-- auto screen scale factor --> <meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/> <!-- auto screen scale factor --> </activity> </application> <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/> <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/> <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application. Remove the comment if you do not require these default permissions. --> <!-- %%INSERT_PERMISSIONS --> <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application. Remove the comment if you do not require these default features. --> <!-- %%INSERT_FEATURES --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> </manifest>
Works fine.
-
-
Thanks! While following your steps I get an error. In the application output it says; "Unable to start "pdapp.mediascanner"."
Using logcat I get:
I/ActivityManager( 712): START u0 {flg=0x10000000 cmp=pdapp.mediascanner/.MediaScanner} from uid 2000 on display 0 W/ActivityManager( 712): Permission Denial: starting Intent { flg=0x10000000 cmp=pdapp.mediascanner/.MediaScanner } from null (pid=21117, uid=2000) not exported from uid 10104 I/art (21117): System.exit called, status: 1 I/AndroidRuntime(21117): VM exiting with result code 1.
And also this:
W/PackageManager( 1369): Failure retrieving resources for pdapp.mediascanner: Resource ID #0x0
I followed your steps to the point.