aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/jar/org/qtproject/qt/android
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/jar/org/qtproject/qt/android')
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java105
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java35
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java30
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtModelIndex.java42
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java206
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java49
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java17
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.java304
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc277
-rw-r--r--src/quick/jar/org/qtproject/qt/android/QtSignalListener.java17
10 files changed, 1082 insertions, 0 deletions
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
new file mode 100644
index 0000000000..40c635235f
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModel.java
@@ -0,0 +1,105 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractItemModel
+{
+ public QtAbstractItemModel(){};
+ public abstract int columnCount(QtModelIndex parent);
+ public abstract Object data(QtModelIndex index, int role);
+ public abstract QtModelIndex index(int row, int column, QtModelIndex parent);
+ public abstract QtModelIndex parent(QtModelIndex index);
+ public abstract int rowCount(QtModelIndex parent);
+
+ public native boolean canFetchMore(QtModelIndex parent);
+ public native void fetchMore(QtModelIndex parent);
+ public native boolean hasChildren(QtModelIndex parent);
+ public native boolean hasIndex(int row, int column, QtModelIndex parent);
+
+ public HashMap<Integer, String> roleNames()
+ {
+ return (HashMap<Integer, String>)jni_roleNames();
+ }
+
+ public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_sibling(row, column, parent);
+ }
+
+ protected final void beginInsertColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertColumns(parent, first, last);
+ }
+
+ protected final void beginInsertRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginInsertRows(parent, first, last);
+ }
+ protected final boolean beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveColumns(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final boolean beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild)
+ {
+ return jni_beginMoveRows(sourceParent, sourceFirst, sourceLast, destinationParent,
+ destinationChild);
+ }
+ protected final void beginRemoveColumns(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveColumns(parent, first, last);
+ }
+ protected final void beginRemoveRows(QtModelIndex parent, int first, int last)
+ {
+ jni_beginRemoveRows(parent, first, last);
+ }
+ protected final void beginResetModel() { jni_beginResetModel(); }
+
+ protected final QtModelIndex createIndex(int row, int column, long id)
+ {
+ return (QtModelIndex)jni_createIndex(row, column, id);
+ }
+ protected final void endInsertColumns() { jni_endInsertColumns(); }
+ protected final void endInsertRows() { jni_endInsertRows(); }
+ protected final void endMoveColumns() { jni_endMoveColumns(); }
+ protected final void endMoveRows() { jni_endMoveRows(); }
+ protected final void endRemoveColumns() { jni_endRemoveColumns(); }
+ protected final void endRemoveRows() { jni_endRemoveRows(); }
+ protected final void endResetModel() { jni_endResetModel(); }
+
+ private native void jni_beginInsertColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginInsertRows(QtModelIndex parent, int first, int last);
+ private native boolean jni_beginMoveColumns(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native boolean jni_beginMoveRows(QtModelIndex sourceParent, int sourceFirst,
+ int sourceLast, QtModelIndex destinationParent,
+ int destinationChild);
+ private native void jni_beginRemoveColumns(QtModelIndex parent, int first, int last);
+ private native void jni_beginRemoveRows(QtModelIndex parent, int first, int last);
+ private native void jni_beginResetModel();
+ private native Object jni_createIndex(int row, int column, long id);
+ private native void jni_endInsertColumns();
+ private native void jni_endInsertRows();
+ private native void jni_endMoveColumns();
+ private native void jni_endMoveRows();
+ private native void jni_endRemoveColumns();
+ private native void jni_endRemoveRows();
+ private native void jni_endResetModel();
+ private native Object jni_roleNames();
+ private native Object jni_sibling(int row, int column, QtModelIndex parent);
+
+ private long m_nativeReference = 0;
+ private QtAbstractItemModel(long nativeReference) { m_nativeReference = nativeReference; }
+ private void detachFromNative() { m_nativeReference = 0; };
+ private long nativeReference() { return m_nativeReference; }
+ private void setNativeReference(long nativeReference) { m_nativeReference = nativeReference; }
+ private static boolean instanceOf(Object obj) { return (obj instanceof QtAbstractItemModel); }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
new file mode 100644
index 0000000000..6432a3e12e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractItemModelProxy.java
@@ -0,0 +1,35 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+class QtAndroidItemModelProxy extends QtAbstractItemModel
+{
+ @Override public int columnCount(QtModelIndex parent) { return jni_columnCount(parent); };
+ @Override public Object data(QtModelIndex index, int role) { return jni_data(index, role); }
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return (QtModelIndex)jni_index(row, column, parent);
+ }
+ @Override public QtModelIndex parent(QtModelIndex index)
+ {
+ return (QtModelIndex)jni_parent(index);
+ }
+ @Override public int rowCount(QtModelIndex parent) { return jni_rowCount(parent); }
+
+ private native int jni_columnCount(QtModelIndex parent);
+ private native Object jni_data(QtModelIndex index, int role);
+ private native Object jni_index(int row, int column, QtModelIndex parent);
+ private native Object jni_parent(QtModelIndex index);
+ private native int jni_rowCount(QtModelIndex parent);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
new file mode 100644
index 0000000000..5a49caca9c
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtAbstractListModel.java
@@ -0,0 +1,30 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.util.HashMap;
+
+public abstract class QtAbstractListModel extends QtAbstractItemModel
+{
+ public QtAbstractListModel(){};
+
+ @Override public final int columnCount(QtModelIndex parent) { return parent.isValid() ? 0 : 1; }
+
+ @Override public QtModelIndex index(int row, int column, QtModelIndex parent)
+ {
+ return hasIndex(row, column, parent) ? createIndex(row, column, 0) : new QtModelIndex();
+ }
+
+ @Override public final QtModelIndex parent(QtModelIndex index) { return new QtModelIndex(); }
+
+ @Override public final boolean hasChildren(QtModelIndex parent)
+ {
+ return parent.isValid() ? false : (rowCount(new QtModelIndex()) > 0);
+ }
+
+ @Override public QtModelIndex sibling(int row, int column, QtModelIndex parent)
+ {
+ return index(row, column, new QtModelIndex());
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
new file mode 100644
index 0000000000..955c736ec4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtModelIndex.java
@@ -0,0 +1,42 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+public class QtModelIndex
+{
+ public QtModelIndex() { }
+ public int column() { return (int)m_privateData[1]; }
+ public native Object data(int role);
+ public native long internalId();
+ public native boolean isValid();
+ public native QtModelIndex parent();
+ public int row() { return (int)m_privateData[0]; }
+
+ private long[] m_privateData = { -1 /*row*/, -1 /*column*/, 0 /*internalId*/,
+ 0 /*modelReference*/ };
+ private QtModelIndex m_parent = null;
+ private QtModelIndex(int row, int column, long internalId, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = internalId;
+ m_privateData[3] = modelReference;
+ m_parent = null;
+ }
+ private QtModelIndex(int row, int column, QtModelIndex parent, long modelReference)
+ {
+ m_privateData[0] = row;
+ m_privateData[1] = column;
+ m_privateData[2] = 0;
+ m_privateData[3] = modelReference;
+ m_parent = parent;
+ }
+ private void detachFromNative()
+ {
+ m_privateData[0] = -1;
+ m_privateData[1] = -1;
+ m_privateData[2] = 0;
+ m_privateData[3] = 0;
+ };
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
new file mode 100644
index 0000000000..19d063762e
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlComponent.java
@@ -0,0 +1,206 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.HashSet;
+
+/**
+ * @Since 6.8
+ *
+ * The QtQmlComponent represents a QML component that can be loaded by a QtQuickView instance
+ * This abstract class should be extended to be used by a QtQuickView. It provides QtQuickView with
+ * essential information to load the QML component it represents.
+ * It also offers convenient methods for seamless interaction with the QtQuickView that loads it.
+ **/
+public abstract class QtQmlComponent
+{
+ private final static String TAG = "QtQmlComponent";
+
+ private WeakReference<QtQuickView> m_viewReference;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private HashSet<Integer> m_signalListenerIds = new HashSet<>();
+
+ /**
+ * Implement this to return the library name that this component belongs to.
+ **/
+ protected abstract String getLibraryName();
+ /**
+ * Implement this to return the module name that this component belongs to.
+ **/
+ protected abstract String getModuleName();
+ /**
+ * Implement this to return the qrc (Qt Resource) path of this QML component.
+ **/
+ protected abstract String getFilePath();
+
+ /**
+ * Sets a StatusChangeListener to listen to status changes.
+ * <p>
+ * @param listener an instance of a StatusChangeListener interface
+ **/
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
+ {
+ m_statusChangeListener = listener;
+ QtQuickView view = getQuickView();
+ if (view != null)
+ view.setStatusChangeListener(listener);
+ }
+
+ /**
+ * Gets the QtQuickView instance that has loaded this component.
+ * <p>
+ * @return Returns an instance of QtQuickView or null if this component is not loaded by any
+ * QtQuickView.
+ **/
+ protected QtQuickView getQuickView()
+ {
+ if (m_viewReference != null)
+ return m_viewReference.get();
+ return null;
+ }
+
+ /**
+ * Checks if this is currently attached to a QtQuickView instance
+ * <p>
+ * @return Returns true if this is attached to a QtQuickView instance, otherwise, returns false.
+ **/
+ protected boolean isViewAttached() { return getQuickView() != null; }
+
+ /**
+ * Attaches this to a QtQuickView instance.
+ **/
+ protected void attachView(QtQuickView view)
+ {
+ m_viewReference = new WeakReference<>(view);
+ if (view != null)
+ view.setStatusChangeListener(m_statusChangeListener);
+ }
+
+ /**
+ * Detaches this from the QtQuickView to which it has previously been attached. A call to this
+ * method will disconnect all signal listeners that have been connected before.
+ **/
+ protected void detachView()
+ {
+ QtQuickView view = getQuickView();
+ if (view != null) {
+ for (int signalListenerId : m_signalListenerIds)
+ view.disconnectSignalListener(signalListenerId);
+
+ view.setStatusChangeListener(null);
+ m_viewReference.clear();
+ if (m_statusChangeListener != null)
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.NULL);
+ }
+ }
+
+ /**
+ * Implement this to return more information about the QML Component.
+ * Default implementation returns an empty HashMap.
+ **/
+ protected HashMap<String, Object> attributes() { return new HashMap<>(); }
+
+ /**
+ * Sets the value of an existing property on the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool, and string. This function does not add
+ * properties to the QML root object if they do not exist but prints a warning.
+ * <p>
+ * @param propertyName the name of the existing QML property to set the value of
+ * @param value the value to set the property to QML's int, double/float,
+ bool or string
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ protected void setProperty(String propertyName, Object value)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot set property as the QQmlComponent is not loaded in a QtQuickView.");
+ return;
+ }
+ view.setProperty(propertyName, value);
+ }
+
+ /**
+ * Gets the value of an existing property of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool and string. If the property does not
+ * exist or the status of the QML component is anything other than
+ * {@link QtQuickView#STATUS_READY STATUS_READY}, this function will return null.
+ * <p>
+ * @param propertyName the name of the existing root object property
+ * @throws ClassCastException if the returned type cannot be cast to the requested type.
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ protected <T> T getProperty(String propertyName)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG, "Cannot get property as the QQmlComponent is not loaded in a QtQuickView.");
+ return null;
+ }
+ return view.<T>getProperty(propertyName);
+ }
+
+ /**
+ * Connects a SignalListener to a signal of the QML component if it has already been attached
+ * and loaded by a QtQuickView instance.
+ * <p>
+ * @param signalName the name of the root object signal
+ * @param argType the Class type of the signal argument
+ * @param listener an instance of the QtSignalListener interface
+ * @return a connection ID between signal and listener or the existing connection ID if there is
+ * an existing connection between the same signal and listener. Return a negative value
+ * if the signal does not exist on the QML root object.
+ **/
+ protected <T> int connectSignalListener(String signalName, Class<T> argType,
+ QtSignalListener<T> listener)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot connect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return -1;
+ }
+ int signalListenerId = view.connectSignalListener(signalName, argType, listener);
+ m_signalListenerIds.add(signalListenerId);
+ return signalListenerId;
+ }
+
+ /**
+ * Disconnects a SignalListener with a given id obtained from
+ * {@link QtQuickView#connectSignalListener() connectSignalListener} call, from listening to
+ * a signal.
+ * <p>
+ * @param signalListenerId the connection id
+ * @return Returns true if the connection id is valid and has been successfully removed,
+ * otherwise returns false.
+ **/
+ public boolean disconnectSignalListener(int signalListenerId)
+ {
+ QtQuickView view = getQuickView();
+ if (view == null) {
+ Log.w(TAG,
+ "Cannot disconnect signal listener as the QQmlComponent is not loaded in a "
+ + "QtQuickView.");
+ return false;
+ }
+ m_signalListenerIds.remove(signalListenerId);
+ return view.disconnectSignalListener(signalListenerId);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
new file mode 100644
index 0000000000..02bea77d43
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatus.java
@@ -0,0 +1,49 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import java.lang.IllegalArgumentException;
+
+/**
+ * QtQmlStatus represents the QML component loading status.
+ */
+public enum QtQmlStatus {
+ /**
+ * Not loaded.
+ **/
+ NULL(0),
+
+ /**
+ * Loaded and ready.
+ * Invoking methods that operate on a QML component would succeed <b>only<b> if
+ * the current status is ready.
+ **/
+ READY(1),
+
+ /**
+ *The QML component is getting loaded from network.
+ **/
+ LOADING(2),
+
+ /**
+ * One or more errors has occurred during loading the QML component.
+ **/
+ ERROR(3);
+
+ private final int m_value;
+
+ QtQmlStatus(int value) { this.m_value = value; }
+
+ QtQmlStatus() { this.m_value = ordinal(); }
+
+ static QtQmlStatus fromInt(int value) throws IllegalArgumentException
+ {
+ for (QtQmlStatus enumValue : QtQmlStatus.values()) {
+ if (enumValue.m_value == value) {
+ return enumValue;
+ }
+ }
+ throw new IllegalArgumentException("No QtQmlStatus enum with value " + value);
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
new file mode 100644
index 0000000000..f1190ed8b1
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQmlStatusChangeListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients about the status of QML component loading.
+ **/
+public interface QtQmlStatusChangeListener
+{
+ /**
+ * Called on the Android UI thread when the QML component status has changed.
+ * @param status The current status. The status can be QtQmlStatus.NULL,
+ * QtQmlStatus.READY, QtQmlStatus.LOADING, or QtQmlStatus.ERROR.
+ **/
+ void onStatusChanged(QtQmlStatus status);
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.java b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
new file mode 100644
index 0000000000..bd4519355f
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.java
@@ -0,0 +1,304 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+import java.lang.ref.WeakReference;
+import java.security.InvalidParameterException;
+
+/**
+ * The QtQuickView class lets you easily add QML content to your Android app as a
+ * {@link android.view.View View}. QtQuickView instantiates a QQuickView with a given
+ * QML component source URI path and embeds it inside itself. You can add it in your Android app's
+ * layout as with any other View. QtQuickView is a good choice when you want to extend your non-Qt
+ * Android app with QML content but do not want to make the entire app using the Qt framework.
+ * It brings the power of Qt Quick into your Android app, making it possible to use various Qt Quick
+ * APIs, in Android Java or Kotlin apps.
+ * </p>
+ * <b>Note:</b> This class is a technical preview. It is subject to change, and no source nor
+ * binary compatibility guarantees exist.
+ * <p>
+ * <b>Known limitations:</b>
+ * <p><ul>
+ * <li> Only CMake is supported, not qmake.
+ * <li> Only one QtQuickView can be added to your app, adding multiple outcomes unknown.
+ * </ul><p>
+ * @see <a href="https://doc.qt.io/qt-6/qquickview.html">Qt QQuickView</a>
+ **/
+public class QtQuickView extends QtView {
+ private final static String TAG = "QtQuickView";
+
+ private String m_qmlUri;
+ private String[] m_qmlImportPaths = null;
+ private QtQmlStatusChangeListener m_statusChangeListener = null;
+ private QtQmlStatus m_lastStatus = QtQmlStatus.NULL;
+ private boolean m_hasQueuedStatus = false;
+ private WeakReference<QtQmlComponent> m_loadedComponent;
+
+ native void createQuickView(String qmlUri, int width, int height, long parentWindowReference,
+ long viewReference, String[] qmlImportPaths);
+ native void setRootObjectProperty(long windowReference, String propertyName, Object value);
+ native Object getRootObjectProperty(long windowReference, String propertyName);
+ native int addRootObjectSignalListener(long windowReference, String signalName, Class argType,
+ Object listener);
+ native boolean removeRootObjectSignalListener(long windowReference, int signalListenerId);
+
+ /**
+ * Creates a QtQuickView to load and view a QML component. Instantiating a QtQuickView will load
+ * the Qt libraries, including the app library specified by <code>appName</code>. Then it
+ * creates a QQuickView that loads the QML source specified by <code>qmlUri</code>.
+ * <p>
+ * @param context the parent Context
+ * @param qmlUri the URI of the main QML file
+ * @param appName the name of the Qt app library to load and start. This corresponds to the
+ * target name set in Qt app's CMakeLists.txt
+ * @throws InvalidParameterException if either qmlUri or appName is empty or null
+ * @see <a href="https://doc.qt.io/qt-6/qquickview.html">Qt QQuickView</a>
+ **/
+ public QtQuickView(Context context, String qmlUri, String appName)
+ throws InvalidParameterException {
+ this(context, qmlUri, appName, null);
+ }
+
+ /**
+ * Creates a QtQuickView to load and view a QML component. Instantiating a QtQuickView will load
+ * the Qt libraries, including the app library specified by appName. Then it creates a
+ * QQuickView that loads the QML source specified by qmlUri. This overload accepts an array of
+ * strings in the case where the QML application should load QML modules from custom paths.
+ * <p>
+ * @param context the parent Context
+ * @param qmlUri the URI of the main QML file
+ * @param appName the name of the Qt app library to load and start. This corresponds to
+ * the target name set in the Qt app's CMakeLists.txt
+ * @param qmlImportPaths an array of strings for additional import paths to be passed to
+ QQmlEngine, or null if additional import paths are not required
+ * @throws InvalidParameterException if either qmlUri or appName is empty or null
+ * @see <a href="https://doc.qt.io/qt-6/qqmlengine.html">Qt QQmlEngine</a>
+ **/
+ public QtQuickView(Context context, String qmlUri, String appName, String[] qmlImportPaths)
+ throws InvalidParameterException
+ {
+ super(context, appName);
+ if (qmlUri == null || qmlUri.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQuickView: argument 'qmlUri' may not be empty or null");
+ }
+ m_qmlUri = qmlUri;
+ m_qmlImportPaths = qmlImportPaths;
+ }
+
+ /**
+ * Creates a QtQuickView that can later load and view a QML component by calling
+ * {@link QtQuickView#loadComponent() loadComponent}
+ * <p>
+ * @param context the parent Context
+ **/
+ public QtQuickView(Context context)
+ {
+ super(context);
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * This overload accepts an array of strings in the case where the QML component should load
+ * QML modules from custom paths.
+ * <p>
+ * @param qmlComponent an instance of an object that extends QtQmlComponent
+ * @param qmlImportPaths an array of strings for additional import paths to be passed to
+ * QQmlEngine, or null if additional import paths are not required
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ // TODO: QTBUG-125620 -- Refresh/reset import paths when loading a new component
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent, String[] qmlImportPaths)
+ throws InvalidParameterException
+ {
+ String libName = qmlComponent.getLibraryName();
+ String qmlUri = qmlComponent.getFilePath();
+
+ if (libName == null || libName.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getLibraryName() may not be empty or null");
+ }
+
+ if (qmlUri == null || qmlUri.isEmpty()) {
+ throw new InvalidParameterException(
+ "QtQmlComponent: return value of getFilePath() may not be empty or null");
+ }
+
+ m_qmlUri = qmlUri;
+ m_qmlImportPaths = qmlImportPaths;
+
+ if (m_loadedComponent != null)
+ m_loadedComponent.clear();
+
+ m_loadedComponent = new WeakReference<>(qmlComponent);
+ qmlComponent.detachView();
+ qmlComponent.attachView(this);
+ // The first QQuickView creation happen after first libs loading
+ // and windowReference() returns a reference to native QQuickView
+ // instance, after that. We don't load library again if the view
+ // exists.
+ if (windowReference() == 0) {
+ loadQtLibraries(libName);
+ } else {
+ createQuickView(m_qmlUri, getWidth(), getHeight(), 0, windowReference(),
+ m_qmlImportPaths);
+ }
+ }
+
+ /**
+ * Loads a QML component represented by a QtQmlComponent. The library name and the qrc path of
+ * the QML component will be extracted from the QtQmlComponent to load the QML component.
+ * <p>
+ * @param qmlComponent an instance of a class that extends QtQmlComponent
+ * @throws InvalidParameterException if QtQmlComponent does not contain valid information
+ * about the module name, and the qrc path.
+ */
+ public <T extends QtQmlComponent> void loadComponent(T qmlComponent)
+ throws InvalidParameterException
+ {
+ loadComponent(qmlComponent, null);
+ }
+
+ @Override
+ protected void createWindow(long parentWindowReference) {
+ createQuickView(m_qmlUri, getWidth(), getHeight(), parentWindowReference, windowReference(),
+ m_qmlImportPaths);
+ }
+
+ /**
+ * Sets the value of an existing property on the QML root object. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool and string. This function does not add
+ * properties to the QML root object if they do not exist, but prints a warning.
+ * <p>
+ * @param propertyName the name of the existing root object property to set the value of
+ * @param value the value to set the property to QML's int, double/float, bool or
+ string
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ public void setProperty(String propertyName, Object value)
+ {
+ setRootObjectProperty(windowReference(), propertyName, value);
+ }
+
+ /**
+ * Gets the value of an existing property of the QML root object. The supported types are
+ * {@link java.lang.Integer}, {@link java.lang.Double}, {@link java.lang.Float},
+ * {@link java.lang.Boolean} and {@link java.lang.String}. These types get converted to their
+ * corresponding QML types int, double/float, bool and string. If the property does not
+ * exist or the status of the QML component is anything other than
+ * {@link QtQuickView#STATUS_READY STATUS_READY}, this function will return null.
+ * <p>
+ * @param propertyName the name of the existing root object property
+ * @throws ClassCastException if the returned type could not be casted to the requested type.
+ * @see <a href="https://doc.qt.io/qt-6/qml-int.html">QML int</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-double.html">QML double/float</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-bool.html">QML bool</a>
+ * @see <a href="https://doc.qt.io/qt-6/qml-string.html">QML string</a>
+ **/
+ // getRootObjectProperty always returns a primitive type or an Object
+ // so it is safe to suppress the unchecked warning
+ @SuppressWarnings("unchecked")
+ public <T> T getProperty(String propertyName)
+ {
+ return (T)getRootObjectProperty(windowReference(), propertyName);
+ }
+
+ /**
+ * Connects a SignalListener to a signal of the QML root object.
+ * <p>
+ * @param signalName the name of the root object signal
+ * @param argType the Class type of the signal argument
+ * @param listener an instance of the QtSignalListener interface
+ * @return a connection id between signal and listener or the existing connection id if there is
+ * an existing connection between the same signal and listener. Return a negative value
+ * if the signal does not exists on the QML root object.
+ **/
+ public <T> int connectSignalListener(String signalName, Class<T> argType,
+ QtSignalListener<T> listener)
+ {
+ int signalListenerId =
+ addRootObjectSignalListener(windowReference(), signalName, argType, listener);
+ if (signalListenerId < 0) {
+ Log.w(TAG, "The signal " + signalName + " does not exist in the root object "
+ + "or the arguments do not match with the listener.");
+ }
+ return signalListenerId;
+ }
+
+ /**
+ * Disconnects a SignalListener with a given id obtained from
+ * {@link QtQuickView#connectSignalListener() connectSignalListener} call, from listening to
+ * a signal.
+ * <p>
+ * @param signalListenerId the connection id
+ * @return Returns true if the connection id is valid and has been successfuly removed,
+ * otherwise returns false.
+ **/
+ public boolean disconnectSignalListener(int signalListenerId)
+ {
+ return removeRootObjectSignalListener(windowReference(), signalListenerId);
+ }
+
+ /**
+ * Gets the status of the QML component.
+ * <p>
+ * @return Returns QtQmlStatus.READY when the QML component is ready. Invoking methods that
+ * operate on the QML root object ({@link QtQuickView#setProperty() setProperty},
+ * {@link QtQuickView#getProperty() getProperty}, and
+ * {@link QtQuickView#addSignalListener() addSignalListener}) would succeed <b>only</b>
+ * if the current status is QtQmlStatus.READY. It can also return QtQmlStatus.NULL,
+ * QtQmlStatus.LOADING, or QtQmlStatus.ERROR based on the status of the underlaying
+ QQuickView instance.
+ * @see <a href="https://doc.qt.io/qt-6/qquickview.html">QQuickView</a>
+ **/
+ public QtQmlStatus getStatus()
+ {
+ return m_lastStatus;
+ }
+
+ /**
+ * Sets a QtQmlStatusChangeListener to listen to status changes.
+ * <p>
+ * @param listener an instance of a QtQmlStatusChangeListener interface
+ **/
+ public void setStatusChangeListener(QtQmlStatusChangeListener listener)
+ {
+ m_statusChangeListener = listener;
+
+ if (m_hasQueuedStatus) {
+ QtNative.runAction(() -> { m_statusChangeListener.onStatusChanged(m_lastStatus); });
+ m_hasQueuedStatus = false;
+ }
+ }
+
+ private void handleStatusChange(int status)
+ {
+ try {
+ m_lastStatus = QtQmlStatus.fromInt(status);
+ } catch (IllegalArgumentException e) {
+ m_lastStatus = QtQmlStatus.NULL;
+ e.printStackTrace();
+ }
+
+ if (m_statusChangeListener != null)
+ QtNative.runAction(() -> {
+ m_statusChangeListener.onStatusChanged(QtQmlStatus.fromInt(status));
+ });
+ else
+ m_hasQueuedStatus = true;
+ }
+}
diff --git a/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
new file mode 100644
index 0000000000..d603ac4144
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtQuickView.qdoc
@@ -0,0 +1,277 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtquickview-android-class.html
+ \title Qt Quick View Android Class
+ \ingroup qt_android_classes
+ \brief Allows you to add QML content to your Android app as a View.
+ \techpreview
+ \since 6.7
+
+ The QtQuickView class lets you easily add QML content to your Android app as
+ a \l {Android: View}{View}.
+
+ \target QtQuickView
+ \table
+ \row
+ \li Class:
+ \li QtQuickView
+ \row
+ \li Package Name:
+ \li org.qtproject.qt.android
+ \row
+ \li Extends:
+ \li org.qtproject.qt.android.QtView
+
+ – org.qtproject.qt.android.QtLayout
+
+ –– android.view.ViewGroup
+ \endtable
+
+ \section1 Detailed description
+
+ The QtQuickView class lets you easily add QML content to your Android app as
+ a \l {Android: View}{View}. \c QtQuickView instantiates a \l QQuickView with
+ a given QML component source (a local or network file) and embeds it to itself.
+ You can add it to your Android app's layout as with any other View. \c QtQuickView
+ is a good choice when you want to extend your non-Qt Android app with QML content but
+ do not want to make the entire app using the Qt framework. It brings the power
+ of Qt Quick into your Android app, making it possible to use various Qt Quick
+ APIs in Android apps.
+
+ A typical use of the class:
+
+ \code
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ ...
+
+ QtQuickView qmlView = new QtQuickView(this, "qrc:/qt/qml/target/main.qml", "target");
+ qmlView.setStatusChangeListener(status -> {
+ Log.i(TAG, "QML loading status changed to " + status);
+ });
+
+ // Add QML to your layout
+ layout.addView(qmlView, params);
+ ...
+ }
+ \endcode
+
+ For a more detailed example, see \l {QML in Android Studio Projects}.
+
+ \section1 QtQuickView in an Android Service
+
+ It is also possible to add a QtQuickView from a Service context by using
+ the Android WindowManager interface:
+
+ \code
+ @Override
+ public void onCreate() {
+ m_windowManager = getSystemService(WindowManager.class);
+ m_qtView = new QtQuickView(this, "qrc:/qt/qml/target/main.qml", "target");
+ WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
+ 640, 320,
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
+ PixelFormat.TRANSLUCENT);
+ m_windowManager.addView(m_qtView, layoutParams);
+ }
+ \endcode
+
+ To clean up the QtQuickView and Qt libraries, the onDestroy() lifecycle
+ function can be used:
+
+ \code
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ m_windowManager.removeView(m_qtView);
+ m_qtView = null;
+ }
+ \endcode
+
+ \note Adding a QtQuickView from a Service context requires your application
+ to have the \l {Android: SYSTEM_ALERT_WINDOW}{SYSTEM_ALERT_WINDOW}
+ permission, and to be signed with the platform key.
+
+ \note QML views embedded within a Service context do not
+ support keyboard input or accessibility features.
+
+ \section1 Constructors
+
+ \section2 public QtQuickView(Context parent, String qmlUri, String appName)
+
+ Creates a QtQuickView to load and render a QML component. Instantiating a
+ QtQuickView will load the Qt libraries, including the app library specified
+ by \e appName. Then, it creates a QQuickView that loads the QML source specified
+ by \e qmlUri.
+
+ \section3 Parameters
+
+ \list
+ \li \b context: the parent Context.
+ \li \b qmlUri: the URI of the main QML file.
+ \li \b appName: the name of the Qt app library to load and start.
+ This corresponds to the target name set in the Qt app's CMakeLists.txt.
+ \endlist
+
+ \section3 Throws
+
+ Throws a \l {Android: InvalidParameterException}{InvalidParameterException} if
+ a parameter is invalid.
+
+ \section2 public QtQuickView(Context context, String qmlUri, String appName, String[] qmlImportPaths)
+
+ Creates a QtQuickView to load and view a QML component. Instantiating a
+ QtQuickView will load the Qt libraries, including the app library specified
+ by \e appName. Then, it creates a QQuickView that loads the QML source specified
+ by \e qmlUri. This overload accepts an array of strings \e qmlImportPaths in the
+ case where the QML application should load QML modules from custom paths.
+
+ \section3 Parameters
+
+ \list
+ \li \b context: the parent Context.
+ \li \b qmlUri: the URI of the main QML file.
+ \li \b appName: the name of the Qt app library to load and start.
+ This corresponds to the target name set in the Qt app's CMakeLists.txt.
+ \li \b qmlImportPaths: an array of strings for additional import paths to
+ be passed to.
+ \endlist
+
+ \section3 Throws
+
+ Throws a \l {Android: InvalidParameterException}{InvalidParameterException} if
+ a parameter is invalid.
+
+ \section1 Interfaces
+
+ \section2 public interface SignalListener<T>
+ \target SignalListener
+
+ Invoked on the Android UI thread when the signal has been emitted.
+
+ \section3 Parameters
+
+ \list
+ \li \b signalName: literal signal name
+ \li \b value: the value delivered by the signal or null if the signal is
+ without a parameter.
+ \endlist
+
+ \section2 public interface StatusChangeListener
+ \target StatusChangeListener
+
+ Invoked on the Android UI thread when the QML component status has changed.
+
+ \section3 Parameters
+
+ \list
+ \li \b status: The current status.
+ \endlist
+
+ \section1 Fields
+
+ \section2 Status values
+ \target Status values
+
+ The status can be \e STATUS_NULL, \e STATUS_READY, \e STATUS_LOADING or
+ \e STATUS_ERROR. For more information, see \l {QQuickView::Status}.
+
+ \section1 Methods
+
+ \section2 public void setProperty(String propertyName, Object value)
+ \target setProperty()
+
+ Sets the value of an existing property on the QML root object. The supported
+ types are \c Integer, \c Double, \c Float, \c Boolean, and \c String. These
+ types get converted to their corresponding QML types int, double/float, bool,
+ and string. This function does not add properties to the QML root object if
+ they do not exist.
+
+ \section3 Parameters
+ \list
+ \li \b propertyName: the name of the existing root object property to set its value
+ \li \b value: the value of the property
+ \endlist
+
+ \section2 public <T extends Object> T getProperty(String propertyName)
+ \target getProperty()
+
+ Gets the value of an existing property of the QML root object. The supported
+ return types are \e Integer, \e Double, \e Float, \e Boolean, and \e String.
+ These types get converted from their corresponding QML types int, double/float,
+ bool, and string.
+
+ \section3 Parameters
+ \list
+ \li \b propertyName: the name of the existing root object property.
+ \endlist
+
+ \section3 Returns
+
+ If the property does not exist or the status of the QML component is
+ anything other than \l {Status values}{STATUS_READY}, this function will return null.
+
+ \section3 Throws
+
+ Throws a \l {Android: ClassCastException}{ClassCastException} if type casting fails.
+
+ \section2 public <T> int addSignalListener(String signalName, Class<T> argType, SignalListener<T> listener)
+ \target addSignalListener()
+
+ Associates a \l {SignalListener} with a signal of the QML root object.
+
+ \section3 Parameters
+ \list
+ \li \b signalName: the name of the root object signal.
+ \li \b argType: the Class type of the signal argument.
+ \li \b listener: an instance of the SignalListener interface.
+ \endlist
+
+ \section3 Returns
+
+ A \c {Connection ID} between signal and listener or the existing connection
+ ID if there is an existing connection between the same signal and listener.
+ Returns a negative value if the signal does not exist on the QML root object.
+
+ \section2 public boolean removeSignalListener(int signalListenerId)
+
+ Stops a \l {SignalListener} with a given id obtained from \l addSignalListener()
+ call, from listening to a signal.
+
+ \section3 Parameters
+ \list
+ \li \b signalListenerId: the connection ID.
+ \endlist
+
+ \section3 Returns
+ \e True if the connection ID is valid and has been successfully removed,
+ otherwise returns false.
+
+ \section2 public int getStatus()
+ \target getStatus()
+
+ Gets the \l {Status values}{status} of the QML component.
+
+ \section3 Returns
+
+ \e STATUS_READY when the QML is ready. Invoking methods that operate on the QML
+ root object, such as \l {setProperty()}, \l {getProperty()}, and
+ \l {addSignalListener()}, would succeed \b only if the current status is
+ \c STATUS_READY. It can also return other \l {Status values}{status} values
+ representing the status of the underlying QQuickView instance.
+
+ \section2 public void setStatusChangeListener(StatusChangeListener listener)
+
+ Sets a \l {StatusChangeListener} to listen to status changes.
+
+ \section3 Parameters
+
+ \list
+ \li \b listener: an instance of a \l {StatusChangeListener} interface.
+ \endlist
+*/
diff --git a/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
new file mode 100644
index 0000000000..195f983be4
--- /dev/null
+++ b/src/quick/jar/org/qtproject/qt/android/QtSignalListener.java
@@ -0,0 +1,17 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+package org.qtproject.qt.android;
+
+/**
+ * A callback that notifies clients when a signal is emitted from the QML component.
+ **/
+@FunctionalInterface
+public interface QtSignalListener<T> {
+ /**
+ * Called on the Android UI thread when the signal has been emitted.
+ * @param signalName literal signal name
+ * @param value the value delivered by the signal or null if the signal is parameterless
+ **/
+ void onSignalEmitted(String signalName, T value);
+}