From 0a92d881bb91d3ff14187e7838af1cad9ad1070c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tinja=20Paavosepp=C3=A4?= Date: Tue, 5 Sep 2023 09:01:46 +0300 Subject: [PATCH] Android: Make QtLayout per window instead of per screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each QAndroidPlatformWindow has its own QtLayout, instead of one for the whole app/screen. This paves the way for addition of child windows. Task-number: QTBUG-116187 Change-Id: I36c68cea1a5f27ded3696bcfc2fbc04d9a8ce79e Reviewed-by: Tor Arne Vestbø Reviewed-by: Assam Boudjelthia --- src/android/jar/CMakeLists.txt | 1 + .../qt/android/QtAccessibilityDelegate.java | 22 +-- .../qt/android/QtActivityDelegate.java | 180 ++++++------------ .../org/qtproject/qt/android/QtSurface.java | 29 ++- .../org/qtproject/qt/android/QtWindow.java | 114 +++++++++++ .../platforms/android/androidjnimain.cpp | 123 +----------- .../platforms/android/androidjnimain.h | 8 - .../android/qandroidplatformforeignwindow.cpp | 58 +++--- .../android/qandroidplatformforeignwindow.h | 10 +- .../android/qandroidplatformopenglwindow.cpp | 8 +- .../android/qandroidplatformscreen.cpp | 51 +++-- .../android/qandroidplatformscreen.h | 5 +- .../android/qandroidplatformvulkanwindow.cpp | 4 +- .../android/qandroidplatformwindow.cpp | 132 ++++++++++--- .../android/qandroidplatformwindow.h | 22 ++- 15 files changed, 385 insertions(+), 382 deletions(-) create mode 100644 src/android/jar/src/org/qtproject/qt/android/QtWindow.java diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index 87f1e030d19..82460b553c7 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/QtWindow.java ) qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android 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 82b8976144e..9eaefed2a7c 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java @@ -36,9 +36,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate private View m_view = null; private final AccessibilityManager m_manager; - private final QtActivityDelegate m_activityDelegate; - private final Activity m_activity; - private final ViewGroup m_layout; + private final QtLayout m_layout; // The accessible object that currently has the "accessibility focus" // usually indicated by a yellow rectangle on screen. @@ -62,13 +60,11 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate } } - public QtAccessibilityDelegate(Activity activity, ViewGroup layout, QtActivityDelegate activityDelegate) + public QtAccessibilityDelegate(QtLayout layout) { - m_activity = activity; m_layout = layout; - m_activityDelegate = activityDelegate; - m_manager = (AccessibilityManager) m_activity.getSystemService(Context.ACCESSIBILITY_SERVICE); + m_manager = (AccessibilityManager) m_layout.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); if (m_manager != null) { AccessibilityManagerListener accServiceListener = new AccessibilityManagerListener(); if (!m_manager.addAccessibilityStateChangeListener(accServiceListener)) @@ -89,7 +85,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate try { View view = m_view; if (view == null) { - view = new View(m_activity); + view = new View(m_layout.getContext()); view.setId(View.NO_ID); } @@ -105,7 +101,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // if all is fine, add it to the layout if (m_view == null) { //m_layout.addAccessibilityView(view); - m_layout.addView(view, m_activityDelegate.getSurfaceCount(), + m_layout.addView(view, m_layout.getChildCount(), new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } m_view = view; @@ -289,7 +285,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate return null; } - if (m_activityDelegate.getSurfaceCount() == 0) + if (m_layout.getChildCount() == 0) return null; final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); @@ -356,7 +352,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // Spit out the entire hierarchy for debugging purposes // dumpNodes(-1); - if (m_activityDelegate.getSurfaceCount() != 0) { + if (m_layout.getChildCount() == 0) { int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1); for (int id : ids) result.addChild(m_view, id); @@ -388,7 +384,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); node.setPackageName(m_view.getContext().getPackageName()); - if (m_activityDelegate.getSurfaceCount() == 0 || !QtNativeAccessibility.populateNode(virtualViewId, node)) { + if (m_layout.getChildCount() == 0 || !QtNativeAccessibility.populateNode(virtualViewId, node)) { return node; } @@ -439,7 +435,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { - if (virtualViewId == View.NO_ID || m_activityDelegate.getSurfaceCount() == 0) { + if (virtualViewId == View.NO_ID || m_layout.getChildCount() == 0) { return getNodeForView(); } return getNodeForVirtualViewId(virtualViewId); 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 6a87c187be0..8f98dfa28fe 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -11,6 +11,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; import android.graphics.Rect; import android.os.Build; import android.util.DisplayMetrics; @@ -36,9 +37,8 @@ class QtActivityDelegate { private Activity m_activity; - private HashMap m_surfaces = null; - private HashMap m_nativeViews = null; private QtLayout m_layout = null; + private HashMap m_topLevelWindows; private ImageView m_splashScreen = null; private boolean m_splashScreenSticky = false; @@ -48,6 +48,7 @@ class QtActivityDelegate private QtDisplayManager m_displayManager = null; private QtInputDelegate m_inputDelegate = null; + private boolean m_membersInitialized = false; QtActivityDelegate(Activity activity) { @@ -55,6 +56,7 @@ class QtActivityDelegate QtNative.setActivity(m_activity); setActionBarVisibility(false); + setActivityBackgroundDrawable(); } QtDisplayManager displayManager() { @@ -116,7 +118,7 @@ class QtActivityDelegate public void startNativeApplication(String appParams, String mainLib) { - if (m_surfaces != null) + if (m_membersInitialized) return; initMembers(); @@ -134,6 +136,8 @@ class QtActivityDelegate private void initMembers() { m_layout = new QtLayout(m_activity); + m_membersInitialized = true; + m_topLevelWindows = new HashMap(); m_displayManager = new QtDisplayManager(m_activity); m_displayManager.registerDisplayListener(); @@ -173,8 +177,6 @@ class QtActivityDelegate e.printStackTrace(); } - m_surfaces = new HashMap<>(); - m_nativeViews = new HashMap<>(); m_activity.registerForContextMenu(m_layout); m_activity.setContentView(m_layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, @@ -293,9 +295,7 @@ class QtActivityDelegate @UsedFromNativeCode public void initializeAccessibility() { - final QtActivityDelegate currentDelegate = this; - QtNative.runAction(() -> m_accessibilityDelegate = new QtAccessibilityDelegate(m_activity, - m_layout, currentDelegate)); + QtNative.runAction(() -> m_accessibilityDelegate = new QtAccessibilityDelegate(m_layout)); } void handleUiModeChange(int uiMode) @@ -377,135 +377,52 @@ class QtActivityDelegate } @UsedFromNativeCode - public void insertNativeView(int id, View view, int x, int y, int w, int h) { - QtNative.runAction(() -> { - if (m_dummyView != null) { - m_layout.removeView(m_dummyView); - m_dummyView = null; - } - - if (m_nativeViews.containsKey(id)) - m_layout.removeView(m_nativeViews.remove(id)); - - if (w < 0 || h < 0) { - view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - } else { - view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); - } - - view.setId(id); - m_layout.addView(view); - m_nativeViews.put(id, view); - }); - } - - @UsedFromNativeCode - public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) { - QtNative.runAction(() -> { - if (m_surfaces.size() == 0) { - TypedValue attr = new TypedValue(); - m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true); - if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT && attr.type <= TypedValue.TYPE_LAST_COLOR_INT) { - m_activity.getWindow().setBackgroundDrawable(new ColorDrawable(attr.data)); - } else { - m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId, m_activity.getTheme())); - } + public void addTopLevelWindow(final QtWindow window) + { + QtNative.runAction(()-> { + if (m_topLevelWindows.size() == 0) { if (m_dummyView != null) { m_layout.removeView(m_dummyView); m_dummyView = null; } } - if (m_surfaces.containsKey(id)) - m_layout.removeView(m_surfaces.remove(id)); + window.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); - QtSurface surface = new QtSurface(m_activity, id, onTop, imageDepth); - if (w < 0 || h < 0) { - surface.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.MATCH_PARENT)); - } else { - surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); - } - - // Native views are always inserted in the end of the stack (i.e., on top). - // All other views are stacked based on the order they are created. - final int surfaceCount = getSurfaceCount(); - m_layout.addView(surface, surfaceCount); - - m_surfaces.put(id, surface); + m_layout.addView(window, m_topLevelWindows.size()); + m_topLevelWindows.put(window.getId(), window); if (!m_splashScreenSticky) hideSplashScreen(); }); } @UsedFromNativeCode - public void setSurfaceGeometry(int id, int x, int y, int w, int h) { - QtNative.runAction(() -> { - if (m_surfaces.containsKey(id)) { - QtSurface surface = m_surfaces.get(id); - if (surface != null) - surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); - else - Log.e(QtNative.QtTAG, "setSurfaceGeometry(): surface is null!"); - } else if (m_nativeViews.containsKey(id)) { - View view = m_nativeViews.get(id); - if (view != null) - view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); - else - Log.e(QtNative.QtTAG, "setSurfaceGeometry(): view is null!"); - } else { - Log.e(QtNative.QtTAG, "Surface " + id + " not found!"); + public void removeTopLevelWindow(final int id) + { + QtNative.runAction(()-> { + if (m_topLevelWindows.containsKey(id)) { + QtWindow window = m_topLevelWindows.remove(id); + if (m_topLevelWindows.isEmpty()) { + // Keep last frame in stack until it is replaced to get correct + // shutdown transition + m_dummyView = window; + } else { + m_layout.removeView(window); + } } }); } @UsedFromNativeCode - public void destroySurface(int id) { - QtNative.runAction(() -> { - View view = null; - - if (m_surfaces.containsKey(id)) { - view = m_surfaces.remove(id); - } else if (m_nativeViews.containsKey(id)) { - view = m_nativeViews.remove(id); - } else { - Log.e(QtNative.QtTAG, "Surface " + id + " not found!"); - } - - if (view == null) - return; - - // Keep last frame in stack until it is replaced to get correct - // shutdown transition - if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) { - m_dummyView = view; - } else { - m_layout.removeView(view); - } - }); - } - - public int getSurfaceCount() - { - return m_surfaces.size(); - } - - @UsedFromNativeCode - public void bringChildToFront(int id) + public void bringChildToFront(final int id) { QtNative.runAction(() -> { - View view = m_surfaces.get(id); - if (view != null) { - final int surfaceCount = getSurfaceCount(); - if (surfaceCount > 0) - m_layout.moveChild(view, surfaceCount - 1); - return; + QtWindow window = m_topLevelWindows.get(id); + if (window != null) { + m_layout.moveChild(window, m_topLevelWindows.size() - 1); } - - view = m_nativeViews.get(id); - if (view != null) - m_layout.moveChild(view, -1); }); } @@ -513,17 +430,26 @@ class QtActivityDelegate public void bringChildToBack(int id) { QtNative.runAction(() -> { - View view = m_surfaces.get(id); - if (view != null) { - m_layout.moveChild(view, 0); - return; - } - - view = m_nativeViews.get(id); - if (view != null) { - final int index = getSurfaceCount(); - m_layout.moveChild(view, index); - } + QtWindow window = m_topLevelWindows.get(id); + if (window != null) + m_layout.moveChild(window, 0); }); } + + private void setActivityBackgroundDrawable() + { + TypedValue attr = new TypedValue(); + m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, + attr, true); + Drawable backgroundDrawable; + if (attr.type >= TypedValue.TYPE_FIRST_COLOR_INT && + attr.type <= TypedValue.TYPE_LAST_COLOR_INT) { + backgroundDrawable = new ColorDrawable(attr.data); + } else { + backgroundDrawable = m_activity.getResources(). + getDrawable(attr.resourceId, m_activity.getTheme()); + } + + m_activity.getWindow().setBackgroundDrawable(backgroundDrawable); + } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java index 92050c88855..7682d87d96c 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java @@ -9,6 +9,7 @@ import android.content.Context; import android.graphics.PixelFormat; import android.view.GestureDetector; import android.view.MotionEvent; +import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; @@ -16,24 +17,33 @@ import android.view.SurfaceView; class QtSurface extends SurfaceView implements SurfaceHolder.Callback { private final GestureDetector m_gestureDetector; + private Object m_accessibilityDelegate = null; + private SurfaceChangedCallback m_surfaceCallback; + private final int m_windowId; - public QtSurface(Context context, int id, boolean onTop, int imageDepth) + interface SurfaceChangedCallback { + void onSurfaceChanged(Surface surface); + } + + public QtSurface(Context context, SurfaceChangedCallback surfaceCallback, int id, boolean onTop, + int imageDepth) { super(context); setFocusable(false); setFocusableInTouchMode(false); setZOrderMediaOverlay(onTop); + m_surfaceCallback = surfaceCallback; getHolder().addCallback(this); if (imageDepth == 16) getHolder().setFormat(PixelFormat.RGB_565); else getHolder().setFormat(PixelFormat.RGBA_8888); - setId(id); + m_windowId = id; m_gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { public void onLongPress(MotionEvent event) { - QtInputDelegate.longPress(getId(), (int) event.getX(), (int) event.getY()); + QtInputDelegate.longPress(m_windowId, (int) event.getX(), (int) event.getY()); } }); m_gestureDetector.setIsLongpressEnabled(true); @@ -49,14 +59,15 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback { if (width < 1 || height < 1) return; - - QtNative.setSurface(getId(), holder.getSurface()); + if (m_surfaceCallback != null) + m_surfaceCallback.onSurfaceChanged(holder.getSurface()); } @Override public void surfaceDestroyed(SurfaceHolder holder) { - QtNative.setSurface(getId(), null); + if (m_surfaceCallback != null) + m_surfaceCallback.onSurfaceChanged(null); } @Override @@ -67,7 +78,7 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback // In case when Surface is moved, we should also add this move to event position event.setLocation(event.getX() + getX(), event.getY() + getY()); - QtInputDelegate.sendTouchEvent(event, getId()); + QtInputDelegate.sendTouchEvent(event, m_windowId); m_gestureDetector.onTouchEvent(event); return true; } @@ -75,13 +86,13 @@ class QtSurface extends SurfaceView implements SurfaceHolder.Callback @Override public boolean onTrackballEvent(MotionEvent event) { - QtInputDelegate.sendTrackballEvent(event, getId()); + QtInputDelegate.sendTrackballEvent(event, m_windowId); return true; } @Override public boolean onGenericMotionEvent(MotionEvent event) { - return QtInputDelegate.sendGenericMotionEvent(event, getId()); + return QtInputDelegate.sendGenericMotionEvent(event, m_windowId); } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java new file mode 100644 index 00000000000..ba19e8dba16 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java @@ -0,0 +1,114 @@ +// Copyright (C) 2023 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; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.view.Surface; +import android.view.View; +import android.view.ViewGroup; + +import java.util.HashMap; + +public class QtWindow extends QtLayout implements QtSurface.SurfaceChangedCallback { + private final static String TAG = "QtWindow"; + + private QtSurface m_surface; + private View m_nativeView; + private Handler m_androidHandler; + + private static native void setSurface(int windowId, Surface surface); + + public QtWindow(Context context) + { + super(context); + setId(View.generateViewId()); + } + + @Override + public void onSurfaceChanged(Surface surface) + { + setSurface(getId(), surface); + } + + public void createSurface(final boolean onTop, + final int x, final int y, final int w, final int h, + final int imageDepth) + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + 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)); + + addView(surface, 0); + m_surface = surface; + } + }); + } + + public void destroySurface() + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + if (m_surface != null) { + removeView(m_surface); + m_surface = null; + } + } + }); + } + + public void setSurfaceGeometry(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); + } + }); + } + + public void setNativeView(final View view, + final int x, final int y, final int w, final int h) + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + if (m_nativeView != null) + removeView(m_nativeView); + + m_nativeView = view; + m_nativeView.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + + addView(m_nativeView); + } + }); + } + + public void removeNativeView() + { + QtNative.runAction(new Runnable() { + @Override + public void run() { + if (m_nativeView != null) { + removeView(m_nativeView); + m_nativeView = null; + } + } + }); + } +} diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index fdf4611ff64..d59c170095d 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -70,10 +70,6 @@ static void *m_mainLibraryHnd = nullptr; static QList m_applicationParams; static sem_t m_exitSemaphore, m_terminateSemaphore; -QHash m_surfaces; - -Q_CONSTINIT static QBasicMutex m_surfacesMutex; - static QAndroidPlatformIntegration *m_androidPlatformIntegration = nullptr; @@ -319,56 +315,6 @@ namespace QtAndroid return manufacturer + u' ' + model; } - jint generateViewId() - { - return QJniObject::callStaticMethod("android/view/View", "generateViewId", "()I"); - } - - int createSurface(QAndroidPlatformWindow *window, const QRect &geometry, bool onTop, int imageDepth) - { - QJniEnvironment env; - if (!env.jniEnv()) - return -1; - - m_surfacesMutex.lock(); - jint surfaceId = generateViewId(); - m_surfaces[surfaceId] = window; - m_surfacesMutex.unlock(); - - jint x = 0, y = 0, w = -1, h = -1; - if (!geometry.isNull()) { - x = geometry.x(); - y = geometry.y(); - w = std::max(geometry.width(), 1); - h = std::max(geometry.height(), 1); - } - qtActivityDelegate().callMethod("createSurface", surfaceId, jboolean(onTop), - x, y, w, h, imageDepth); - return surfaceId; - } - - int insertNativeView(QtJniTypes::View view, const QRect &geometry) - { - m_surfacesMutex.lock(); - jint surfaceId = generateViewId(); - m_surfaces[surfaceId] = nullptr; // dummy - m_surfacesMutex.unlock(); - - jint x = 0, y = 0, w = -1, h = -1; - if (!geometry.isNull()) - geometry.getRect(&x, &y, &w, &h); - - qtActivityDelegate().callMethod("insertNativeView", - surfaceId, - view, - x, - y, - qMax(w, 1), - qMax(h, 1)); - - return surfaceId; - } - void setViewVisibility(jobject view, bool visible) { QJniObject::callStaticMethod(m_applicationClass, @@ -378,56 +324,6 @@ namespace QtAndroid visible); } - void setSurfaceGeometry(int surfaceId, const QRect &geometry) - { - if (surfaceId == -1) - return; - - QJniEnvironment env; - if (!env.jniEnv()) - return; - jint x = 0, y = 0, w = -1, h = -1; - if (!geometry.isNull()) { - x = geometry.x(); - y = geometry.y(); - w = geometry.width(); - h = geometry.height(); - } - qtActivityDelegate().callMethod("setSurfaceGeometry", surfaceId, x, y, w, h); - } - - - void destroySurface(int surfaceId) - { - if (surfaceId == -1) - return; - - { - QMutexLocker lock(&m_surfacesMutex); - const auto &it = m_surfaces.find(surfaceId); - if (it != m_surfaces.end()) - m_surfaces.erase(it); - } - - qtActivityDelegate().callMethod("destroySurface", surfaceId); - } - - void bringChildToFront(int surfaceId) - { - if (surfaceId == -1) - return; - - qtActivityDelegate().callMethod("bringChildToFront", surfaceId); - } - - void bringChildToBack(int surfaceId) - { - if (surfaceId == -1) - return; - - qtActivityDelegate().callMethod("bringChildToBack", surfaceId); - } - bool blockEventLoopsWhenSuspended() { static bool block = qEnvironmentVariableIntValue("QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED"); @@ -595,21 +491,6 @@ static void terminateQt(JNIEnv *env, jclass /*clazz*/) sem_post(&m_exitSemaphore); } -static void setSurface(JNIEnv *env, jobject thiz, jint id, jobject jSurface) -{ - Q_UNUSED(env); - Q_UNUSED(thiz); - - QMutexLocker lock(&m_surfacesMutex); - const auto &it = m_surfaces.find(id); - if (it == m_surfaces.end()) - return; - - auto surfaceClient = it.value(); - if (surfaceClient) - surfaceClient->onSurfaceChanged(jSurface); -} - static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWidthPixels, jint screenHeightPixels, jint availableLeftPixels, jint availableTopPixels, jint availableWidthPixels, @@ -802,7 +683,6 @@ static JNINativeMethod methods[] = { { "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication }, { "terminateQt", "()V", (void *)terminateQt }, { "waitForServiceSetup", "()V", (void *)waitForServiceSetup }, - { "setSurface", "(ILjava/lang/Object;)V", (void *)setSurface }, { "updateWindow", "()V", (void *)updateWindow }, { "updateApplicationState", "(I)V", (void *)updateApplicationState }, { "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult }, @@ -948,7 +828,8 @@ Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/) || !QtAndroidMenu::registerNatives(env) || !QtAndroidAccessibility::registerNatives(env) || !QtAndroidDialogHelpers::registerNatives(env) - || !QAndroidPlatformClipboard::registerNatives(env)) { + || !QAndroidPlatformClipboard::registerNatives(env) + || !QAndroidPlatformWindow::registerNatives(env)) { __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed"); return -1; } diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h index 090e87d7f7b..f65f82d6c3d 100644 --- a/src/plugins/platforms/android/androidjnimain.h +++ b/src/plugins/platforms/android/androidjnimain.h @@ -28,7 +28,6 @@ class QBasicMutex; Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate") Q_DECLARE_JNI_CLASS(QtInputDelegate, "org/qtproject/qt/android/QtInputDelegate") -Q_DECLARE_JNI_CLASS(View, "android/view/View"); namespace QtAndroid { @@ -36,14 +35,7 @@ namespace QtAndroid QAndroidPlatformIntegration *androidPlatformIntegration(); void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration); void setQtThread(QThread *thread); - - int createSurface(QAndroidPlatformWindow *window, const QRect &geometry, bool onTop, int imageDepth); - int insertNativeView(QtJniTypes::View view, const QRect &geometry); void setViewVisibility(jobject view, bool visible); - void setSurfaceGeometry(int surfaceId, const QRect &geometry); - void destroySurface(int surfaceId); - void bringChildToFront(int surfaceId); - void bringChildToBack(int surfaceId); QWindow *topLevelWindowAt(const QPoint &globalPos); int availableWidthPixels(); diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index c2ce2c84b2e..0fc83d05c38 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -6,12 +6,12 @@ #include #include #include +#include QT_BEGIN_NAMESPACE QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle) - : QAndroidPlatformWindow(window), - m_surfaceId(-1) + : QAndroidPlatformWindow(window), m_view(nullptr), m_nativeViewInserted(false) { m_view = reinterpret_cast(nativeHandle); if (m_view.isValid()) @@ -22,34 +22,17 @@ QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow() { if (m_view.isValid()) QtAndroid::setViewVisibility(m_view.object(), false); - if (m_surfaceId != -1) - QtAndroid::destroySurface(m_surfaceId); -} -void QAndroidPlatformForeignWindow::lower() -{ - if (m_surfaceId == -1) - return; + m_nativeQtWindow.callMethod("removeNativeView"); - QAndroidPlatformWindow::lower(); - QtAndroid::bringChildToBack(m_surfaceId); -} - -void QAndroidPlatformForeignWindow::raise() -{ - if (m_surfaceId == -1) - return; - - QAndroidPlatformWindow::raise(); - QtAndroid::bringChildToFront(m_surfaceId); } void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect) { QAndroidPlatformWindow::setGeometry(rect); - if (m_surfaceId != -1) - QtAndroid::setSurfaceGeometry(m_surfaceId, rect); + if (m_nativeViewInserted) + setSurfaceGeometry(rect); } void QAndroidPlatformForeignWindow::setVisible(bool visible) @@ -60,22 +43,21 @@ void QAndroidPlatformForeignWindow::setVisible(bool visible) QtAndroid::setViewVisibility(m_view.object(), visible); QAndroidPlatformWindow::setVisible(visible); - if (!visible && m_surfaceId != -1) { - QtAndroid::destroySurface(m_surfaceId); - m_surfaceId = -1; - } else if (m_surfaceId == -1) { - m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry()); + if (!visible && m_nativeViewInserted) { + m_nativeQtWindow.callMethod("removeNativeView"); + m_nativeViewInserted = false; + } else if (!m_nativeViewInserted) { + addViewToWindow(); } } void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState state) { - if (state <= Qt::ApplicationHidden - && m_surfaceId != -1) { - QtAndroid::destroySurface(m_surfaceId); - m_surfaceId = -1; - } else if (m_view.isValid() && m_surfaceId == -1){ - m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry()); + if (state <= Qt::ApplicationHidden && m_nativeViewInserted) { + m_nativeQtWindow.callMethod("removeNativeView"); + m_nativeViewInserted = false; + } else if (m_view.isValid() && !m_nativeViewInserted){ + addViewToWindow(); } QAndroidPlatformWindow::applicationStateChanged(state); @@ -86,4 +68,14 @@ void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window) Q_UNUSED(window); } +void QAndroidPlatformForeignWindow::addViewToWindow() +{ + jint x = 0, y = 0, w = -1, h = -1; + if (!geometry().isNull()) + geometry().getRect(&x, &y, &w, &h); + + m_nativeQtWindow.callMethod("setNativeView", m_view, x, y, qMax(w, 1), qMax(h, 1)); + m_nativeViewInserted = true; +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index 7ddacda17f0..19588c7ad7e 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -10,13 +10,13 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_JNI_CLASS(View, "android/view/View") + class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow { public: explicit QAndroidPlatformForeignWindow(QWindow *window, WId nativeHandle); ~QAndroidPlatformForeignWindow(); - void lower() override; - void raise() override; void setGeometry(const QRect &rect) override; void setVisible(bool visible) override; void applicationStateChanged(Qt::ApplicationState state) override; @@ -24,8 +24,10 @@ public: bool isForeignWindow() const override { return true; } private: - int m_surfaceId; - QJniObject m_view; + void addViewToWindow(); + + QtJniTypes::View m_view; + bool m_nativeViewInserted; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index 7f2252a4e93..7ffa79e2c1e 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -58,12 +58,14 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) { - if (QAndroidEventDispatcherStopper::stopped() || QGuiApplication::applicationState() == Qt::ApplicationSuspended) + if (QAndroidEventDispatcherStopper::stopped() || + QGuiApplication::applicationState() == Qt::ApplicationSuspended || !window()->isTopLevel()) { return m_eglSurface; + } QMutexLocker lock(&m_surfaceMutex); - if (m_nativeSurfaceId == -1) { + if (!m_surfaceCreated) { AndroidDeadlockProtector protector; if (!protector.acquire()) return m_eglSurface; @@ -83,7 +85,7 @@ EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) bool QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config) { QMutexLocker lock(&m_surfaceMutex); - if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid()) + if (!m_surfaceCreated || !m_androidSurfaceObject.isValid()) return false; // makeCurrent is NOT needed. createEgl(config); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index 268772e2655..9e20b7ac4bd 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -132,16 +132,16 @@ QAndroidPlatformScreen::~QAndroidPlatformScreen() { } -QWindow *QAndroidPlatformScreen::topWindow() const +QWindow *QAndroidPlatformScreen::topVisibleWindow() const { for (QAndroidPlatformWindow *w : m_windowStack) { - if (w->window()->type() == Qt::Window || - w->window()->type() == Qt::Popup || - w->window()->type() == Qt::Dialog) { + Qt::WindowType type = w->window()->type(); + if (w->window()->isVisible() && + (type == Qt::Window || type == Qt::Popup || type == Qt::Dialog)) { return w->window(); } } - return 0; + return nullptr; } QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const @@ -162,37 +162,34 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) return; m_windowStack.prepend(window); + QtAndroid::qtActivityDelegate().callMethod("addTopLevelWindow", window->nativeWindow()); - QWindow *w = topWindow(); - QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); - topWindowChanged(w); + if (window->window()->isVisible()) + topVisibleWindowChanged(); } void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) { - if (window->parent() && window->isRaster()) - return; - m_windowStack.removeOne(window); if (m_windowStack.contains(window)) qWarning() << "Failed to remove window"; - QWindow *w = topWindow(); - QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); - topWindowChanged(w); + QtAndroid::qtActivityDelegate().callMethod("removeTopLevelWindow", window->nativeViewId()); + + topVisibleWindowChanged(); } void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window) { int index = m_windowStack.indexOf(window); - if (index <= 0) + if (index < 0) return; - m_windowStack.move(index, 0); - - QWindow *w = topWindow(); - QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); - topWindowChanged(w); + if (index > 0) { + m_windowStack.move(index, 0); + QtAndroid::qtActivityDelegate().callMethod("bringChildToFront", window->nativeViewId()); + } + topVisibleWindowChanged(); } void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window) @@ -201,10 +198,9 @@ 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("bringChildToBack", window->nativeViewId()); - QWindow *w = topWindow(); - QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); - topWindowChanged(w); + topVisibleWindowChanged(); } void QAndroidPlatformScreen::setPhysicalSize(const QSize &size) @@ -284,13 +280,14 @@ void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state) w->applicationStateChanged(state); } -void QAndroidPlatformScreen::topWindowChanged(QWindow *w) +void QAndroidPlatformScreen::topVisibleWindowChanged() { + QWindow *w = topVisibleWindow(); + QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason); QtAndroidMenu::setActiveTopLevelWindow(w); - - if (w != 0) { + if (w && w->handle()) { QAndroidPlatformWindow *platformWindow = static_cast(w->handle()); - if (platformWindow != 0) + if (platformWindow) platformWindow->updateSystemUiVisibility(); } } diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 0e2f788886b..e7ce6ed59f0 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -37,7 +37,7 @@ public: int currentMode() const override { return m_currentMode; } int preferredMode() const override { return m_currentMode; } qreal refreshRate() const override { return m_refreshRate; } - inline QWindow *topWindow() const; + inline QWindow *topVisibleWindow() const; QWindow *topLevelAt(const QPoint & p) const override; void addWindow(QAndroidPlatformWindow *window); @@ -45,7 +45,7 @@ public: void raise(QAndroidPlatformWindow *window); void lower(QAndroidPlatformWindow *window); - void topWindowChanged(QWindow *w); + void topVisibleWindowChanged(); int displayId() const override; public slots: @@ -60,7 +60,6 @@ public slots: protected: typedef QList WindowStackType; WindowStackType m_windowStack; - QRect m_availableGeometry; int m_depth; QImage::Format m_format; diff --git a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp index df87240c2b0..43b3a903734 100644 --- a/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformvulkanwindow.cpp @@ -94,7 +94,7 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() clearSurface(); QMutexLocker lock(&m_surfaceMutex); - if (m_nativeSurfaceId == -1) { + if (!m_surfaceCreated) { AndroidDeadlockProtector protector; if (!protector.acquire()) return &m_vkSurface; @@ -102,7 +102,7 @@ VkSurfaceKHR *QAndroidPlatformVulkanWindow::vkSurface() m_surfaceWaitCondition.wait(&m_surfaceMutex); } - if (m_nativeSurfaceId == -1 || !m_androidSurfaceObject.isValid()) + if (!m_surfaceCreated || !m_androidSurfaceObject.isValid()) return &m_vkSurface; QJniEnvironment env; diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 23b83834d45..1e30799ae45 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -14,11 +14,15 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcQpaWindow, "qt.qpa.window") + Q_CONSTINIT static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) - : QPlatformWindow(window), m_androidSurfaceObject(nullptr) + : QPlatformWindow(window), m_nativeQtWindow(QNativeInterface::QAndroidApplication::context()), + 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 @@ -44,8 +48,15 @@ QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) if (requestedNativeGeometry != finalNativeGeometry) setGeometry(finalNativeGeometry); } + platformScreen()->addWindow(this); } +QAndroidPlatformWindow::~QAndroidPlatformWindow() +{ + platformScreen()->removeWindow(this); +} + + void QAndroidPlatformWindow::lower() { platformScreen()->lower(this); @@ -76,23 +87,19 @@ void QAndroidPlatformWindow::setGeometry(const QRect &rect) void QAndroidPlatformWindow::setVisible(bool visible) { - if (visible) - updateSystemUiVisibility(); - 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()); } + requestActivateWindow(); + } else if (window() == qGuiApp->focusWindow()) { + platformScreen()->topVisibleWindowChanged(); } - if (visible) - platformScreen()->addWindow(this); - else - platformScreen()->removeWindow(this); - QRect availableGeometry = screen()->availableGeometry(); if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0) QPlatformWindow::setVisible(visible); @@ -125,7 +132,14 @@ Qt::WindowFlags QAndroidPlatformWindow::windowFlags() const void QAndroidPlatformWindow::setParent(const QPlatformWindow *window) { - Q_UNUSED(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 + if (window) { + platformScreen()->removeWindow(this); + } else { + platformScreen()->addWindow(this); + } } QAndroidPlatformScreen *QAndroidPlatformWindow::platformScreen() const @@ -140,7 +154,8 @@ void QAndroidPlatformWindow::propagateSizeHints() void QAndroidPlatformWindow::requestActivateWindow() { - platformScreen()->topWindowChanged(window()); + if (!blockedByModal()) + raise(); } void QAndroidPlatformWindow::updateSystemUiVisibility() @@ -176,25 +191,62 @@ void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState) void QAndroidPlatformWindow::createSurface() { + const QRect rect = geometry(); + jint x = 0, y = 0, w = -1, h = -1; + if (!rect.isNull()) { + x = rect.x(); + y = rect.y(); + w = std::max(rect.width(), 1); + h = std::max(rect.height(), 1); + } + const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint); - m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32); + + m_nativeQtWindow.callMethod("createSurface", windowStaysOnTop, x, y, w, h, 32); + m_surfaceCreated = true; } void QAndroidPlatformWindow::destroySurface() { - if (m_nativeSurfaceId != -1) { - QtAndroid::destroySurface(m_nativeSurfaceId); - m_nativeSurfaceId = -1; + if (m_surfaceCreated) { + m_nativeQtWindow.callMethod("destroySurface"); + m_surfaceCreated = false; } } -void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &rect) +void QAndroidPlatformWindow::setSurfaceGeometry(const QRect &geometry) { - if (m_nativeSurfaceId != -1) - QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect); + if (!m_surfaceCreated) + return; + + jint x = 0; + jint y = 0; + jint w = -1; + jint h = -1; + if (!geometry.isNull()) { + x = geometry.x(); + y = geometry.y(); + w = geometry.width(); + h = geometry.height(); + } + m_nativeQtWindow.callMethod("setSurfaceGeometry", x, y, w, h); } -void QAndroidPlatformWindow::sendExpose() +void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface) +{ + lockSurface(); + m_androidSurfaceObject = surface; + if (m_androidSurfaceObject.isValid()) // wait until we have a valid surface to draw into + m_surfaceWaitCondition.wakeOne(); + unlockSurface(); + + if (m_androidSurfaceObject.isValid()) { + // repaint the window, when we have a valid surface + sendExpose(); + } +} + +void QAndroidPlatformWindow::sendExpose() const { QRect availableGeometry = screen()->availableGeometry(); if (!geometry().isNull() && !availableGeometry.isNull()) { @@ -203,15 +255,41 @@ void QAndroidPlatformWindow::sendExpose() } } -void QAndroidPlatformWindow::onSurfaceChanged(QtJniTypes::Surface surface) +bool QAndroidPlatformWindow::blockedByModal() const { - lockSurface(); - m_androidSurfaceObject = surface; - if (m_androidSurfaceObject.isValid()) - m_surfaceWaitCondition.wakeOne(); - unlockSurface(); - if (m_androidSurfaceObject.isValid()) - sendExpose(); + QWindow *modalWindow = QGuiApplication::modalWindow(); + return modalWindow && modalWindow != window(); +} + +void QAndroidPlatformWindow::setSurface(JNIEnv *env, jobject object, jint windowId, + QtJniTypes::Surface surface) +{ + Q_UNUSED(env) + Q_UNUSED(object) + + if (!qGuiApp) + return; + + const QList windows = qGuiApp->allWindows(); + for (QWindow * window : windows) { + if (!window->handle()) + continue; + QAndroidPlatformWindow *platformWindow = + static_cast(window->handle()); + if (platformWindow->nativeViewId() == windowId) + platformWindow->onSurfaceChanged(surface); + } +} + +bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env) +{ + if (!env.registerNativeMethods(QtJniTypes::Traits::className(), + {Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow)})) { + qCCritical(lcQpaWindow) << "RegisterNatives failed for" + << QtJniTypes::Traits::className(); + return false; + } + return true; } QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index a676ef1dd3b..88949d84daa 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -17,6 +17,8 @@ QT_BEGIN_NAMESPACE +Q_DECLARE_LOGGING_CATEGORY(lcQpaWindow) +Q_DECLARE_JNI_CLASS(QtWindow, "org/qtproject/qt/android/QtWindow") Q_DECLARE_JNI_CLASS(Surface, "android/view/Surface") class QAndroidPlatformScreen; @@ -25,7 +27,7 @@ class QAndroidPlatformWindow: public QPlatformWindow { public: explicit QAndroidPlatformWindow(QWindow *window); - + ~QAndroidPlatformWindow(); void lower() override; void raise() override; @@ -49,9 +51,12 @@ public: void updateSystemUiVisibility(); inline bool isRaster() const { return m_isRaster; } bool isExposed() const override; + QtJniTypes::QtWindow nativeWindow() const { return m_nativeQtWindow; } virtual void applicationStateChanged(Qt::ApplicationState); + int nativeViewId() const { return m_nativeViewId; } + static bool registerNatives(QJniEnvironment &env); void onSurfaceChanged(QtJniTypes::Surface surface); protected: @@ -60,20 +65,27 @@ protected: void unlockSurface() { m_surfaceMutex.unlock(); } void createSurface(); void destroySurface(); - void setSurfaceGeometry(const QRect &rect); - void sendExpose(); + void setSurfaceGeometry(const QRect &geometry); + void sendExpose() const; + bool blockedByModal() const; -protected: Qt::WindowFlags m_windowFlags; Qt::WindowStates m_windowState; bool m_isRaster; WId m_windowId; + + QtJniTypes::QtWindow m_nativeQtWindow; // The Android Surface, accessed from multiple threads, guarded by m_surfaceMutex QtJniTypes::Surface m_androidSurfaceObject; QWaitCondition m_surfaceWaitCondition; - int m_nativeSurfaceId = -1; + int m_nativeViewId = -1; + bool m_surfaceCreated = false; QMutex m_surfaceMutex; + +private: + static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface); + Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface) }; QT_END_NAMESPACE