From 030a60d68152a7d4b1c7eb5005d2da97ed5532a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= Date: Tue, 31 Oct 2023 14:52:30 +0200 Subject: [PATCH] Android: Add support for foreign window acting as embedding container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the case when our foreign window is created to act as a parent for embedding Qt content into a native Android app, we need a more "hands off" approach. If the foreign window represents an Android view which the user has created outside of Qt, we should not try to reparent it since it already has a parent in the view hierarchy. Neither should we try to remove it from the hierarchy, or set its visibility. Change-Id: Iea496578a40f45ebdd73947a1bb0e46a7131108c Reviewed-by: Assam Boudjelthia Reviewed-by: Tor Arne Vestbø (cherry picked from commit 5ba91c9decb4d13d7f7176bc7ce29b40007a19c5) Reviewed-by: Qt Cherry-pick Bot --- .../android/qandroidplatformforeignwindow.cpp | 38 ++++++++++++++++--- .../android/qandroidplatformforeignwindow.h | 2 + .../android/qandroidplatformwindow.cpp | 10 +++++ .../android/qandroidplatformwindow.h | 1 + 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index 038af6b09b8..befc8d4d00f 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -14,12 +14,20 @@ QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WI : QAndroidPlatformWindow(window), m_view(nullptr), m_nativeViewInserted(false) { m_view = reinterpret_cast(nativeHandle); + if (isEmbeddingContainer()) { + m_nativeViewId = m_view.callMethod("getId"); + return; + } + if (m_view.isValid()) QtAndroid::setViewVisibility(m_view.object(), false); } QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow() { + if (isEmbeddingContainer()) + return; + if (m_view.isValid()) QtAndroid::setViewVisibility(m_view.object(), false); @@ -31,13 +39,16 @@ void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect) { QAndroidPlatformWindow::setGeometry(rect); + if (isEmbeddingContainer()) + return; + if (m_nativeViewInserted) setNativeGeometry(rect); } void QAndroidPlatformForeignWindow::setVisible(bool visible) { - if (!m_view.isValid()) + if (!m_view.isValid() || isEmbeddingContainer()) return; QtAndroid::setViewVisibility(m_view.object(), visible); @@ -53,18 +64,33 @@ void QAndroidPlatformForeignWindow::setVisible(bool visible) void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState state) { - if (state <= Qt::ApplicationHidden && m_nativeViewInserted) { - m_nativeQtWindow.callMethod("removeNativeView"); - m_nativeViewInserted = false; - } else if (m_view.isValid() && !m_nativeViewInserted){ - addViewToWindow(); + if (!isEmbeddingContainer()) { + if (state <= Qt::ApplicationHidden + && m_nativeViewInserted) { + m_nativeQtWindow.callMethod("removeNativeView"); + m_nativeViewInserted = false; + } else if (m_view.isValid() && !m_nativeViewInserted){ + addViewToWindow(); + } } QAndroidPlatformWindow::applicationStateChanged(state); } +WId QAndroidPlatformForeignWindow::winId() const +{ + if (isEmbeddingContainer() && m_view.isValid()) + return reinterpret_cast(m_view.object()); + if (m_nativeQtWindow.isValid()) + return reinterpret_cast(m_nativeQtWindow.object()); + return 0L; +} + void QAndroidPlatformForeignWindow::addViewToWindow() { + if (isEmbeddingContainer()) + return; + jint x = 0, y = 0, w = -1, h = -1; if (!geometry().isNull()) geometry().getRect(&x, &y, &w, &h); diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index 52b9ac3a4f4..503524ccedf 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -22,6 +22,8 @@ public: void applicationStateChanged(Qt::ApplicationState state) override; bool isForeignWindow() const override { return true; } + WId winId() const override; + private: void addViewToWindow(); diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 6681f1d20dd..434d87a88ea 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -45,6 +45,9 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) setGeometry(finalNativeGeometry); } + if (isEmbeddingContainer()) + return; + if (parent()) m_nativeParentQtWindow = static_cast(parent())->nativeWindow(); @@ -296,6 +299,13 @@ bool QAndroidPlatformWindow::blockedByModal() const return modalWindow && modalWindow != window(); } +bool QAndroidPlatformWindow::isEmbeddingContainer() const +{ + // Returns true if the window is a wrapper for a foreign window solely to allow embedding Qt + // into a native Android app, in which case we should not try to control it more than we "need" to + return !QtAndroid::isQtApplication() && window()->isTopLevel(); +} + void QAndroidPlatformWindow::setSurface(JNIEnv *env, jobject object, jint windowId, QtJniTypes::Surface surface) { diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 1c95ca123b6..ab54c25e060 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -69,6 +69,7 @@ protected: void setNativeGeometry(const QRect &geometry); void sendExpose() const; bool blockedByModal() const; + bool isEmbeddingContainer() const; Qt::WindowFlags m_windowFlags; Qt::WindowStates m_windowState;