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
5#include <QDebug>
6#include <QTime>
7
8#include <qpa/qwindowsysteminterface.h>
9
13#include "androidjnimain.h"
14#include "androidjnimenu.h"
15
16#include <android/bitmap.h>
17#include <android/native_window_jni.h>
18#include <qguiapplication.h>
19
20#include <QtCore/QJniObject>
21#include <QtCore/QJniEnvironment>
22#include <QtGui/QGuiApplication>
23#include <QtGui/QWindow>
24#include <QtGui/private/qwindow_p.h>
25#include <vector>
26
28
29#ifdef QANDROIDPLATFORMSCREEN_DEBUG
30class ScopedProfiler
31{
32public:
33 ScopedProfiler(const QString &msg)
34 {
35 m_msg = msg;
36 m_timer.start();
37 }
38 ~ScopedProfiler()
39 {
40 qDebug() << m_msg << m_timer.elapsed();
41 }
42
43private:
44 QTime m_timer;
45 QString m_msg;
46};
47
48# define PROFILE_SCOPE ScopedProfiler ___sp___(__func__)
49#else
50# define PROFILE_SCOPE
51#endif
52
53Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
54Q_DECLARE_JNI_CLASS(DisplayMetrics, "android/util/DisplayMetrics")
55Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
56Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
57Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
58Q_DECLARE_JNI_CLASS(QtWindowInterface, "org/qtproject/qt/android/QtWindowInterface")
59
60Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
61
62QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
63 : QObject(), QPlatformScreen()
64{
65 // Raster only apps should set QT_ANDROID_RASTER_IMAGE_DEPTH to 16
66 // is way much faster than 32
67 if (qEnvironmentVariableIntValue("QT_ANDROID_RASTER_IMAGE_DEPTH") == 16) {
68 m_format = QImage::Format_RGB16;
69 m_depth = 16;
70 } else {
71 m_format = QImage::Format_ARGB32_Premultiplied;
72 m_depth = 32;
73 }
74
75 connect(qGuiApp, &QGuiApplication::applicationStateChanged, this,
76 &QAndroidPlatformScreen::applicationStateChanged);
77
78 if (!displayObject.isValid())
79 return;
80
81 m_name = displayObject.callObjectMethod<jstring>("getName").toString();
82 m_refreshRate = displayObject.callMethod<jfloat>("getRefreshRate");
83 m_displayId = displayObject.callMethod<jint>("getDisplayId");
84 m_size = sizeForDisplayId(m_displayId);
85 m_availableGeometry = defaultAvailableGeometry();
86
87 const auto context = QNativeInterface::QAndroidApplication::context();
88 const auto resources = context.callMethod<QtJniTypes::Resources>("getResources");
89 const auto metrics = resources.callMethod<QtJniTypes::DisplayMetrics>("getDisplayMetrics");
90 m_xdpi = QtJniTypes::QtDisplayManager::callStaticMethod<jfloat>("getXDpi", metrics);
91 m_ydpi = QtJniTypes::QtDisplayManager::callStaticMethod<jfloat>("getYDpi", metrics);
92
93 // Potentially densityDpi could be used instead of xpdi/ydpi to do the calculation,
94 // but the results are not consistent with devices specs.
95 // (https://issuetracker.google.com/issues/194120500)
96 setPhysicalSizeFromPixels(m_size);
97
98 if (QNativeInterface::QAndroidApplication::sdkVersion() >= 23) {
99 const QJniObject currentMode = displayObject.callObjectMethod<QtJniTypes::DisplayMode>("getMode");
100 m_currentMode = currentMode.callMethod<jint>("getModeId");
101
102 const QJniObject supportedModes = displayObject.callObjectMethod<QtJniTypes::DisplayMode[]>(
103 "getSupportedModes");
104 const auto modeArray = jobjectArray(supportedModes.object());
105
106 QJniEnvironment env;
107 const auto size = env->GetArrayLength(modeArray);
108 for (jsize i = 0; i < size; ++i) {
109 const auto mode = QJniObject::fromLocalRef(env->GetObjectArrayElement(modeArray, i));
110 m_modes << QPlatformScreen::Mode {
111 .size = QSize { mode.callMethod<jint>("getPhysicalWidth"),
112 mode.callMethod<jint>("getPhysicalHeight") },
113 .refreshRate = mode.callMethod<jfloat>("getRefreshRate")
114 };
115 }
116 }
117}
118
122
123QSize QAndroidPlatformScreen::sizeForDisplayId(int displayId)
124{
125 using namespace QtJniTypes;
126 const auto context = QNativeInterface::QAndroidApplication::context();
127 const auto display = QtDisplayManager::callStaticMethod<Display>(
128 "getDisplay", context, displayId);
129 const auto sizeObj = QtDisplayManager::callStaticMethod<Size>(
130 "getDisplaySize", context, display);
131
132 return QSize(sizeObj.callMethod<int>("getWidth"), sizeObj.callMethod<int>("getHeight"));
133
134}
135
137{
138 for (QAndroidPlatformWindow *w : m_windowStack) {
139 Qt::WindowType type = w->window()->type();
140 if (w->window()->isVisible() &&
141 (type == Qt::Window || type == Qt::Popup || type == Qt::Dialog)) {
142 return w->window();
143 }
144 }
145 return nullptr;
146}
147
148QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
149{
150 for (QAndroidPlatformWindow *w : m_windowStack) {
151 if (w->geometry().contains(p, false) && w->window()->isVisible())
152 return w->window();
153 }
154 return 0;
155}
156
158{
159 if (window->parent() && window->isRaster())
160 return;
161
162 if (m_windowStack.contains(window))
163 return;
164
165 m_windowStack.prepend(window);
166
168 reg->callInterface<QtJniTypes::QtWindowInterface, void>("addTopLevelWindow",
169 window->nativeWindow());
170
171 if (window->window()->isVisible())
173}
174
176{
177 m_windowStack.removeOne(window);
178
179 if (m_windowStack.contains(window))
180 qWarning() << "Failed to remove window";
181
183 reg->callInterface<QtJniTypes::QtWindowInterface, void>("removeTopLevelWindow",
184 window->nativeViewId());
185
187}
188
190{
191 int index = m_windowStack.indexOf(window);
192 if (index < 0)
193 return;
194 if (index > 0) {
195 m_windowStack.move(index, 0);
196
198 reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToFront",
199 window->nativeViewId());
200 }
202}
203
205{
206 int index = m_windowStack.indexOf(window);
207 if (index == -1 || index == (m_windowStack.size() - 1))
208 return;
209 m_windowStack.move(index, m_windowStack.size() - 1);
210
212 reg->callInterface<QtJniTypes::QtWindowInterface, void>("bringChildToBack",
213 window->nativeViewId());
214
216}
217
218void QAndroidPlatformScreen::setPhysicalSize(const QSize &size)
219{
220 m_physicalSize = size;
221}
222
224{
225 m_physicalSize = QSize(
226 qRound(double(size.width()) / m_xdpi * 25.4),
227 qRound(double(size.height()) / m_ydpi * 25.4));
228}
229
230void QAndroidPlatformScreen::setSize(const QSize &size)
231{
232 m_size = size;
233 QWindowSystemInterface::handleScreenGeometryChange(
234 QPlatformScreen::screen(), geometry(), availableGeometry());
235}
236
238{
239 return m_displayId;
240}
241
243{
244 if (refreshRate == m_refreshRate)
245 return;
246 m_refreshRate = refreshRate;
247 QWindowSystemInterface::handleScreenRefreshRateChange(QPlatformScreen::screen(), refreshRate);
248}
249
250void QAndroidPlatformScreen::setOrientation(Qt::ScreenOrientation orientation)
251{
252 QWindowSystemInterface::handleScreenOrientationChange(QPlatformScreen::screen(), orientation);
253}
254
256{
257 if (m_availableGeometry == rect)
258 return;
259
260 QRect oldGeometry = m_availableGeometry;
261
262 m_availableGeometry = rect;
263 m_size = sizeForDisplayId(m_displayId);
264 QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry(), availableGeometry());
265 resizeMaximizedWindows();
266
267 if (oldGeometry.width() == 0 && oldGeometry.height() == 0 && rect.width() > 0 && rect.height() > 0) {
268 QList<QWindow *> windows = QGuiApplication::allWindows();
269 for (int i = 0; i < windows.size(); ++i) {
270 QWindow *w = windows.at(i);
271 if (w->handle()) {
272 QRect geometry = w->handle()->geometry();
273 if (geometry.width() > 0 && geometry.height() > 0)
274 QWindowSystemInterface::handleExposeEvent(w, QRect(QPoint(0, 0), geometry.size()));
275 }
276 }
277 }
278}
279
280void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
281{
282 for (QAndroidPlatformWindow *w : std::as_const(m_windowStack))
283 w->applicationStateChanged(state);
284}
285
287{
288 QWindow *w = topVisibleWindow();
289 QWindowSystemInterface::handleFocusWindowChanged(w, Qt::ActiveWindowFocusReason);
291 if (w && w->handle()) {
292 QAndroidPlatformWindow *platformWindow = static_cast<QAndroidPlatformWindow *>(w->handle());
293 if (platformWindow) {
294 platformWindow->updateSystemUiVisibility();
295 platformWindow->updateFocusedEditText();
296 }
297 }
298}
299
300static const int androidLogicalDpi = 72;
301
303{
305 return QDpi(lDpi, lDpi);
306}
307
312
314{
315 return QAndroidPlatformIntegration::m_orientation;
316}
317
319{
320 return QAndroidPlatformIntegration::m_nativeOrientation;
321}
322
323QRect &QAndroidPlatformScreen::defaultAvailableGeometry()
324{
325 static QRect defaultAvailableGeometry;
326 return defaultAvailableGeometry;
327}
328QT_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:29
void setActiveTopLevelWindow(QWindow *window)
AndroidBackendRegister * backendRegister()
double pixelDensity()
static const int androidLogicalDpi
#define qGuiApp