Android: Implement interface for window-related backend

Add QtWindowInterface interface, to access native functionality related
to windows.

QtActivityBase now follows QtNative.onAppStateDetailsChanged in order
to register and unregister functionalities of QtActivityDelegate.

Task-number: QTBUG-118874
Change-Id: Ifad33bd7aac7683081f026f0591ef496909be095
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
Petri Virkkunen 2024-03-11 14:04:01 +02:00
parent 124eaa6b22
commit 46a23b1fae
8 changed files with 75 additions and 20 deletions

View File

@ -41,6 +41,7 @@ set(java_sources
src/org/qtproject/qt/android/QtEmbeddedViewInterface.java
src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java
src/org/qtproject/qt/android/BackendRegister.java
src/org/qtproject/qt/android/QtWindowInterface.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android

View File

@ -19,7 +19,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
public class QtActivityBase extends Activity
public class QtActivityBase extends Activity implements QtNative.AppStateDetailsListener
{
private String m_applicationParams = "";
private boolean m_isCustomThemeSet = false;
@ -96,6 +96,8 @@ public class QtActivityBase extends Activity
m_delegate = new QtActivityDelegate(this);
QtNative.registerAppStateListener(this);
handleActivityRestart();
addReferrer(getIntent());
@ -107,6 +109,14 @@ public class QtActivityBase extends Activity
loader.getMainLibraryPath());
}
@Override
public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
if (details.isStarted)
m_delegate.registerBackends();
else
m_delegate.unregisterBackends();
}
@Override
protected void onStart()
{
@ -153,6 +163,7 @@ public class QtActivityBase extends Activity
{
super.onDestroy();
if (!m_retainNonConfigurationInstance) {
QtNative.unregisterAppStateListener(this);
QtNative.terminateQt();
QtNative.setActivity(null);
QtNative.getQtThread().exit();

View File

@ -26,20 +26,19 @@ import android.view.Menu;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsetsController;
import android.widget.ImageView;
import android.widget.PopupMenu;
import java.util.HashMap;
class QtActivityDelegate extends QtActivityDelegateBase
class QtActivityDelegate extends QtActivityDelegateBase implements QtWindowInterface
{
private static final String QtTAG = "QtActivityDelegate";
private QtRootLayout m_layout = null;
private ImageView m_splashScreen = null;
private boolean m_splashScreenSticky = false;
private boolean m_backendsRegistered = false;
private View m_dummyView = null;
private HashMap<Integer, View> m_nativeViews = new HashMap<Integer, View>();
@ -53,6 +52,22 @@ class QtActivityDelegate extends QtActivityDelegateBase
setActivityBackgroundDrawable();
}
void registerBackends()
{
if (!m_backendsRegistered) {
m_backendsRegistered = true;
BackendRegister.registerBackend(QtWindowInterface.class,
(QtWindowInterface)QtActivityDelegate.this);
}
}
void unregisterBackends()
{
if (m_backendsRegistered) {
m_backendsRegistered = false;
BackendRegister.unregisterBackend(QtWindowInterface.class);
}
}
@UsedFromNativeCode
@Override
@ -61,9 +76,8 @@ class QtActivityDelegate extends QtActivityDelegateBase
return m_layout;
}
@UsedFromNativeCode
@Override
void setSystemUiVisibility(int systemUiVisibility)
public void setSystemUiVisibility(int systemUiVisibility)
{
QtNative.runAction(() -> {
m_displayManager.setSystemUiVisibility(systemUiVisibility);
@ -310,7 +324,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
@UsedFromNativeCode
@Override
void removeTopLevelWindow(final int id)
public void removeTopLevelWindow(final int id)
{
QtNative.runAction(()-> {
if (m_topLevelWindows.containsKey(id)) {
@ -328,7 +342,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
@UsedFromNativeCode
@Override
void bringChildToFront(final int id)
public void bringChildToFront(final int id)
{
QtNative.runAction(() -> {
QtWindow window = m_topLevelWindows.get(id);
@ -339,7 +353,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
@UsedFromNativeCode
@Override
void bringChildToBack(int id)
public void bringChildToBack(int id)
{
QtNative.runAction(() -> {
QtWindow window = m_topLevelWindows.get(id);

View File

@ -55,11 +55,6 @@ abstract class QtActivityDelegateBase
void hideSplashScreen(final int duration) {}
void openContextMenu(final int x, final int y, final int w, final int h) {}
void setActionBarVisibility(boolean visible) {}
void addTopLevelWindow(final QtWindow window) {}
void removeTopLevelWindow(final int id) {}
void bringChildToFront(final int id) {}
void bringChildToBack(int id) {}
void setSystemUiVisibility(int systemUiVisibility) {}
QtActivityDelegateBase(Activity activity)
{

View File

@ -22,12 +22,13 @@ import java.util.ArrayList;
import java.util.HashMap;
class QtEmbeddedDelegate extends QtActivityDelegateBase
implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface
implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface
{
// TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649
private QtView m_view;
private QtNative.ApplicationStateDetails m_stateDetails;
private boolean m_windowLoaded = false;
private boolean m_backendsRegistered = false;
public QtEmbeddedDelegate(Activity context) {
super(context);
@ -89,6 +90,13 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) {
synchronized (this) {
m_stateDetails = details;
if (details.isStarted && !m_backendsRegistered) {
m_backendsRegistered = true;
BackendRegister.registerBackend(QtWindowInterface.class, (QtWindowInterface)this);
} else if (!details.isStarted && m_backendsRegistered) {
m_backendsRegistered = false;
BackendRegister.unregisterBackend(QtWindowInterface.class);
}
}
}

View File

@ -0,0 +1,11 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
@UsedFromNativeCode
interface QtWindowInterface {
default void addTopLevelWindow(final QtWindow window) { }
default void removeTopLevelWindow(final int id) { }
default void bringChildToFront(final int id) { }
default void bringChildToBack(int id) { }
default void setSystemUiVisibility(int systemUiVisibility) { }
}

View File

@ -94,6 +94,7 @@ static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
Q_CONSTINIT static QBasicAtomicInt startQtAndroidPluginCalled = Q_BASIC_ATOMIC_INITIALIZER(0);
Q_DECLARE_JNI_CLASS(QtEmbeddedDelegateFactory, "org/qtproject/qt/android/QtEmbeddedDelegateFactory")
Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
namespace QtAndroid
{
@ -184,7 +185,9 @@ namespace QtAndroid
// TODO move calls from here to where they logically belong
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
qtActivityDelegate().callMethod<void>("setSystemUiVisibility", jint(uiVisibility));
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtWindowInterface, void>("setSystemUiVisibility",
jint(uiVisibility));
}
// FIXME: avoid direct access to QtActivityDelegate

View File

@ -57,6 +57,7 @@ Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
@ -162,7 +163,10 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
return;
m_windowStack.prepend(window);
QtAndroid::qtActivityDelegate().callMethod<void>("addTopLevelWindow", window->nativeWindow());
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtWindowInterface, void>("addTopLevelWindow",
window->nativeWindow());
if (window->window()->isVisible())
topVisibleWindowChanged();
@ -175,7 +179,9 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
if (m_windowStack.contains(window))
qWarning() << "Failed to remove window";
QtAndroid::qtActivityDelegate().callMethod<void>("removeTopLevelWindow", window->nativeViewId());
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtWindowInterface, void>("removeTopLevelWindow",
window->nativeViewId());
topVisibleWindowChanged();
}
@ -187,7 +193,10 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
return;
if (index > 0) {
m_windowStack.move(index, 0);
QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToFront", window->nativeViewId());
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToFront",
window->nativeViewId());
}
topVisibleWindowChanged();
}
@ -198,7 +207,10 @@ void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
if (index == -1 || index == (m_windowStack.size() - 1))
return;
m_windowStack.move(index, m_windowStack.size() - 1);
QtAndroid::qtActivityDelegate().callMethod<void>("bringChildToBack", window->nativeViewId());
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToBack",
window->nativeViewId());
topVisibleWindowChanged();
}