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(); }
-
@SMEG You will need to create a background service, there is no other way.
See https://doc.qt.io/qt-5/android-services.html -
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. -
@SMEG In the article you link there is a link to whole source code of that example project: https://github.com/KDAB/android