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