11#include <qguiapplication.h>
12#include <qpa/qwindowsysteminterface.h>
13#include <private/qhighdpiscaling_p.h>
14#include <private/qjnihelpers_p.h>
18Q_LOGGING_CATEGORY(lcQpaWindow,
"qt.qpa.window")
20Q_DECLARE_JNI_CLASS(QtWindowInterface,
"org/qtproject/qt/android/QtWindowInterface")
21Q_DECLARE_JNI_CLASS(QtInputInterface,
"org/qtproject/qt/android/QtInputInterface")
22Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
23 "org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
24Q_DECLARE_JNI_CLASS(QtDisplayManager,
"org/qtproject/qt/android/QtWindowInterface")
26QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
27 : QPlatformWindow(window), m_nativeQtWindow(
nullptr),
28 m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(
nullptr),
29 m_androidSurfaceObject(
nullptr)
31 if (window->surfaceType() == QSurface::RasterSurface)
32 window->setSurfaceType(QSurface::OpenGLSurface);
40 QWindow *window = QPlatformWindow::window();
44 if (!androidParent->isEmbeddingContainer())
45 m_nativeParentQtWindow = androidParent->nativeWindow();
49 QtJniTypes::QtInputConnectionListener listener =
50 reg->callInterface<QtJniTypes::QtInputInterface, QtJniTypes::QtInputConnectionListener>(
51 "getInputConnectionListener");
53 m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
54 QNativeInterface::QAndroidApplication::context(),
55 isForeignWindow(), m_nativeParentQtWindow, listener);
56 m_nativeViewId = m_nativeQtWindow.callMethod<jint>(
"getId");
58 m_windowFlags = Qt::Widget;
59 m_windowState = Qt::WindowNoState;
62 m_isRaster = window->surfaceType() == QSurface::RasterSurface;
63 setWindowState(window->windowStates());
66 const bool forceMaximize = m_windowState & (Qt::WindowMaximized | Qt::WindowFullScreen);
67 const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
69 setGeometry(nativeScreenGeometry);
71 const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
72 const QRect availableDeviceIndependentGeometry = (window->parent())
73 ? window->parent()->geometry()
74 : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
76 const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
77 window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
78 availableDeviceIndependentGeometry.height());
79 setGeometry(finalNativeGeometry);
82 if (window->isTopLevel())
83 platformScreen()->addWindow(
this);
85 static bool ok =
false;
86 static const int value = qEnvironmentVariableIntValue(
"QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
91 }
else if (platformScreen()->windows().size() <= 1) {
97 qCDebug(lcQpaWindow) <<
"Window" << m_nativeViewId <<
"using surface container type"
98 <<
static_cast<
int>(m_surfaceContainerType);
103 const auto guard = destructionGuard();
104 if (window()->isTopLevel())
105 platformScreen()->removeWindow(
this);
111 if (m_nativeParentQtWindow.isValid()) {
112 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToBack", nativeViewId());
115 platformScreen()->lower(
this);
120 if (m_nativeParentQtWindow.isValid()) {
121 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToFront", nativeViewId());
122 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
126 platformScreen()->raise(
this);
131 return m_safeAreaMargins;
136 m_safeAreaMargins = safeMargins;
142 Q_ASSERT(m_nativeQtWindow.isValid());
148 if (!rect.isNull()) {
154 m_nativeQtWindow.callMethod<
void>(
"setGeometry", x, y, w, h);
157 QWindowSystemInterface::handleGeometryChange(window(), rect);
165 if (window()->isTopLevel()) {
166 if (!visible && window() ==
qGuiApp->focusWindow()) {
167 platformScreen()->topVisibleWindowChanged();
170 if ((m_windowState & Qt::WindowFullScreen)
171 || (window()->flags() & Qt::ExpandedClientAreaHint)) {
172 setGeometry(platformScreen()->geometry());
173 }
else if (m_windowState & Qt::WindowMaximized) {
174 setGeometry(platformScreen()->availableGeometry());
180 m_nativeQtWindow.callMethod<
void>(
"setVisible", visible);
182 if (geometry().isEmpty() || screen()->availableGeometry().isEmpty())
185 QPlatformWindow::setVisible(visible);
190 if (m_windowState == state)
193 QPlatformWindow::setWindowState(state);
194 m_windowState = state;
196 if (window()->isVisible())
202 if (m_windowFlags == flags)
205 m_windowFlags = flags;
210 return m_windowFlags;
215 using namespace QtJniTypes;
219 if (androidWindow->isEmbeddingContainer())
222 if (!m_nativeParentQtWindow.isValid())
223 platformScreen()->removeWindow(
this);
225 const QtWindow parentWindow = androidWindow->nativeWindow();
227 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent", parentWindow.object());
228 m_nativeParentQtWindow = parentWindow;
230 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent",
nullptr);
231 m_nativeParentQtWindow = QJniObject();
232 platformScreen()->addWindow(
this);
238 return m_nativeQtWindow.isValid() ?
reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
260 const int flags = window()->flags();
261 const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
262 if (!isNonRegularWindow) {
263 const bool isFullScreen = (m_windowState & Qt::WindowFullScreen);
264 const bool expandedToCutout = (flags & Qt::ExpandedClientAreaHint);
265 QtAndroid::backendRegister()->callInterface<QtJniTypes::QtWindowInterface,
void>(
266 "setSystemUiVisibility", isFullScreen, expandedToCutout);
272 m_nativeQtWindow.callMethod<
void>(
"updateFocusedEditText");
277 return qApp->applicationState() > Qt::ApplicationHidden
278 && window()->isVisible()
279 && !window()->geometry().isEmpty();
286 region = QRect(QPoint(), geometry().size());
288 QWindowSystemInterface::handleExposeEvent(window(), region);
289 QWindowSystemInterface::flushWindowSystemEvents();
294 const bool windowStaysOnTop =
bool(window()->flags() & Qt::WindowStaysOnTopHint);
295 const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), qreal(1.0));
297 m_nativeQtWindow.callMethod<
void>(
"createSurface", windowStaysOnTop, 32, isOpaque,
298 m_surfaceContainerType);
305 m_nativeQtWindow.callMethod<
void>(
"destroySurface");
313 const bool surfaceIsValid = surface.isValid();
314 qCDebug(lcQpaWindow) <<
"onSurfaceChanged(): valid Surface received" << surfaceIsValid;
315 m_androidSurfaceObject = surface;
316 if (surfaceIsValid) {
318 m_surfaceWaitCondition.wakeOne();
330 QRect availableGeometry = screen()->availableGeometry();
331 if (!geometry().isNull() && !availableGeometry.isNull()) {
332 QWindowSystemInterface::handleExposeEvent(window(),
333 QRegion(QRect(QPoint(), geometry().size())));
339 QWindow *modalWindow = QGuiApplication::modalWindow();
340 return modalWindow && modalWindow != window();
351 QtJniTypes::Surface surface)
359 const QList<QWindow*> windows =
qGuiApp->allWindows();
360 for (QWindow * window : windows) {
361 if (!window->handle())
363 QAndroidPlatformWindow *platformWindow =
364 static_cast<QAndroidPlatformWindow *>(window->handle());
365 const auto guard = platformWindow->destructionGuard();
366 if (!platformWindow->m_androidSurfaceCreated)
368 if (platformWindow->nativeViewId() == windowId)
369 platformWindow->onSurfaceChanged(surface);
374 jboolean focus, jint windowId)
380 qCWarning(lcQpaWindow,
381 "windowFocusChanged event received for non-existing window %d", windowId);
386 QWindowSystemInterface::handleFocusWindowChanged(window);
387 }
else if (!focus && window ==
qGuiApp->focusWindow()) {
389 QWindowSystemInterface::handleFocusWindowChanged(
nullptr);
394 QtJniTypes::Insets insets, jint id)
402 if (!insets.isValid())
406 for (QWindow *window :
qGuiApp->allWindows()) {
407 if (!window->handle())
409 QAndroidPlatformWindow *pw =
static_cast<QAndroidPlatformWindow *>(window->handle());
410 if (pw->nativeViewId() == id) {
419 QMargins safeMargins = QMargins(
420 insets.getField<
int>(
"left"),
421 insets.getField<
int>(
"top"),
422 insets.getField<
int>(
"right"),
423 insets.getField<
int>(
"bottom"));
425 if (safeMargins != pWindow->safeAreaMargins()) {
426 pWindow->setSafeAreaMargins(safeMargins);
427 QWindowSystemInterface::handleSafeAreaMarginsChanged(pWindow->window());
436 if (QGuiApplication::instance() !=
nullptr) {
437 const auto tlw = QGuiApplication::topLevelWindows();
438 for (QWindow *w : tlw) {
444 const QRect availableGeometry = w->screen()->availableGeometry();
445 const QRect geometry = w->geometry();
446 const bool isPositiveGeometry = (geometry.width() > 0 && geometry.height() > 0);
447 const bool isPositiveAvailableGeometry =
448 (availableGeometry.width() > 0 && availableGeometry.height() > 0);
450 if (isPositiveGeometry && isPositiveAvailableGeometry) {
451 const QRegion region = QRegion(QRect(QPoint(), w->geometry().size()));
452 QWindowSystemInterface::handleExposeEvent(w, region);
457Q_DECLARE_JNI_NATIVE_METHOD(updateWindows)
460
461
462
463
464
465
466QMutexLocker<QMutex> QAndroidPlatformWindow::destructionGuard()
468 return QMutexLocker(&m_destructionMutex);
473 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
475 Q_JNI_NATIVE_METHOD(updateWindows),
476 Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
477 Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow),
478 Q_JNI_NATIVE_SCOPED_METHOD(safeAreaMarginsChanged, QAndroidPlatformWindow)
480 qCCritical(lcQpaWindow) <<
"RegisterNatives failed for"
481 << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)