Work with the timer in Sailfish OS on long time intervals

Introduction


Quite often, with the implementation of any logic in the application, there is a need to trigger some function after a certain period of time. The most obvious example of this need is the timer application. For example, cooktimer or Saildoro .

As mentioned in one of the previous articles, you can use the standard Timer element or its C ++ equivalent, QTimer , to add a timer to an application on Sailfish OS. However, by default, the operation of these timers is suspended for long periods of time due to the fact that the device can go into "sleep". The developers of the two applications mentioned above have just encountered this problem.

This article presents a standard for the system, but unfortunately an undocumented way to handle this behavior of Sailfish OS.

starting point


As a starting point, an “abstract” application for Sailfish OS will be considered, in which some functionality needs to be triggered after a long period of time. At the same time, the timer operation is described not in the QML code, but in a class in C ++:

Header
 class TimerWrapper : public QObject { Q_OBJECT public: //    explicit TimerWrapper(QObject *parent = 0); ~TimerWrapper(); Q_INVOKABLE void start(int interval); //     Q_INVOKABLE void stop(); //     signals: void pomodoroFinished(int start, int end); //    void activeChanged(); //     private: QTimer *_timer; //   int _startTime; //    }; 


Source
 #include "timerwrapper.h" /** *  . */ TimerWrapper::TimerWrapper(QObject *parent) : QObject(parent) { _timer = new QTimer(this); //    _timer->setSingleShot(true); //     //           connect(_timer, &QTimer::timeout, [=]() { emit activeChanged(); eemit pomodoroFinished(_startTime, QDateTime::currentDateTime().toMSecsSinceEpoch()); }); } /** *  . */ TimerWrapper::~TimerWrapper() { delete _timer; _timer = nullptr; } /** *     . * @:param: interval -      */ void TimerWrapper::start(int interval) { _startTime = QDateTime::currentMSecsSinceEpoch(); //    _timer->start(interval); //   emit activeChanged(); //      } /** *    . */ void TimerWrapper::stop() { _timer->stop(); //   emit activeChanged(); //     } 


An object of this class must be registered in QML:

main.cpp
 #ifdef QT_QML_DEBUG #include <QtQuick> #endif #include <QGuiApplication> #include <QQmlContext> #include <QQuickView> #include <QScopedPointer> #include <sailfishapp.h> #include "timerwrapper.h" int main(int argc, char *argv[]) { //    QScopedPointer<QGuiApplication> application(SailfishApp::application(argc, argv)); //      QScopedPointer<QQuickView> view(SailfishApp::createView()); //    QScopedPointer<TimerWrapper> timer(new TimerWrapper(view.data())); //    view->rootContext()->setContextProperty("timer", timer.data()); //     QML- view->setSource(SailfishApp::pathTo("qml/harbour-application.qml")); //   view->show(); //   return application->exec(); } 


With this approach, as mentioned in the introduction, there can be a suspension of the timer operation over long time intervals.

Decision


The first option to prevent the timer from falling asleep was proposed in the developer mailing list and caught on in the cooktimer application. Here it is proposed to start an additional timer, which calls the D-Bus method req_display_cancel_blanking_pause once a minute to prevent the device from falling asleep. It is obvious that such an implementation is not optimal and cumbersome. First, when using this approach, the device battery discharges faster. Secondly, a minor code appears in the project that can be avoided.

And you can avoid the use of secondary code because Sailfish OS already provides two possible solutions to the problem posed: the ScreenBlank and KeepAlive elements.

Using the first approach involves a constantly active screen. This is a working but straightforward approach that actively consumes the device’s battery. Thus, it can be used, but in a limited circle of situations.

 import QtQuick 2.0 //       QML import Sailfish.Silica 1.0 //     Sailfish OS UI import Sailfish.Media 1.0 //      ScreenBlank ApplicationWindow //     { initialPage: Component { FirstPage { } } //     cover: Qt.resolvedUrl("cover/CoverPage.qml") //    ScreenBlank { //       id: screenBlank //    suspend: true //    } } 

In turn, the use of the KeepAlive element is a more democratic approach. It consumes less battery power, as it does not keep the device screen constantly on, and at the same time, either does not allow the device to go into a deep sleep, or “wakes” it at a certain point in time, thanks to which the timer will continue to work and long periods of time.

 import QtQuick 2.0 //       QML import Sailfish.Silica 1.0 //     Sailfish OS UI import org.nemomobile.keepalive 1.1 //      KeepAlive ApplicationWindow //     { initialPage: Component { FirstPage { } } //     cover: Qt.resolvedUrl("cover/CoverPage.qml") //    KeepAlive { //       id: keepAlive //    enabled: true //       } } 

It is worth noting that, in principle, the work of all three of these methods is a regular appeal to the system methods of D-Bus, which was discussed in a previous article.

Conclusion


As part of this short note, three possible ways to prevent the device from deep falling asleep are described. It can be concluded that for background tasks (for example, a timer) it is optimal to use the KeepAlive element, and if there is a need to constantly display information to the user, then ScreenBlank .

Source: https://habr.com/ru/post/413389/


All Articles