From 2755853cdc28918402bed9150a615874b487ae66 Mon Sep 17 00:00:00 2001 From: Jon Beniston Date: Fri, 17 Feb 2023 21:57:09 +0000 Subject: [PATCH] Android: Prevent app from being put to sleep when running. Add menu to keep screen on. --- plugins/channelrx/heatmap/readme.md | 4 +++- sdrbase/maincore.cpp | 29 ++++++++++++++++++++++++ sdrbase/maincore.h | 3 +++ sdrbase/util/android.cpp | 34 +++++++++++++++++++++++++++-- sdrbase/util/android.h | 4 ++++ sdrgui/mainwindow.cpp | 17 +++++++++++++++ sdrgui/mainwindow.h | 3 +++ 7 files changed, 91 insertions(+), 3 deletions(-) diff --git a/plugins/channelrx/heatmap/readme.md b/plugins/channelrx/heatmap/readme.md index 98f6ff568..1df03df96 100644 --- a/plugins/channelrx/heatmap/readme.md +++ b/plugins/channelrx/heatmap/readme.md @@ -8,9 +8,11 @@ To view the Heat Map visually, the [Map Feature](../../feature/map/readme.md) sh To record data for a heat map, a GPS is required, and Preferences > My Position should have "Auto-update from GPS" enabled. -On Android, GPS setup should be automatic. On Windows/Linux/Mac, a GPS supporting NMEA via a serial port at 4800 baud is required. +On Windows/Linux/Mac, a GPS supporting NMEA via a serial port at 4800 baud is required. The COM port / serial device should be specfied via the QT_NMEA_SERIAL_PORT environment variable before SDRangel is started. +On Android, GPS setup should be automatic. GPS position updates may stop on Android when the screen is off. To keep the screen on, press the View > Keep Screen On menu. + ![A Heat Map](../../../doc/img/HeatMap_plugin_map.png)

Interface

diff --git a/sdrbase/maincore.cpp b/sdrbase/maincore.cpp index bbe70eb9c..43f73ec61 100644 --- a/sdrbase/maincore.cpp +++ b/sdrbase/maincore.cpp @@ -28,6 +28,9 @@ #include "device/deviceset.h" #include "device/deviceapi.h" #include "channel/channelapi.h" +#ifdef ANDROID +#include "util/android.h" +#endif #include "maincore.h" @@ -75,6 +78,9 @@ MainCore::MainCore() m_masterElapsedTimer.start(); // Position can take a while to determine, so we start updates at program startup initPosition(); +#ifdef ANDROID + QObject::connect(this, &MainCore::deviceStateChanged, this, &MainCore::updateWakeLock); +#endif } MainCore::~MainCore() @@ -394,3 +400,26 @@ void MainCore::positionError(QGeoPositionInfoSource::Error positioningError) { qWarning() << "MainCore::positionError: " << positioningError; } + +#ifdef ANDROID +// On Android, we want to prevent the app from being put to sleep, when any +// device is running +void MainCore::updateWakeLock() +{ + bool running = false; + for (int i = 0; i < m_deviceSets.size(); i++) + { + if (m_deviceSets[i]->m_deviceAPI->state() == DeviceAPI::StRunning) + { + running = true; + break; + } + } + if (running) { + Android::acquireWakeLock(); + } else { + Android::releaseWakeLock(); + } +} +#endif + diff --git a/sdrbase/maincore.h b/sdrbase/maincore.h index d2dfe0576..c7672b2af 100644 --- a/sdrbase/maincore.h +++ b/sdrbase/maincore.h @@ -892,6 +892,9 @@ public slots: void positionUpdated(const QGeoPositionInfo &info); void positionUpdateTimeout(); void positionError(QGeoPositionInfoSource::Error positioningError); +#ifdef ANDROID + void updateWakeLock(); +#endif signals: void deviceSetAdded(int index, DeviceAPI *device); diff --git a/sdrbase/util/android.cpp b/sdrbase/util/android.cpp index 62d74d0a9..955fd6104 100644 --- a/sdrbase/util/android.cpp +++ b/sdrbase/util/android.cpp @@ -155,8 +155,6 @@ void Android::closeUSBDevice(int fd) QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); if (activity.isValid()) { activity.callMethod("closeUSBDevice", "(I)V", fd); - } else { - qCritical() << "MainCore::closeUSBDevice: activity is not valid."; } } } @@ -169,6 +167,38 @@ void Android::moveTaskToBack() } } +void Android::acquireWakeLock() +{ + QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + if (activity.isValid()) { + activity.callMethod("acquireWakeLock"); + } +} + +void Android::releaseWakeLock() +{ + QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + if (activity.isValid()) { + activity.callMethod("releaseWakeLock"); + } +} + +void Android::acquireScreenLock() +{ + QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + if (activity.isValid()) { + activity.callMethod("acquireScreenLock"); + } +} + +void Android::releaseScreenLock() +{ + QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); + if (activity.isValid()) { + activity.callMethod("releaseScreenLock"); + } +} + #endif // QT6 // Redirect qDebug/qWarning to Android log, so we can view remotely with adb diff --git a/sdrbase/util/android.h b/sdrbase/util/android.h index ef97d5eed..945076afd 100644 --- a/sdrbase/util/android.h +++ b/sdrbase/util/android.h @@ -36,6 +36,10 @@ public: static void closeUSBDevice(int fd); static void moveTaskToBack(); static void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& msg); + static void acquireWakeLock(); + static void releaseWakeLock(); + static void acquireScreenLock(); + static void releaseScreenLock(); }; diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index efa2f96af..5ade12109 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -1637,6 +1637,12 @@ void MainWindow::createMenuBar(QToolButton *button) fullscreenAction->setToolTip("Toggle fullscreen view"); fullscreenAction->setCheckable(true); QObject::connect(fullscreenAction, &QAction::triggered, this, &MainWindow::on_action_View_Fullscreen_toggled); +#ifdef ANDROID + QAction *keepscreenonAction = viewMenu->addAction("&Keep screen on"); + keepscreenonAction->setToolTip("Prevent screen from switching off"); + keepscreenonAction->setCheckable(true); + QObject::connect(keepscreenonAction, &QAction::triggered, this, &MainWindow::on_action_View_KeepScreenOn_toggled); +#endif QAction *newWorkspaceAction = workspacesMenu->addAction("&New"); newWorkspaceAction->setToolTip("Add a new workspace"); @@ -2183,6 +2189,17 @@ void MainWindow::removeEmptyWorkspaces() #endif } +#ifdef ANDROID +void MainWindow::on_action_View_KeepScreenOn_toggled(bool checked) +{ + if (checked) { + Android::acquireScreenLock(); + } else { + Android::releaseScreenLock(); + } +} +#endif + void MainWindow::on_action_View_Fullscreen_toggled(bool checked) { if(checked) { diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 6243a241f..5af37cc08 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -179,6 +179,9 @@ private slots: void handleMessages(); void handleWorkspaceVisibility(Workspace *workspace, bool visibility); +#ifdef ANDROID + void on_action_View_KeepScreenOn_toggled(bool checked); +#endif void on_action_View_Fullscreen_toggled(bool checked); void on_action_saveAll_triggered(); void on_action_Configurations_triggered();