From 8c2ad19efca68c5a065cdc104814d90552774f07 Mon Sep 17 00:00:00 2001 From: Martchus Date: Thu, 9 Jan 2025 21:51:20 +0100 Subject: [PATCH] Keep main Qt event loop running when Android app is in background * Process Syncthing events and possibly update Android notifications * React to network connection changes (metered vs. not metered) while the app is in background This might not be ideal: * According to the documentation it'll lead to crashes when the app tries to draw while in background. I didn't run into any problems after a brief test so far, though. * UI code will run unneccassarily while the app is in the background. The code is already unassinging the main thread affinity of models to reduce this. It is unfortunately not possible to move the QML engine due to its bindings (`QObject::moveToThread: Can not move objects that contain bindings or are used in bindings to a new thread.`). --- tray/gui/quick/app.cpp | 12 ++++++++++-- tray/gui/quick/app.h | 2 ++ tray/resources/AndroidManifest.xml.in | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/tray/gui/quick/app.cpp b/tray/gui/quick/app.cpp index 495b13ce..8dc75207 100644 --- a/tray/gui/quick/app.cpp +++ b/tray/gui/quick/app.cpp @@ -101,6 +101,7 @@ App::App(bool insecure, QObject *parent) , m_sortFilterDevModel(&m_devModel) , m_changesModel(m_connection) , m_faUrlBase(QStringLiteral("image://fa/")) + , m_uiObjects({&m_dirModel, &m_sortFilterDirModel, &m_devModel, &m_sortFilterDevModel, &m_changesModel}) , m_iconSize(16) , m_tabIndex(-1) , m_importExportStatus(ImportExportStatus::None) @@ -698,14 +699,21 @@ void App::handleNewErrors(const std::vector &errors) void App::handleStateChanged(Qt::ApplicationState state) { if (m_isGuiLoaded && ((state == Qt::ApplicationSuspended) || (state & Qt::ApplicationHidden))) { - qDebug() << "App considered suspended/hidden, reduce polling, stopping UI if requested"; + qDebug() << "App considered suspended/hidden, reducing polling, stopping UI processing"; setCurrentControls(false); + for (auto *const uiObject : m_uiObjects) { + uiObject->moveToThread(nullptr); + } if (m_unloadGuiWhenHidden) { unloadMain(); } } else if (state & Qt::ApplicationActive) { - qDebug() << "App considered active, ensuring UI is loaded"; + qDebug() << "App considered active, continuing polling, resuming UI processing"; setCurrentControls(true); + auto *const uiThread = thread(); + for (auto *const uiObject : m_uiObjects) { + uiObject->moveToThread(uiThread); + } if (!m_isGuiLoaded) { deletePipelineCache(); loadMain(); diff --git a/tray/gui/quick/app.h b/tray/gui/quick/app.h index 3a295047..b7420da3 100644 --- a/tray/gui/quick/app.h +++ b/tray/gui/quick/app.h @@ -35,6 +35,7 @@ #include #endif +#include #include QT_FORWARD_DECLARE_CLASS(QTextDocument) @@ -328,6 +329,7 @@ private Q_SLOTS: QJsonObject m_settings; QString m_faUrlBase; std::optional m_status; + std::array m_uiObjects; QString m_log; int m_iconSize; int m_tabIndex; diff --git a/tray/resources/AndroidManifest.xml.in b/tray/resources/AndroidManifest.xml.in index 3acf60a1..b7fd0f64 100644 --- a/tray/resources/AndroidManifest.xml.in +++ b/tray/resources/AndroidManifest.xml.in @@ -57,6 +57,10 @@ + +