I am developing a Qt-based application for Android. In case the app is launched as a result of opening a file I need to pass it to the Qt application instance. I have created a custom Java activity so as to implement this behavior:
public class MyActivity extends org.qtproject.qt5.android.bindings.QtActivity
{
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent i = getIntent();
String act = i.getAction();
if (act != null) && act.compareTo(Intent.ACTION_VIEW) == 0)
{
int fd = -1;
try
{
fd = getContentResolver().openFileDescriptor(i.getData(), "r").detachFd();
}
catch (IOException e)
{
Log.e("MyActivity::onCreate", "Exception caught: " + e.getMessage());
}
boolean ok = openFd(fd);
}
} // onCreate
private static native boolean openFd(int fd);
} // MyActivity
On the C++ side I have something like this:
#include <QDebug>
#include <jni.h>
jboolean processInputFile(JNIEnv *env, jobject obj, jint fileDescriptor)
{
int fd = (int)fileDescriptor;
qDebug() << "processInputFile called: " << fd;
QFile f;
if (f.open(fd, QIODevice::ReadOnly, QFileDevice::AutoCloseHandle))
{
QFileInfo fi(f);
qDebug() << "Successfully opened the file " << f.fileName() << fi.absoluteFilePath() << fi.canonicalFilePath() << fi.fileName();
return true;
}
else
{
qDebug() << "Failed to open the file: " << f.errorString();
return false;
}
} // processInputFile
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void*)
{
qDebug() << "JNI_OnLoad got called";
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
return -1;
}
jclass javaClass = env->FindClass("com/mycompany/mypackage/MyActivity");
if(!javaClass)
{
return JNI_ERR;
}
// Register methods with env->RegisterNatives
static JNINativeMethod methodsArray[] =
{
{"openFd", "(I)Z", (void*)processInputFile}
};
if(env->RegisterNatives(javaClass, methodsArray, sizeof(methodsArray) / sizeof(methodsArray[0])) < 0)
{
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
int main(int argc, char *argv[])
{
qDebug() << "Calling main()";
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qDebug() << "main arguments:";
for (int i = 0; i < argc; ++i)
qDebug() << argv[i];
// ...
}
The C++ method (processInputFile) gets invoked, but it happens before the main() function is called, therefore the application object has not been created yet. I can't handle the data passed in, because the processing classes do not exist at that moment. So my question is how can I call the methods of Qt application instance from android.app.Activity::onCreate method?
And another thing: is it possible to get the name of the file that was opened? Sometimes the intent's URI looks like "content://downloads/my_downloads/47" and neither conversion method I found worked for it. QFile and QFileInfo also do not return the name for fd. Knowing the name would be useful, for instance, to describe the item that is being processed, whereas 47 is not really meaningful.