Android: Add support for multiple embedded views in Android Service

To enable adding and managing multiple QtQuickViews,
QtServiceEmbeddedDelegate now hosts a set of QtViews instead of a
single one.

To avoid crashing if the QML view has a TextField, do not allow
QtWindow to create a QtEditText if the service usecase is detected.

Fixes: QTBUG-129412
Task-number: QTBUG-127422
Task-number: QTBUG-128563
Change-Id: I70784657ed6cb2aa853160605f4663e517f0e6db
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit 1656a2f58c759c25e6a89435a65c1d0fceba8a09)
This commit is contained in:
Petri Virkkunen 2024-09-02 15:40:49 +03:00
parent 46dbb74249
commit 9cd561f355
2 changed files with 19 additions and 25 deletions

View File

@ -13,6 +13,8 @@ import android.view.Display;
import android.view.View; import android.view.View;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import java.util.HashSet;
/** /**
* QtServiceEmbeddedDelegate is used for embedding QML into Android Service contexts. Implements * QtServiceEmbeddedDelegate is used for embedding QML into Android Service contexts. Implements
* {@link QtEmbeddedViewInterface} so it can be used by QtView to communicate with the Qt layer. * {@link QtEmbeddedViewInterface} so it can be used by QtView to communicate with the Qt layer.
@ -20,8 +22,7 @@ import android.util.DisplayMetrics;
class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.AppStateDetailsListener class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.AppStateDetailsListener
{ {
private final Service m_service; private final Service m_service;
private QtView m_view; private HashSet<QtView> m_views = new HashSet<QtView>();
private boolean m_windowLoaded = false;
QtServiceEmbeddedDelegate(Service service) QtServiceEmbeddedDelegate(Service service)
{ {
@ -38,17 +39,14 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App
synchronized (this) { synchronized (this) {
if (ready) { if (ready) {
QtNative.runAction(() -> { QtNative.runAction(() -> {
if (m_view == null)
return;
final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics(); final DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
final int maxWidth = m_view.getWidth(); final int maxWidth = metrics.widthPixels;
final int maxHeight = m_view.getHeight(); final int maxHeight = metrics.heightPixels;
final int width = maxWidth; final int width = maxWidth;
final int height = maxHeight; final int height = maxHeight;
final int insetLeft = m_view.getLeft(); final int insetLeft = 0;
final int insetTop = m_view.getTop(); final int insetTop = 0;
final DisplayManager dm = m_service.getSystemService(DisplayManager.class); final DisplayManager dm = m_service.getSystemService(DisplayManager.class);
QtDisplayManager.setDisplayMetrics( QtDisplayManager.setDisplayMetrics(
@ -58,7 +56,6 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App
QtDisplayManager.getRefreshRate( QtDisplayManager.getRefreshRate(
dm.getDisplay(Display.DEFAULT_DISPLAY))); dm.getDisplay(Display.DEFAULT_DISPLAY)));
}); });
createRootWindow();
} }
} }
} }
@ -73,30 +70,25 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App
@Override @Override
public void addView(QtView view) public void addView(QtView view)
{ {
m_view = view; if (m_views.add(view)) {
QtNative.runAction(() -> { QtNative.runAction(() -> createRootWindow(view));
createRootWindow(); }
});
} }
@Override @Override
public void removeView(QtView view) public void removeView(QtView view)
{ {
if (m_view == view) { m_views.remove(view);
m_view = null; if (m_views.isEmpty())
m_windowLoaded = false;
// If the embedded view is destroyed, do cleanup:
cleanup(); cleanup();
}
} }
// QtEmbeddedViewInterface implementation end // QtEmbeddedViewInterface implementation end
private void createRootWindow() private void createRootWindow(QtView view)
{ {
if (m_view != null && !m_windowLoaded) { if (m_views.contains(view)) {
QtView.createRootWindow(m_view, m_view.getLeft(), m_view.getTop(), m_view.getWidth(), QtView.createRootWindow(view, view.getLeft(), view.getTop(), view.getWidth(),
m_view.getHeight()); view.getHeight());
m_windowLoaded = true;
} }
} }

View File

@ -3,6 +3,7 @@
package org.qtproject.qt.android; package org.qtproject.qt.android;
import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -42,7 +43,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
// to QAndroidPlatformWindow::setVisible(). // to QAndroidPlatformWindow::setVisible().
setVisible(false); setVisible(false);
if (!isForeignWindow) { if (!isForeignWindow && context instanceof Activity) {
// TODO QTBUG-122552 - Service keyboard input not implemented
m_editText = new QtEditText(context, listener); m_editText = new QtEditText(context, listener);
m_editText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO); m_editText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
QtNative.runAction(() -> { QtNative.runAction(() -> {