QtQuickView statuslistener CI tests
This test adds basic loading status tests for QtQuickView on Android. The test uses a primary QtQuickView which has the TestCases, and a Communicator QML_ELEMENT C++ class to load other QML files into a secondary QtQuickView contained in the hosting layout. The hosting activity listens to QtQuickView status changed signals, and sends those directly to the Communicator object, which emits a signal with the status information to the TestCases. Task-number: QTBUG-133439 Change-Id: I01a3a1dc3124036d8290a248b9b2d1bb4010033d Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
58272fe764
commit
e4971b51f8
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(basic)
|
||||
add_subdirectory(signallistener)
|
||||
add_subdirectory(statuslistener)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -0,0 +1,34 @@
|
|||
<?xml version="1.0"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.qtproject.qt.android.qtquickview_statuslistener"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="-- %%INSERT_VERSION_CODE%% --"
|
||||
android:versionName="-- %%INSERT_VERSION_NAME%% --">
|
||||
|
||||
<supports-screens
|
||||
android:anyDensity="true"
|
||||
android:largeScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:smallScreens="true" />
|
||||
|
||||
<application
|
||||
android:name="org.qtproject.qt.android.bindings.QtApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:label="-- %%INSERT_APP_NAME%% --"
|
||||
android:icon="-- %%INSERT_APP_ICON%% --"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowBackup="true"
|
||||
android:fullBackupOnly="false">
|
||||
<activity
|
||||
android:name="org.qtproject.qt.android.qtquickview_statuslistener.TestActivity"
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="unspecified"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -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(",")
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
|
@ -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.
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TestActivity>("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<void>("loadQtQuickView", qmlUri);
|
||||
}
|
||||
|
||||
void TestActivityCommunicator::jni_onQtQuickViewStatusChanged(JNIEnv *, jclass, jint status)
|
||||
{
|
||||
Q_ASSERT(s_instance);
|
||||
emit s_instance->qtQuickViewStatusChanged(status);
|
||||
}
|
|
@ -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 <QtCore/qobject.h>
|
||||
#include <QtQml/qqmlengine.h>
|
||||
#include <QtCore/qjnitypes.h>
|
||||
|
||||
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
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (C) 2025 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
#include <QtQuickTest/6.10.0/QtQuickTest/private/quickforandroidtest_p.h>
|
||||
|
||||
QUICK_FOR_ANDROID_TEST_MAIN("tst_qtquickview_statuslistener")
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/qmlFrame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/qmlFrame2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,15 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
|
@ -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.
|
Loading…
Reference in New Issue