1From d947f2e5ca72f4a88aa71b545492550695464a41 Mon Sep 17 00:00:00 2001 2From: Andy Shaw <andy.shaw@qt.io> 3Date: Tue, 4 Feb 2020 11:39:29 +0100 4Subject: [PATCH 2/4] Android: Add support for getting information about 5 content uris 6 7This enables things like size(), exists() to work with Android content 8uris with the provided uri given from a filedialog. It is expected that 9it is always a full path due to the nature of content uris, so relative 10paths will not work. 11 12Change-Id: I9c9ea42833677eb9d937b33e9dd42ee2a7d9c7c5 13Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io> 14Reviewed-by: BogDan Vatra <bogdan@kdab.com> 15--- 16 .../org/qtproject/qt5/android/QtNative.java | 57 +++++++++++++++++++ 17 .../android/androidcontentfileengine.cpp | 47 ++++++++++++++- 18 .../android/androidcontentfileengine.h | 6 ++ 19 3 files changed, 108 insertions(+), 2 deletions(-) 20 21diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 22index f3c4189400..caf6c6ea8a 100644 23--- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 24+++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java 25@@ -44,6 +44,7 @@ import java.io.File; 26 import java.io.FileNotFoundException; 27 import java.util.ArrayList; 28 import java.util.concurrent.Semaphore; 29+import java.io.IOException; 30 31 import android.app.Activity; 32 import android.app.Service; 33@@ -70,6 +71,7 @@ import android.view.Menu; 34 import android.view.MotionEvent; 35 import android.view.View; 36 import android.view.InputDevice; 37+import android.database.Cursor; 38 39 import java.lang.reflect.Method; 40 import java.security.KeyStore; 41@@ -231,6 +233,61 @@ public class QtNative 42 } 43 } 44 45+ public static long getSize(Context context, String contentUrl) 46+ { 47+ Uri uri = getUriWithValidPermission(context, contentUrl, "r"); 48+ long size = -1; 49+ 50+ if (uri == null) { 51+ Log.e(QtTAG, "getSize(): No permissions to open Uri"); 52+ return size; 53+ } 54+ 55+ try { 56+ ContentResolver resolver = context.getContentResolver(); 57+ Cursor cur = resolver.query(uri, null, null, null, null); 58+ if (cur != null) { 59+ if (cur.moveToFirst()) 60+ size = cur.getLong(5); // size column 61+ cur.close(); 62+ } 63+ return size; 64+ } catch (IllegalArgumentException e) { 65+ Log.e(QtTAG, "getSize(): Invalid Uri"); 66+ return size; 67+ } catch (UnsupportedOperationException e) { 68+ Log.e(QtTAG, "getSize(): Unsupported operation for given Uri"); 69+ return size; 70+ } 71+ } 72+ 73+ public static boolean checkFileExists(Context context, String contentUrl) 74+ { 75+ Uri uri = getUriWithValidPermission(context, contentUrl, "r"); 76+ boolean exists = false; 77+ 78+ if (uri == null) { 79+ Log.e(QtTAG, "checkFileExists(): No permissions to open Uri"); 80+ return exists; 81+ } 82+ 83+ try { 84+ ContentResolver resolver = context.getContentResolver(); 85+ Cursor cur = resolver.query(uri, null, null, null, null); 86+ if (cur != null) { 87+ exists = true; 88+ cur.close(); 89+ } 90+ return exists; 91+ } catch (IllegalArgumentException e) { 92+ Log.e(QtTAG, "checkFileExists(): Invalid Uri"); 93+ return exists; 94+ } catch (UnsupportedOperationException e) { 95+ Log.e(QtTAG, "checkFileExists(): Unsupported operation for given Uri"); 96+ return false; 97+ } 98+ } 99+ 100 // this method loads full path libs 101 public static void loadQtLibraries(final ArrayList<String> libraries) 102 { 103diff --git a/src/plugins/platforms/android/androidcontentfileengine.cpp b/src/plugins/platforms/android/androidcontentfileengine.cpp 104index 1444407195..3e3bdc2592 100644 105--- a/src/plugins/platforms/android/androidcontentfileengine.cpp 106+++ b/src/plugins/platforms/android/androidcontentfileengine.cpp 107@@ -44,9 +44,10 @@ 108 109 #include <QDebug> 110 111-AndroidContentFileEngine::AndroidContentFileEngine(const QString &fileName) 112- : QFSFileEngine(fileName) 113+AndroidContentFileEngine::AndroidContentFileEngine(const QString &f) 114+ : m_file(f) 115 { 116+ setFileName(f); 117 } 118 119 bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) 120@@ -78,6 +79,48 @@ bool AndroidContentFileEngine::open(QIODevice::OpenMode openMode) 121 return QFSFileEngine::open(openMode, fd, QFile::AutoCloseHandle); 122 } 123 124+qint64 AndroidContentFileEngine::size() const 125+{ 126+ const jlong size = QJNIObjectPrivate::callStaticMethod<jlong>( 127+ "org/qtproject/qt5/android/QtNative", "getSize", 128+ "(Landroid/content/Context;Ljava/lang/String;)J", QtAndroidPrivate::context(), 129+ QJNIObjectPrivate::fromString(fileName(DefaultName)).object()); 130+ return (qint64)size; 131+} 132+ 133+AndroidContentFileEngine::FileFlags AndroidContentFileEngine::fileFlags(FileFlags type) const 134+{ 135+ FileFlags commonFlags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag); 136+ FileFlags flags; 137+ const bool exists = QJNIObjectPrivate::callStaticMethod<jboolean>( 138+ "org/qtproject/qt5/android/QtNative", "checkFileExists", 139+ "(Landroid/content/Context;Ljava/lang/String;)Z", QtAndroidPrivate::context(), 140+ QJNIObjectPrivate::fromString(fileName(DefaultName)).object()); 141+ if (!exists) 142+ return flags; 143+ flags = FileType | commonFlags; 144+ return type & flags; 145+} 146+ 147+QString AndroidContentFileEngine::fileName(FileName f) const 148+{ 149+ switch (f) { 150+ case PathName: 151+ case AbsolutePathName: 152+ case CanonicalPathName: 153+ case DefaultName: 154+ case AbsoluteName: 155+ case CanonicalName: 156+ return m_file; 157+ case BaseName: 158+ { 159+ const int pos = m_file.lastIndexOf(QChar(QLatin1Char('/'))); 160+ return m_file.mid(pos); 161+ } 162+ default: 163+ return QString(); 164+ } 165+} 166 167 AndroidContentFileEngineHandler::AndroidContentFileEngineHandler() = default; 168 AndroidContentFileEngineHandler::~AndroidContentFileEngineHandler() = default; 169diff --git a/src/plugins/platforms/android/androidcontentfileengine.h b/src/plugins/platforms/android/androidcontentfileengine.h 170index db3def03d6..09e5d77553 100644 171--- a/src/plugins/platforms/android/androidcontentfileengine.h 172+++ b/src/plugins/platforms/android/androidcontentfileengine.h 173@@ -47,6 +47,12 @@ class AndroidContentFileEngine : public QFSFileEngine 174 public: 175 AndroidContentFileEngine(const QString &fileName); 176 bool open(QIODevice::OpenMode openMode) override; 177+ qint64 size() const override; 178+ FileFlags fileFlags(FileFlags type = FileInfoAll) const override; 179+ QString fileName(FileName file = DefaultName) const override; 180+private: 181+ QString m_file; 182+ 183 }; 184 185 class AndroidContentFileEngineHandler : public QAbstractFileEngineHandler 186-- 1872.26.2 188 189