From 8b0d9a16db7bcfb5d6439b8863aded5c583f9ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Thu, 28 Aug 2014 12:18:14 +0200 Subject: Android: Improve the foreign-window implementation Adds: - Improved geometry calculations (e.g, inside a parent) - Change visibility - proper stacking order. Native views now reserve the top of the stack to ensure that they stay visible. - React to application state changes. Change-Id: I35de0396937fff37ffcd272c9a7d8e9873a91dfb Reviewed-by: Paul Olav Tvete --- src/plugins/platforms/android/androidjnimain.cpp | 34 +++++----- .../android/qandroidplatformforeignwindow.cpp | 74 +++++++++++++++++++--- .../android/qandroidplatformforeignwindow.h | 11 +++- .../platforms/android/qandroidplatformwindow.h | 3 + 4 files changed, 93 insertions(+), 29 deletions(-) (limited to 'src/plugins/platforms/android') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index be1fd49c0c..17a587b333 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -69,7 +69,6 @@ static AAssetManager *m_assetManager = Q_NULLPTR; static jobject m_resourcesObj = Q_NULLPTR; static jobject m_activityObject = Q_NULLPTR; static jmethodID m_createSurfaceMethodID = Q_NULLPTR; -static jmethodID m_insertNativeViewMethodID = Q_NULLPTR; static jmethodID m_setSurfaceGeometryMethodID = Q_NULLPTR; static jmethodID m_destroySurfaceMethodID = Q_NULLPTR; @@ -345,27 +344,24 @@ namespace QtAndroid int insertNativeView(jobject view, const QRect &geometry) { - QJNIEnvironmentPrivate env; - if (!env) - return 0; - m_surfacesMutex.lock(); const int surfaceId = m_surfaceId++; + m_surfaces[surfaceId] = Q_NULLPTR; // dummy m_surfacesMutex.unlock(); jint x = 0, y = 0, w = -1, h = -1; - if (!geometry.isNull()) { - x = geometry.x(); - y = geometry.y(); - w = std::max(geometry.width(), 1); - h = std::max(geometry.height(), 1); - } - - env->CallStaticVoidMethod(m_applicationClass, - m_insertNativeViewMethodID, - surfaceId, - view, - x, y, w, h); + if (!geometry.isNull()) + geometry.getRect(&x, &y, &w, &h); + + QJNIObjectPrivate::callStaticMethod(m_applicationClass, + "insertNativeView", + "(ILandroid/view/View;IIII)V", + surfaceId, + view, + x, + y, + qMax(w, 1), + qMax(h, 1)); return surfaceId; } @@ -539,6 +535,9 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface, { QMutexLocker lock(&m_surfacesMutex); const auto &it = m_surfaces.find(id); + if (it.value() == Q_NULLPTR) // This should never happen... + return; + if (it == m_surfaces.end()) { qWarning()<<"Can't find surface" << id; return; @@ -718,7 +717,6 @@ static int registerNatives(JNIEnv *env) } GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIIII)V"); - GET_AND_CHECK_STATIC_METHOD(m_insertNativeViewMethodID, m_applicationClass, "insertNativeView", "(ILandroid/view/View;IIII)V"); GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V"); GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V"); diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp index e8f7b3d145..af409d13a0 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.cpp @@ -34,16 +34,17 @@ #include "qandroidplatformforeignwindow.h" #include "androidjnimain.h" #include +#include +#include + +QT_BEGIN_NAMESPACE QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window) - : QAndroidPlatformWindow(window) + : QAndroidPlatformWindow(window), + m_surfaceId(-1) { const WId wId = window->property("_q_foreignWinId").value(); - if (wId) { - m_view = reinterpret_cast(wId); - Q_ASSERT(m_view.isValid()); - m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry()); - } + m_view = reinterpret_cast(wId); } QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow() @@ -54,9 +55,64 @@ QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow() void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect) { - if (rect == geometry()) + QWindow *parent = window()->parent(); + QRect newGeometry = rect; + + if (parent != 0) + newGeometry.moveTo(parent->mapToGlobal(rect.topLeft())); + + if (newGeometry == geometry()) + return; + + QAndroidPlatformWindow::setGeometry(newGeometry); + + if (m_surfaceId != -1) + QtAndroid::setSurfaceGeometry(m_surfaceId, newGeometry); +} + +void QAndroidPlatformForeignWindow::setVisible(bool visible) +{ + if (!m_view.isValid()) + return; + + QAndroidPlatformWindow::setVisible(visible); + + if (!visible && m_surfaceId != -1) { + QtAndroid::destroySurface(m_surfaceId); + m_surfaceId = -1; + } else if (m_surfaceId == -1) { + m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry()); + } +} + +void QAndroidPlatformForeignWindow::applicationStateChanged(Qt::ApplicationState state) +{ + if (state <= Qt::ApplicationHidden + && QtAndroid::blockEventLoopsWhenSuspended() + && m_surfaceId != -1) { + QtAndroid::destroySurface(m_surfaceId); + m_surfaceId = -1; + } else if (m_view.isValid() && m_surfaceId == -1){ + m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry()); + } + + QAndroidPlatformWindow::applicationStateChanged(state); +} + +void QAndroidPlatformForeignWindow::setParent(const QPlatformWindow *window) +{ + QRect newGeometry = geometry(); + + if (window != 0) + newGeometry.moveTo(window->mapToGlobal(geometry().topLeft())); + + if (newGeometry != geometry()) + QAndroidPlatformWindow::setGeometry(newGeometry); + + if (m_surfaceId == -1) return; - QAndroidPlatformWindow::setGeometry(rect); - QtAndroid::setSurfaceGeometry(m_surfaceId, rect); + QtAndroid::setSurfaceGeometry(m_surfaceId, newGeometry); } + +QT_END_NAMESPACE diff --git a/src/plugins/platforms/android/qandroidplatformforeignwindow.h b/src/plugins/platforms/android/qandroidplatformforeignwindow.h index cb04142696..974ffbc376 100644 --- a/src/plugins/platforms/android/qandroidplatformforeignwindow.h +++ b/src/plugins/platforms/android/qandroidplatformforeignwindow.h @@ -38,16 +38,23 @@ #include "qandroidplatformwindow.h" #include +QT_BEGIN_NAMESPACE + class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow { public: explicit QAndroidPlatformForeignWindow(QWindow *window); ~QAndroidPlatformForeignWindow(); - void setGeometry(const QRect &rect); + void setGeometry(const QRect &rect) Q_DECL_OVERRIDE; + void setVisible(bool visible) Q_DECL_OVERRIDE; + void applicationStateChanged(Qt::ApplicationState state) Q_DECL_OVERRIDE; + void setParent(const QPlatformWindow *window) Q_DECL_OVERRIDE; private: + int m_surfaceId; QJNIObjectPrivate m_view; - int m_surfaceId = -1; }; +QT_END_NAMESPACE + #endif // QANDROIDPLATFORMFOREIGNWINDOW_H diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index f01f36ee27..edf062bcb4 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -65,6 +65,9 @@ public: void requestActivateWindow(); void updateStatusBarVisibility(); inline bool isRaster() const { + if ((window()->flags() & Qt::ForeignWindow) == Qt::ForeignWindow) + return false; + return window()->surfaceType() == QSurface::RasterSurface || window()->surfaceType() == QSurface::RasterGLSurface; } -- cgit v1.2.3