From 2d4201817bb0baac0e92d1b859bb758619f264ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Burak=20Han=C3=A7erli?= <burak.hancerli@qt.io>
Date: Mon, 25 Nov 2024 15:29:10 +0000
Subject: [PATCH] * add: option to prevent device from sleeping * fix: UDP
 broadcast timer was not started * fix: suppress the error caused by the
 debuggable package after upgrading build tools * cicd: update to Qt 6.8.0 and
 Android Build Tools 34.0.0 * chore: move the package name from manifest XML
 to CMake (it was causing warnings during the build)

---
 cicd/gitlab-ci.yml                    |  4 +++-
 cicd/stages/build.yml                 |  4 ++--
 cicd/stages/test.yml                  |  7 +++++++
 src/CMakeLists.txt                    | 13 ++++++++-----
 src/SettingsPage.qml                  |  9 +++++++++
 src/android/AndroidManifest.xml.in    |  2 +-
 src/backend/backend.cpp               | 26 ++++++++++++++++++++++++++
 src/backend/backend.h                 |  4 ++++
 src/backend/dsconnector/dsmanager.cpp |  6 ++++++
 src/backend/settings.cpp              | 11 +++++++++++
 src/backend/settings.h                |  2 ++
 tests/CMakeLists.txt                  |  9 ++++-----
 tests/android/AndroidManifest.xml     |  1 -
 tests/scripts/run_test.sh             | 12 ++++++------
 14 files changed, 89 insertions(+), 21 deletions(-)

diff --git a/cicd/gitlab-ci.yml b/cicd/gitlab-ci.yml
index 293b389..d7c2153 100644
--- a/cicd/gitlab-ci.yml
+++ b/cicd/gitlab-ci.yml
@@ -1,6 +1,8 @@
 variables:
-  QDS_CI_QT_VERSION: "6.7.3"
+  QDS_CI_QT_VERSION: "6.8.0"
   QDS_CI_ARTIFACTS_PATH: "${CI_PROJECT_DIR}/artifacts"
+  QDS_CI_ANDROID_SDK_VERSION: "34.0.0"
+  QDS_CI_SKIP_TESTS: "true"
   DEBIAN_FRONTEND: non-interactive
   GIT_SUBMODULE_STRATEGY: recursive
 
diff --git a/cicd/stages/build.yml b/cicd/stages/build.yml
index 0398e84..cd84e57 100644
--- a/cicd/stages/build.yml
+++ b/cicd/stages/build.yml
@@ -45,8 +45,8 @@
 .copy-and-sign-apks: &copy-and-sign-apks
   - cp -r ${QDS_CI_JOB_BUILD_PATH}/src/android-build/build/outputs/apk/release/* ${QDS_CI_JOB_ARTIFACTS_PATH_APP}
   - cp -r ${QDS_CI_JOB_BUILD_PATH}/tests/android-build/build/outputs/apk/release/* ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}
-  - echo ${QDS_VAR_PASS} | ${DOCKER_ENV_ANDROID_SDK_ROOT}/build-tools/30.0.3/apksigner sign -verbose -ks ${CI_PROJECT_DIR}/cicd/android/android_release.keystore -out ${QDS_CI_JOB_ARTIFACTS_PATH_APP}/android-build-release.apk ${QDS_CI_JOB_ARTIFACTS_PATH_APP}/android-build-release-unsigned.apk
-  - echo ${QDS_VAR_PASS} | ${DOCKER_ENV_ANDROID_SDK_ROOT}/build-tools/30.0.3/apksigner sign -verbose -ks ${CI_PROJECT_DIR}/cicd/android/android_release.keystore -out ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}/android-build-release.apk ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}/android-build-release-unsigned.apk
+  - echo ${QDS_VAR_PASS} | ${DOCKER_ENV_ANDROID_SDK_ROOT}/build-tools/${QDS_CI_ANDROID_SDK_VERSION}/apksigner sign -verbose -ks ${CI_PROJECT_DIR}/cicd/android/android_release.keystore -out ${QDS_CI_JOB_ARTIFACTS_PATH_APP}/android-build-release.apk ${QDS_CI_JOB_ARTIFACTS_PATH_APP}/android-build-release-unsigned.apk
+  - echo ${QDS_VAR_PASS} | ${DOCKER_ENV_ANDROID_SDK_ROOT}/build-tools/${QDS_CI_ANDROID_SDK_VERSION}/apksigner sign -verbose -ks ${CI_PROJECT_DIR}/cicd/android/android_release.keystore -out ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}/android-build-release.apk ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}/android-build-release-unsigned.apk
   - rm -f ${QDS_CI_JOB_ARTIFACTS_PATH_APP}/android-build-release-unsigned.apk ${QDS_CI_JOB_ARTIFACTS_PATH_TEST}/android-build-release-unsigned.apk
 
 .copy-and-sign-aab: &copy-and-sign-aab
diff --git a/cicd/stages/test.yml b/cicd/stages/test.yml
index ceb5c5c..b6f63a4 100644
--- a/cicd/stages/test.yml
+++ b/cicd/stages/test.yml
@@ -12,6 +12,13 @@ test-x86_64:
     GIT_SUBMODULE_STRATEGY: none
     QDS_CI_JOB_TEST_RESULTS_PATH: ${CI_PROJECT_DIR}/test
   script:
+    - |
+      if [[ ${QDS_CI_SKIP_TESTS} == "false" ]]; then
+        echo "Running tests";
+      else
+        echo "Skipping tests";
+        exit 0;
+      fi
     - |
       export ANDROID_SDK_ROOT=/opt/android
       export PATH=$PATH:${ANDROID_SDK_ROOT}/cmdline-tools/latest/bin/
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1b0744a..21e6ee6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -76,13 +76,16 @@ target_include_directories(qtuiviewerlib PUBLIC
     ${CMAKE_CURRENT_SOURCE_DIR}
 )
 
-set_property(TARGET ${PROJECT_NAME}
-    APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
+set_property(TARGET qtuiviewerlib
+    APPEND PROPERTY QT_ANDROID_PACKAGE_NAME "io.qt.qtdesignviewer"
 )
 
-set_property(TARGET ${PROJECT_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
-    ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
-    ${ANDROID_OPENSSL_PATH}/libssl_3.so
+set_target_properties(${PROJECT_NAME} PROPERTIES QT_ANDROID_PACKAGE_NAME "io.qt.qtdesignviewer")
+set_property(TARGET ${PROJECT_NAME}
+    APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
+    APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
+        ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
+        ${ANDROID_OPENSSL_PATH}/libssl_3.so
 )
 
 # this needs to be increased with every new release
diff --git a/src/SettingsPage.qml b/src/SettingsPage.qml
index ef97860..865b297 100644
--- a/src/SettingsPage.qml
+++ b/src/SettingsPage.qml
@@ -34,6 +34,15 @@ Flickable {
             onToggled: backend.setAutoScaleProject(checked)
         }
 
+        SwitchSettingsItem {
+            Layout.fillWidth: true
+            horizontalPadding: 20
+            text: qsTr("Keep screen on")
+            subText: qsTr("Prevents the device from going to sleep while the app is running")
+            checked: backend.keepScreenOn() ? Qt.Checked : Qt.Unchecked
+            onToggled: backend.setKeepScreenOn(checked)
+        }
+
         SettingsItem {
             Layout.fillWidth: true
             horizontalPadding: 20
diff --git a/src/android/AndroidManifest.xml.in b/src/android/AndroidManifest.xml.in
index 6640426..e9456e4 100644
--- a/src/android/AndroidManifest.xml.in
+++ b/src/android/AndroidManifest.xml.in
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer"
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     android:installLocation="auto" android:versionCode="@GOOGLE_PLAY_APP_VERSION@"
     android:versionName="@CMAKE_VAR_GIT_VERSION@">
     <!-- %%INSERT_PERMISSIONS -->
diff --git a/src/backend/backend.cpp b/src/backend/backend.cpp
index e23fab4..17c2976 100644
--- a/src/backend/backend.cpp
+++ b/src/backend/backend.cpp
@@ -26,6 +26,7 @@
 #include "backend.h"
 
 #include <QDesktopServices>
+#include <QJniObject>
 #include <QNetworkInterface>
 
 #include "logger.h"
@@ -36,6 +37,8 @@
 #define buildType "Release"
 #endif
 
+#define FLAG_KEEP_SCREEN_ON 0x00000080
+
 Backend::Backend(QObject *parent)
     : QObject(parent)
 {
@@ -87,6 +90,8 @@ Backend::Backend(QObject *parent)
     qDebug() << "-- Build ABI: " << QSysInfo::buildAbi();
     qDebug() << "-- Build CPU architecture: " << QSysInfo::buildCpuArchitecture();
     qDebug() << "-- Device unique ID: " << m_settings.deviceUuid();
+
+    setAndroidScreenOn(keepScreenOn());
 }
 
 Backend::~Backend()
@@ -248,6 +253,27 @@ void Backend::setAutoScaleProject(bool autoScaleProject)
     m_settings.setAutoScaleProject(autoScaleProject);
 }
 
+bool Backend::keepScreenOn() const
+{
+    return m_settings.keepScreenOn();
+}
+
+void Backend::setKeepScreenOn(bool keepScreenOn)
+{
+    m_settings.setKeepScreenOn(keepScreenOn);
+    setAndroidScreenOn(keepScreenOn);
+}
+
+void Backend::setAndroidScreenOn(bool on)
+{
+    QNativeInterface::QAndroidApplication::runOnAndroidMainThread([=]() {
+        QJniObject activity = QNativeInterface::QAndroidApplication::context();
+        QJniObject window = activity.callObjectMethod("getWindow", "()Landroid/view/Window;");
+        on ? window.callMethod<void>("addFlags", "(I)V", FLAG_KEEP_SCREEN_ON)
+           : window.callMethod<void>("clearFlags", "(I)V", FLAG_KEEP_SCREEN_ON);
+    });
+}
+
 QString Backend::lastDesignStudioIp() const
 {
     return m_dsManager ? m_dsManager->getDesignStudioIp({}) : QString();
diff --git a/src/backend/backend.h b/src/backend/backend.h
index fa90207..2114e6e 100644
--- a/src/backend/backend.h
+++ b/src/backend/backend.h
@@ -60,6 +60,7 @@ private:
 
     void initDsManager();
     void initProjectManager();
+    void setAndroidScreenOn(bool on);
 
     void runProject(const QString &id, const QByteArray &projectData);
 
@@ -87,6 +88,9 @@ public slots:
     bool autoScaleProject() const;
     void setAutoScaleProject(bool autoScaleProject);
 
+    bool keepScreenOn() const;
+    void setKeepScreenOn(bool keepScreenOn);
+
     QString lastDesignStudioIp() const;
 };
 
diff --git a/src/backend/dsconnector/dsmanager.cpp b/src/backend/dsconnector/dsmanager.cpp
index c0a4c32..7785c8f 100644
--- a/src/backend/dsconnector/dsmanager.cpp
+++ b/src/backend/dsconnector/dsmanager.cpp
@@ -41,7 +41,13 @@ void DesignStudioManager::init()
         const int port = 53452;
         udpSocket.writeDatagram(datagram, QHostAddress::LocalHost, port);
         udpSocket.writeDatagram(datagram, QHostAddress::Broadcast, port);
+        udpSocket.writeDatagram(datagram, QHostAddress::AnyIPv4, port);
+        udpSocket.writeDatagram(datagram, QHostAddress::AnyIPv6, port);
+        udpSocket.writeDatagram(datagram, QHostAddress::Any, port);
+        // this is useful for Android emulator
+        udpSocket.writeDatagram(datagram, QHostAddress("10.0.2.2"), port);
     });
+    m_discoveryTimer.start();
 }
 
 void DesignStudioManager::incomingConnection()
diff --git a/src/backend/settings.cpp b/src/backend/settings.cpp
index b192fc7..3e6eccf 100644
--- a/src/backend/settings.cpp
+++ b/src/backend/settings.cpp
@@ -81,6 +81,12 @@ void Settings::setDeviceUuid(const QString &deviceUuid)
     saveSettings();
 }
 
+void Settings::setKeepScreenOn(const bool &enabled)
+{
+    m_settings["keepScreenOn"] = enabled;
+    saveSettings();
+}
+
 QString Settings::deviceUuid() const
 {
     return m_settings["deviceUuid"].toString();
@@ -90,3 +96,8 @@ bool Settings::autoScaleProject() const
 {
     return m_settings["autoScale"].toBool();
 }
+
+bool Settings::keepScreenOn() const
+{
+    return m_settings["keepScreenOn"].toBool();
+}
diff --git a/src/backend/settings.h b/src/backend/settings.h
index b88309b..eb87bb2 100644
--- a/src/backend/settings.h
+++ b/src/backend/settings.h
@@ -12,9 +12,11 @@ public:
 
     void setAutoScaleProject(const bool &enabled);
     void setDeviceUuid(const QString &deviceUuid);
+    void setKeepScreenOn(const bool &enabled);
 
     bool autoScaleProject() const;
     QString deviceUuid() const;
+    bool keepScreenOn() const;
 
 private:
     QJsonObject m_settings;
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3e1c7b1..af81f22 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -16,11 +16,10 @@ target_link_libraries(
     qtuiviewerlib
 )
 
+set_target_properties(${TARGET_NAME} PROPERTIES QT_ANDROID_PACKAGE_NAME "io.qt.qtdesignviewer.test")
 set_property(TARGET ${TARGET_NAME}
     APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android
-)
-
-set_property(TARGET ${TARGET_NAME} PROPERTY QT_ANDROID_EXTRA_LIBS
-    ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
-    ${ANDROID_OPENSSL_PATH}/libssl_3.so
+    APPEND PROPERTY QT_ANDROID_EXTRA_LIBS
+        ${ANDROID_OPENSSL_PATH}/libcrypto_3.so
+        ${ANDROID_OPENSSL_PATH}/libssl_3.so
 )
diff --git a/tests/android/AndroidManifest.xml b/tests/android/AndroidManifest.xml
index 0af4173..294377b 100644
--- a/tests/android/AndroidManifest.xml
+++ b/tests/android/AndroidManifest.xml
@@ -1,6 +1,5 @@
 <?xml version="1.0"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="io.qt.qtdesignviewer.test"
     android:installLocation="auto" android:versionCode="1" android:versionName="1">
     <!-- %%INSERT_PERMISSIONS -->
     <!-- %%INSERT_FEATURES -->
diff --git a/tests/scripts/run_test.sh b/tests/scripts/run_test.sh
index 6015ffa..409d7aa 100755
--- a/tests/scripts/run_test.sh
+++ b/tests/scripts/run_test.sh
@@ -2,11 +2,11 @@
 # This script is used to run the test on the device and collect the logs and the test results.
 # Precondition: The device/emulator is connected/running and the test application is installed on it.
 
-adb shell "run-as io.qt.qtuiviewer.test rm -rf /data/data/io.qt.qtuiviewer.test/files/output.junitxml"
-adb shell am start -e applicationArguments "'-o output.junitxml,junitxml -v2'" -n io.qt.qtuiviewer.test/org.qtproject.qt.android.bindings.QtActivity
+adb shell "run-as io.qt.qtdesignviewer.test rm -rf /data/data/io.qt.qtdesignviewer.test/files/output.junitxml"
+adb shell am start -e applicationArguments "'-o output.junitxml,junitxml -v2'" -n io.qt.qtdesignviewer.test/org.qtproject.qt.android.bindings.QtActivity
 
 counter=0
-while [ -z "$(adb shell pidof -s io.qt.qtuiviewer.test)" ]; do
+while [ -z "$(adb shell pidof -s io.qt.qtdesignviewer.test)" ]; do
     echo "Waiting for test to start"
     sleep 0.1
     counter=$((counter + 1))
@@ -16,11 +16,11 @@ while [ -z "$(adb shell pidof -s io.qt.qtuiviewer.test)" ]; do
     fi
 done
 
-PID_OF_TEST=$(adb shell pidof -s io.qt.qtuiviewer.test)
+PID_OF_TEST=$(adb shell pidof -s io.qt.qtdesignviewer.test)
 echo "PID of test: ${PID_OF_TEST}"
 
 counter=0
-while [ -n "$(adb shell pidof -s io.qt.qtuiviewer.test)" ]; do
+while [ -n "$(adb shell pidof -s io.qt.qtdesignviewer.test)" ]; do
     echo "Waiting for test to finish. Elapsed time: $counter seconds"
     sleep 1
     counter=$((counter + 1))
@@ -32,4 +32,4 @@ done
 
 adb logcat -d --pid=${PID_OF_TEST}
 adb logcat -d --pid=${PID_OF_TEST} >logcat.txt
-adb shell "run-as io.qt.qtuiviewer.test cat /data/data/io.qt.qtuiviewer.test/files/output.junitxml" >output.junit.xml
+adb shell "run-as io.qt.qtdesignviewer.test cat /data/data/io.qt.qtdesignviewer.test/files/output.junitxml" >output.junit.xml
-- 
GitLab