Android: Add support for getting information about content uris

This enables things like size(), exists() to work with Android content
uris with the provided uri given from a filedialog. It is expected that
it is always a full path due to the nature of content uris, so relative
paths will not work.

Change-Id: I9c9ea42833677eb9d937b33e9dd42ee2a7d9c7c5
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
Reviewed-by: BogDan Vatra <bogdan@kdab.com>
This commit is contained in:
Andy Shaw 2020-02-04 11:39:29 +01:00 committed by Assam Boudjelthia
parent ca9de96233
commit 7e5f38aec6
3 changed files with 108 additions and 2 deletions

View File

@ -44,6 +44,7 @@ import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.io.IOException;
import android.app.Activity; import android.app.Activity;
import android.app.Service; import android.app.Service;
@ -70,6 +71,7 @@ import android.view.Menu;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.InputDevice; import android.view.InputDevice;
import android.database.Cursor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.security.KeyStore; import java.security.KeyStore;
@ -231,6 +233,61 @@ public class QtNative
} }
} }
public static long getSize(Context context, String contentUrl)
{
Uri uri = getUriWithValidPermission(context, contentUrl, "r");
long size = -1;
if (uri == null) {
Log.e(QtTAG, "getSize(): No permissions to open Uri");
return size;
}
try {
ContentResolver resolver = context.getContentResolver();
Cursor cur = resolver.query(uri, null, null, null, null);
if (cur != null) {
if (cur.moveToFirst())
size = cur.getLong(5); // size column
cur.close();
}
return size;
} catch (IllegalArgumentException e) {
Log.e(QtTAG, "getSize(): Invalid Uri");
return size;
} catch (UnsupportedOperationException e) {
Log.e(QtTAG, "getSize(): Unsupported operation for given Uri");
return size;
}
}
public static boolean checkFileExists(Context context, String contentUrl)
{
Uri uri = getUriWithValidPermission(context, contentUrl, "r");
boolean exists = false;
if (uri == null) {
Log.e(QtTAG, "checkFileExists(): No permissions to open Uri");
return exists;
}
try {
ContentResolver resolver = context.getContentResolver();
Cursor cur = resolver.query(uri, null, null, null, null);
if (cur != null) {
exists = true;
cur.close();
}
return exists;
} catch (IllegalArgumentException e) {
Log.e(QtTAG, "checkFileExists(): Invalid Uri");
return exists;
} catch (UnsupportedOperationException e) {
Log.e(QtTAG, "checkFileExists(): Unsupported operation for given Uri");
return false;
}
}
// this method loads full path libs // this method loads full path libs
public static void loadQtLibraries(final ArrayList<String> libraries) public static void loadQtLibraries(final ArrayList<String> libraries)
{ {

View File

@ -44,9 +44,10 @@
#include <QDebug> #include <QDebug>
AndroidContentFileEngine::AndroidContentFileEngine(const QString &fileName) AndroidContentFileEngine::AndroidContentFileEngine(const QString &f)
: QFSFileEngine(fileName) : m_file(f)
{ {
setFileName(f);
} }
bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode)
@ -78,6 +79,48 @@ bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode)
return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle); return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle);
} }
qint64 AndroidContentFileEngine::size() const
{
const jlong size = QJNIObjectPrivate::callStaticMethod<jlong>(
"org/qtproject/qt5/android/QtNative", "getSize",
"(Landroid/content/Context;Ljava/lang/String;)J", QtAndroidPrivate::context(),
QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
return (qint64)size;
}
AndroidContentFileEngine::FileFlags AndroidContentFileEngine::fileFlags(FileFlags type) const
{
FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
FileFlags flags;
const bool exists = QJNIObjectPrivate::callStaticMethod<jboolean>(
"org/qtproject/qt5/android/QtNative", "checkFileExists",
"(Landroid/content/Context;Ljava/lang/String;)Z", QtAndroidPrivate::context(),
QJNIObjectPrivate::fromString(fileName(DefaultName)).object());
if (!exists)
return flags;
flags = FileType | commonFlags;
return type & flags;
}
QString AndroidContentFileEngine::fileName(FileName f) const
{
switch (f) {
case PathName:
case AbsolutePathName:
case CanonicalPathName:
case DefaultName:
case AbsoluteName:
case CanonicalName:
return m_file;
case BaseName:
{
const int pos = m_file.lastIndexOf(QChar(QLatin1Char('/')));
return m_file.mid(pos);
}
default:
return QString();
}
}
AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default; AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default;
AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default; AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default;

View File

@ -47,6 +47,12 @@ class AndroidContentFileEngine : public QFSFileEngine
public: public:
AndroidContentFileEngine(const QString &fileName); AndroidContentFileEngine(const QString &fileName);
bool open(QIODevice::OpenMode openMode) override; bool open(QIODevice::OpenMode openMode) override;
qint64 size() const override;
FileFlags fileFlags(FileFlags type = FileInfoAll) const override;
QString fileName(FileName file = DefaultName) const override;
private:
QString m_file;
}; };
class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler