Skip to content

Commit

Permalink
fix: add separate method for reading files to fix file reading on And…
Browse files Browse the repository at this point in the history
…roid TV
  • Loading branch information
albexk committed Nov 11, 2024
1 parent 81ef931 commit 815d9fa
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 27 deletions.
37 changes: 37 additions & 0 deletions client/android/src/org/amnezia/vpn/AmneziaActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import android.content.Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
import android.content.ServiceConnection
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.net.VpnService
import android.os.Build
import android.os.Bundle
Expand All @@ -21,6 +22,8 @@ import android.os.IBinder
import android.os.Looper
import android.os.Message
import android.os.Messenger
import android.os.ParcelFileDescriptor
import android.provider.OpenableColumns
import android.provider.Settings
import android.view.MotionEvent
import android.view.WindowManager.LayoutParams
Expand All @@ -29,6 +32,7 @@ import android.widget.Toast
import androidx.annotation.MainThread
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import java.io.FileNotFoundException
import java.io.IOException
import kotlin.LazyThreadSafetyMode.NONE
import kotlin.text.RegexOption.IGNORE_CASE
Expand Down Expand Up @@ -72,6 +76,7 @@ class AmneziaActivity : QtActivity() {
private var isInBoundState = false
private var notificationStateReceiver: BroadcastReceiver? = null
private lateinit var vpnServiceMessenger: IpcMessenger
private var pfd: ParcelFileDescriptor? = null

private val actionResultHandlers = mutableMapOf<Int, ActivityResultHandler>()
private val permissionRequestHandlers = mutableMapOf<Int, PermissionRequestHandler>()
Expand Down Expand Up @@ -564,6 +569,11 @@ class AmneziaActivity : QtActivity() {
}
}
}.also {
if (packageManager.resolveActivity(it, PackageManager.MATCH_DEFAULT_ONLY) == null) {
Log.w(TAG, "Not found activity for ACTION_OPEN_DOCUMENT intent")
it.action = Intent.ACTION_GET_CONTENT
}

try {
startActivityForResult(it, OPEN_FILE_ACTION_CODE, ActivityResultHandler(
onAny = {
Expand All @@ -582,6 +592,33 @@ class AmneziaActivity : QtActivity() {
}
}

@Suppress("unused")
fun getFd(fileName: String): Int = try {
Log.v(TAG, "Get fd for $fileName")
pfd = contentResolver.openFileDescriptor(Uri.parse(fileName), "r")
pfd?.fd ?: -1
} catch (e: FileNotFoundException) {
Log.e(TAG, "Failed to get fd: $e")
-1
}

@Suppress("unused")
fun closeFd() {
Log.v(TAG, "Close fd")
pfd?.close()
pfd = null
}

@Suppress("unused")
fun getFileName(uri: String): String {
contentResolver.query(Uri.parse(uri), arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { cursor ->
if (cursor.moveToFirst() && !cursor.isNull(0)) {
return cursor.getString(0)
}
}
return ""
}

@Suppress("unused")
@SuppressLint("UnsupportedChromeOsCameraSystemFeature")
fun isCameraPresent(): Boolean = applicationContext.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
Expand Down
25 changes: 20 additions & 5 deletions client/platforms/android/android_controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,7 @@ QString AndroidController::openFile(const QString &filter)
QString fileName;
connect(this, &AndroidController::fileOpened, this,
[&fileName, &wait](const QString &uri) {
qDebug() << "Android event: file opened; uri:" << uri;
fileName = QQmlFile::urlToLocalFileOrQrc(uri);
qDebug() << "Qt url to local file:" << fileName;
// if qt failed, try using just uri
if (fileName.isEmpty()) fileName = uri;
fileName = uri;
wait.quit();
},
static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::SingleShotConnection));
Expand All @@ -177,6 +173,25 @@ QString AndroidController::openFile(const QString &filter)
return fileName;
}

int AndroidController::getFd(const QString &fileName)
{
return callActivityMethod<jint>("getFd", "(Ljava/lang/String;)I",
QJniObject::fromString(fileName).object<jstring>());
}

void AndroidController::closeFd()
{
callActivityMethod("closeFd", "()V");
}

QString AndroidController::getFileName(const QString &uri)
{
auto fileName = callActivityMethod<jstring, jstring>("getFileName", "(Ljava/lang/String;)Ljava/lang/String;",
QJniObject::fromString(uri).object<jstring>());
QJniEnvironment env;
return AndroidUtils::convertJString(env.jniEnv(), fileName.object<jstring>());
}

bool AndroidController::isCameraPresent()
{
return callActivityMethod<jboolean>("isCameraPresent", "()Z");
Expand Down
3 changes: 3 additions & 0 deletions client/platforms/android/android_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class AndroidController : public QObject
void resetLastServer(int serverIndex);
void saveFile(const QString &fileName, const QString &data);
QString openFile(const QString &filter);
int getFd(const QString &fileName);
void closeFd();
QString getFileName(const QString &uri);
bool isCameraPresent();
bool isOnTv();
void startQrReaderActivity();
Expand Down
22 changes: 12 additions & 10 deletions client/ui/controllers/importController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "core/errorstrings.h"
#include "core/serialization/serialization.h"
#include "systemController.h"
#include "utilities.h"

#ifdef Q_OS_ANDROID
Expand Down Expand Up @@ -76,17 +77,18 @@ ImportController::ImportController(const QSharedPointer<ServersModel> &serversMo

bool ImportController::extractConfigFromFile(const QString &fileName)
{
QFile file(fileName);

if (file.open(QIODevice::ReadOnly)) {
QString data = file.readAll();

m_configFileName = QFileInfo(file.fileName()).fileName();
return extractConfigFromData(data);
QString data;
if (!SystemController::readFile(fileName, &data)) {
emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
}

emit importErrorOccurred(ErrorCode::ImportOpenConfigError, false);
return false;
m_configFileName = QFileInfo(QFile(fileName).fileName()).fileName();
#ifdef Q_OS_ANDROID
if (m_configFileName.isEmpty()) {
m_configFileName = AndroidController::instance()->getFileName(fileName);
}
#endif
return extractConfigFromData(data);
}

bool ImportController::extractConfigFromData(QString data)
Expand Down
8 changes: 2 additions & 6 deletions client/ui/controllers/settingsController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,8 @@ void SettingsController::backupAppConfig(const QString &fileName)

void SettingsController::restoreAppConfig(const QString &fileName)
{
QFile file(fileName);

file.open(QIODevice::ReadOnly);

QByteArray data = file.readAll();

QByteArray data;
SystemController::readFile(fileName, &data);
restoreAppConfigFromData(data);
}

Expand Down
6 changes: 2 additions & 4 deletions client/ui/controllers/sitesController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,12 @@ void SitesController::removeSite(int index)

void SitesController::importSites(const QString &fileName, bool replaceExisting)
{
QFile file(fileName);

if (!file.open(QIODevice::ReadOnly)) {
QByteArray jsonData;
if (!SystemController::readFile(fileName, &jsonData)) {
emit errorOccurred(tr("Can't open file: %1").arg(fileName));
return;
}

QByteArray jsonData = file.readAll();
QJsonDocument jsonDocument = QJsonDocument::fromJson(jsonData);
if (jsonDocument.isNull()) {
emit errorOccurred(tr("Failed to parse JSON data from file: %1").arg(fileName));
Expand Down
27 changes: 26 additions & 1 deletion client/ui/controllers/systemController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ SystemController::SystemController(const std::shared_ptr<Settings> &settings, QO
{
}

void SystemController::saveFile(QString fileName, const QString &data)
void SystemController::saveFile(const QString &fileName, const QString &data)
{
#if defined Q_OS_ANDROID
AndroidController::instance()->saveFile(fileName, data);
Expand Down Expand Up @@ -62,6 +62,31 @@ void SystemController::saveFile(QString fileName, const QString &data)
#endif
}

bool SystemController::readFile(const QString &fileName, QByteArray *data)
{
#ifdef Q_OS_ANDROID
int fd = AndroidController::instance()->getFd(fileName);
if (fd == -1) return false;
QFile file;
if(!file.open(fd, QIODevice::ReadOnly)) return false;
data->assign(file.readAll());
AndroidController::instance()->closeFd();
#else
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) return false;
data->assign(file.readAll());
#endif
return true;
}

bool SystemController::readFile(const QString &fileName, QString *data)
{
QByteArray byteArray;
if(!readFile(fileName, &byteArray)) return false;
data->assign(byteArray);
return true;
}

QString SystemController::getFileName(const QString &acceptLabel, const QString &nameFilter,
const QString &selectedFile, const bool isSaveMode, const QString &defaultSuffix)
{
Expand Down
4 changes: 3 additions & 1 deletion client/ui/controllers/systemController.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ class SystemController : public QObject
public:
explicit SystemController(const std::shared_ptr<Settings> &setting, QObject *parent = nullptr);

static void saveFile(QString fileName, const QString &data);
static void saveFile(const QString &fileName, const QString &data);
static bool readFile(const QString &fileName, QByteArray *data);
static bool readFile(const QString &fileName, QString *data);

public slots:
QString getFileName(const QString &acceptLabel, const QString &nameFilter, const QString &selectedFile = "",
Expand Down

0 comments on commit 815d9fa

Please sign in to comment.