diff --git a/tests/auto/qtquickview/CMakeLists.txt b/tests/auto/qtquickview/CMakeLists.txt index 81b76a27f1..aeec982df8 100644 --- a/tests/auto/qtquickview/CMakeLists.txt +++ b/tests/auto/qtquickview/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(basic) add_subdirectory(signallistener) +add_subdirectory(statuslistener) diff --git a/tests/auto/qtquickview/statuslistener/CMakeLists.txt b/tests/auto/qtquickview/statuslistener/CMakeLists.txt new file mode 100644 index 0000000000..3577d5e275 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/CMakeLists.txt @@ -0,0 +1,24 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.22) + project(tst_qtquickview_statuslistener LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) + find_package(Qt6 REQUIRED COMPONENTS Quick) +endif() + +qt_standard_project_setup() + +# Dummy test - just so this can be detected by ctest. +# Actual test implementation is under ${CMAKE_CURRENT_SOURCE_DIR}/android/qml/ +# Add a source file, otherwise no test target is actually created. +qt_internal_add_test(tst_qtquickview_statuslistener + SOURCES + empty.cpp +) + +set_target_properties(tst_qtquickview_statuslistener + PROPERTIES + QT_ANDROID_PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android +) diff --git a/tests/auto/qtquickview/statuslistener/android/AndroidManifest.xml b/tests/auto/qtquickview/statuslistener/android/AndroidManifest.xml new file mode 100644 index 0000000000..bc5a92406b --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/tests/auto/qtquickview/statuslistener/android/build.gradle b/tests/auto/qtquickview/statuslistener/android/build.gradle new file mode 100644 index 0000000000..29391c9674 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/build.gradle @@ -0,0 +1,67 @@ +plugins { + id 'com.android.application' version '8.3.0' + id 'org.qtproject.qt.gradleplugin' version '1.2' +} + +def home = System.properties['user.home'] +def ndkPath = System.getenv('ANDROID_NDK_ROOT') +QtBuild { + qtPath = file(home + '/work/install') + projectPath = file('qml/') + qtKitDir = file(home + '/work/install/target') + extraCMakeArguments = ['-DANDROID_NDK_ROOT=' + ndkPath] +} + +android { + /******************************************************* + * The following variables: + * - androidBuildToolsVersion, + * - androidCompileSdkVersion + * - qtAndroidDir - holds the path to qt android files + * needed to build any Qt application + * on Android. + * - qtGradlePluginType - whether to build an app or a library + * + * are defined in gradle.properties file. This file is + * updated by QtCreator and androiddeployqt tools. + * Changing them manually might break the compilation! + *******************************************************/ + + namespace androidPackageName + compileSdkVersion androidCompileSdkVersion + buildToolsVersion androidBuildToolsVersion + ndkVersion androidNdkVersion + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] + res.srcDirs = [qtAndroidDir + '/res', 'res'] + } + } + + tasks.withType(JavaCompile) { + options.incremental = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + lintOptions { + abortOnError false + } + + // Do not compress Qt binary resources file + aaptOptions { + noCompress 'rcc' + } + + defaultConfig { + resConfig "en" + minSdkVersion qtMinSdkVersion + targetSdkVersion qtTargetSdkVersion + ndk.abiFilters = qtTargetAbiList.split(",") + } +} diff --git a/tests/auto/qtquickview/statuslistener/android/qml/CMakeLists.txt b/tests/auto/qtquickview/statuslistener/android/qml/CMakeLists.txt new file mode 100644 index 0000000000..fd5ec46f72 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/CMakeLists.txt @@ -0,0 +1,39 @@ +# Copyright (C) 2025 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.22) + +project(tst_qtquickview_statuslistener_qml LANGUAGES CXX) + +find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +find_package(Qt6 REQUIRED COMPONENTS Quick QuickTest QuickTestPrivate) + +qt_standard_project_setup() + +qt_add_executable(tst_qtquickview_statuslistener_qml + tst_qtquickview.cpp) + +set_source_files_properties(TestView.qml PROPERTIES QT_QML_GENERATE_JAVA_CLASS TRUE) +set_source_files_properties(Invalid.qml PROPERTIES + QT_QML_SKIP_QMLDIR_ENTRY TRUE + QT_QML_SKIP_QMLLINT TRUE + QT_QML_SKIP_CACHEGEN TRUE) + +qt_add_qml_module(tst_qtquickview_statuslistener_qml + URI TestViewModule + VERSION 1.0 + QML_FILES + Valid.qml + Invalid.qml + TestView.qml + SOURCES + testactivitycommunicator.h testactivitycommunicator.cpp +) + +set_target_properties(tst_qtquickview_statuslistener_qml + PROPERTIES + QT_ANDROID_PACKAGE_NAME "org.qtproject.qt.android.tst_qtquickview_statuslistener_qml") + +target_link_libraries(tst_qtquickview_statuslistener_qml PRIVATE + Qt::Core Qt::Quick Qt::QuickTest Qt::QuickTestPrivate +) diff --git a/tests/auto/qtquickview/statuslistener/android/qml/Invalid.qml b/tests/auto/qtquickview/statuslistener/android/qml/Invalid.qml new file mode 100644 index 0000000000..61e12178ee --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/Invalid.qml @@ -0,0 +1,9 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick + +Item { + id: root + Hello, this is some text in the middle of your otherwise nicely formed QML file. +} diff --git a/tests/auto/qtquickview/statuslistener/android/qml/TestView.qml b/tests/auto/qtquickview/statuslistener/android/qml/TestView.qml new file mode 100644 index 0000000000..a34b8318c5 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/TestView.qml @@ -0,0 +1,45 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtTest + +Item { + id: root + + TestActivityCommunicator { + id: communicator + } + + SignalSpy { + id: qtQuickViewStatusSpy + target: communicator + signalName: "qtQuickViewStatusChanged" + } + + TestCase { + id: validQmlFile + name: "Valid QML file" + + function test_valid() { + qtQuickViewStatusSpy.clear() + communicator.loadQtQuickView("qrc:/TestViewModule/Valid.qml"); + qtQuickViewStatusSpy.wait() + compare(qtQuickViewStatusSpy.count, 1) + compare(qtQuickViewStatusSpy.signalArguments[0][0], 1) + } + } + + TestCase { + id: invalidQmlFile + name: "Invalid QML file" + + function test_invalid() { + qtQuickViewStatusSpy.clear() + communicator.loadQtQuickView("qrc:/TestViewModule/Invalid.qml"); + qtQuickViewStatusSpy.wait() + compare(qtQuickViewStatusSpy.count, 1) + compare(qtQuickViewStatusSpy.signalArguments[0][0], 3) + } + } +} diff --git a/tests/auto/qtquickview/statuslistener/android/qml/Valid.qml b/tests/auto/qtquickview/statuslistener/android/qml/Valid.qml new file mode 100644 index 0000000000..bbd1e95e03 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/Valid.qml @@ -0,0 +1,20 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +import QtQuick +import QtTest + +Item { + id: root + + Rectangle { + anchors.fill: parent + color: "#00FF00" + + Text { + anchors.centerIn: parent + text: "QML" + color: "black" + } + } +} diff --git a/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.cpp b/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.cpp new file mode 100644 index 0000000000..b02fb40e70 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "testactivitycommunicator.h" + +using namespace QtJniTypes; + +static TestActivityCommunicator *s_instance; + +TestActivityCommunicator::TestActivityCommunicator(QObject *parent) + : QObject{ parent }, + m_activity(TestActivity::callStaticMethod("instance")) +{ + s_instance = this; + TestActivity::registerNativeMethods({ + Q_JNI_NATIVE_SCOPED_METHOD(jni_onQtQuickViewStatusChanged, TestActivityCommunicator) + }); +} + +TestActivityCommunicator::~TestActivityCommunicator() +{ + s_instance = nullptr; +} + +TestActivityCommunicator *TestActivityCommunicator::instance() +{ + return s_instance; +} + +void TestActivityCommunicator::loadQtQuickView(const QString &qmlUri) +{ + m_activity.callMethod("loadQtQuickView", qmlUri); +} + +void TestActivityCommunicator::jni_onQtQuickViewStatusChanged(JNIEnv *, jclass, jint status) +{ + Q_ASSERT(s_instance); + emit s_instance->qtQuickViewStatusChanged(status); +} diff --git a/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.h b/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.h new file mode 100644 index 0000000000..769a3b7604 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/testactivitycommunicator.h @@ -0,0 +1,37 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef TESTACTIVITYCOMMUNICATOR_H +#define TESTACTIVITYCOMMUNICATOR_H + +#include +#include +#include + +Q_DECLARE_JNI_CLASS(TestActivity, + "org/qtproject/qt/android/qtquickview_statuslistener/TestActivity") + +class TestActivityCommunicator : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + explicit TestActivityCommunicator(QObject *parent = nullptr); + ~TestActivityCommunicator(); + + static TestActivityCommunicator *instance(); + +public slots: + void loadQtQuickView(const QString &qmlUri); + +signals: + void qtQuickViewStatusChanged(int status); + +private: + QtJniTypes::TestActivity m_activity; + + static void jni_onQtQuickViewStatusChanged(JNIEnv *, jclass, jint status); + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(jni_onQtQuickViewStatusChanged) +}; + +#endif // TESTACTIVITYCOMMUNICATOR_H diff --git a/tests/auto/qtquickview/statuslistener/android/qml/tst_qtquickview.cpp b/tests/auto/qtquickview/statuslistener/android/qml/tst_qtquickview.cpp new file mode 100644 index 0000000000..8f29983fb2 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/qml/tst_qtquickview.cpp @@ -0,0 +1,6 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include + +QUICK_FOR_ANDROID_TEST_MAIN("tst_qtquickview_statuslistener") diff --git a/tests/auto/qtquickview/statuslistener/android/res/layout/main.xml b/tests/auto/qtquickview/statuslistener/android/res/layout/main.xml new file mode 100644 index 0000000000..6832617b66 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/res/layout/main.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + diff --git a/tests/auto/qtquickview/statuslistener/android/settings.gradle b/tests/auto/qtquickview/statuslistener/android/settings.gradle new file mode 100644 index 0000000000..a6b2c64381 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/settings.gradle @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} diff --git a/tests/auto/qtquickview/statuslistener/android/src/org/qtproject/qt/android/qtquickview_statuslistener/TestActivity.java b/tests/auto/qtquickview/statuslistener/android/src/org/qtproject/qt/android/qtquickview_statuslistener/TestActivity.java new file mode 100644 index 0000000000..69764f9603 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/android/src/org/qtproject/qt/android/qtquickview_statuslistener/TestActivity.java @@ -0,0 +1,65 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +package org.qtproject.qt.android.qtquickview_statuslistener; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.FrameLayout; +import org.qtproject.qt.android.QtQmlStatus; +import org.qtproject.qt.android.QtQmlStatusChangeListener; +import org.qtproject.qt.android.QtQuickView; +import org.qtproject.qt.android.QtQuickViewContent; +import org.qtproject.qt.android.tst_qtquickview_statuslistener_qml.TestViewModule.TestView; + +public class TestActivity extends Activity implements QtQmlStatusChangeListener +{ + native void jni_onQtQuickViewStatusChanged(int status); + + private final TestView m_testView = new TestView(); + private QtQuickView m_quickView; + private QtQuickView m_testingView; + private static TestActivity m_instance; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + m_instance = this; + m_quickView = new QtQuickView(this); + + final FrameLayout qmlFrame = findViewById(R.id.qmlFrame); + final ViewGroup.LayoutParams params = new FrameLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + qmlFrame.addView(m_quickView, params); + m_quickView.loadContent(m_testView); + } + + public void loadQtQuickView(String qmlUri) + { + runOnUiThread(() -> { + FrameLayout parent = findViewById(R.id.qmlFrame2); + if (m_testingView != null) + parent.removeView(m_testingView); + + m_testingView = new QtQuickView(this, qmlUri, "tst_qtquickview_statuslistener_qml"); + m_testingView.setStatusChangeListener(new QtQmlStatusChangeListener() { + @Override + public void onStatusChanged(QtQmlStatus status) { + jni_onQtQuickViewStatusChanged(status.ordinal()); + } + }); + parent.addView(m_testingView, + new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + }); + } + + public TestView testView() { return m_testView; } + + public static TestActivity instance() { return m_instance; } +} diff --git a/tests/auto/qtquickview/statuslistener/empty.cpp b/tests/auto/qtquickview/statuslistener/empty.cpp new file mode 100644 index 0000000000..b8a0b724c2 --- /dev/null +++ b/tests/auto/qtquickview/statuslistener/empty.cpp @@ -0,0 +1,4 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +// Left empty on purpose.