diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 1a01197..d1e6ce5 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -30,77 +30,69 @@ AppContext::AppContext(QCommandLineParser *cmdargs) { this->cmdargs = cmdargs; AppContext::isQML = false; + // OS & env #if defined(Q_OS_MAC) + this->isMac = true; this->isTorSocks = qgetenv("DYLD_INSERT_LIBRARIES").indexOf("libtorsocks") >= 0; +#elif __ANDROID__ + this->isAndroid = true; #elif defined(Q_OS_LINUX) + this->isLinux = true; this->isTorSocks = qgetenv("LD_PRELOAD").indexOf("libtorsocks") >= 0; + this->isTails = TailsOS::detect(); + this->isWhonix = WhonixOS::detect(); #elif defined(Q_OS_WIN) + this->isWindows = true; this->isTorSocks = false; #endif + this->androidDebug = cmdargs->isSet("android-debug"); - this->isTails = TailsOS::detect(); - this->isWhonix = WhonixOS::detect(); - - //Paths + // Paths + this->pathGenericData = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); this->configRoot = QDir::homePath(); - if (isTails) { // #if defined(PORTABLE) - QString portablePath = []{ - QString appImagePath = qgetenv("APPIMAGE"); - if (appImagePath.isEmpty()) { - qDebug() << "Not an appimage, using currentPath()"; - return QDir::currentPath() + "/.wowlet"; - } - - QFileInfo appImageDir(appImagePath); - return appImageDir.absoluteDir().path() + "/.wowlet"; - }(); - - - if (QDir().mkpath(portablePath)) { - this->configRoot = portablePath; - } else { - qCritical() << "Unable to create portable directory: " << portablePath; - } - } - this->accountName = Utils::getUnixAccountName(); this->homeDir = QDir::homePath(); + this->configDirectory = QString("%1/.config/wowlet/").arg(this->configRoot); + this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr"); + + if (isTails) this->setupPathsTails(); + QString walletDir = config()->get(Config::walletDirectory).toString(); - if (walletDir.isEmpty()) { -#if defined(Q_OS_LINUX) or defined(Q_OS_MAC) - this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot); - this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot); -#elif defined(Q_OS_WIN) - this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero"; - this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); -#endif + if(walletDir.isEmpty()) { + if (isAndroid && !androidDebug) setupPathsAndroid(); + else if (isWindows) setupPathsWindows(); + else if (isLinux || isMac) setupPathsUnix(); } else { this->defaultWalletDir = walletDir; this->defaultWalletDirRoot = walletDir; } +#ifdef __ANDROID__ + // can haz disk I/O? + QVector perms = { + "android.permission.WRITE_EXTERNAL_STORAGE", + "android.permission.READ_EXTERNAL_STORAGE" + }; + Utils::androidAskPermissions(perms); +#endif + // Create wallet dirs + qDebug() << "creating " << defaultWalletDir; if (!QDir().mkpath(defaultWalletDir)) qCritical() << "Unable to create dir: " << defaultWalletDir; - this->configDirectory = QString("%1/.config/wowlet/").arg(this->configRoot); -#if defined(Q_OS_UNIX) - if(!this->configDirectory.endsWith('/')) - this->configDirectory = QString("%1/").arg(this->configDirectory); -#endif - this->configDirectoryVR = QString("%1%2").arg(this->configDirectory, "vr"); - // Create some directories createConfigDirectory(this->configDirectory); - -// if(this->cmdargs->isSet("stagenet")) -// this->networkType = NetworkType::STAGENET; -// else if(this->cmdargs->isSet("testnet")) -// this->networkType = NetworkType::TESTNET; -// else this->networkType = NetworkType::MAINNET; + qDebug() << "configRoot: " << this->configRoot; + qDebug() << "homeDir: " << this->homeDir; + qDebug() << "customWalletDir: " << walletDir; + qDebug() << "defaultWalletDir: " << this->defaultWalletDir; + qDebug() << "defaultWalletDirRoot: " << this->defaultWalletDirRoot; + qDebug() << "configDirectory: " << this->configDirectory; + // auto nodeSourceUInt = config()->get(Config::nodeSource).toUInt(); // AppContext::nodeSource = static_cast(nodeSourceUInt); this->nodes = new Nodes(this, this->networkClearnet); @@ -558,12 +550,14 @@ void AppContext::createConfigDirectory(const QString &dir) { } } +#ifdef HAS_OPENVR auto config_dir_vr = QString("%1%2").arg(dir, "vr"); if(!Utils::dirExists(config_dir_vr)) { qDebug() << QString("Creating directory: %1").arg(config_dir_vr); if (!QDir().mkpath(config_dir_vr)) throw std::runtime_error("Could not create directory " + config_dir_vr.toStdString()); } +#endif } void AppContext::createWalletWithoutSpecifyingSeed(const QString &name, const QString &password) { @@ -949,3 +943,38 @@ void AppContext::refreshModels() { this->currentWallet->coins()->refresh(this->currentWallet->currentSubaddressAccount()); // Todo: set timer for refreshes } + +void AppContext::setupPathsUnix() { + this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->configRoot); + this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->configRoot); +} + +void AppContext::setupPathsWindows() { + this->defaultWalletDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Wownero"; + this->defaultWalletDirRoot = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); +} + +void AppContext::setupPathsAndroid() { + this->defaultWalletDir = QString("%1/Wownero/wallets").arg(this->pathGenericData); + this->defaultWalletDirRoot = QString("%1/Wownero").arg(this->pathGenericData); +} + +void AppContext::setupPathsTails() { + QString portablePath = []{ + QString appImagePath = qgetenv("APPIMAGE"); + if (appImagePath.isEmpty()) { + qDebug() << "Not an appimage, using currentPath()"; + return QDir::currentPath() + "/.wowlet"; + } + + QFileInfo appImageDir(appImagePath); + return appImageDir.absoluteDir().path() + "/.wowlet"; + }(); + + if (QDir().mkpath(portablePath)) { + this->configRoot = portablePath; + } else { + qCritical() << "Unable to create portable directory: " << portablePath; + } +} + diff --git a/src/appcontext.h b/src/appcontext.h index ad334ef..9aec9b6 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -39,7 +39,12 @@ public: ~AppContext() override; bool isTails = false; bool isWhonix = false; + bool isAndroid = false; + bool isLinux = false; + bool isMac = false; + bool isWindows = false; bool isDebug = false; + bool androidDebug = false; // Donation config const QString donationAddress = "Wo3MWeKwtA918DU4c69hVSNgejdWFCRCuWjShRY66mJkU2Hv58eygJWDJS1MNa2Ge5M1WjUkGHuLqHkweDxwZZU42d16v94mP"; @@ -50,6 +55,7 @@ public: QString coinName = "wownero"; bool isTorSocks = false; + QString pathGenericData; QString homeDir; QString accountName; QString configRoot; @@ -215,6 +221,11 @@ private: WalletKeysFilesModel *m_walletKeysFilesModel; const int m_donationBoundary = 15; QTimer m_storeTimer; + + void setupPathsUnix(); + void setupPathsWindows(); + void setupPathsAndroid(); + void setupPathsTails(); }; #endif //WOWLET_APPCONTEXT_H diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index d5ea6ad..5fb2721 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2014-2021, The Monero Project. +#include + #include "Wallet.h" #include "TransactionHistory.h" diff --git a/src/main.cpp b/src/main.cpp index 7654e4e..c54a072 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,6 +14,12 @@ #include "vr/main.h" #endif +#ifdef HAS_ANDROID_DEBUG +#include "mobile/main.h" +#elif HAS_ANDROID +#include "mobile/main.h" +#endif + #if defined(Q_OS_WIN) #include #endif @@ -44,6 +50,10 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { argv_ << QString::fromStdString(argv[i]); } + QCoreApplication::setApplicationName("wowlet"); + QCoreApplication::setOrganizationDomain("wownero.org"); + QCoreApplication::setOrganizationName("wownero.org"); + QCommandLineParser parser; parser.setApplicationDescription("wowlet"); parser.addHelpOption(); @@ -91,9 +101,12 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { QCommandLineOption openVROption(QStringList() << "openvr", "Start Wowlet OpenVR"); parser.addOption(openVROption); - QCommandLineOption openVRDebugOption(QStringList() << "openvr-debug", "Start the Wowlet VR interface without initializing OpenVR - for debugging purposes."); + QCommandLineOption openVRDebugOption(QStringList() << "openvr-debug", "Start the Wowlet VR interface without initializing OpenVR - for debugging purposes. Requires -DOPENVR=ON CMake definition."); parser.addOption(openVRDebugOption); + QCommandLineOption androidDebugOption(QStringList() << "android-debug", "Start the Android interface without actually running on Android - for debugging purposes. Requires -DANDROID_DEBUG=ON CMake definition."); + parser.addOption(androidDebugOption); + auto parsed = parser.parse(argv_); if(!parsed) { qCritical() << parser.errorText(); @@ -111,13 +124,29 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { bool backgroundAddressEnabled = parser.isSet(backgroundOption); bool openVREnabled = parser.isSet(openVROption); bool cliMode = exportContacts || exportTxHistory || backgroundAddressEnabled; - + bool androidDebug = parser.isSet(androidDebugOption); + bool android = false; +#ifdef __ANDROID__ + android = true; +#endif qRegisterMetaType>(); #ifdef HAS_QML qputenv("QML_DISABLE_DISK_CACHE", "1"); #endif + if(android || androidDebug) { +#ifndef HAS_QML + qCritical() << "Wowlet compiled without QML support. Try -DQML=ON"; + return 1; +#endif + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QGuiApplication mobile_app(argc, argv); + auto *ctx = new AppContext(&parser); + auto *mobile = new mobile::Mobile(ctx, &parser, &mobile_app); + return mobile_app.exec(); + } + if(openVREnabled) { #ifdef HAS_OPENVR QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); @@ -138,9 +167,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { if(cliMode) { auto *ctx = new AppContext(&parser); QCoreApplication cli_app(argc, argv); - QCoreApplication::setApplicationName("wowlet"); - QCoreApplication::setOrganizationDomain("wownero.org"); - QCoreApplication::setOrganizationName("wownero.org"); ctx->applicationPath = QString(argv[0]); ctx->isDebug = debugMode; @@ -191,10 +217,6 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { QApplication app(argc, argv); - QApplication::setApplicationName("wowlet"); - QApplication::setOrganizationDomain("wownero.org"); - QApplication::setOrganizationName("wownero.org"); - parser.process(app); // Parse again for --help and --version if(!quiet) { @@ -204,8 +226,10 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { if (stagenet) info["Mode"] = "Stagenet"; else if (testnet) info["Mode"] = "Testnet"; else info["Mode"] = "Mainnet"; +#ifndef QT_NO_SSL info["SSL"] = QSslSocket::sslLibraryVersionString(); info["SSL build"] = QSslSocket::sslLibraryBuildVersionString(); +#endif for (const auto &k: info.keys()) qWarning().nospace().noquote() << QString("%1: %2").arg(k).arg(info[k]); } diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index c62cd84..ca9aee9 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -256,11 +256,14 @@ QStandardItem *Utils::qStandardItem(const QString& text, QFont &font) { } QString Utils::getUnixAccountName() { +#ifdef __ANDROID__ + return ""; +#endif QString accountName = qgetenv("USER"); // mac/linux if (accountName.isEmpty()) accountName = qgetenv("USERNAME"); // Windows if (accountName.isEmpty()) - throw std::runtime_error("Could derive system account name from env vars: USER or USERNAME"); + throw std::runtime_error("Could not derive system account name from env vars: USER or USERNAME"); return accountName; } @@ -454,4 +457,27 @@ QTextCharFormat Utils::addressTextFormat(const SubaddressIndex &index) { return rec; } return QTextCharFormat(); -} \ No newline at end of file +} + +#ifdef __ANDROID__ +bool Utils::androidAskPermissions(const QVector &permissions) { + bool rtn = true; + if(QtAndroid::androidSdkVersion() >= 23) { + for(const QString &permission : permissions) { + auto result = QtAndroid::checkPermission(permission); + if(result != QtAndroid::PermissionResult::Granted) { + auto resultHash = QtAndroid::requestPermissionsSync(QStringList({permission})); + if(resultHash[permission] != QtAndroid::PermissionResult::Granted) { + qDebug() << "Fail to get permission" << permission; + rtn = false; + } else { + qDebug() << "Permission" << permission << "granted!"; + } + } else { + qDebug() << "Permission" << permission << "already granted!"; + } + } + } + return rtn; +} +#endif \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h index 9cee19f..444e6f8 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -8,6 +8,9 @@ #include #include #include +#ifdef __ANDROID__ +#include +#endif #include @@ -80,10 +83,13 @@ public: static QTextCharFormat addressTextFormat(const SubaddressIndex &index); template - static QString QtEnumToString (const QEnum value) - { + static QString QtEnumToString (const QEnum value) { return QString::fromStdString(std::string(QMetaEnum::fromType().valueToKey(value))); } + +#ifdef __ANDROID__ + static bool androidAskPermissions(const QVector &permissions); +#endif }; class AppContext; // forward declaration