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

View File

@ -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);
}
if (!geometry.isNull())
geometry.getRect(&x, &y, &w, &h);
env->CallStaticVoidMethod(m_applicationClass,
m_insertNativeViewMethodID,
surfaceId,
view,
x, y, w, h);
QJNIObjectPrivate::callStaticMethod<void>(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");

View File

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

View File

@ -38,16 +38,23 @@
#include "qandroidplatformwindow.h"
#include <QtCore/private/qjni_p.h>
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

View File

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