2

I'm deploying a Qt application on Android. It connects a BLE device, receives and log notifications.

When the Android device goes to standby, my app stops receiving BLE notifications (I'm not receiving QLowEnergyService::characteristicChanged signal anymore), when I make it quit standby mode, notifications are being received again.

I found this post: How do I prevent an Android device from going to sleep programmatically?, and thanks to QAndroidJniObject I could implement the lock in my app (see How do I prevent an Android device from going to sleep from Qt application).

However:

  • If I use SCREEN_DIM_WAKE_LOCK, screen won't go to standby and I continue receiving my notifications.
  • If I use PARTIAL_WAKE_LOCK, screen goes to standby, but then I won't receive my notifications (as if not creating any lock actually)

I'm not satisfied by SCREEN_DIM_WAKE_LOCK because:

  • Keeping the screen ON will empty my battery
  • I need the screen to turn OFF as the app is running all night next to a sleeping bed (acquiering user physiological measurements overnight)

But, keeping only the CPU alive (what PARTIAL_WAKE_LOCK is supposed to do) is not enough.

An idea how I can have this screen be turned off and continue receiving my BLE notifications? Is there another locking system? java code is acceptable as and answer as far as it is light enought to be ported to Qt through QAndroidJniObject.

jpo38
  • 20,821
  • 10
  • 70
  • 151
  • Have you heard about [foreground service](https://developer.android.com/guide/components/services)? AFAIK, using foreground service alone is enough to receive BLE notifications (if you don't need to consider battery usage) – reTs Aug 24 '18 at 08:56
  • @reTs: Unfortunately, this is all handled by Qt libs...I don't have direct access to Android API – jpo38 Aug 24 '18 at 09:01

1 Answers1

1

My guess is that you are acquiring the PARTIAL_WAKE_LOCK okay, but when the screen is turned off, your application goes into "background running" and by default, the AndroidManifest.xml generated by Qt disables background running.

Open your "AndroidManifest.xml" file and switch to the "XML Source." Scroll down and find this section:

        <!-- Background running -->
        <!-- Warning: changing this value to true may cause unexpected crashes if the
                      application still try to draw after
                      "applicationStateChanged(Qt::ApplicationSuspended)"
                      signal is sent! -->
        <meta-data android:name="android.app.background_running" android:value="true"/>
        <!-- Background running -->

By default, "android.app.background_running" is set to "false" and your application execution will be halted when the screen turns off or the user switches to different application running in the foreground. You need android.app.background_running to be set to "true" as I have in the above snippet.

When your application is running in the background, you are presumably not allowed to draw any changes to the screen or else suffer unexpected crashes. For my application, I only have one MainWindow displayed and I seem to be able to avoid the problem by implementing an applicationStateChanged() slot like this:

class MainWindow : public QMainWindow
{
    (...)
    public slots:
        void applicationStateChanged(Qt::ApplicationState state);
}

void MainWindow::applicationStateChanged(Qt::ApplicationState state)
{
    if(state != Qt::ApplicationActive)
    {
        // Don't update GUI if we're not the active application
        ui->centralWidget->setVisible(false);
        qDebug() << "Hiding GUI because not active state: " << state;
    }
    else
    {
        ui->centralWidget->setVisible(true);
        qDebug() << "Showing GUI because active now.";
    }
}

This function will get called automatically whenever the user turns off the screen or switches to a different foreground app.

From my experience, it is not 100% guaranteed that your application will remain running even with the above change (you just get to live a little longer). Android seems to have a mind of it's own where it will decide to sometimes kill off processes that aren't running in the foreground. Perhaps the situation will be better on higher end Android devices than what I have (every Android device I own has less than 1GB of RAM).

Do not use this for life support or other mission critical situations.


Edit from jpo38, as main window may be a QDialog or possible be showing a QDialog at some point, would'nt it be better to disable redrawing this was rather than hiding QMainWindow's central widget?:

bool Application::notify(QObject * receiver, QEvent * event) 
{
    if ( event && 
         event->type() == QEvent::Paint )
    {
        if ( applicationState() != Qt::ApplicationActive )
        {
            return false;
        }
    }
    return QApplication::notify(receiver,event);
}
jpo38
  • 20,821
  • 10
  • 70
  • 151
K9spud
  • 323
  • 1
  • 7
  • Thanks! Modifying the manifest as recommanded worked perfectly as expected with a PARTIAL_WAKE_LOCK lock. Surprisingly, I did not have to do anything with the `applicationStateChanged` (even if my app draws a lot of things in real-time). Maybe this part is handled by Qt itself... – jpo38 Sep 06 '18 at 14:10
  • No, I don't think Qt handles this itself. It'll seemingly work at first, but eventually it'll end up crashing someday. Even if it don't, it's still a bad practice to leave all those real-time drawings going on while the screen is turned off -- that's wasting CPU time for stuff that the user can't even see. Turn that code off and it'll help conserve battery power, which will make your users happier. – K9spud Sep 06 '18 at 19:20
  • See my edit, I'm wondering if overriding `Application::notify` may be a smarter way to do this. – jpo38 Sep 07 '18 at 07:02
  • Yes, if that works, it seems like a good solution to me. Only downside I can see is that it might stop working in Qt6 or later, given this vague note in the help file for QCoreApplication::notify(): "Future direction: **This function will not be called for objects that live outside the main thread in Qt 6.** Applications that need that functionality should find other solutions for their event inspection needs in the meantime. **The change may be extended to the main thread, causing this function to be deprecated.**" – K9spud Sep 08 '18 at 18:19