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 <paul.tvete@digia.com>
This commit is contained in:
Christian Strømme 2014-08-28 12:18:14 +02:00 committed by Christian Stromme
parent c30687f519
commit 8b0d9a16db
5 changed files with 98 additions and 33 deletions

View File

@ -1025,8 +1025,8 @@ public class QtActivityDelegate
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
} }
view.setId(id);
m_layout.addView(view); m_layout.addView(view);
m_layout.bringChildToFront(view);
m_nativeViews.put(id, view); m_nativeViews.put(id, view);
} }
@ -1057,9 +1057,11 @@ public class QtActivityDelegate
surface.setLayoutParams( new QtLayout.LayoutParams(w, h, x, y)); surface.setLayoutParams( new QtLayout.LayoutParams(w, h, x, y));
} }
m_layout.addView(surface); // Native views are always inserted in the end of the stack (i.e., on top).
if (onTop) // All other views are stacked based on the order they are created.
m_layout.bringChildToFront(surface); final int index = m_layout.getChildCount() - m_nativeViews.size() - 1;
m_layout.addView(surface, index < 0 ? 0 : index);
m_surfaces.put(id, surface); m_surfaces.put(id, surface);
} }
@ -1070,7 +1072,6 @@ public class QtActivityDelegate
} else if (m_nativeViews.containsKey(id)) { } else if (m_nativeViews.containsKey(id)) {
View view = m_nativeViews.get(id); View view = m_nativeViews.get(id);
view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
m_layout.bringChildToFront(view);
} else { } else {
Log.e(QtNative.QtTAG, "Surface " + id +" not found!"); Log.e(QtNative.QtTAG, "Surface " + id +" not found!");
return; return;

View File

@ -69,7 +69,6 @@ static AAssetManager *m_assetManager = Q_NULLPTR;
static jobject m_resourcesObj = Q_NULLPTR; static jobject m_resourcesObj = Q_NULLPTR;
static jobject m_activityObject = Q_NULLPTR; static jobject m_activityObject = Q_NULLPTR;
static jmethodID m_createSurfaceMethodID = Q_NULLPTR; static jmethodID m_createSurfaceMethodID = Q_NULLPTR;
static jmethodID m_insertNativeViewMethodID = Q_NULLPTR;
static jmethodID m_setSurfaceGeometryMethodID = Q_NULLPTR; static jmethodID m_setSurfaceGeometryMethodID = Q_NULLPTR;
static jmethodID m_destroySurfaceMethodID = Q_NULLPTR; static jmethodID m_destroySurfaceMethodID = Q_NULLPTR;
@ -345,27 +344,24 @@ namespace QtAndroid
int insertNativeView(jobject view, const QRect &geometry) int insertNativeView(jobject view, const QRect &geometry)
{ {
QJNIEnvironmentPrivate env;
if (!env)
return 0;
m_surfacesMutex.lock(); m_surfacesMutex.lock();
const int surfaceId = m_surfaceId++; const int surfaceId = m_surfaceId++;
m_surfaces[surfaceId] = Q_NULLPTR; // dummy
m_surfacesMutex.unlock(); m_surfacesMutex.unlock();
jint x = 0, y = 0, w = -1, h = -1; jint x = 0, y = 0, w = -1, h = -1;
if (!geometry.isNull()) { if (!geometry.isNull())
x = geometry.x(); geometry.getRect(&x, &y, &w, &h);
y = geometry.y();
w = std::max(geometry.width(), 1);
h = std::max(geometry.height(), 1);
}
env->CallStaticVoidMethod(m_applicationClass, QJNIObjectPrivate::callStaticMethod<void>(m_applicationClass,
m_insertNativeViewMethodID, "insertNativeView",
"(ILandroid/view/View;IIII)V",
surfaceId, surfaceId,
view, view,
x, y, w, h); x,
y,
qMax(w, 1),
qMax(h, 1));
return surfaceId; return surfaceId;
} }
@ -539,6 +535,9 @@ static void setSurface(JNIEnv *env, jobject /*thiz*/, jint id, jobject jSurface,
{ {
QMutexLocker lock(&m_surfacesMutex); QMutexLocker lock(&m_surfacesMutex);
const auto &it = m_surfaces.find(id); const auto &it = m_surfaces.find(id);
if (it.value() == Q_NULLPTR) // This should never happen...
return;
if (it == m_surfaces.end()) { if (it == m_surfaces.end()) {
qWarning()<<"Can't find surface" << id; qWarning()<<"Can't find surface" << id;
return; 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_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_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V");
GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V"); GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V");

View File

@ -34,16 +34,17 @@
#include "qandroidplatformforeignwindow.h" #include "qandroidplatformforeignwindow.h"
#include "androidjnimain.h" #include "androidjnimain.h"
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <qpa/qwindowsysteminterface.h>
#include <QtCore/private/qjnihelpers_p.h>
QT_BEGIN_NAMESPACE
QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window) QAndroidPlatformForeignWindow::QAndroidPlatformForeignWindow(QWindow *window)
: QAndroidPlatformWindow(window) : QAndroidPlatformWindow(window),
m_surfaceId(-1)
{ {
const WId wId = window->property("_q_foreignWinId").value<WId>(); const WId wId = window->property("_q_foreignWinId").value<WId>();
if (wId) {
m_view = reinterpret_cast<jobject>(wId); m_view = reinterpret_cast<jobject>(wId);
Q_ASSERT(m_view.isValid());
m_surfaceId = QtAndroid::insertNativeView(m_view.object(), geometry());
}
} }
QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow() QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
@ -54,9 +55,64 @@ QAndroidPlatformForeignWindow::~QAndroidPlatformForeignWindow()
void QAndroidPlatformForeignWindow::setGeometry(const QRect &rect) 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; return;
QAndroidPlatformWindow::setGeometry(rect); QAndroidPlatformWindow::setGeometry(newGeometry);
QtAndroid::setSurfaceGeometry(m_surfaceId, rect);
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;
QtAndroid::setSurfaceGeometry(m_surfaceId, newGeometry);
}
QT_END_NAMESPACE

View File

@ -38,16 +38,23 @@
#include "qandroidplatformwindow.h" #include "qandroidplatformwindow.h"
#include <QtCore/private/qjni_p.h> #include <QtCore/private/qjni_p.h>
QT_BEGIN_NAMESPACE
class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow class QAndroidPlatformForeignWindow : public QAndroidPlatformWindow
{ {
public: public:
explicit QAndroidPlatformForeignWindow(QWindow *window); explicit QAndroidPlatformForeignWindow(QWindow *window);
~QAndroidPlatformForeignWindow(); ~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: private:
int m_surfaceId;
QJNIObjectPrivate m_view; QJNIObjectPrivate m_view;
int m_surfaceId = -1;
}; };
QT_END_NAMESPACE
#endif // QANDROIDPLATFORMFOREIGNWINDOW_H #endif // QANDROIDPLATFORMFOREIGNWINDOW_H

View File

@ -65,6 +65,9 @@ public:
void requestActivateWindow(); void requestActivateWindow();
void updateStatusBarVisibility(); void updateStatusBarVisibility();
inline bool isRaster() const { inline bool isRaster() const {
if ((window()->flags() & Qt::ForeignWindow) == Qt::ForeignWindow)
return false;
return window()->surfaceType() == QSurface::RasterSurface return window()->surfaceType() == QSurface::RasterSurface
|| window()->surfaceType() == QSurface::RasterGLSurface; || window()->surfaceType() == QSurface::RasterGLSurface;
} }