I am trying to register a QtQuick Android application to open a certain class of files and handle them.
From what I gather, when a file is opened with a QApplication
it results in a QEvent::FileOpen
being fired.
The strongest (if inconclusive) evidence for this I have is this commit found in a production system, plus a number of blog posts and Google results.
So, I first create a new empty QtQuick project.
I then write an EventFilter, like this:
#include <QtGui>
#include <QApplication>
#include <QFileOpenEvent>
class MyEventFilter : public QObject {
public:
MyEventFilter();
virtual ~MyEventFilter();
protected:
virtual bool eventFilter(QObject* object,QEvent* event);
};
#include "myeventfilter.h"
MyEventFilter::MyEventFilter() : QObject () {}
MyEventFilter::~MyEventFilter() {}
bool MyEventFilter::eventFilter(QObject* object,QEvent* e) {
qDebug() << "Received" << e->type();
if (e->type() == QEvent::FileOpen) {
QFile file(static_cast<QFileOpenEvent *>(e)->file());
qDebug() << "File to open:" << file.fileName();
// This is where I would do stuff
return true;
} else {
return QObject::eventFilter(object,e);
}
}
I then register it and edit my manifest accordingly, by adding
<intent-filter android:label="Foo File" android:priority="1">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file" android:host="success"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.foo"/>
</intent-filter>
At this point, I launch my application in the Android emulator.
When I open a .foo
file from ES File Explorer in my AVD with Nexus 5, API 22, my application is indeed brought in the foreground, but no FileOpen
events are logged.
If I set up a breakpoint inside my filter method I don't seem to be hitting it.
This puzzles me.
I tried the alternate approach by extending QApplication
and overloading event(QEvent *)
with pretty much the same results (no hits).
What could I be doing wrong?
Please find the complete repository for this MWE here.
I'm gonna answer my own question after perusing Bogdan's tutorials and receiving some invaluable help from #qt
on Freenode.
It looks like opening a file in Android does not, in fact, result in a QEvent::FileOpen
, which is useful only on systems with a window manager.
Instead, one has to subclass QtActivity
and override onIntent
in Java, then call an appropriate C++ method with JNI:
package com.foo;
import android.content.Intent;
import org.qtproject.qt5.android.bindings.QtActivity;
class Bar
{
public static native void openUri(String uri);
// Notice the 'native' keyword
}
public class MyActivity extends QtActivity {
public void onNewIntent(Intent i) {
if (i.getAction() == Intent.ACTION_VIEW) {
Bar.openUri(i.getData().toString());
}
super.onNewIntent(i);
}
}
class URIHandler : public QObject {
public:
void openUri(QString uri) {
qDebug() << "Open URI" << uri;
}
}
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_com_foo_Bar_openUri(JNIEnv *env,
jobject obj,
jstring uri)
{
jboolean isCopy;
isCopy = false;
const char* utf = env->GetStringUTFChars(uri, &isCopy);
handler.openUri(QString(utf));
env->ReleaseStringUTFChars(uri, utf);
}
#ifdef __cplusplus
}
#endif
Note that there are some tricky subtleties with JNI method names.
You can find the updated, working version of this example here.