12#include <qguiapplication.h>
13#include <qpa/qwindowsysteminterface.h>
14#include <private/qhighdpiscaling_p.h>
15#include <private/qjnihelpers_p.h>
19Q_LOGGING_CATEGORY(lcQpaWindow,
"qt.qpa.window")
21Q_DECLARE_JNI_CLASS(QtWindowInterface,
"org/qtproject/qt/android/QtWindowInterface")
22Q_DECLARE_JNI_CLASS(QtInputInterface,
"org/qtproject/qt/android/QtInputInterface")
23Q_DECLARE_JNI_CLASS(QtInputConnectionListener,
24 "org/qtproject/qt/android/QtInputConnection$QtInputConnectionListener")
25Q_DECLARE_JNI_CLASS(QtDisplayManager,
"org/qtproject/qt/android/QtWindowInterface")
26Q_DECLARE_JNI_CLASS(QtWindowInsetsController,
"org/qtproject/qt/android/QtWindowInsetsController")
28QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
29 : QPlatformWindow(window), m_nativeQtWindow(
nullptr),
30 m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(
nullptr),
31 m_androidSurfaceObject(
nullptr)
33 if (window->surfaceType() == QSurface::RasterSurface)
34 window->setSurfaceType(QSurface::OpenGLSurface);
42 QWindow *window = QPlatformWindow::window();
46 if (!androidParent->isEmbeddingContainer())
47 m_nativeParentQtWindow = androidParent->nativeWindow();
51 QtJniTypes::QtInputConnectionListener listener =
52 reg->callInterface<QtJniTypes::QtInputInterface, QtJniTypes::QtInputConnectionListener>(
53 "getInputConnectionListener");
55 m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
56 QNativeInterface::QAndroidApplication::context(),
57 isForeignWindow(), m_nativeParentQtWindow, listener);
58 m_nativeViewId = m_nativeQtWindow.callMethod<jint>(
"getId");
62 m_isRaster = window->surfaceType() == QSurface::RasterSurface;
65 const bool forceMaximize = window->windowStates() & (Qt::WindowMaximized | Qt::WindowFullScreen);
66 const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
68 setGeometry(nativeScreenGeometry);
70 const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
71 const QRect availableDeviceIndependentGeometry = (window->parent())
72 ? window->parent()->geometry()
73 : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
75 const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
76 window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
77 availableDeviceIndependentGeometry.height());
78 setGeometry(finalNativeGeometry);
81 if (window->isTopLevel())
82 platformScreen()->addWindow(
this);
84 static bool ok =
false;
85 static const int value = qEnvironmentVariableIntValue(
"QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
90 }
else if (platformScreen()->windows().size() <= 1) {
96 qCDebug(lcQpaWindow) <<
"Window" <<
m_nativeViewId <<
"using surface container type"
102 const auto guard = destructionGuard();
103 if (window()->isTopLevel())
104 platformScreen()->removeWindow(
this);
110 if (m_nativeParentQtWindow.isValid()) {
111 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToBack", nativeViewId());
114 platformScreen()->lower(
this);
119 if (m_nativeParentQtWindow.isValid()) {
120 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToFront", nativeViewId());
121 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
124 updateSystemUiVisibility(window()->windowStates(), window()->flags());
125 platformScreen()->raise(
this);
130 return m_safeAreaMargins;
135 m_safeAreaMargins = safeMargins;
141 Q_ASSERT(m_nativeQtWindow.isValid());
147 if (!rect.isNull()) {
153 m_nativeQtWindow.callMethod<
void>(
"setGeometry", x, y, w, h);
156 QWindowSystemInterface::handleGeometryChange(window(), rect);
164 if (window()->isTopLevel()) {
165 if (!visible && window() ==
qGuiApp->focusWindow()) {
166 platformScreen()->topVisibleWindowChanged();
168 const Qt::WindowStates states = window()->windowStates();
169 const Qt::WindowFlags flags = window()->flags();
170 updateSystemUiVisibility(states, flags);
171 if (states & Qt::WindowFullScreen || flags & Qt::ExpandedClientAreaHint)
172 setGeometry(platformScreen()->geometry());
173 else if (states & Qt::WindowMaximized)
174 setGeometry(platformScreen()->availableGeometry());
179 m_nativeQtWindow.callMethod<
void>(
"setVisible", visible);
181 if (geometry().isEmpty() || screen()->availableGeometry().isEmpty())
184 QPlatformWindow::setVisible(visible);
189 QPlatformWindow::setWindowState(state);
191 if (window()->isVisible())
192 updateSystemUiVisibility(state, window()->flags());
197 QPlatformWindow::setWindowFlags(flags);
199 if (window()->isVisible())
200 updateSystemUiVisibility(window()->windowStates(), flags);
205 using namespace QtJniTypes;
209 if (androidWindow->isEmbeddingContainer())
212 if (!m_nativeParentQtWindow.isValid())
213 platformScreen()->removeWindow(
this);
215 const QtWindow parentWindow = androidWindow->nativeWindow();
217 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent", parentWindow.object());
218 m_nativeParentQtWindow = parentWindow;
220 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent",
nullptr);
221 m_nativeParentQtWindow = QJniObject();
222 platformScreen()->addWindow(
this);
228 return m_nativeQtWindow.isValid() ?
reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
250 const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
251 if (!isNonRegularWindow) {
252 auto iface =
qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
253 iface->runOnAndroidMainThread([=]() {
254 using namespace QtJniTypes;
255 auto activity = iface->context().object<Activity>();
256 if (states & Qt::WindowFullScreen)
257 QtWindowInsetsController::callStaticMethod(
"showFullScreen", activity);
258 else if (flags & Qt::ExpandedClientAreaHint)
259 QtWindowInsetsController::callStaticMethod(
"showExpanded", activity);
261 QtWindowInsetsController::callStaticMethod(
"showNormal", activity);
268 m_nativeQtWindow.callMethod<
void>(
"updateFocusedEditText");
273 return qApp->applicationState() > Qt::ApplicationHidden
274 && window()->isVisible()
275 && !window()->geometry().isEmpty();
282 region = QRect(QPoint(), geometry().size());
284 QWindowSystemInterface::handleExposeEvent(window(), region);
285 QWindowSystemInterface::flushWindowSystemEvents();
290 const bool windowStaysOnTop =
bool(window()->flags() & Qt::WindowStaysOnTopHint);
291 const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), qreal(1.0));
293 m_nativeQtWindow.callMethod<
void>(
"createSurface", windowStaysOnTop, 32, isOpaque,
294 m_surfaceContainerType);
301 m_nativeQtWindow.callMethod<
void>(
"destroySurface");
309 const bool surfaceIsValid = surface.isValid();
310 qCDebug(lcQpaWindow) <<
"onSurfaceChanged(): valid Surface received" << surfaceIsValid;
311 m_androidSurfaceObject = surface;
312 if (surfaceIsValid) {
314 m_surfaceWaitCondition.wakeOne();
326 QRect availableGeometry = screen()->availableGeometry();
327 if (!geometry().isNull() && !availableGeometry.isNull()) {
328 QWindowSystemInterface::handleExposeEvent(window(),
329 QRegion(QRect(QPoint(), geometry().size())));
335 QWindow *modalWindow = QGuiApplication::modalWindow();
336 return modalWindow && modalWindow != window();
347 QtJniTypes::Surface surface)
355 const QList<QWindow*> windows =
qGuiApp->allWindows();
356 for (QWindow * window : windows) {
357 if (!window->handle())
359 QAndroidPlatformWindow *platformWindow =
360 static_cast<QAndroidPlatformWindow *>(window->handle());
361 const auto guard = platformWindow->destructionGuard();
362 if (!platformWindow->m_androidSurfaceCreated)
364 if (platformWindow->nativeViewId() == windowId)
365 platformWindow->onSurfaceChanged(surface);
370 jboolean focus, jint windowId)
376 qCWarning(lcQpaWindow,
377 "windowFocusChanged event received for non-existing window %d", windowId);
382 QWindowSystemInterface::handleFocusWindowChanged(window);
383 }
else if (!focus && window ==
qGuiApp->focusWindow()) {
385 QWindowSystemInterface::handleFocusWindowChanged(
nullptr);
390 QtJniTypes::Insets insets, jint id)
398 if (!insets.isValid())
402 for (QWindow *window :
qGuiApp->allWindows()) {
403 if (!window->handle())
405 QAndroidPlatformWindow *pw =
static_cast<QAndroidPlatformWindow *>(window->handle());
406 if (pw->nativeViewId() == id) {
415 QMargins safeMargins = QMargins(
416 insets.getField<
int>(
"left"),
417 insets.getField<
int>(
"top"),
418 insets.getField<
int>(
"right"),
419 insets.getField<
int>(
"bottom"));
421 if (safeMargins != pWindow->safeAreaMargins()) {
422 pWindow->setSafeAreaMargins(safeMargins);
423 QWindowSystemInterface::handleSafeAreaMarginsChanged(pWindow->window());
432 if (QGuiApplication::instance() !=
nullptr) {
433 const auto tlw = QGuiApplication::topLevelWindows();
434 for (QWindow *w : tlw) {
440 const QRect availableGeometry = w->screen()->availableGeometry();
441 const QRect geometry = w->geometry();
442 const bool isPositiveGeometry = (geometry.width() > 0 && geometry.height() > 0);
443 const bool isPositiveAvailableGeometry =
444 (availableGeometry.width() > 0 && availableGeometry.height() > 0);
446 if (isPositiveGeometry && isPositiveAvailableGeometry) {
447 const QRegion region = QRegion(QRect(QPoint(), w->geometry().size()));
448 QWindowSystemInterface::handleExposeEvent(w, region);
453Q_DECLARE_JNI_NATIVE_METHOD(updateWindows)
456
457
458
459
460
461
462QMutexLocker<QMutex> QAndroidPlatformWindow::destructionGuard()
464 return QMutexLocker(&m_destructionMutex);
467Q_CONSTINIT
static QBasicAtomicInt g_surfacesCounter = Q_BASIC_ATOMIC_INITIALIZER(0);
471 return g_surfacesCounter.loadRelaxed();
476 g_surfacesCounter.fetchAndAddRelaxed(1);
481 int cur = g_surfacesCounter.loadRelaxed();
486 if (g_surfacesCounter.testAndSetRelaxed(cur, cur - 1))
493 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
495 Q_JNI_NATIVE_METHOD(updateWindows),
496 Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
497 Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow),
498 Q_JNI_NATIVE_SCOPED_METHOD(safeAreaMarginsChanged, QAndroidPlatformWindow)
500 qCCritical(lcQpaWindow) <<
"RegisterNatives failed for"
501 << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
Combined button and popup list for selecting options.
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)