Add handling of screen hotplug
When a display is connected to an Android device a notification is sent to the platform layer of the application. The QAndroidPlatformIntegration will create a platform screen and add it to QWindowSystem. Task-number: QAA-1257 Change-Id: Id2cf6b47363630c3b5c93c0bc778e2058d8372b3 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
70b3df00f9
commit
9ce8d4890f
@ -559,7 +559,9 @@ public class QtActivityDelegate
|
||||
private final DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener()
|
||||
{
|
||||
@Override
|
||||
public void onDisplayAdded(int displayId) { }
|
||||
public void onDisplayAdded(int displayId) {
|
||||
QtNative.handleScreenAdded(displayId);
|
||||
}
|
||||
|
||||
private boolean isSimilarRotation(int r1, int r2)
|
||||
{
|
||||
@ -586,10 +588,13 @@ public class QtActivityDelegate
|
||||
|
||||
float refreshRate = display.getRefreshRate();
|
||||
QtNative.handleRefreshRateChanged(refreshRate);
|
||||
QtNative.handleScreenChanged(displayId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayRemoved(int displayId) { }
|
||||
public void onDisplayRemoved(int displayId) {
|
||||
QtNative.handleScreenRemoved(displayId);
|
||||
}
|
||||
};
|
||||
|
||||
public boolean updateActivity(Activity activity)
|
||||
|
@ -595,6 +595,17 @@ public class QtNative
|
||||
});
|
||||
}
|
||||
|
||||
public static Display getDisplay(int displayId)
|
||||
{
|
||||
Context context = getContext();
|
||||
DisplayManager displayManager =
|
||||
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
|
||||
if (displayManager != null) {
|
||||
return displayManager.getDisplay(displayId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Display> getAvailableDisplays()
|
||||
{
|
||||
Context context = getContext();
|
||||
@ -1412,6 +1423,9 @@ public class QtNative
|
||||
double density, float refreshRate);
|
||||
public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
|
||||
public static native void handleRefreshRateChanged(float refreshRate);
|
||||
public static native void handleScreenAdded(int displayId);
|
||||
public static native void handleScreenChanged(int displayId);
|
||||
public static native void handleScreenRemoved(int displayId);
|
||||
// screen methods
|
||||
public static native void handleUiDarkModeChanged(int newUiMode);
|
||||
|
||||
|
@ -755,6 +755,24 @@ static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat ref
|
||||
m_androidPlatformIntegration->setRefreshRate(refreshRate);
|
||||
}
|
||||
|
||||
static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
|
||||
{
|
||||
if (m_androidPlatformIntegration)
|
||||
m_androidPlatformIntegration->handleScreenAdded(displayId);
|
||||
}
|
||||
|
||||
static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
|
||||
{
|
||||
if (m_androidPlatformIntegration)
|
||||
m_androidPlatformIntegration->handleScreenChanged(displayId);
|
||||
}
|
||||
|
||||
static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
|
||||
{
|
||||
if (m_androidPlatformIntegration)
|
||||
m_androidPlatformIntegration->handleScreenRemoved(displayId);
|
||||
}
|
||||
|
||||
static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
|
||||
{
|
||||
QAndroidPlatformIntegration::setAppearance(
|
||||
@ -795,7 +813,10 @@ static JNINativeMethod methods[] = {
|
||||
{ "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
|
||||
{ "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
|
||||
{ "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind },
|
||||
{ "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged }
|
||||
{ "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged },
|
||||
{ "handleScreenAdded", "(I)V", (void *)handleScreenAdded },
|
||||
{ "handleScreenChanged", "(I)V", (void *)handleScreenChanged },
|
||||
{ "handleScreenRemoved", "(I)V", (void *)handleScreenRemoved }
|
||||
};
|
||||
|
||||
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
|
||||
|
@ -61,6 +61,21 @@ Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
|
||||
|
||||
Q_DECLARE_JNI_TYPE(List, "Ljava/util/List;")
|
||||
|
||||
namespace {
|
||||
|
||||
QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
|
||||
{
|
||||
const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>(
|
||||
QtJniTypes::className<QtJniTypes::QtNative>(),
|
||||
"getDisplay",
|
||||
displayId);
|
||||
if (!display.isValid())
|
||||
return nullptr;
|
||||
return new QAndroidPlatformScreen(display);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
|
||||
{
|
||||
if (resource=="JavaVM")
|
||||
@ -168,7 +183,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶
|
||||
if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
|
||||
qFatal("Could not bind GL_ES API");
|
||||
|
||||
static const int primaryDisplayId = QJniObject::getStaticField<jint>(
|
||||
m_primaryDisplayId = QJniObject::getStaticField<jint>(
|
||||
QtJniTypes::className<QtJniTypes::Display>(), "DEFAULT_DISPLAY");
|
||||
|
||||
const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>(
|
||||
@ -179,14 +194,15 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶
|
||||
for (int i = 0; i < numberOfAvailableDisplays; ++i) {
|
||||
const QJniObject display =
|
||||
nativeDisplaysList.callObjectMethod<jobject, jint>("get", jint(i));
|
||||
|
||||
const bool isPrimary = (primaryDisplayId == display.callMethod<jint>("getDisplayId"));
|
||||
const int displayId = display.callMethod<jint>("getDisplayId");
|
||||
const bool isPrimary = (m_primaryDisplayId == displayId);
|
||||
auto screen = new QAndroidPlatformScreen(display);
|
||||
|
||||
if (isPrimary)
|
||||
m_primaryScreen = screen;
|
||||
|
||||
QWindowSystemInterface::handleScreenAdded(screen, isPrimary);
|
||||
m_screens[displayId] = screen;
|
||||
}
|
||||
|
||||
if (numberOfAvailableDisplays == 0) {
|
||||
@ -545,6 +561,49 @@ void QAndroidPlatformIntegration::setRefreshRate(qreal refreshRate)
|
||||
QMetaObject::invokeMethod(m_primaryScreen, "setRefreshRate", Qt::AutoConnection,
|
||||
Q_ARG(qreal, refreshRate));
|
||||
}
|
||||
|
||||
void QAndroidPlatformIntegration::handleScreenAdded(int displayId)
|
||||
{
|
||||
auto result = m_screens.insert(displayId, nullptr);
|
||||
if (result.first->second == nullptr) {
|
||||
auto it = result.first;
|
||||
it->second = createScreenForDisplayId(displayId);
|
||||
if (it->second == nullptr)
|
||||
return;
|
||||
const bool isPrimary = (m_primaryDisplayId == displayId);
|
||||
if (isPrimary)
|
||||
m_primaryScreen = it->second;
|
||||
QWindowSystemInterface::handleScreenAdded(it->second, isPrimary);
|
||||
} else {
|
||||
qWarning() << "Display with id" << displayId << "already exists.";
|
||||
}
|
||||
}
|
||||
|
||||
void QAndroidPlatformIntegration::handleScreenChanged(int displayId)
|
||||
{
|
||||
auto it = m_screens.find(displayId);
|
||||
if (it == m_screens.end() || it->second == nullptr) {
|
||||
handleScreenAdded(displayId);
|
||||
}
|
||||
// We do not do anything more here as handling of change of
|
||||
// rotation and refresh rate is done in QtActivityDelegate java class
|
||||
// which calls QAndroidPlatformIntegration::setOrientation, and
|
||||
// QAndroidPlatformIntegration::setRefreshRate accordingly.
|
||||
}
|
||||
|
||||
void QAndroidPlatformIntegration::handleScreenRemoved(int displayId)
|
||||
{
|
||||
auto it = m_screens.find(displayId);
|
||||
|
||||
if (it == m_screens.end())
|
||||
return;
|
||||
|
||||
if (it->second != nullptr)
|
||||
QWindowSystemInterface::handleScreenRemoved(it->second);
|
||||
|
||||
m_screens.erase(it);
|
||||
}
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
|
||||
QPlatformVulkanInstance *QAndroidPlatformIntegration::createPlatformVulkanInstance(QVulkanInstance *instance) const
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include <qpa/qplatformopenglcontext.h>
|
||||
#include <qpa/qplatformoffscreensurface.h>
|
||||
#include <qpa/qplatformtheme.h>
|
||||
#include <private/qflatmap_p.h>
|
||||
#include <QtCore/qvarlengtharray.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <memory>
|
||||
@ -75,6 +77,10 @@ public:
|
||||
|
||||
QPlatformFontDatabase *fontDatabase() const override;
|
||||
|
||||
void handleScreenAdded(int displayId);
|
||||
void handleScreenChanged(int displayId);
|
||||
void handleScreenRemoved(int displayId);
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
QPlatformClipboard *clipboard() const override;
|
||||
#endif
|
||||
@ -132,6 +138,17 @@ private:
|
||||
QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface;
|
||||
QAndroidPlatformServices *m_androidPlatformServices;
|
||||
|
||||
// Handling the multiple screens connected. Every display is identified
|
||||
// with an unique (autoincremented) displayID. The values of this ID will
|
||||
// not repeat during the OS runtime. We use this value as the key in the
|
||||
// storage of screens.
|
||||
QFlatMap<int, QAndroidPlatformScreen *, std::less<int>
|
||||
, QVarLengthArray<int, 10>
|
||||
, QVarLengthArray<QAndroidPlatformScreen *, 10> > m_screens;
|
||||
// ID of the primary display, in documentation it is said to be always 0,
|
||||
// but nevertheless it is retrieved
|
||||
int m_primaryDisplayId = 0;
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
QPlatformClipboard *m_androidPlatformClipboard;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user