From 25af67f6a17c2dd8577d5043d1589b72dc7f293d Mon Sep 17 00:00:00 2001
From: SeeLook <seelook@gmail.com>
Date: Mon, 12 Apr 2021 14:06:21 +0200
Subject: [PATCH] [Android] Do not ask for access permission at very beginning

- ask only when user will really need access to any file
---
 src/dialogs/tlevelcreatoritem.cpp     |  7 +++++++
 src/dialogs/tlevelselector.cpp        |  7 ++++++-
 src/libs/core/Android/tandroid.cpp    | 27 +++++++++++++++------------
 src/libs/core/Android/tandroid.h      |  4 +++-
 src/libs/core/Android/tfiledialog.cpp |  1 +
 src/libs/core/exam/texam.cpp          |  8 +++++++-
 src/libs/core/tglobals.cpp            | 23 ++++++++++++++---------
 src/libs/core/tnootkaqml.cpp          |  8 ++++++++
 src/main.cpp                          | 13 ++++++++-----
 src/main/texamexecutor.cpp            |  7 +++++++
 src/main/tstartexamitem.cpp           |  2 ++
 11 files changed, 78 insertions(+), 29 deletions(-)

diff --git a/src/dialogs/tlevelcreatoritem.cpp b/src/dialogs/tlevelcreatoritem.cpp
index a3d776031..0aec202d6 100644
--- a/src/dialogs/tlevelcreatoritem.cpp
+++ b/src/dialogs/tlevelcreatoritem.cpp
@@ -24,6 +24,9 @@
 #include <tglobals.h>
 #include <texamparams.h>
 #include <Android/tfiledialog.h>
+#if defined (Q_OS_ANDROID)
+  #include <Android/tandroid.h>
+#endif
 
 #include <QtCore/qtimer.h>
 #include <QtCore/qfileinfo.h>
@@ -92,6 +95,10 @@ void TlevelCreatorItem::continueLevelSave(const QString& name, const QString& de
   m_level->name = name;
   m_level->desc = desc;
 
+#if defined (Q_OS_ANDROID)
+  if (GLOB->E->levelsDir.isEmpty())
+    GLOB->E->levelsDir = Tandroid::getExternalPath();
+#endif
   // Saving to file
   QLatin1String dotNel(".nel");
   QString fName = QDir::toNativeSeparators(GLOB->E->levelsDir + QLatin1String("/") + m_level->name);
diff --git a/src/dialogs/tlevelselector.cpp b/src/dialogs/tlevelselector.cpp
index 47efd0d1c..9784384ba 100644
--- a/src/dialogs/tlevelselector.cpp
+++ b/src/dialogs/tlevelselector.cpp
@@ -24,6 +24,9 @@
 #include <tglobals.h>
 #include <tpath.h>
 #include <Android/tfiledialog.h>
+#if defined (Q_OS_ANDROID)
+  #include <Android/tandroid.h>
+#endif
 
 #include <QtCore/qsettings.h>
 #include <QtCore/qdiriterator.h>
@@ -177,7 +180,9 @@ QString TlevelSelector::levelFile(int id) const {
 void TlevelSelector::loadFromFile(QString levelFile) {
   if (levelFile.isEmpty())
 #if defined (Q_OS_ANDROID)
-    levelFile = TfileDialog::getOpenFileName(GLOB->E->levelsDir, QStringLiteral("nel"));
+  if (GLOB->E->levelsDir.isEmpty())
+    GLOB->E->levelsDir = Tandroid::getExternalPath();
+  levelFile = TfileDialog::getOpenFileName(GLOB->E->levelsDir, QStringLiteral("nel"));
 #else
     levelFile = TfileDialog::getOpenFileName(tr("Load exam level"), GLOB->E->levelsDir, levelFilterTxt() + QLatin1String(" (*.nel)"));
 #endif
diff --git a/src/libs/core/Android/tandroid.cpp b/src/libs/core/Android/tandroid.cpp
index 40a1e8310..05503d5fa 100644
--- a/src/libs/core/Android/tandroid.cpp
+++ b/src/libs/core/Android/tandroid.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2015-2020 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2015-2021 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -24,6 +24,7 @@
 #include <QtCore/qfileinfo.h>
 #include <QtWidgets/qmessagebox.h>
 #include <QtWidgets/qapplication.h>
+#include <QtCore/qstandardpaths.h>
 
 #include <QtCore/qdebug.h>
 
@@ -76,13 +77,20 @@ bool Tandroid::hasWriteAccess() {
 }
 
 
+void Tandroid::askForWriteAcces() {
+  if (QtAndroid::androidSdkVersion() >= 23) {
+    const QString writeID("android.permission.WRITE_EXTERNAL_STORAGE");
+    if (QtAndroid::checkPermission(writeID) != QtAndroid::PermissionResult::Granted) {
+      auto perms = QtAndroid::requestPermissionsSync(QStringList() << writeID);
+      qDebug() << writeID << (perms[writeID] == QtAndroid::PermissionResult::Granted);
+    }
+  }
+}
+
 QString Tandroid::getExternalPath() {
   QString extPath;
   if (getAPIlevelNr() < 19) { // look for SD card only before Kitkat, otherwise it is inaccessible
     extPath = qgetenv("SECONDARY_STORAGE");
-    //  QAndroidJniObject mediaDir = QAndroidJniObject::callStaticObjectMethod("android/os/Environment",
-    //                                                                         "getExternalStorageDirectory", "()Ljava/io/File;");
-    //  QString extPath = mediaDir.callObjectMethod("getAbsolutePath", "()Ljava/lang/String;").toString();
     if (!extPath.isEmpty()) {
       if (!QFileInfo(extPath).isWritable()) {
         qDebug() << "[Tandroid] No write access to secondary storage!";
@@ -91,16 +99,11 @@ QString Tandroid::getExternalPath() {
     }
   }
 
-  if(QtAndroid::androidSdkVersion() >= 23) {
-      const QString PermissionID("android.permission.WRITE_EXTERNAL_STORAGE");
-      if (QtAndroid::checkPermission(PermissionID) != QtAndroid::PermissionResult::Granted) {
-          auto perms = QtAndroid::requestPermissionsSync(QStringList() << PermissionID);
-          qDebug() << PermissionID << (perms[PermissionID] == QtAndroid::PermissionResult::Granted);
-      }
-  }
+  askForWriteAcces();
 
   if (extPath.isEmpty())
-    extPath = qgetenv("EXTERNAL_STORAGE"); // return primary storage path (device internal)
+    extPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
+//    extPath = qgetenv("EXTERNAL_STORAGE"); // return primary storage path (device internal)
   if (!QFileInfo(extPath).isWritable()) {
     qDebug() << "[Tandroid] No write access to primary storage!";
     extPath.clear();
diff --git a/src/libs/core/Android/tandroid.h b/src/libs/core/Android/tandroid.h
index 0a23c04a8..6f66871ff 100644
--- a/src/libs/core/Android/tandroid.h
+++ b/src/libs/core/Android/tandroid.h
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2015-2020 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2015-2021 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -47,6 +47,8 @@ namespace Tandroid {
        */
   bool hasWriteAccess();
 
+  void askForWriteAcces();
+
       /**
        * Returns command line argument (usually exam/level file name.
        */
diff --git a/src/libs/core/Android/tfiledialog.cpp b/src/libs/core/Android/tfiledialog.cpp
index 9233ae007..70f277203 100644
--- a/src/libs/core/Android/tfiledialog.cpp
+++ b/src/libs/core/Android/tfiledialog.cpp
@@ -163,6 +163,7 @@ TfileDialog::TfileDialog(const QString& directory, const QString& filter, Eaccep
 {
   showMaximized();
 
+  Tandroid::askForWriteAcces();
 // left side menu
   m_menu = new QListWidget(this);
   m_menu->setIconSize(QSize(60, 60));
diff --git a/src/libs/core/exam/texam.cpp b/src/libs/core/exam/texam.cpp
index a522d37cd..7a28a32de 100644
--- a/src/libs/core/exam/texam.cpp
+++ b/src/libs/core/exam/texam.cpp
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2011-2020 by Tomasz Bojczuk                             *
+ *   Copyright (C) 2011-2021 by Tomasz Bojczuk                             *
  *   seelook@gmail.com                                                     *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
@@ -26,6 +26,9 @@
 #include <QtCore/qdir.h>
 #include <QtCore/qsettings.h>
 #include <QtWidgets/qmessagebox.h>
+#if defined (Q_OS_ANDROID)
+  #include <Android/tandroid.h>
+#endif
 
 #include <QtCore/qdebug.h>
 
@@ -202,6 +205,9 @@ void Texam::skipLast(bool skip) {
 
 
 Texam::EerrorType Texam::loadFromFile(const QString& fileName) {
+#if defined (Q_OS_ANDROID)
+  Tandroid::askForWriteAcces();
+#endif
   m_okTime = 0;
   m_tmpMist = 0;
   m_tmpHalf = 0;
diff --git a/src/libs/core/tglobals.cpp b/src/libs/core/tglobals.cpp
index 5188aceed..d43a72583 100755
--- a/src/libs/core/tglobals.cpp
+++ b/src/libs/core/tglobals.cpp
@@ -517,9 +517,12 @@ void Tglobals::loadSettings(QSettings* cfg) {
       S->scientificOctaves = cfg->value(QStringLiteral("scientificOctaves"), false).toBool();
       Tnote::scientificOctaves = S->scientificOctaves;
 #if defined (Q_OS_ANDROID)
-      S->lastXmlDir = cfg->value(QStringLiteral("lastXmlDir"), Tandroid::getExternalPath()).toString();
-      if (!QFileInfo::exists(S->lastXmlDir)) // reset if doesn't exist
-        S->lastXmlDir = Tandroid::getExternalPath();
+      bool hasWriteAccess = Tandroid::hasWriteAccess();
+      if (hasWriteAccess) {
+        S->lastXmlDir = cfg->value(QStringLiteral("lastXmlDir"), Tandroid::getExternalPath()).toString();
+        if (!QFileInfo::exists(S->lastXmlDir) || !QFileInfo(S->lastXmlDir).isWritable()) // reset if doesn't exist
+          S->lastXmlDir = Tandroid::getExternalPath();
+      }
 #endif
   cfg->endGroup();
 
@@ -614,12 +617,14 @@ void Tglobals::loadSettings(QSettings* cfg) {
       if (E->studentName.isEmpty())
         E->studentName = systemUserName();
 #if defined (Q_OS_ANDROID)
-      E->examsDir = cfg->value(QStringLiteral("examsDir"), Tandroid::getExternalPath()).toString();
-      if (!QFileInfo::exists(E->examsDir)) // reset if doesn't exist
-        E->examsDir = Tandroid::getExternalPath();
-      E->levelsDir = cfg->value(QStringLiteral("levelsDir"), Tandroid::getExternalPath()).toString();
-      if (!QFileInfo::exists(E->levelsDir))
-        E->levelsDir = Tandroid::getExternalPath();
+      if (hasWriteAccess) {
+        E->examsDir = cfg->value(QStringLiteral("examsDir"), Tandroid::getExternalPath()).toString();
+        if (!QFileInfo::exists(E->examsDir) || !QFileInfo(E->examsDir).isWritable()) // reset if doesn't exist
+          E->examsDir = Tandroid::getExternalPath();
+        E->levelsDir = cfg->value(QStringLiteral("levelsDir"), Tandroid::getExternalPath()).toString();
+        if (!QFileInfo::exists(E->levelsDir) || !QFileInfo(E->levelsDir).isWritable())
+          E->levelsDir = Tandroid::getExternalPath();
+      }
 #else
       E->examsDir = cfg->value(QStringLiteral("examsDir"), QDir::homePath()).toString();
       if (!QFileInfo::exists(E->examsDir)) // reset if doesn't exist
diff --git a/src/libs/core/tnootkaqml.cpp b/src/libs/core/tnootkaqml.cpp
index 5645c7b3b..dc1d1dd1a 100755
--- a/src/libs/core/tnootkaqml.cpp
+++ b/src/libs/core/tnootkaqml.cpp
@@ -37,6 +37,10 @@
 #include "music/ttuneobject.h"
 #include "tmtr.h"
 #include "tcolor.h"
+#if defined (Q_OS_ANDROID)
+  #include <Android/tandroid.h>
+#endif
+
 
 #include <QtQml/qqmlengine.h>
 #include <QtCore/qtimer.h>
@@ -290,6 +294,8 @@ Tinstrument TnootkaQML::instr(int type) {
 QString TnootkaQML::getXmlToOpen() {
   QString openFile;
 #if defined (Q_OS_ANDROID)
+  if (GLOB->lastXmlDir().isEmpty())
+    GLOB->setLastXmlDir(Tandroid::getExternalPath());
   openFile = TfileDialog::getOpenFileName(GLOB->lastXmlDir(), QStringLiteral("xml|musicxml"));
 #else
   openFile = TfileDialog::getOpenFileName(qApp->translate("TmainScoreObject", "Open melody file"), GLOB->lastXmlDir(),
@@ -305,6 +311,8 @@ QString TnootkaQML::getXmlToSave(const QString& fileName) {
   QString saveFile;
   QString filter;
 #if defined (Q_OS_ANDROID)
+  if (GLOB->lastXmlDir().isEmpty())
+    GLOB->setLastXmlDir(Tandroid::getExternalPath());
   saveFile = TfileDialog::getSaveFileName(GLOB->lastXmlDir() + QLatin1String("/") + fileName,
                                           QStringLiteral("musicxml|xml"));
 #else
diff --git a/src/main.cpp b/src/main.cpp
index 050523ee9..c95004e93 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -90,11 +90,14 @@ int main(int argc, char *argv[])
   qputenv("QT_ANDROID_VOLUME_KEYS", "1"); // Handle volume keys by Qt, lock native Android behavior
 
   // log to any writable storage
- logFile = Tandroid::getExternalPath() + QStringLiteral("/nootka-log.txt");
-  if (QFile::exists(logFile))
-    QFile::remove(logFile);
-  qInstallMessageHandler(myMessageOutput);
-  qDebug() << "==== NOOTKA LOG =======\n" << QDateTime::currentDateTime().toString();
+  if (Tandroid::hasWriteAccess()) {
+    logFile = Tandroid::getExternalPath() + QStringLiteral("/nootka-log.txt");
+    Tandroid::askForWriteAcces();
+    if (QFile::exists(logFile))
+      QFile::remove(logFile);
+    qInstallMessageHandler(myMessageOutput);
+    qDebug() << "==== NOOTKA LOG =======\n" << QDateTime::currentDateTime().toString();
+  }
 #else
   qputenv("QT_QUICK_CONTROLS_STYLE", ""); // reset style environment var - other styles can cause crashes
 #endif
diff --git a/src/main/texamexecutor.cpp b/src/main/texamexecutor.cpp
index 3e29655f2..f5526144d 100644
--- a/src/main/texamexecutor.cpp
+++ b/src/main/texamexecutor.cpp
@@ -44,6 +44,9 @@
 #include "tnameitem.h"
 #include "tmainscoreobject.h"
 #include <Android/tfiledialog.h>
+#if defined (Q_OS_ANDROID)
+  #include <Android/tandroid.h>
+#endif
 
 #include <QtCore/qdatetime.h>
 #include <QtCore/qtimer.h>
@@ -79,6 +82,10 @@ void debugStyle(TQAunit &qa) {
  * but when such a file exists in current exam directory some time mark is added.
  */
 QString getExamFileName(Texam* e) {
+#if defined (Q_OS_ANDROID)
+  if (GLOB->E->examsDir.isEmpty())
+    GLOB->E->examsDir = Tandroid::getExternalPath();
+#endif
   auto fName = QDir::toNativeSeparators(GLOB->E->examsDir + QLatin1String("/") + e->userName() + QLatin1String("-") + e->level()->name);
   fName = fName.replace(QLatin1String("."), QLatin1String("")); //HACK: file dialogues don't like dots in the names
   if (QFileInfo::exists(fName  + QLatin1String(".noo")))
diff --git a/src/main/tstartexamitem.cpp b/src/main/tstartexamitem.cpp
index 52d27266e..2d6ab1c41 100644
--- a/src/main/tstartexamitem.cpp
+++ b/src/main/tstartexamitem.cpp
@@ -124,6 +124,8 @@ void TstartExamItem::continuePrevExam() {
 
 void TstartExamItem::examFromFileDialog() {
 #if defined (Q_OS_ANDROID)
+  if (GLOB->E->examsDir.isEmpty())
+    GLOB->E->examsDir = Tandroid::getExternalPath();
   QString fileName = TfileDialog::getOpenFileName(GLOB->E->examsDir, QStringLiteral("noo"));
 #else
   QString fileName = TfileDialog::getOpenFileName(TexTrans::loadExamFileTxt(), GLOB->E->examsDir, TexTrans::examFilterTxt());
-- 
GitLab