Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qandroidplatformscreen.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 BogDan Vatra <bogdan@kde.org>
2// Copyright (C) 2016 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#include <QDebug>
7#include <QTime>
8
9#include <qpa/qwindowsysteminterface.h>
10
14#include "androidjnimain.h"
15#include "androidjnimenu.h"
16
17#include <android/bitmap.h>
18#include <android/native_window_jni.h>
19#include <qguiapplication.h>
20
21#include <QtCore/QJniObject>
22#include <QtCore/QJniEnvironment>
23#include <QtGui/QGuiApplication>
24#include <QtGui/QWindow>
25#include <QtGui/private/qwindow_p.h>
26#include <QtGui/private/qmath_p.h>
27#include <vector>
28
30
31#ifdef QANDROIDPLATFORMSCREEN_DEBUG
32class ScopedProfiler
33{
34public:
35 ScopedProfiler(const QString &msg)
36 {
37 m_msg = msg;
38 m_timer.start();
39 }
40 ~ScopedProfiler()
41 {
42 qDebug() << m_msg << m_timer.elapsed();
43 }
44
45private:
46 QTime m_timer;
47 QString m_msg;
48};
49
50# define PROFILE_SCOPE ScopedProfiler ___sp___(__func__)
51#else
52# define PROFILE_SCOPE
53#endif
54
55Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
56Q_DECLARE_JNI_CLASS(DisplayMetrics, "android/util/DisplayMetrics")
57Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
58Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
59Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
60Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
61
62Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
63
64QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
65 : QObject(), QPlatformScreen()
66{
67 // Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16
68 // is way much faster than 32
69 if (qEnvironmentVariableIntValue("QT_ANDROID_RASTER_IMAGE_DEPTH") == 16) {
70 m_format = QImage::Format_RGB16;
71 m_depth = 16;
72 } else {
73 m_format = QImage::Format_ARGB32_Premultiplied;
74 m_depth = 32;
75 }
76
77 connect(qGuiApp, &QGuiApplication::applicationStateChanged, this,
78 &QAndroidPlatformScreen::applicationStateChanged);
79
80 if (!displayObject.isValid())
81 return;
82
83 m_name = displayObject.callObjectMethod<jstring>("getName").toString();
84 m_refreshRate = displayObject.callMethod<jfloat>("getRefreshRate");
85 m_displayId = displayObject.callMethod<jint>("getDisplayId");
86 m_size = sizeForDisplayId(m_displayId);
87 m_availableGeometry = defaultAvailableGeometry();
88
89 const auto context = QNativeInterface::QAndroidApplication::context();
90 const auto resources = context.callMethod<QtJniTypes::Resources>("getResources");
91 const auto metrics = resources.callMethod<QtJniTypes::DisplayMetrics>("getDisplayMetrics");
92 m_xdpi = QtJniTypes::QtDisplayManager::callStaticMethod<jfloat>("getXDpi", metrics);
93 m_ydpi = QtJniTypes::QtDisplayManager::callStaticMethod<jfloat>("getYDpi", metrics);
94
95 // Potentially densityDpi could be used instead of xpdi/ydpi to do the calculation,
96 // but the results are not consistent with devices specs.
97 // (https://issuetracker.google.com/issues/194120500)
98 setPhysicalSizeFromPixels(m_size);
99
100 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) {
101 const QJniObject currentMode = displayObject.callObjectMethod<QtJniTypes::DisplayMode>("getMode");
102 m_currentMode = currentMode.callMethod<jint>("getModeId");
103
104 const QJniObject supportedModes = displayObject.callObjectMethod<QtJniTypes::DisplayMode[]>(
105 "getSupportedModes");
106 const auto modeArray = jobjectArray(supportedModes.object());
107
108 QJniEnvironment env;
109 const auto size = env->GetArrayLength(modeArray);
110 for (jsize i = 0; i < size; ++i) {
111 const auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modeArray, i));
112 m_modes << QPlatformScreen::Mode {
113 .size = QSize { mode.callMethod<jint>("getPhysicalWidth"),
114 mode.callMethod<jint>("getPhysicalHeight") },
115 .refreshRate = mode.callMethod<jfloat>("getRefreshRate")
116 };
117 }
118 }
119}
120
124
125QSize QAndroidPlatformScreen::sizeForDisplayId(int displayId)
126{
127 using namespace QtJniTypes;
128 const auto context = QNativeInterface::QAndroidApplication::context();
129 const auto display = QtDisplayManager::callStaticMethod<Display>(
130 "getDisplay", context, displayId);
131 const auto sizeObj = QtDisplayManager::callStaticMethod<Size>(
132 "getDisplaySize", context, display);
133
134 return QSize(sizeObj.callMethod<int>("getWidth"), sizeObj.callMethod<int>("getHeight"));
135
136}
137
139{
140 for (QAndroidPlatformWindow *w : m_windowStack) {
141 Qt::WindowType type = w->window()->type();
142 if (w->window()->isVisible() &&
143 (type == Qt::Window || type == Qt::Popup || type == Qt::Dialog)) {
144 return w->window();
145 }
146 }
147 return nullptr;
148}
149
150QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
151{
152 for (QAndroidPlatformWindow *w : m_windowStack) {
153 if (w->geometry().contains(p, false) && w->window()->isVisible())
154 return w->window();
155 }
156 return 0;
157}
158
160{
161 if (window->parent() && window->isRaster())
162 return;
163
164 if (m_windowStack.contains(window))
165 return;
166
167 m_windowStack.prepend(window);
168
170 reg->callInterface<QtJniTypes::QtWindowInterface, void>("addTopLevelWindow",
171 window->nativeWindow());
172
173 if (window->window()->isVisible())
175}
176
178{
179 m_windowStack.removeOne(window);
180
181 if (m_windowStack.contains(window))
182 qWarning() << "Failed to remove window";
183
185 reg->callInterface<QtJniTypes::QtWindowInterface, void>("removeTopLevelWindow",
186 window->nativeViewId());
187
189}
190
192{
193 int index = m_windowStack.indexOf(window);
194 if (index < 0)
195 return;
196 if (index > 0) {
197 m_windowStack.move(index, 0);
198
200 reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToFront",
201 window->nativeViewId());
202 }
204}
205
207{
208 int index = m_windowStack.indexOf(window);
209 if (index == -1 || index == (m_windowStack.size() - 1))
210 return;
211 m_windowStack.move(index, m_windowStack.size() - 1);
212
214 reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToBack",
215 window->nativeViewId());
216
218}
219
220void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
221{
222 m_physicalSize = size;
223}
224
226{
227 const bool isPortrait = size.height() > size.width();
228 const bool swapped = isPortrait != (nativeOrientation() == Qt::PortraitOrientation);
229 const qreal widthDPI = swapped ? m_ydpi : m_xdpi;
230 const qreal heightDPI = swapped ? m_xdpi : m_ydpi;
231 m_physicalSize = QSizeF(size.width() / widthDPI * Q_MM_PER_INCH,
232 size.height() / heightDPI * Q_MM_PER_INCH);
233}
234
235void QAndroidPlatformScreen::setSize(const QSize &size)
236{
237 m_size = size;
238 setPhysicalSizeFromPixels(size);
239 QWindowSystemInterface::handleScreenGeometryChange(
240 QPlatformScreen::screen(), geometry(), availableGeometry());
241}
242
244{
245 return m_displayId;
246}
247
249{
250 if (refreshRate == m_refreshRate)
251 return;
252 m_refreshRate = refreshRate;
253 QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), refreshRate);
254}
255
256void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation)
257{
258 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation);
259}
260
262{
263 if (m_availableGeometry == rect)
264 return;
265
266 QRect oldGeometry = m_availableGeometry;
267
268 m_availableGeometry = rect;
269 setSize(sizeForDisplayId(m_displayId));
270 resizeMaximizedWindows();
271
272 if (oldGeometry.width() == 0 && oldGeometry.height() == 0 && rect.width() > 0 && rect.height() > 0) {
273 QList<QWindow *> windows = QGuiApplication::allWindows();
274 for (int i = 0; i < windows.size(); ++i) {
275 QWindow *w = windows.at(i);
276 if (w->handle()) {
277 QRect geometry = w->handle()->geometry();
278 if (geometry.width() > 0 && geometry.height() > 0)
279 QWindowSystemInterface::handleExposeEvent(w, QRect(QPoint(0, 0), geometry.size()));
280 }
281 }
282 }
283}
284
285void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
286{
287 for (QAndroidPlatformWindow *w : std::as_const(m_windowStack))
288 w->applicationStateChanged(state);
289}
290
292{
293 QWindow *w = topVisibleWindow();
294 QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
296 if (w && w->handle()) {
297 QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
298 if (platformWindow) {
299 platformWindow->updateSystemUiVisibility(w->windowStates(), w->flags());
300 platformWindow->updateFocusedEditText();
301 }
302 }
303}
304
305static const int androidLogicalDpi = 72;
306
308{
310 return QDpi(lDpi, lDpi);
311}
312
317
319{
320 return QAndroidPlatformIntegration::m_orientation;
321}
322
324{
325 return QAndroidPlatformIntegration::m_nativeOrientation;
326}
327
328QRect &QAndroidPlatformScreen::defaultAvailableGeometry()
329{
330 static QRect defaultAvailableGeometry;
331 return defaultAvailableGeometry;
332}
333QT_END_NAMESPACE
Qt::ScreenOrientation orientation() const override
Reimplement this function in subclass to return the current orientation of the screen,...
void lower(QAndroidPlatformWindow *window)
void setPhysicalSizeFromPixels(const QSize &size)
QWindow * topLevelAt(const QPoint &p) const override
Return the given top level window for a given position.
QDpi logicalBaseDpi() const override
Reimplement to return the base logical DPI for the platform.
QDpi logicalDpi() const override
Reimplement this function in subclass to return the logical horizontal and vertical dots per inch met...
void raise(QAndroidPlatformWindow *window)
void setAvailableGeometry(const QRect &rect)
void removeWindow(QAndroidPlatformWindow *window)
Qt::ScreenOrientation nativeOrientation() const override
Reimplement this function in subclass to return the native orientation of the screen,...
void setSize(const QSize &size)
void setRefreshRate(qreal refreshRate)
void addWindow(QAndroidPlatformWindow *window)
\inmodule QtCore\reentrant
Definition qpoint.h:30
Combined button and popup list for selecting options.
void setActiveTopLevelWindow(QWindow *window)
AndroidBackendRegister * backendRegister()
double pixelDensity()
static const int androidLogicalDpi
#define qGuiApp