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 <assam.boudjelthia@qt.io>
(cherry picked from commit 0af53d3e87464a0638e4fdb8b68287912281a2a6)
This commit is contained in:
Tinja Paavoseppä 2024-06-06 09:28:33 +03:00 committed by Petri Virkkunen
parent a228a3e7b6
commit 46dbb74249
4 changed files with 41 additions and 44 deletions

View File

@ -20,23 +20,20 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
class QtEmbeddedDelegate extends QtActivityDelegateBase class QtEmbeddedDelegate extends QtActivityDelegateBase
implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface, implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface,
QtMenuInterface QtMenuInterface
{ {
private static final String QtTAG = "QtEmbeddedDelegate"; private static final String QtTAG = "QtEmbeddedDelegate";
// TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649 private final HashSet<QtView> m_views = new HashSet<>();
private QtView m_view;
private QtNative.ApplicationStateDetails m_stateDetails; private QtNative.ApplicationStateDetails m_stateDetails;
private boolean m_windowLoaded = false;
private boolean m_backendsRegistered = false; private boolean m_backendsRegistered = false;
QtEmbeddedDelegate(Activity context) { QtEmbeddedDelegate(Activity context) {
super(context); super(context);
m_stateDetails = QtNative.getStateDetails(); m_stateDetails = QtNative.getStateDetails();
QtNative.registerAppStateListener(this); QtNative.registerAppStateListener(this);
@ -111,7 +108,6 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
@Override @Override
public void onNativePluginIntegrationReadyChanged(boolean ready) public void onNativePluginIntegrationReadyChanged(boolean ready)
{ {
synchronized (this) {
if (ready) { if (ready) {
QtNative.runAction(() -> { QtNative.runAction(() -> {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
@ -119,8 +115,6 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
metrics.heightPixels); metrics.heightPixels);
}); });
createRootWindow();
}
} }
} }
@ -138,26 +132,26 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
} }
@Override @Override
public void queueLoadWindow() public void addView(QtView view)
{ {
synchronized (this) { if (m_views.add(view)) {
if (m_stateDetails.nativePluginIntegrationReady) QtNative.runAction(() -> { createRootWindow(view); });
createRootWindow();
} }
} }
@Override @Override
public void setView(QtView view) public void removeView(QtView view)
{ {
m_view = view; m_views.remove(view.getId());
} }
// QtEmbeddedViewInterface implementation end // QtEmbeddedViewInterface implementation end
private void createRootWindow() { // This gets called from Android thread
if (m_view != null && !m_windowLoaded) { private void createRootWindow(QtView view) {
QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(), // No use in creating a QQuickView for a View that has been removed
m_view.getHeight()); if (m_views.contains(view)) {
m_windowLoaded = true; QtView.createRootWindow(view, view.getLeft(), view.getTop(), view.getWidth(),
view.getHeight());
} }
} }
@ -174,12 +168,12 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
@Override @Override
public void openContextMenu(final int x, final int y, final int w, final int h) public void openContextMenu(final int x, final int y, final int w, final int h)
{ {
m_view.postDelayed(() -> {
final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText(); final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
if (focusedEditText == null) { if (focusedEditText == null) {
Log.w(QtTAG, "No focused view when trying to open context menu"); Log.w(QtTAG, "No focused view when trying to open context menu");
return; return;
} }
focusedEditText.postDelayed(() -> {
PopupMenu popup = new PopupMenu(m_activity, focusedEditText); PopupMenu popup = new PopupMenu(m_activity, focusedEditText);
QtNative.fillContextMenu(popup.getMenu()); QtNative.fillContextMenu(popup.getMenu());
popup.setOnMenuItemClickListener(menuItem -> popup.setOnMenuItemClickListener(menuItem ->

View File

@ -10,6 +10,6 @@ package org.qtproject.qt.android;
**/ **/
interface QtEmbeddedViewInterface { interface QtEmbeddedViewInterface {
void startQtApplication(String appParams, String mainLib); void startQtApplication(String appParams, String mainLib);
void setView(QtView view); void addView(QtView view);
void queueLoadWindow(); void removeView(QtView view);
}; };

View File

@ -71,20 +71,22 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App
} }
@Override @Override
public void setView(QtView view) public void addView(QtView view)
{ {
m_view = view; m_view = view;
// If the embedded view is destroyed, do cleanup: QtNative.runAction(() -> {
if (view == null) createRootWindow();
cleanup(); });
} }
@Override @Override
public void queueLoadWindow() public void removeView(QtView view)
{ {
synchronized (this) { if (m_view == view) {
if (QtNative.getStateDetails().nativePluginIntegrationReady) m_view = null;
createRootWindow(); m_windowLoaded = false;
// If the embedded view is destroyed, do cleanup:
cleanup();
} }
} }
// QtEmbeddedViewInterface implementation end // QtEmbeddedViewInterface implementation end

View File

@ -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 * 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 @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
m_viewInterface.setView(this); m_viewInterface.addView(this);
m_viewInterface.queueLoadWindow();
} }
@Override @Override
protected void onDetachedFromWindow() { protected void onDetachedFromWindow() {
super.onDetachedFromWindow(); super.onDetachedFromWindow();
destroyWindow(); destroyWindow();
m_viewInterface.setView(null); m_viewInterface.removeView(this);
} }
@Override @Override