From 2bc7d38bd63843c4598ed501e3adbf0e39162c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= Date: Fri, 8 Dec 2023 11:24:43 +0200 Subject: [PATCH] Android: Make QtWindow wrap the QtLayout instead of inherit it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The layout is a ViewGroup, and should be created in the Android UI thread, while for ease of use on C++ side we should be able to construct the Java object in the platform window constructor to avoid later calls not having a valid object reference. Trying to make a blocking call to Android thread from Qt thread can lead to dead locks, so move only the creation of the layout itself into Android thread, making the QtWindow a wrapper for it, which we can immediately return to C++/Qt thread. Most of the calls made to QtWindow are anyway already passed to the Android UI thread. As a drive by, add a missing QtNative.runAction() to bringChildToFront(). Change-Id: Ib2495ddda8267384656557cbe40be5da869f82c3 Reviewed-by: Tor Arne Vestbø --- .../qt/android/QtActivityDelegate.java | 12 ++-- .../org/qtproject/qt/android/QtWindow.java | 69 +++++++++++-------- .../android/qandroidplatformwindow.cpp | 10 ++- 3 files changed, 52 insertions(+), 39 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java index b7d1f207daf..8f6114a7c2f 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -386,11 +386,11 @@ class QtActivityDelegate } } - window.setLayoutParams(new ViewGroup.LayoutParams( + window.getLayout().setLayoutParams(new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - m_layout.addView(window, m_topLevelWindows.size()); + m_layout.addView(window.getLayout(), m_topLevelWindows.size()); m_topLevelWindows.put(window.getId(), window); if (!m_splashScreenSticky) hideSplashScreen(); @@ -406,9 +406,9 @@ class QtActivityDelegate if (m_topLevelWindows.isEmpty()) { // Keep last frame in stack until it is replaced to get correct // shutdown transition - m_dummyView = window; + m_dummyView = window.getLayout(); } else { - m_layout.removeView(window); + m_layout.removeView(window.getLayout()); } } }); @@ -420,7 +420,7 @@ class QtActivityDelegate QtNative.runAction(() -> { QtWindow window = m_topLevelWindows.get(id); if (window != null) { - m_layout.moveChild(window, m_topLevelWindows.size() - 1); + m_layout.moveChild(window.getLayout(), m_topLevelWindows.size() - 1); } }); } @@ -431,7 +431,7 @@ class QtActivityDelegate QtNative.runAction(() -> { QtWindow window = m_topLevelWindows.get(id); if (window != null) - m_layout.moveChild(window, 0); + m_layout.moveChild(window.getLayout(), 0); }); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java index 757b00d93f8..79e7b96cb9b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java @@ -11,33 +11,46 @@ import android.view.ViewGroup; import java.util.HashMap; -public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallback { +public class QtWindow implements QtSurface.SurfaceChangedCallback { private final static String TAG = "QtWindow"; + private QtLayout m_layout; private QtSurface m_surface; private View m_nativeView; private HashMap m_childWindows = new HashMap(); private QtWindow m_parentWindow; + private int m_id; private static native void setSurface(int windowId, Surface surface); public QtWindow(Context context, QtWindow parentWindow) { - super(context); - setId(View.generateViewId()); - - setParent(parentWindow); + m_id = View.generateViewId(); + QtNative.runAction(() -> { + m_layout = new QtLayout(context); + setParent(parentWindow); + }); } void setVisible(boolean visible) { QtNative.runAction(() -> { if (visible) - setVisibility(View.VISIBLE); + m_layout.setVisibility(View.VISIBLE); else - setVisibility(View.INVISIBLE); + m_layout.setVisibility(View.INVISIBLE); }); } + public int getId() + { + return m_id; + } + + public QtLayout getLayout() + { + return m_layout; + } + @Override public void onSurfaceChanged(Surface surface) { @@ -58,15 +71,15 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { if (m_surface != null) - removeView(m_surface); + m_layout.removeView(m_surface); - setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + m_layout.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); // TODO currently setting child windows to onTop, since their surfaces // now get created earlier than the parents -> they are behind the parent window // without this, and SurfaceView z-ordering is limited boolean tempOnTop = onTop || (m_parentWindow != null); - QtSurface surface = new QtSurface(getContext(), QtWindow.this, + QtSurface surface = new QtSurface(m_layout.getContext(), QtWindow.this, QtWindow.this.getId(), tempOnTop, imageDepth); surface.setLayoutParams(new QtLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, @@ -74,7 +87,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba // The QtSurface of this window will be added as the first of the stack. // All other views are stacked based on the order they are created. - addView(surface, 0); + m_layout.addView(surface, 0); m_surface = surface; } }); @@ -86,7 +99,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { if (m_surface != null) { - removeView(m_surface); + m_layout.removeView(m_surface); m_surface = null; } } @@ -98,7 +111,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba QtNative.runAction(new Runnable() { @Override public void run() { - QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + m_layout.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); } }); } @@ -109,7 +122,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { m_childWindows.put(window.getId(), window); - addView(window, getChildCount()); + m_layout.addView(window.getLayout(), m_layout.getChildCount()); } }); } @@ -120,7 +133,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { if (m_childWindows.containsKey(id)) - removeView(m_childWindows.remove(id)); + m_layout.removeView(m_childWindows.remove(id).getLayout()); } }); } @@ -132,33 +145,35 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { if (m_nativeView != null) - removeView(m_nativeView); + m_layout.removeView(m_nativeView); m_nativeView = view; - QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + m_layout.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); m_nativeView.setLayoutParams(new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - addView(m_nativeView); + m_layout.addView(m_nativeView); } }); } public void bringChildToFront(int id) { - View view = m_childWindows.get(id); - if (view != null) { - if (getChildCount() > 0) - moveChild(view, getChildCount() - 1); - } + QtNative.runAction(()-> { + QtWindow window = m_childWindows.get(id); + if (window != null) { + if (m_layout.getChildCount() > 0) + m_layout.moveChild(window.getLayout(), m_layout.getChildCount() - 1); + } + }); } public void bringChildToBack(int id) { QtNative.runAction(new Runnable() { @Override public void run() { - View view = m_childWindows.get(id); - if (view != null) { - moveChild(view, 0); + QtWindow window = m_childWindows.get(id); + if (window != null) { + m_layout.moveChild(window.getLayout(), 0); } } }); @@ -170,7 +185,7 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba @Override public void run() { if (m_nativeView != null) { - removeView(m_nativeView); + m_layout.removeView(m_nativeView); m_nativeView = null; } } diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 9a633e97afe..84a4eab3892 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -51,12 +51,10 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) if (parent()) m_nativeParentQtWindow = static_cast(parent())->nativeWindow(); - QNativeInterface::QAndroidApplication::runOnAndroidMainThread([this]() { - m_nativeQtWindow = QJniObject::construct( - QNativeInterface::QAndroidApplication::context(), - m_nativeParentQtWindow); - m_nativeViewId = m_nativeQtWindow.callMethod("getId"); - }).waitForFinished(); + m_nativeQtWindow = QJniObject::construct( + QNativeInterface::QAndroidApplication::context(), + m_nativeParentQtWindow); + m_nativeViewId = m_nativeQtWindow.callMethod("getId"); if (window->isTopLevel()) platformScreen()->addWindow(this);