diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index 82460b553c7..a4463291a9b 100644 --- a/src/android/jar/CMakeLists.txt +++ b/src/android/jar/CMakeLists.txt @@ -29,6 +29,7 @@ set(java_sources src/org/qtproject/qt/android/QtClipboardManager.java src/org/qtproject/qt/android/QtDisplayManager.java src/org/qtproject/qt/android/UsedFromNativeCode.java + src/org/qtproject/qt/android/QtRootLayout.java src/org/qtproject/qt/android/QtWindow.java ) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java index 9eaefed2a7c..991fb364916 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java @@ -59,7 +59,8 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate return dispatchHoverEvent(event); } } - + // TODO do we want to have one QtAccessibilityDelegate for the whole app (QtRootLayout) or + // e.g. one per window? public QtAccessibilityDelegate(QtLayout layout) { m_layout = layout; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java index 8f98dfa28fe..b7d1f207daf 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -37,13 +37,12 @@ class QtActivityDelegate { private Activity m_activity; - private QtLayout m_layout = null; + private QtRootLayout m_layout = null; private HashMap m_topLevelWindows; private ImageView m_splashScreen = null; private boolean m_splashScreenSticky = false; private View m_dummyView = null; - private QtAccessibilityDelegate m_accessibilityDelegate = null; private QtDisplayManager m_displayManager = null; @@ -135,7 +134,7 @@ class QtActivityDelegate private void initMembers() { - m_layout = new QtLayout(m_activity); + m_layout = new QtRootLayout(m_activity); m_membersInitialized = true; m_topLevelWindows = new HashMap(); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java index 2643a9afcf7..5f560db7a50 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java @@ -30,37 +30,6 @@ class QtLayout extends ViewGroup super(context, attrs, defStyle); } - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) - { - Activity activity = (Activity)getContext(); - if (activity == null) - return; - - DisplayMetrics realMetrics = new DisplayMetrics(); - Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) - ? activity.getWindowManager().getDefaultDisplay() - : activity.getDisplay(); - - if (display == null) - return; - - display.getRealMetrics(realMetrics); - if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) { - // This is an intermediate state during display rotation. - // The new size is still reported for old orientation, while - // realMetrics contain sizes for new orientation. Setting - // such parameters will produce inconsistent results, so - // we just skip them. - // We will have another onSizeChanged() with normal values - // a bit later. - return; - } - - QtDisplayManager.setApplicationDisplayMetrics(activity, w, h); - QtDisplayManager.handleOrientationChanges(activity, true); - } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { @@ -79,11 +48,15 @@ class QtLayout extends ViewGroup int childRight; int childBottom; - QtLayout.LayoutParams lp - = (QtLayout.LayoutParams) child.getLayoutParams(); - - childRight = lp.x + child.getMeasuredWidth(); - childBottom = lp.y + child.getMeasuredHeight(); + if (child.getLayoutParams() instanceof QtLayout.LayoutParams) { + QtLayout.LayoutParams lp + = (QtLayout.LayoutParams) child.getLayoutParams(); + childRight = lp.x + child.getMeasuredWidth(); + childBottom = lp.y + child.getMeasuredHeight(); + } else { + childRight = child.getMeasuredWidth(); + childBottom = child.getMeasuredHeight(); + } maxWidth = Math.max(maxWidth, childRight); maxHeight = Math.max(maxHeight, childBottom); @@ -181,6 +154,11 @@ class QtLayout extends ViewGroup this.y = y; } + public LayoutParams(int width, int height) + { + super(width, height); + } + /** * {@inheritDoc} */ diff --git a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java new file mode 100644 index 00000000000..54f4ea1ee08 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java @@ -0,0 +1,74 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// Copyright (C) 2012 BogDan Vatra +// 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; + +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.util.DisplayMetrics; +import android.view.Display; + +/** + A layout which corresponds to one Activity, i.e. is the root layout where the top level window + and handles orientation changes. +*/ +public class QtRootLayout extends QtLayout +{ + + private int m_activityDisplayRotation = -1; + private int m_ownDisplayRotation = -1; + private int m_nativeOrientation = -1; + + public QtRootLayout(Context context) + { + super(context); + } + + public void setActivityDisplayRotation(int rotation) + { + m_activityDisplayRotation = rotation; + } + + public void setNativeOrientation(int orientation) + { + m_nativeOrientation = orientation; + } + + public int displayRotation() + { + return m_ownDisplayRotation; + } + + @Override + protected void onSizeChanged (int w, int h, int oldw, int oldh) + { + Activity activity = (Activity)getContext(); + if (activity == null) + return; + + DisplayMetrics realMetrics = new DisplayMetrics(); + Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) + ? activity.getWindowManager().getDefaultDisplay() + : activity.getDisplay(); + + if (display == null) + return; + + display.getRealMetrics(realMetrics); + if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) { + // This is an intermediate state during display rotation. + // The new size is still reported for old orientation, while + // realMetrics contain sizes for new orientation. Setting + // such parameters will produce inconsistent results, so + // we just skip them. + // We will have another onSizeChanged() with normal values + // a bit later. + return; + } + + QtDisplayManager.setApplicationDisplayMetrics(activity, w, h); + QtDisplayManager.handleOrientationChanges(activity, true); + } +} diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java index ba19e8dba16..757b00d93f8 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java @@ -4,8 +4,6 @@ package org.qtproject.qt.android; import android.content.Context; -import android.os.Handler; -import android.os.Looper; import android.util.Log; import android.view.Surface; import android.view.View; @@ -18,14 +16,26 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba private QtSurface m_surface; private View m_nativeView; - private Handler m_androidHandler; + private HashMap m_childWindows = new HashMap(); + private QtWindow m_parentWindow; private static native void setSurface(int windowId, Surface surface); - public QtWindow(Context context) + public QtWindow(Context context, QtWindow parentWindow) { super(context); setId(View.generateViewId()); + + setParent(parentWindow); + } + + void setVisible(boolean visible) { + QtNative.runAction(() -> { + if (visible) + setVisibility(View.VISIBLE); + else + setVisibility(View.INVISIBLE); + }); } @Override @@ -34,6 +44,12 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba setSurface(getId(), surface); } + public void removeWindow() + { + if (m_parentWindow != null) + m_parentWindow.removeChildWindow(getId()); + } + public void createSurface(final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth) @@ -44,11 +60,20 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba if (m_surface != null) removeView(m_surface); - QtSurface surface = new QtSurface(getContext(), - QtWindow.this, QtWindow.this.getId(), - onTop, imageDepth); - surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + // TODO currently setting child windows to onTop, since their surfaces + // now get created earlier than the parents -> they are behind the parent window + // without this, and SurfaceView z-ordering is limited + boolean tempOnTop = onTop || (m_parentWindow != null); + QtSurface surface = new QtSurface(getContext(), QtWindow.this, + QtWindow.this.getId(), tempOnTop, imageDepth); + surface.setLayoutParams(new QtLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + + // The QtSurface of this window will be added as the first of the stack. + // All other views are stacked based on the order they are created. addView(surface, 0); m_surface = surface; } @@ -68,16 +93,34 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba }); } - public void setSurfaceGeometry(final int x, final int y, final int w, final int h) + public void setGeometry(final int x, final int y, final int w, final int h) { QtNative.runAction(new Runnable() { @Override public void run() { - QtLayout.LayoutParams lp = new QtLayout.LayoutParams(w, h, x, y); - if (m_surface != null) - m_surface.setLayoutParams(lp); - else if (m_nativeView != null) - m_nativeView.setLayoutParams(lp); + QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + } + }); + } + + public void addChildWindow(QtWindow window) + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + m_childWindows.put(window.getId(), window); + addView(window, getChildCount()); + } + }); + } + + public void removeChildWindow(int id) + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + if (m_childWindows.containsKey(id)) + removeView(m_childWindows.remove(id)); } }); } @@ -92,13 +135,35 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba removeView(m_nativeView); m_nativeView = view; - m_nativeView.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); - + QtWindow.this.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + m_nativeView.setLayoutParams(new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); addView(m_nativeView); } }); } + public void bringChildToFront(int id) + { + View view = m_childWindows.get(id); + if (view != null) { + if (getChildCount() > 0) + moveChild(view, getChildCount() - 1); + } + } + + public void bringChildToBack(int id) { + QtNative.runAction(new Runnable() { + @Override + public void run() { + View view = m_childWindows.get(id); + if (view != null) { + moveChild(view, 0); + } + } + }); + } + public void removeNativeView() { QtNative.runAction(new Runnable() { @@ -111,4 +176,22 @@ public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallba } }); } + + void setParent(QtWindow parentWindow) + { + if (m_parentWindow == parentWindow) + return; + + if (m_parentWindow != null) + m_parentWindow.removeChildWindow(getId()); + + m_parentWindow = parentWindow; + if (m_parentWindow != null) + m_parentWindow.addChildWindow(this); + } + + QtWindow parent() + { + return m_parentWindow; + } } diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index 0fc83d05c38..038af6b09b8 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -32,7 +32,7 @@ void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect) QAndroidPlatformWindow::setGeometry(rect); if (m_nativeViewInserted) - setSurfaceGeometry(rect); + setNativeGeometry(rect); } void QAndroidPlatformForeignWindow::setVisible(bool visible) @@ -63,11 +63,6 @@ void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState QAndroidPlatformWindow::applicationStateChanged(state); } -void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window) -{ - Q_UNUSED(window); -} - void QAndroidPlatformForeignWindow::addViewToWindow() { jint x = 0, y = 0, w = -1, h = -1; diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index 19588c7ad7e..52b9ac3a4f4 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -20,7 +20,6 @@ public: void setGeometry(const QRect &rect) override; void setVisible(bool visible) override; void applicationStateChanged(Qt::ApplicationState state) override; - void setParent(const QPlatformWindow *window) override; bool isForeignWindow() const override { return true; } private: diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 7ffa79e2c1e..13d14eb3913 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -45,7 +45,9 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); - setSurfaceGeometry(rect); + + + setNativeGeometry(rect); QRect availableGeometry = screen()->availableGeometry(); if (rect.width() > 0 @@ -59,7 +61,7 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) { if (QAndroidEventDispatcherStopper::stopped() || - QGuiApplication::applicationState() == Qt::ApplicationSuspended || !window()->isTopLevel()) { + QGuiApplication::applicationState() == Qt::ApplicationSuspended) { return m_eglSurface; } diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index e7ce6ed59f0..84efc43630b 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -44,7 +44,6 @@ public: void removeWindow(QAndroidPlatformWindow *window); void raise(QAndroidPlatformWindow *window); void lower(QAndroidPlatformWindow *window); - void topVisibleWindowChanged(); int displayId() const override; diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp index 43b3a903734..4bf4f44fa10 100644 --- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp @@ -39,7 +39,8 @@ void QAndroidPlatformVulkanWindow::setGeometry(const QRect &rect) m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); - setSurfaceGeometry(rect); + if (m_surfaceCreated) + setNativeGeometry(rect); QRect availableGeometry = screen()->availableGeometry(); if (rect.width() > 0 diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 1e30799ae45..9a633e97afe 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -19,10 +19,9 @@ Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window") Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) - : QPlatformWindow(window), m_nativeQtWindow(QNativeInterface::QAndroidApplication::context()), + : QPlatformWindow(window), m_nativeQtWindow(nullptr), m_nativeParentQtWindow(nullptr), m_androidSurfaceObject(nullptr) { - m_nativeViewId = m_nativeQtWindow.callMethod("getId"); m_windowFlags = Qt::Widget; m_windowState = Qt::WindowNoState; // the surfaceType is overwritten in QAndroidPlatformOpenGLWindow ctor so let's save @@ -48,22 +47,44 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) if (requestedNativeGeometry != finalNativeGeometry) setGeometry(finalNativeGeometry); } - platformScreen()->addWindow(this); + + if (parent()) + m_nativeParentQtWindow = static_cast(parent())->nativeWindow(); + + QNativeInterface::QAndroidApplication::runOnAndroidMainThread([this]() { + m_nativeQtWindow = QJniObject::construct( + QNativeInterface::QAndroidApplication::context(), + m_nativeParentQtWindow); + m_nativeViewId = m_nativeQtWindow.callMethod("getId"); + }).waitForFinished(); + + if (window->isTopLevel()) + platformScreen()->addWindow(this); } QAndroidPlatformWindow::~QAndroidPlatformWindow() { - platformScreen()->removeWindow(this); + if (window()->isTopLevel()) + platformScreen()->removeWindow(this); } void QAndroidPlatformWindow::lower() { + if (m_nativeParentQtWindow.isValid()) { + m_nativeParentQtWindow.callMethod("bringChildToBack", nativeViewId()); + return; + } platformScreen()->lower(this); } void QAndroidPlatformWindow::raise() { + if (m_nativeParentQtWindow.isValid()) { + m_nativeParentQtWindow.callMethod("bringChildToFront", nativeViewId()); + QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason); + return; + } updateSystemUiVisibility(); platformScreen()->raise(this); } @@ -87,16 +108,20 @@ void QAndroidPlatformWindow::setGeometry(const QRect &rect) void QAndroidPlatformWindow::setVisible(bool visible) { + m_nativeQtWindow.callMethod("setVisible", visible); + if (visible) { - updateSystemUiVisibility(); - if ((m_windowState & Qt::WindowFullScreen) - || ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) { - setGeometry(platformScreen()->geometry()); - } else if (m_windowState & Qt::WindowMaximized) { - setGeometry(platformScreen()->availableGeometry()); + if (window()->isTopLevel()) { + updateSystemUiVisibility(); + if ((m_windowState & Qt::WindowFullScreen) + || ((m_windowState & Qt::WindowMaximized) && (window()->flags() & Qt::MaximizeUsingFullscreenGeometryHint))) { + setGeometry(platformScreen()->geometry()); + } else if (m_windowState & Qt::WindowMaximized) { + setGeometry(platformScreen()->availableGeometry()); + } + requestActivateWindow(); } - requestActivateWindow(); - } else if (window() == qGuiApp->focusWindow()) { + } else if (window()->isTopLevel() && window() == qGuiApp->focusWindow()) { platformScreen()->topVisibleWindowChanged(); } @@ -132,13 +157,22 @@ Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const void QAndroidPlatformWindow::setParent(const QPlatformWindow *window) { - // even though we do not yet support child windows properly, any windows getting a parent - // should be removed from screen's window stack which is only for top level windows, - // and respectively any window becoming top level should go in there + using namespace QtJniTypes; if (window) { - platformScreen()->removeWindow(this); + // If we were a top level window, remove from screen + if (!m_nativeParentQtWindow.isValid()) + platformScreen()->removeWindow(this); + + const QAndroidPlatformWindow *androidWindow = + static_cast(window); + const QtWindow parentWindow = androidWindow->nativeWindow(); + // If this was a child window of another window, the java method takes care of that + m_nativeQtWindow.callMethod("setParent", parentWindow.object()); + m_nativeParentQtWindow = parentWindow; } else { + m_nativeQtWindow.callMethod("setParent", nullptr); platformScreen()->addWindow(this); + m_nativeParentQtWindow = QJniObject(); } } @@ -154,6 +188,7 @@ void QAndroidPlatformWindow::propagateSizeHints() void QAndroidPlatformWindow::requestActivateWindow() { + // raise() will handle differences between top level and child windows, and requesting focus if (!blockedByModal()) raise(); } @@ -214,7 +249,7 @@ void QAndroidPlatformWindow::destroySurface() } } -void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &geometry) +void QAndroidPlatformWindow::setNativeGeometry(const QRect &geometry) { if (!m_surfaceCreated) return; @@ -229,7 +264,7 @@ void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &geometry) w = geometry.width(); h = geometry.height(); } - m_nativeQtWindow.callMethod("setSurfaceGeometry", x, y, w, h); + m_nativeQtWindow.callMethod("setGeometry", x, y, w, h); } void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface) diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 88949d84daa..6f85bbf9ece 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -65,7 +65,7 @@ protected: void unlockSurface() { m_surfaceMutex.unlock(); } void createSurface(); void destroySurface(); - void setSurfaceGeometry(const QRect &geometry); + void setNativeGeometry(const QRect &geometry); void sendExpose() const; bool blockedByModal() const; @@ -76,6 +76,7 @@ protected: WId m_windowId; QtJniTypes::QtWindow m_nativeQtWindow; + QtJniTypes::QtWindow m_nativeParentQtWindow; // The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex QtJniTypes::Surface m_androidSurfaceObject; QWaitCondition m_surfaceWaitCondition; diff --git a/tests/manual/embeddedwindows/main.cpp b/tests/manual/embeddedwindows/main.cpp index 904839cfa3b..0d897abd9e4 100644 --- a/tests/manual/embeddedwindows/main.cpp +++ b/tests/manual/embeddedwindows/main.cpp @@ -3,7 +3,7 @@ #include -#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_WIN) || QT_CONFIG(xcb) +#if defined(Q_OS_MACOS) || defined(Q_OS_IOS) || defined(Q_OS_WIN) || QT_CONFIG(xcb) || defined(ANDROID) #include "../../shared/nativewindow.h" #define HAVE_NATIVE_WINDOW #endif diff --git a/tests/shared/nativewindow.h b/tests/shared/nativewindow.h index 8b5ad97836c..bddc0f12163 100644 --- a/tests/shared/nativewindow.h +++ b/tests/shared/nativewindow.h @@ -14,6 +14,12 @@ # include #elif QT_CONFIG(xcb) # include +#elif defined(ANDROID) +# include +# include +# include +Q_DECLARE_JNI_CLASS(View, "android/view/View") +Q_DECLARE_JNI_CLASS(ViewParent, "android/view/ViewParent") #endif class NativeWindow @@ -28,6 +34,8 @@ public: using Handle = HWND; #elif QT_CONFIG(xcb) using Handle = xcb_window_t; +#elif defined(ANDROID) + using Handle = QtJniTypes::View;; #endif NativeWindow(); @@ -249,6 +257,48 @@ void NativeWindow::setParent(WId parent) parent ? Handle(parent) : screen->root, 0, 0); } +#elif defined (ANDROID) +NativeWindow::NativeWindow() +{ + m_handle = QJniObject::construct( + QNativeInterface::QAndroidApplication::context()); + m_handle.callMethod("setBackgroundColor", 0xffffaaff); +} + +NativeWindow::~NativeWindow() +{ +} + +NativeWindow::operator WId() const +{ + return reinterpret_cast(m_handle.object()); +} + +void NativeWindow::setGeometry(const QRect &rect) +{ + // No-op, the view geometry is handled by the QWindow constructed from it +} + +QRect NativeWindow::geometry() const +{ + int x = m_handle.callMethod("getX"); + int y = m_handle.callMethod("getY"); + int w = m_handle.callMethod("getWidth"); + int h = m_handle.callMethod("getHeight"); + return QRect(x, y, w, h); +} + +WId NativeWindow::parentWinId() const +{ + // TODO note, the returned object is a ViewParent, not necessarily + // a View - what is this used for? + using namespace QtJniTypes; + ViewParent parentView = m_handle.callMethod("getParent"); + if (parentView.isValid()) + return reinterpret_cast(parentView.object()); + return 0L; +} + #endif #endif // NATIVEWINDOW_H