17#include <QtCore/private/qjnihelpers_p.h>
18#include <QtCore/QJniObject>
22using namespace QtAndroid;
51 reg->callInterface<QtJniTypes::QtMenuInterface>(
"resetOptionsMenu");
57 reg->callInterface<QtJniTypes::QtMenuInterface>(
"openOptionsMenu");
68 reg->callInterface<QtJniTypes::QtMenuInterface,
void>(
"openContextMenu", anchorRect.x(),
69 anchorRect.y(), anchorRect.width(),
78 reg->callInterface<QtJniTypes::QtMenuInterface>(
"closeContextMenu");
113 Qt::WindowFlags flags = window ? window->flags() : Qt::WindowFlags();
117 bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
118 if (isNonRegularWindow)
127 for (QAndroidPlatformMenuBar *menuBar : std::as_const(menuBars)) {
128 if (menuBar->parentWindow() == window) {
129 visibleMenuBar = menuBar;
156 while (i < s.size()) {
158 if (s.at(i - 1) != u'&')
160 if (i < s.size() && s.at(i) == u'&')
167 static void fillMenuItem(JNIEnv *env, jobject menuItem,
bool checkable,
bool checked,
bool enabled,
bool visible,
const QIcon &icon=QIcon())
169 env->DeleteLocalRef(env->CallObjectMethod(menuItem, setCheckableMenuItemMethodID, checkable));
170 env->DeleteLocalRef(env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked));
171 env->DeleteLocalRef(env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled));
173 if (!icon.isNull()) {
174 int sz = qMax(36, qEnvironmentVariableIntValue(
"QT_ANDROID_APP_ICON_SIZE"));
175 QImage img = icon.pixmap(QSize(sz,sz),
179 QIcon::On).toImage();
181 env->DeleteLocalRef(env->CallObjectMethod(menuItem,
182 setIconMenuItemMethodID,
183 createBitmapDrawable(createBitmap(img, env), env)));
187 env->DeleteLocalRef(env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible));
194 for (QAndroidPlatformMenuItem *item : items) {
195 if (item->isSeparator())
197 QString itemText = removeAmpersandEscapes(item->text());
198 jstring jtext = env->NewString(
reinterpret_cast<
const jchar *>(itemText.data()),
200 jint menuId = platformMenu->menuId(item);
201 jobject menuItem = env->CallObjectMethod(menu,
207 env->DeleteLocalRef(jtext);
215 env->DeleteLocalRef(menuItem);
225 env->CallVoidMethod(menu, clearMenuMethodID);
232 QMutexLocker lockMenuBarMutex(visibleMenuBar->menusListMutex());
233 if (menus.size() == 1) {
234 order = addAllMenuItemsToMenu(env, menu,
static_cast<QAndroidPlatformMenu *>(menus.front()));
236 for (QAndroidPlatformMenu *item : menus) {
237 QString itemText = removeAmpersandEscapes(item->text());
238 jstring jtext = env->NewString(
reinterpret_cast<
const jchar *>(itemText.data()),
240 jint menuId = visibleMenuBar->menuId(item);
241 jobject menuItem = env->CallObjectMethod(menu,
247 env->DeleteLocalRef(jtext);
258 return order ? JNI_TRUE : JNI_FALSE;
271 if (menus.size() == 1) {
302 env->CallVoidMethod(menu, clearMenuMethodID);
307 QString menuText = removeAmpersandEscapes(visibleMenu->text());
308 jstring jtext = env->NewString(
reinterpret_cast<
const jchar*>(menuText.data()),
310 env->CallObjectMethod(menu, setHeaderTitleContextMenuMethodID, jtext);
311 env->DeleteLocalRef(jtext);
318 env->CallVoidMethod(menu, clearMenuMethodID);
342 for (QAndroidPlatformMenu *menu : std::as_const(pendingContextMenus)) {
343 if (menu->isVisible())
364 if (!pendingContextMenus.empty())
365 showContextMenu(pendingContextMenus.takeLast(), QRect());
369 {
"onPrepareOptionsMenu",
"(Landroid/view/Menu;)Z", (
void *)onPrepareOptionsMenu},
370 {
"onOptionsItemSelected",
"(IZ)Z", (
void *)onOptionsItemSelected},
371 {
"onOptionsMenuClosed",
"(Landroid/view/Menu;)V", (
void*)onOptionsMenuClosed},
372 {
"onCreateContextMenu",
"(Landroid/view/ContextMenu;)V", (
void *)onCreateContextMenu},
373 {
"fillContextMenu",
"(Landroid/view/Menu;)V", (
void *)fillContextMenu},
374 {
"onContextItemSelected",
"(IZ)Z", (
void *)onContextItemSelected},
375 {
"onContextMenuClosed",
"(Landroid/view/Menu;)V", (
void*)onContextMenuClosed},
378#define FIND_AND_CHECK_CLASS(CLASS_NAME)
379 clazz = env->FindClass(CLASS_NAME);
381 __android_log_print(ANDROID_LOG_FATAL, qtTagText(), classErrorMsgFmt(), CLASS_NAME);
385#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
386 VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE);
388 __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE);
392#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
393 VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE);
395 __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE);
399#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE)
400 VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE);
402 __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), FIELD_NAME, FIELD_SIGNATURE);
408 jclass appClass = applicationClass();
410 if (!env.registerNativeMethods(appClass, methods,
sizeof(
methods) /
sizeof(
methods[0]))) {
411 __android_log_print(ANDROID_LOG_FATAL,
"Qt",
"RegisterNatives failed");
418 GET_AND_CHECK_METHOD(addMenuItemMethodID, clazz,
"add",
"(IIILjava/lang/CharSequence;)Landroid/view/MenuItem;");
419 jfieldID menuNoneFiledId;
421 menuNoneValue = env->GetStaticIntField(clazz, menuNoneFiledId);
424 GET_AND_CHECK_METHOD(setHeaderTitleContextMenuMethodID, clazz,
"setHeaderTitle",
"(Ljava/lang/CharSequence;)Landroid/view/ContextMenu;");
427 GET_AND_CHECK_METHOD(setCheckableMenuItemMethodID, clazz,
"setCheckable",
"(Z)Landroid/view/MenuItem;");
428 GET_AND_CHECK_METHOD(setCheckedMenuItemMethodID, clazz,
"setChecked",
"(Z)Landroid/view/MenuItem;");
429 GET_AND_CHECK_METHOD(setEnabledMenuItemMethodID, clazz,
"setEnabled",
"(Z)Landroid/view/MenuItem;");
430 GET_AND_CHECK_METHOD(setIconMenuItemMethodID, clazz,
"setIcon",
"(Landroid/graphics/drawable/Drawable;)Landroid/view/MenuItem;");
431 GET_AND_CHECK_METHOD(setVisibleMenuItemMethodID, clazz,
"setVisible",
"(Z)Landroid/view/MenuItem;");
#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE)
#define FIND_AND_CHECK_CLASS(CLASS_NAME)
#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE)
static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu)
static jmethodID setHeaderTitleContextMenuMethodID
void hideContextMenu(QAndroidPlatformMenu *menu)
static jboolean onContextItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
static QString removeAmpersandEscapes(QString s)
static QList< QAndroidPlatformMenu * > pendingContextMenus
static QSet< QAndroidPlatformMenuBar * > menuBars
void setActiveTopLevelWindow(QWindow *window)
void removeMenuBar(QAndroidPlatformMenuBar *menuBar)
void syncMenu(QAndroidPlatformMenu *)
static void onCreateContextMenu(JNIEnv *env, jobject thiz, jobject menu)
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu)
static jmethodID clearMenuMethodID
static QAndroidPlatformMenuBar * visibleMenuBar
static jmethodID addMenuItemMethodID
void addMenuBar(QAndroidPlatformMenuBar *menuBar)
static jmethodID setIconMenuItemMethodID
static void onContextMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
static void onOptionsMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
static QWindow * activeTopLevelWindow
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
static jmethodID setCheckableMenuItemMethodID
static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject thiz, jobject menu)
static QAndroidPlatformMenu * visibleMenu
static void fillMenuItem(JNIEnv *env, jobject menuItem, bool checkable, bool checked, bool enabled, bool visible, const QIcon &icon=QIcon())
bool registerNatives(QJniEnvironment &env)
static jmethodID setCheckedMenuItemMethodID
void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window)
static jmethodID setVisibleMenuItemMethodID
static void fillContextMenu(JNIEnv *env, jobject thiz, jobject menu)
static jmethodID setEnabledMenuItemMethodID
static jboolean onOptionsItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
static JNINativeMethod methods[]
AndroidBackendRegister * backendRegister()
Q_DECLARE_JNI_CLASS(MotionEvent, "android/view/MotionEvent")