diff --git a/QtAndroidTools/QAndroidAppPermissions.cpp b/QtAndroidTools/QAndroidAppPermissions.cpp index dc41dc9..16a41ff 100644 --- a/QtAndroidTools/QAndroidAppPermissions.cpp +++ b/QtAndroidTools/QAndroidAppPermissions.cpp @@ -106,6 +106,11 @@ bool QAndroidAppPermissions::shouldShowRequestPermissionInfo(const QString &perm return false; } +bool QAndroidAppPermissions::isPermissionGranted(const QString &permissionName) +{ + return (QtAndroid::checkPermission(permissionName) == QtAndroid::PermissionResult::Granted) ? true : false; +} + void QAndroidAppPermissions::RequestPermissionResults(const QtAndroid::PermissionResultMap &ResultMap) { emit requestPermissionsResults(ConvertToVariantList(ResultMap)); diff --git a/QtAndroidTools/QAndroidAppPermissions.h b/QtAndroidTools/QAndroidAppPermissions.h index 4a66227..69a4e2b 100644 --- a/QtAndroidTools/QAndroidAppPermissions.h +++ b/QtAndroidTools/QAndroidAppPermissions.h @@ -41,6 +41,7 @@ public: Q_INVOKABLE void requestPermissions(const QStringList &permissionsNameList); Q_INVOKABLE void requestPermission(const QString &permissionName); Q_INVOKABLE bool shouldShowRequestPermissionInfo(const QString &permissionName); + Q_INVOKABLE bool isPermissionGranted(const QString &permissionName); signals: void requestPermissionsResults(const QVariantList &results); diff --git a/QtAndroidTools/QAndroidGoogleDrive.cpp b/QtAndroidTools/QAndroidGoogleDrive.cpp index 0938f02..816cee0 100644 --- a/QtAndroidTools/QAndroidGoogleDrive.cpp +++ b/QtAndroidTools/QAndroidGoogleDrive.cpp @@ -30,6 +30,20 @@ QAndroidGoogleDrive::QAndroidGoogleDrive() : m_JavaGoogleDrive("com/falsinsoft/q QtAndroid::androidActivity().object()) { m_pInstance = this; + + if(m_JavaGoogleDrive.isValid()) + { + const JNINativeMethod JniMethod[] = { + {"downloadProgress", "(D)V", reinterpret_cast(&QAndroidGoogleDrive::DownloadProgress)}, + {"downloadComplete", "()V", reinterpret_cast(&QAndroidGoogleDrive::DownloadComplete)} + }; + QAndroidJniEnvironment JniEnv; + jclass ObjectClass; + + ObjectClass = JniEnv->GetObjectClass(m_JavaGoogleDrive.object()); + JniEnv->RegisterNatives(ObjectClass, JniMethod, sizeof(JniMethod)/sizeof(JNINativeMethod)); + JniEnv->DeleteLocalRef(ObjectClass); + } LoadScopeDefinitions(); } @@ -126,6 +140,41 @@ QString QAndroidGoogleDrive::getRootId() return RootId; } +bool QAndroidGoogleDrive::downloadFile(const QString &FileId, const QString &LocalFilePath) +{ + if(m_JavaGoogleDrive.isValid()) + { + return m_JavaGoogleDrive.callMethod("downloadFile", + "(Ljava/lang/String;Ljava/lang/String;)Z", + QAndroidJniObject::fromString(FileId).object(), + QAndroidJniObject::fromString(LocalFilePath).object() + ); + } + return false; +} + +void QAndroidGoogleDrive::DownloadProgress(JNIEnv *env, jobject thiz, jdouble Progress) +{ + Q_UNUSED(env) + Q_UNUSED(thiz) + + if(m_pInstance != nullptr) + { + emit m_pInstance->downloadProgress(Progress); + } +} + +void QAndroidGoogleDrive::DownloadComplete(JNIEnv *env, jobject thiz) +{ + Q_UNUSED(env) + Q_UNUSED(thiz) + + if(m_pInstance != nullptr) + { + emit m_pInstance->downloadComplete(); + } +} + void QAndroidGoogleDrive::LoadScopeDefinitions() { const char ScopesClass[] = "com/google/api/services/drive/DriveScopes"; diff --git a/QtAndroidTools/QAndroidGoogleDrive.h b/QtAndroidTools/QAndroidGoogleDrive.h index a1c6548..25c955b 100644 --- a/QtAndroidTools/QAndroidGoogleDrive.h +++ b/QtAndroidTools/QAndroidGoogleDrive.h @@ -58,11 +58,14 @@ public: Q_INVOKABLE bool authenticate(const QString &AppName, const QString &ScopeName); Q_INVOKABLE QVariantList getFilesList(const QString &Query = QString()); Q_INVOKABLE QString getRootId(); + Q_INVOKABLE bool downloadFile(const QString &FileId, const QString &LocalFilePath); bool isAuthenticated() { return m_isAuthenticated; } signals: void isAuthenticatedChanged(); + void downloadProgress(double progress); + void downloadComplete(); private: const QAndroidJniObject m_JavaGoogleDrive; @@ -70,5 +73,8 @@ private: bool m_isAuthenticated = false; QString m_ScopeList[8]; + static void DownloadProgress(JNIEnv *env, jobject thiz, jdouble Progress); + static void DownloadComplete(JNIEnv *env, jobject thiz); + void LoadScopeDefinitions(); }; diff --git a/QtAndroidTools/src/com/falsinsoft/qtandroidtools/AndroidGoogleDrive.java b/QtAndroidTools/src/com/falsinsoft/qtandroidtools/AndroidGoogleDrive.java index aec4169..954bee7 100644 --- a/QtAndroidTools/src/com/falsinsoft/qtandroidtools/AndroidGoogleDrive.java +++ b/QtAndroidTools/src/com/falsinsoft/qtandroidtools/AndroidGoogleDrive.java @@ -42,6 +42,8 @@ import com.google.android.gms.common.api.Scope; import com.google.api.client.extensions.android.http.AndroidHttp; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; +import com.google.api.client.googleapis.media.MediaHttpDownloaderProgressListener; +import com.google.api.client.googleapis.media.MediaHttpDownloader; import com.google.api.client.json.gson.GsonFactory; import com.google.api.services.drive.Drive; import com.google.api.services.drive.DriveScopes; @@ -51,6 +53,8 @@ import com.google.api.services.drive.model.FileList; import java.util.Collections; import java.util.List; import java.io.IOException; +import java.io.OutputStream; +import java.io.FileOutputStream; public class AndroidGoogleDrive { @@ -116,6 +120,7 @@ public class AndroidGoogleDrive } catch(IOException e) { + Log.d(TAG, e.toString()); return null; } @@ -151,13 +156,9 @@ public class AndroidGoogleDrive .get("root") .execute(); } - catch(UserRecoverableAuthIOException e) - { - Log.d(TAG, "Authorization scope not requested at signin!"); - return null; - } catch(IOException e) { + Log.d(TAG, e.toString()); return null; } @@ -167,6 +168,44 @@ public class AndroidGoogleDrive return null; } + public boolean downloadFile(String FileId, String LocalFilePath) + { + if(mDriveService != null) + { + try + { + Drive.Files.Get FileDownloadRequest = mDriveService.files().get(FileId); + FileDownloadRequest.getMediaHttpDownloader().setProgressListener(new FileDownloadProgressListener()); + FileDownloadRequest.executeMediaAndDownloadTo(new FileOutputStream(LocalFilePath)); + } + catch(IOException e) + { + Log.d(TAG, e.toString()); + return false; + } + + return true; + } + + return false; + } + + private class FileDownloadProgressListener implements MediaHttpDownloaderProgressListener + { + public void progressChanged(MediaHttpDownloader downloader) + { + switch(downloader.getDownloadState()) + { + case MEDIA_IN_PROGRESS: + downloadProgress(downloader.getProgress()); + break; + case MEDIA_COMPLETE: + downloadComplete(); + break; + } + } + } + public static class DriveFile { public String id; @@ -174,4 +213,7 @@ public class AndroidGoogleDrive public String mimeType; public String[] parents; } + + private static native void downloadProgress(double progress); + private static native void downloadComplete(); } diff --git a/QtAndroidToolsDemo/tools/AndroidGoogleDrive.qml b/QtAndroidToolsDemo/tools/AndroidGoogleDrive.qml index 3681d0c..76ff687 100644 --- a/QtAndroidToolsDemo/tools/AndroidGoogleDrive.qml +++ b/QtAndroidToolsDemo/tools/AndroidGoogleDrive.qml @@ -8,6 +8,15 @@ Page { id: page padding: 0 + Connections { + target: QtAndroidGoogleDrive + onDownloadProgress: { + } + onDownloadComplete: { + downloadCompleteMsg.open(); + } + } + Column { width: parent.width * 0.9 height: parent.height * 0.9 @@ -62,7 +71,7 @@ Page { ListView { id: filesListView width: parent.width * 0.95 - height: parent.height + height: parent.height - 2 anchors.centerIn: parent model: filesListModel boundsBehavior: Flickable.StopAtBounds @@ -71,10 +80,33 @@ Page { height: fileInfoColumn.implicitHeight + 10 Column { id: fileInfoColumn + width: parent.width + Text { font.pixelSize: 13; text: 'Id: ' + id } Text { font.pixelSize: 13; text: 'Name: ' + name } Text { font.pixelSize: 13; text: 'MimeType: ' + mimeType } Text { font.pixelSize: 13; text: 'ParentId: ' + parentId } + + Button { + width: parent.width + text: "Download" + visible: mimeType !== "application/vnd.google-apps.folder" + onClicked: { + if(QtAndroidAppPermissions.isPermissionGranted("android.permission.WRITE_EXTERNAL_STORAGE")) + { + var downloadPath = QtAndroidSystem.getFolderPath(QtAndroidSystem.FOLDER_DOWNLOAD); + + if(QtAndroidGoogleDrive.downloadFile(id, downloadPath + "/" + name) === false) + { + downloadNotStartedMsg.open(); + } + } + else + { + permissionNotGrantedMsg.open(); + } + } + } } } @@ -86,4 +118,23 @@ Page { } } } + + MessageDialog { + id: permissionNotGrantedMsg + standardButtons: StandardButton.Ok + title: "Warning" + text: "For file download the app need the WRITE_EXTERNAL_STORAGE permission. Go in the App Permission section and request the permission" + } + MessageDialog { + id: downloadCompleteMsg + standardButtons: StandardButton.Ok + title: "Advise" + text: "Download is complete!" + } + MessageDialog { + id: downloadNotStartedMsg + standardButtons: StandardButton.Ok + title: "Warning" + text: "Download not started for an error!" + } }