Android: Implement context menu backend interface

Implements interface for context menu in QtActivityDelegate and
QtEmbeddedDelegate.

Task-number: QTBUG-118874
Change-Id: I799ad1aca4beb789b87830b720abf0963ca09274
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
This commit is contained in:
Petri Virkkunen 2024-03-31 15:37:31 +03:00
parent 2322c71cc7
commit 9319576a59
5 changed files with 80 additions and 20 deletions

View File

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

View File

@ -31,8 +31,8 @@ import android.widget.PopupMenu;
import java.util.HashMap;
class QtActivityDelegate
extends QtActivityDelegateBase implements QtWindowInterface, QtAccessibilityInterface
class QtActivityDelegate extends QtActivityDelegateBase
implements QtWindowInterface, QtAccessibilityInterface, QtMenuInterface
{
private static final String QtTAG = "QtActivityDelegate";
@ -61,6 +61,8 @@ class QtActivityDelegate
(QtWindowInterface)QtActivityDelegate.this);
BackendRegister.registerBackend(QtAccessibilityInterface.class,
(QtAccessibilityInterface)QtActivityDelegate.this);
BackendRegister.registerBackend(QtMenuInterface.class,
(QtMenuInterface)QtActivityDelegate.this);
}
}
@ -70,6 +72,7 @@ class QtActivityDelegate
m_backendsRegistered = false;
BackendRegister.unregisterBackend(QtWindowInterface.class);
BackendRegister.unregisterBackend(QtAccessibilityInterface.class);
BackendRegister.unregisterBackend(QtMenuInterface.class);
}
}
@ -290,27 +293,25 @@ class QtActivityDelegate
});
}
@UsedFromNativeCode
// QtMenuInterface implementation begin
@Override
public void resetOptionsMenu()
{
QtNative.runAction(() -> m_activity.invalidateOptionsMenu());
}
@UsedFromNativeCode
@Override
public void openOptionsMenu()
{
QtNative.runAction(() -> m_activity.openOptionsMenu());
}
private boolean m_contextMenuVisible = false;
public void onCreatePopupMenu(Menu menu)
@Override
public void closeContextMenu()
{
QtNative.fillContextMenu(menu);
m_contextMenuVisible = true;
QtNative.runAction(() -> m_activity.closeContextMenu());
}
@UsedFromNativeCode
@Override
public void openContextMenu(final int x, final int y, final int w, final int h)
{
@ -330,11 +331,14 @@ class QtActivityDelegate
popup.show();
}, 100);
}
// QtMenuInterface implementation end
@UsedFromNativeCode
public void closeContextMenu()
private boolean m_contextMenuVisible = false;
public void onCreatePopupMenu(Menu menu)
{
QtNative.runAction(() -> m_activity.closeContextMenu());
QtNative.fillContextMenu(menu);
m_contextMenuVisible = true;
}
@Override

View File

@ -15,15 +15,19 @@ import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import java.util.ArrayList;
import java.util.HashMap;
class QtEmbeddedDelegate extends QtActivityDelegateBase
implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface
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 QtNative.ApplicationStateDetails m_stateDetails;
@ -93,9 +97,11 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
if (details.isStarted && !m_backendsRegistered) {
m_backendsRegistered = true;
BackendRegister.registerBackend(QtWindowInterface.class, (QtWindowInterface)this);
BackendRegister.registerBackend(QtMenuInterface.class, (QtMenuInterface)this);
} else if (!details.isStarted && m_backendsRegistered) {
m_backendsRegistered = false;
BackendRegister.unregisterBackend(QtWindowInterface.class);
BackendRegister.unregisterBackend(QtMenuInterface.class);
}
}
}
@ -175,4 +181,36 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase
m_windowLoaded = true;
}
}
// QtMenuInterface implementation begin
@Override
public void resetOptionsMenu() { QtNative.runAction(() -> m_activity.invalidateOptionsMenu()); }
@Override
public void openOptionsMenu() { QtNative.runAction(() -> m_activity.openOptionsMenu()); }
@Override
public void closeContextMenu() { QtNative.runAction(() -> m_activity.closeContextMenu()); }
@Override
public void openContextMenu(final int x, final int y, final int w, final int h)
{
QtLayout layout = getQtLayout();
layout.postDelayed(() -> {
final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText();
if (focusedEditText == null) {
Log.w(QtTAG, "No focused view when trying to open context menu");
return;
}
layout.setLayoutParams(focusedEditText, new QtLayout.LayoutParams(w, h, x, y), false);
PopupMenu popup = new PopupMenu(m_activity, focusedEditText);
QtNative.fillContextMenu(popup.getMenu());
popup.setOnMenuItemClickListener(menuItem ->
m_activity.onContextItemSelected(menuItem));
popup.setOnDismissListener(popupMenu ->
m_activity.onContextMenuClosed(popupMenu.getMenu()));
popup.show();
}, 100);
}
// QtMenuInterface implementation end
}

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 QtMenuInterface {
void resetOptionsMenu();
void openOptionsMenu();
void closeContextMenu();
void openContextMenu(final int x, final int y, final int w, final int h);
}

View File

@ -20,6 +20,8 @@ QT_BEGIN_NAMESPACE
using namespace QtAndroid;
Q_DECLARE_JNI_CLASS(QtMenuInterface, "org/qtproject/qt/android/QtMenuInterface");
namespace QtAndroidMenu
{
static QList<QAndroidPlatformMenu *> pendingContextMenus;
@ -44,12 +46,14 @@ namespace QtAndroidMenu
void resetMenuBar()
{
qtActivityDelegate().callMethod<void>("resetOptionsMenu");
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtMenuInterface, void>("resetOptionsMenu");
}
void openOptionsMenu()
{
qtActivityDelegate().callMethod<void>("openOptionsMenu");
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtMenuInterface, void>("openOptionsMenu");
}
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
@ -59,16 +63,18 @@ namespace QtAndroidMenu
pendingContextMenus.append(visibleMenu);
visibleMenu = menu;
menu->aboutToShow();
qtActivityDelegate().callMethod<void>("openContextMenu",
anchorRect.x(), anchorRect.y(),
anchorRect.width(), anchorRect.height());
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtMenuInterface, void>("openContextMenu", anchorRect.x(),
anchorRect.y(), anchorRect.width(),
anchorRect.height());
}
void hideContextMenu(QAndroidPlatformMenu *menu)
{
QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) {
qtActivityDelegate().callMethod<void>("closeContextMenu");
AndroidBackendRegister *reg = QtAndroid::backendRegister();
reg->callInterface<QtJniTypes::QtMenuInterface, void>("closeContextMenu");
pendingContextMenus.clear();
} else {
pendingContextMenus.removeOne(menu);