From 46dbb7424912fd2ee942d72a4dd47fe920a9f786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= Date: Thu, 6 Jun 2024 09:28:33 +0300 Subject: [PATCH] Android: Add support for multiple QtViews in same Context This patch makes it possible to have multiple QtViews in an Android app, provided they are in the same Context. Task-number: QTBUG-127422 Task-number: QTBUG-124116 Change-Id: I3d5bef3f789f23c8495c3b7209bbd3e430d439ac Reviewed-by: Assam Boudjelthia (cherry picked from commit 0af53d3e87464a0638e4fdb8b68287912281a2a6) --- .../qt/android/QtEmbeddedDelegate.java | 56 +++++++++---------- .../qt/android/QtEmbeddedViewInterface.java | 4 +- .../qt/android/QtServiceEmbeddedDelegate.java | 18 +++--- .../src/org/qtproject/qt/android/QtView.java | 7 ++- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java index 3da520c31b3..3c8265f0e0a 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java @@ -20,23 +20,20 @@ import android.view.View; import android.view.ViewGroup; import android.widget.PopupMenu; -import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface, QtMenuInterface { private static final String QtTAG = "QtEmbeddedDelegate"; - // TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649 - private QtView m_view; + private final HashSet m_views = new HashSet<>(); private QtNative.ApplicationStateDetails m_stateDetails; - private boolean m_windowLoaded = false; private boolean m_backendsRegistered = false; QtEmbeddedDelegate(Activity context) { super(context); - m_stateDetails = QtNative.getStateDetails(); QtNative.registerAppStateListener(this); @@ -111,16 +108,13 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase @Override public void onNativePluginIntegrationReadyChanged(boolean ready) { - synchronized (this) { - if (ready) { - QtNative.runAction(() -> { - DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); - QtDisplayManager.setApplicationDisplayMetrics(m_activity, metrics.widthPixels, - metrics.heightPixels); + if (ready) { + QtNative.runAction(() -> { + DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); + QtDisplayManager.setApplicationDisplayMetrics(m_activity, metrics.widthPixels, + metrics.heightPixels); - }); - createRootWindow(); - } + }); } } @@ -138,26 +132,26 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase } @Override - public void queueLoadWindow() + public void addView(QtView view) { - synchronized (this) { - if (m_stateDetails.nativePluginIntegrationReady) - createRootWindow(); + if (m_views.add(view)) { + QtNative.runAction(() -> { createRootWindow(view); }); } } @Override - public void setView(QtView view) + public void removeView(QtView view) { - m_view = view; + m_views.remove(view.getId()); } // QtEmbeddedViewInterface implementation end - private void createRootWindow() { - if (m_view != null && !m_windowLoaded) { - QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(), - m_view.getHeight()); - m_windowLoaded = true; + // This gets called from Android thread + private void createRootWindow(QtView view) { + // No use in creating a QQuickView for a View that has been removed + if (m_views.contains(view)) { + QtView.createRootWindow(view, view.getLeft(), view.getTop(), view.getWidth(), + view.getHeight()); } } @@ -174,12 +168,12 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase @Override public void openContextMenu(final int x, final int y, final int w, final int h) { - m_view.postDelayed(() -> { - final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText(); - if (focusedEditText == null) { - Log.w(QtTAG, "No focused view when trying to open context menu"); - return; - } + final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText(); + if (focusedEditText == null) { + Log.w(QtTAG, "No focused view when trying to open context menu"); + return; + } + focusedEditText.postDelayed(() -> { PopupMenu popup = new PopupMenu(m_activity, focusedEditText); QtNative.fillContextMenu(popup.getMenu()); popup.setOnMenuItemClickListener(menuItem -> diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java index a83a65e32c3..e6d96035cac 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterface.java @@ -10,6 +10,6 @@ package org.qtproject.qt.android; **/ interface QtEmbeddedViewInterface { void startQtApplication(String appParams, String mainLib); - void setView(QtView view); - void queueLoadWindow(); + void addView(QtView view); + void removeView(QtView view); }; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java index d8af626ca0f..36a56947ea6 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java @@ -71,20 +71,22 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App } @Override - public void setView(QtView view) + public void addView(QtView view) { m_view = view; - // If the embedded view is destroyed, do cleanup: - if (view == null) - cleanup(); + QtNative.runAction(() -> { + createRootWindow(); + }); } @Override - public void queueLoadWindow() + public void removeView(QtView view) { - synchronized (this) { - if (QtNative.getStateDetails().nativePluginIntegrationReady) - createRootWindow(); + if (m_view == view) { + m_view = null; + m_windowLoaded = false; + // If the embedded view is destroyed, do cleanup: + cleanup(); } } // QtEmbeddedViewInterface implementation end diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java index 87896071fa0..9e8ed5b2daf 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtView.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java @@ -70,6 +70,8 @@ abstract class QtView extends ViewGroup { } } }); + if (getId() == -1) + setId(View.generateViewId()); } /** * Create a QtView for embedding a QWindow, and load the Qt libraries if they have not already @@ -90,15 +92,14 @@ abstract class QtView extends ViewGroup { @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - m_viewInterface.setView(this); - m_viewInterface.queueLoadWindow(); + m_viewInterface.addView(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); destroyWindow(); - m_viewInterface.setView(null); + m_viewInterface.removeView(this); } @Override