Android: Make QtLayout per window instead of per screen
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ø <tor.arne.vestbo@qt.io> Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
0bfec6cd11
commit
0a92d881bb
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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<Integer, QtSurface> m_surfaces = null;
|
||||
private HashMap<Integer, View> m_nativeViews = null;
|
||||
private QtLayout m_layout = null;
|
||||
private HashMap<Integer, QtWindow> 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<Integer, QtWindow>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
114
src/android/jar/src/org/qtproject/qt/android/QtWindow.java
Normal file
114
src/android/jar/src/org/qtproject/qt/android/QtWindow.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -70,10 +70,6 @@ static void *m_mainLibraryHnd = nullptr;
|
||||
static QList<QByteArray> m_applicationParams;
|
||||
static sem_t m_exitSemaphore, m_terminateSemaphore;
|
||||
|
||||
QHash<int, QAndroidPlatformWindow *> 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<jint>("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<void>("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<void>("insertNativeView",
|
||||
surfaceId,
|
||||
view,
|
||||
x,
|
||||
y,
|
||||
qMax(w, 1),
|
||||
qMax(h, 1));
|
||||
|
||||
return surfaceId;
|
||||
}
|
||||
|
||||
void setViewVisibility(jobject view, bool visible)
|
||||
{
|
||||
QJniObject::callStaticMethod<void>(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<void>("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<void>("destroySurface", surfaceId);
|
||||
}
|
||||
|
||||
void bringChildToFront(int surfaceId)
|
||||
{
|
||||
if (surfaceId == -1)
|
||||
return;
|
||||
|
||||
qtActivityDelegate().callMethod<void>("bringChildToFront", surfaceId);
|
||||
}
|
||||
|
||||
void bringChildToBack(int surfaceId)
|
||||
{
|
||||
if (surfaceId == -1)
|
||||
return;
|
||||
|
||||
qtActivityDelegate().callMethod<void>("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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -6,12 +6,12 @@
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <QtCore/private/qjnihelpers_p.h>
|
||||
#include <QtCore/qjnitypes.h>
|
||||
|
||||
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<jobject>(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<void>("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<void>("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<void>("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<void>("setNativeView", m_view, x, y, qMax(w, 1), qMax(h, 1));
|
||||
m_nativeViewInserted = true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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<void>("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<void>("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<void>("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<void>("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<QAndroidPlatformWindow *>(w->handle());
|
||||
if (platformWindow != 0)
|
||||
if (platformWindow)
|
||||
platformWindow->updateSystemUiVisibility();
|
||||
}
|
||||
}
|
||||
|
@ -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<QAndroidPlatformWindow *> WindowStackType;
|
||||
WindowStackType m_windowStack;
|
||||
|
||||
QRect m_availableGeometry;
|
||||
int m_depth;
|
||||
QImage::Format m_format;
|
||||
|
@ -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;
|
||||
|
@ -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<jint>("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<void>("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<void>("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<void>("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<QWindow*> windows = qGuiApp->allWindows();
|
||||
for (QWindow * window : windows) {
|
||||
if (!window->handle())
|
||||
continue;
|
||||
QAndroidPlatformWindow *platformWindow =
|
||||
static_cast<QAndroidPlatformWindow *>(window->handle());
|
||||
if (platformWindow->nativeViewId() == windowId)
|
||||
platformWindow->onSurfaceChanged(surface);
|
||||
}
|
||||
}
|
||||
|
||||
bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env)
|
||||
{
|
||||
if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
|
||||
{Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow)})) {
|
||||
qCCritical(lcQpaWindow) << "RegisterNatives failed for"
|
||||
<< QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user