Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Can you suggest code to get my Android Client app to continue working when minimized?



  • Hello, I am trying to create apps that automatically synchronize clipboards between Android phones and linux computers that are on the same network. The server and client software I did for the linux computer work fine. I will add windows later and make it available for free.

    My problem is with the Android app on the phone. This app sends clipboard content to the serveur when phone clipboard has changed. It also update the phone clipboard when it receives a new one from the server. The problem is nothing works when the app is minimized. Re-opening the app after the phone clipboard has changed or for getting the clipboard from the linux computer becomes mandatory and annoying. I know it is a restriction from Android not to overload Phone's CPU.

    I have searched the internet to find a solution but found this is a very difficult problem for a newbie like me. Threads, processes, services, etc are no easy concepts.

    Can anyone give me a start on how to modify my code to resolve this problem?

    I am developing on Qt in C++ for Android.

    Thanks in advance, Marc.

    Here is all my code:

    the .h

    #ifndef FENCLIENT_H
    #define FENCLIENT_H
    
    #include <QtWidgets>
    #include <QtNetwork>
    #include <QClipboard>
    #include "ui_fenclient.h"
    
    
    class FenClient : public QWidget, private Ui::FenClient
    {
        Q_OBJECT
    
        public:
            FenClient();
    
        private slots:
            void on_boutonConnexion_clicked();
            void on_boutonEnvoyer_clicked();
            void on_message_returnPressed();
            void donneesRecues();
            void connecte();
            void deconnecte();
            void erreurSocket(QAbstractSocket::SocketError erreur);
            void copiage();
    
        private:
            QTcpSocket *socket; // Représente le serveur
            quint16 tailleMessage;
            QClipboard *clipBoard;
    
    };
    
    
    #endif // FENCLIENT_H
    

    the .cpp

    #include "fenclient.h"
    
    using namespace std;
    #include<iostream>
    #include <ostream>//sinon cout marche pas
    
    FenClient::FenClient()
    {
        setupUi(this);
    
        socket = new QTcpSocket(this);
        connect(socket, SIGNAL(readyRead()), this, SLOT(donneesRecues()));
        connect(socket, SIGNAL(connected()), this, SLOT(connecte()));
        connect(socket, SIGNAL(disconnected()), this, SLOT(deconnecte()));
        connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(erreurSocket(QAbstractSocket::SocketError)));
    
        tailleMessage = 0;
    
        clipBoard = QGuiApplication::clipboard();//Ca a été long mais il me faut ca...pas tout compris
        //QClipboard *clipBoard = QGuiApplication::clipboard();// Bad because it shadows FenClient::clipBoard
        connect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));//serait mieux connect(clipBoard, &QClipboard::dataChanged, this, &FenClient::copiage);
    }
    
    // Tentative de connexion au serveur
    void FenClient::on_boutonConnexion_clicked()
    {
        // On annonce sur la fenêtre qu'on est en train de se connecter
        listeMessages->append(tr("<em>Tentative de connexion en cours...</em>"));
        boutonConnexion->setEnabled(false);
    
        socket->abort(); // On désactive les connexions précédentes s'il y en a
        socket->connectToHost(serveurIP->text(), serveurPort->value()); // On se connecte au serveur demandé
    }
    
    // Envoi d'un message au serveur
    void FenClient::on_boutonEnvoyer_clicked()
    {
        QByteArray paquet;
        QDataStream out(&paquet, QIODevice::WriteOnly);
    
        // On prépare le paquet à envoyer
        QString messageAEnvoyer = message->text();//on enlève tr("<strong>") + pseudo->text() +tr("</strong> : ") +
    
        out << (quint16) 0;
        out << messageAEnvoyer;
        out.device()->seek(0);
        out << (quint16) (paquet.size() - sizeof(quint16));
    
        socket->write(paquet); // On envoie le paquet
    
        message->clear(); // On vide la zone d'écriture du message
        message->setFocus(); // Et on remet le curseur à l'intérieur
    }
    
    // Appuyer sur la touche Entrée a le même effet que cliquer sur le bouton "Envoyer"
    void FenClient::on_message_returnPressed()
    {
        on_boutonEnvoyer_clicked();
    }
    
    // On a reçu un paquet (ou un sous-paquet)
    void FenClient::donneesRecues()
    {
        /* Même principe que lorsque le serveur reçoit un paquet :
        On essaie de récupérer la taille du message
        Une fois qu'on l'a, on attend d'avoir reçu le message entier (en se basant sur la taille annoncée tailleMessage)
        */
        QDataStream in(socket);
    
        if (tailleMessage == 0)
        {
            if (socket->bytesAvailable() < (int)sizeof(quint16))
                 return;
    
            in >> tailleMessage;
        }
    
        if (socket->bytesAvailable() < tailleMessage)
            return;
    
    
        // Si on arrive jusqu'à cette ligne, on peut récupérer le message entier
        QString messageRecu;
        in >> messageRecu;
    
        // On affiche le message sur la zone de Chat
        listeMessages->append(messageRecu);
    
        //clipBoard->disconnect();
        //disconnect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));
        //on met dans le clipBoard
        //QObject::disconnect(clipBoard);//cela cause un changement du clipboard et ca marche pas
        cout << "Avant " << endl;
        QString temporaire=clipBoard->text();
        if (messageRecu == temporaire)
    
        {
        }
        else
            {
            clipBoard->QObject::blockSignals(true);
            clipBoard->setText(messageRecu);
            clipBoard->QObject::blockSignals(false);
            }
        //connect(clipBoard, SIGNAL(dataChanged()), this, SLOT(copiage()));
        cout << "Après " << endl;
    
        // On remet la taille du message à 0 pour pouvoir recevoir de futurs messages
        tailleMessage = 0;
    }
    
    // Ce slot est appelé lorsque la connexion au serveur a réussi
    void FenClient::connecte()
    {
        listeMessages->append(tr("<em>Connexion réussie !</em>"));
        boutonConnexion->setEnabled(true);
    }
    
    // Ce slot est appelé lorsqu'on est déconnecté du serveur
    void FenClient::deconnecte()
    {
        listeMessages->append(tr("<em>Déconnecté du serveur</em>"));
    }
    
    // Ce slot est appelé lorsqu'on que le presse-papiers change
    void FenClient::copiage()
    {   cout << "Copiage= " << endl;
    
        QString textCopie;
    
        //clipBoard->blockSignals(true);
        textCopie = clipBoard->text();
        //clipBoard->blockSignals(false);
    
        QByteArray paquet;
        QDataStream out(&paquet, QIODevice::WriteOnly);
    
        // On prépare le paquet à envoyer
        QString messageAEnvoyer = textCopie;
    
        out << (quint16) 0;
        out << messageAEnvoyer;
        out.device()->seek(0);
        out << (quint16) (paquet.size() - sizeof(quint16));
    
        socket->write(paquet); // On envoie le paquet
    
        //message->clear(); // On vide la zone d'écriture du message
        //message->setFocus(); // Et on remet le curseur à l'intérieur
    
    }
    
    
    
    // Ce slot est appelé lorsqu'il y a une erreur
    void FenClient::erreurSocket(QAbstractSocket::SocketError erreur)
    {
        switch(erreur) // On affiche un message différent selon l'erreur qu'on nous indique
        {
            case QAbstractSocket::HostNotFoundError:
                listeMessages->append(tr("<em>ERREUR : le serveur n'a pas pu être trouvé. Vérifiez l'IP et le port.</em>"));
                break;
            case QAbstractSocket::ConnectionRefusedError:
                listeMessages->append(tr("<em>ERREUR : le serveur a refusé la connexion. Vérifiez si le programme \"serveur\" a bien été lancé. Vérifiez aussi l'IP et le port.</em>"));
                break;
            case QAbstractSocket::RemoteHostClosedError:
                listeMessages->append(tr("<em>ERREUR : le serveur a coupé la connexion.</em>"));
                break;
            default:
                listeMessages->append(tr("<em>ERREUR : ") + socket->errorString() + tr("</em>"));
        }
    
        boutonConnexion->setEnabled(true);
    }
    

    the main.cpp

    #include <QApplication>
    #include "fenclient.h"
    
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
    
        FenClient fenetre;
        fenetre.show();
    
        return app.exec();
    }
    
    

  • Lifetime Qt Champion

    @SMEG You will need to create a background service, there is no other way.
    See https://doc.qt.io/qt-5/android-services.html



  • @jsulm

    Hello,
    Following you recommendation, I was able to add an Android manifest file to my project. Now I am trying to follow the steps described here: https://www.kdab.com/qt-android-create-android-service-using-qt/
    but I block right at the first step!
    It is not clear to me where the author is asking to put these lines of code:

    package com.kdab.training;
    import org.qtproject.qt5.android.bindings.QtService;
    public class MyService extends QtService
    {
    }
    

    Can you tell me where these lines should go?
    It seems the project needs a java file somewhere but I have no clue about where.
    Thanks for your help.


  • Lifetime Qt Champion

    @SMEG In the article you link there is a link to whole source code of that example project: https://github.com/KDAB/android


Log in to reply