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:
Piotr Mikolajczyk 2022-11-25 12:43:26 +01:00
parent 70b3df00f9
commit 9ce8d4890f
5 changed files with 122 additions and 6 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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) \

View File

@ -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 &para
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 &para
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

View File

@ -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