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")
25Q_DECLARE_JNI_CLASS(QtWindowInsetsController,
"org/qtproject/qt/android/QtWindowInsetsController")
27QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window)
28 : QPlatformWindow(window), m_nativeQtWindow(
nullptr),
29 m_surfaceContainerType(SurfaceContainer::TextureView), m_nativeParentQtWindow(
nullptr),
30 m_androidSurfaceObject(
nullptr)
32 if (window->surfaceType() == QSurface::RasterSurface)
33 window->setSurfaceType(QSurface::OpenGLSurface);
41 QWindow *window = QPlatformWindow::window();
45 if (!androidParent->isEmbeddingContainer())
46 m_nativeParentQtWindow = androidParent->nativeWindow();
50 QtJniTypes::QtInputConnectionListener listener =
51 reg->callInterface<QtJniTypes::QtInputInterface, QtJniTypes::QtInputConnectionListener>(
52 "getInputConnectionListener");
54 m_nativeQtWindow = QJniObject::construct<QtJniTypes::QtWindow>(
55 QNativeInterface::QAndroidApplication::context(),
56 isForeignWindow(), m_nativeParentQtWindow, listener);
57 m_nativeViewId = m_nativeQtWindow.callMethod<jint>(
"getId");
61 m_isRaster = window->surfaceType() == QSurface::RasterSurface;
64 const bool forceMaximize = window->windowStates() & (Qt::WindowMaximized | Qt::WindowFullScreen);
65 const QRect nativeScreenGeometry = platformScreen()->availableGeometry();
67 setGeometry(nativeScreenGeometry);
69 const QRect requestedNativeGeometry = QHighDpi::toNativePixels(window->geometry(), window);
70 const QRect availableDeviceIndependentGeometry = (window->parent())
71 ? window->parent()->geometry()
72 : QHighDpi::fromNativePixels(nativeScreenGeometry, window);
74 const QRect finalNativeGeometry = QPlatformWindow::initialGeometry(
75 window, requestedNativeGeometry, availableDeviceIndependentGeometry.width(),
76 availableDeviceIndependentGeometry.height());
77 setGeometry(finalNativeGeometry);
80 if (window->isTopLevel())
81 platformScreen()->addWindow(
this);
83 static bool ok =
false;
84 static const int value = qEnvironmentVariableIntValue(
"QT_ANDROID_SURFACE_CONTAINER_TYPE", &ok);
89 }
else if (platformScreen()->windows().size() <= 1) {
95 qCDebug(lcQpaWindow) <<
"Window" << m_nativeViewId <<
"using surface container type"
96 <<
static_cast<
int>(m_surfaceContainerType);
101 const auto guard = destructionGuard();
102 if (window()->isTopLevel())
103 platformScreen()->removeWindow(
this);
109 if (m_nativeParentQtWindow.isValid()) {
110 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToBack", nativeViewId());
113 platformScreen()->lower(
this);
118 if (m_nativeParentQtWindow.isValid()) {
119 m_nativeParentQtWindow.callMethod<
void>(
"bringChildToFront", nativeViewId());
120 QWindowSystemInterface::handleFocusWindowChanged(window(), Qt::ActiveWindowFocusReason);
123 updateSystemUiVisibility(window()->windowStates(), window()->flags());
124 platformScreen()->raise(
this);
129 return m_safeAreaMargins;
134 m_safeAreaMargins = safeMargins;
140 Q_ASSERT(m_nativeQtWindow.isValid());
146 if (!rect.isNull()) {
152 m_nativeQtWindow.callMethod<
void>(
"setGeometry", x, y, w, h);
155 QWindowSystemInterface::handleGeometryChange(window(), rect);
163 if (window()->isTopLevel()) {
164 if (!visible && window() ==
qGuiApp->focusWindow()) {
165 platformScreen()->topVisibleWindowChanged();
167 const Qt::WindowStates states = window()->windowStates();
168 const Qt::WindowFlags flags = window()->flags();
169 updateSystemUiVisibility(states, flags);
170 if (states & Qt::WindowFullScreen || flags & Qt::ExpandedClientAreaHint)
171 setGeometry(platformScreen()->geometry());
172 else if (states & Qt::WindowMaximized)
173 setGeometry(platformScreen()->availableGeometry());
178 m_nativeQtWindow.callMethod<
void>(
"setVisible", visible);
180 if (geometry().isEmpty() || screen()->availableGeometry().isEmpty())
183 QPlatformWindow::setVisible(visible);
188 QPlatformWindow::setWindowState(state);
190 if (window()->isVisible())
191 updateSystemUiVisibility(state, window()->flags());
196 QPlatformWindow::setWindowFlags(flags);
198 if (window()->isVisible())
199 updateSystemUiVisibility(window()->windowStates(), flags);
204 using namespace QtJniTypes;
208 if (androidWindow->isEmbeddingContainer())
211 if (!m_nativeParentQtWindow.isValid())
212 platformScreen()->removeWindow(
this);
214 const QtWindow parentWindow = androidWindow->nativeWindow();
216 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent", parentWindow.object());
217 m_nativeParentQtWindow = parentWindow;
219 m_nativeQtWindow.callMethod<
void, QtWindow>(
"setParent",
nullptr);
220 m_nativeParentQtWindow = QJniObject();
221 platformScreen()->addWindow(
this);
227 return m_nativeQtWindow.isValid() ?
reinterpret_cast<WId>(m_nativeQtWindow.object()) : 0L;
249 const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
250 if (!isNonRegularWindow) {
251 auto iface =
qGuiApp->nativeInterface<QNativeInterface::QAndroidApplication>();
252 iface->runOnAndroidMainThread([=]() {
253 using namespace QtJniTypes;
254 auto activity = iface->context().object<Activity>();
255 if (states & Qt::WindowFullScreen)
256 QtWindowInsetsController::callStaticMethod(
"showFullScreen", activity);
257 else if (flags & Qt::ExpandedClientAreaHint)
258 QtWindowInsetsController::callStaticMethod(
"showExpanded", activity);
260 QtWindowInsetsController::callStaticMethod(
"showNormal", activity);
267 m_nativeQtWindow.callMethod<
void>(
"updateFocusedEditText");
272 return qApp->applicationState() > Qt::ApplicationHidden
273 && window()->isVisible()
274 && !window()->geometry().isEmpty();
281 region = QRect(QPoint(), geometry().size());
283 QWindowSystemInterface::handleExposeEvent(window(), region);
284 QWindowSystemInterface::flushWindowSystemEvents();
289 const bool windowStaysOnTop =
bool(window()->flags() & Qt::WindowStaysOnTopHint);
290 const bool isOpaque = !format().hasAlpha() && qFuzzyCompare(window()->opacity(), qreal(1.0));
292 m_nativeQtWindow.callMethod<
void>(
"createSurface", windowStaysOnTop, 32, isOpaque,
293 m_surfaceContainerType);
300 m_nativeQtWindow.callMethod<
void>(
"destroySurface");
308 const bool surfaceIsValid = surface.isValid();
309 qCDebug(lcQpaWindow) <<
"onSurfaceChanged(): valid Surface received" << surfaceIsValid;
310 m_androidSurfaceObject = surface;
311 if (surfaceIsValid) {
313 m_surfaceWaitCondition.wakeOne();
325 QRect availableGeometry = screen()->availableGeometry();
326 if (!geometry().isNull() && !availableGeometry.isNull()) {
327 QWindowSystemInterface::handleExposeEvent(window(),
328 QRegion(QRect(QPoint(), geometry().size())));
334 QWindow *modalWindow = QGuiApplication::modalWindow();
335 return modalWindow && modalWindow != window();
346 QtJniTypes::Surface surface)
354 const QList<QWindow*> windows =
qGuiApp->allWindows();
355 for (QWindow * window : windows) {
356 if (!window->handle())
358 QAndroidPlatformWindow *platformWindow =
359 static_cast<QAndroidPlatformWindow *>(window->handle());
360 const auto guard = platformWindow->destructionGuard();
361 if (!platformWindow->m_androidSurfaceCreated)
363 if (platformWindow->nativeViewId() == windowId)
364 platformWindow->onSurfaceChanged(surface);
369 jboolean focus, jint windowId)
375 qCWarning(lcQpaWindow,
376 "windowFocusChanged event received for non-existing window %d", windowId);
381 QWindowSystemInterface::handleFocusWindowChanged(window);
382 }
else if (!focus && window ==
qGuiApp->focusWindow()) {
384 QWindowSystemInterface::handleFocusWindowChanged(
nullptr);
389 QtJniTypes::Insets insets, jint id)
397 if (!insets.isValid())
401 for (QWindow *window :
qGuiApp->allWindows()) {
402 if (!window->handle())
404 QAndroidPlatformWindow *pw =
static_cast<QAndroidPlatformWindow *>(window->handle());
405 if (pw->nativeViewId() == id) {
414 QMargins safeMargins = QMargins(
415 insets.getField<
int>(
"left"),
416 insets.getField<
int>(
"top"),
417 insets.getField<
int>(
"right"),
418 insets.getField<
int>(
"bottom"));
420 if (safeMargins != pWindow->safeAreaMargins()) {
421 pWindow->setSafeAreaMargins(safeMargins);
422 QWindowSystemInterface::handleSafeAreaMarginsChanged(pWindow->window());
431 if (QGuiApplication::instance() !=
nullptr) {
432 const auto tlw = QGuiApplication::topLevelWindows();
433 for (QWindow *w : tlw) {
439 const QRect availableGeometry = w->screen()->availableGeometry();
440 const QRect geometry = w->geometry();
441 const bool isPositiveGeometry = (geometry.width() > 0 && geometry.height() > 0);
442 const bool isPositiveAvailableGeometry =
443 (availableGeometry.width() > 0 && availableGeometry.height() > 0);
445 if (isPositiveGeometry && isPositiveAvailableGeometry) {
446 const QRegion region = QRegion(QRect(QPoint(), w->geometry().size()));
447 QWindowSystemInterface::handleExposeEvent(w, region);
452Q_DECLARE_JNI_NATIVE_METHOD(updateWindows)
455
456
457
458
459
460
461QMutexLocker<QMutex> QAndroidPlatformWindow::destructionGuard()
463 return QMutexLocker(&m_destructionMutex);
468 if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
470 Q_JNI_NATIVE_METHOD(updateWindows),
471 Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
472 Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow),
473 Q_JNI_NATIVE_SCOPED_METHOD(safeAreaMarginsChanged, QAndroidPlatformWindow)
475 qCCritical(lcQpaWindow) <<
"RegisterNatives failed for"
476 << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
Combined button and popup list for selecting options.
AndroidBackendRegister * backendRegister()
QWindow * windowFromId(int windowId)