Android: Release all windows when the application is suspended.

When an application is suspended on Android all its Gl surfaces
are destroyed and can't be used to render anymore, so we should
release them in order to give back to the system the memory used
by them.

[ChangeLog] [Android] Release all windows when the application is
suspended.

Task-number: QTBUG-29069
Change-Id: I038aaa2006da1f3188fccba943ec4ffb3e551cf0
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
BogDan Vatra 2014-07-21 17:09:31 +03:00
parent 734c126826
commit 96f0ff4f28
8 changed files with 83 additions and 22 deletions

View File

@ -418,6 +418,9 @@ namespace QtAndroid
return;
m_surfaces.remove(surfaceId);
if (m_surfaces.isEmpty())
m_surfaceId = 1;
QJNIEnvironmentPrivate env;
if (!env)
return;

View File

@ -58,10 +58,10 @@ QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceForma
void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface)
{
QEGLPlatformContext::swapBuffers(surface);
if (surface->surface()->surfaceClass() == QSurface::Window)
static_cast<QAndroidPlatformOpenGLWindow *>(surface)->checkNativeSurface(eglConfig());
QEGLPlatformContext::swapBuffers(surface);
}
bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud()

View File

@ -57,10 +57,6 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display)
:QAndroidPlatformWindow(window), m_eglDisplay(display)
{
lockSurface();
m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), bool(window->flags() & Qt::WindowStaysOnTopHint), 32);
m_surfaceWaitCondition.wait(&m_surfaceMutex);
unlockSurface();
}
QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
@ -97,6 +93,13 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
{
QMutexLocker lock(&m_surfaceMutex);
if (m_nativeSurfaceId == -1) {
const bool windowStaysOnTop = bool(window()->flags() & Qt::WindowStaysOnTopHint);
m_nativeSurfaceId = QtAndroid::createSurface(this, geometry(), windowStaysOnTop, 32);
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
if (m_eglSurface == EGL_NO_SURFACE) {
m_surfaceMutex.unlock();
checkNativeSurface(config);
@ -120,6 +123,20 @@ void QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
}
void QAndroidPlatformOpenGLWindow::applicationStateChanged(Qt::ApplicationState state)
{
QAndroidPlatformWindow::applicationStateChanged(state);
if (state <= Qt::ApplicationHidden && QtAndroid::blockEventLoopsWhenSuspended()) {
lockSurface();
if (m_nativeSurfaceId != -1) {
QtAndroid::destroySurface(m_nativeSurfaceId);
m_nativeSurfaceId = -1;
}
clearEgl();
unlockSurface();
}
}
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
{
clearEgl();

View File

@ -64,6 +64,8 @@ public:
void checkNativeSurface(EGLConfig config);
void applicationStateChanged(Qt::ApplicationState);
protected:
virtual void surfaceChanged(JNIEnv *jniEnv, jobject surface, int w, int h);
void createEgl(EGLConfig config);

View File

@ -54,6 +54,7 @@
#include <android/bitmap.h>
#include <android/native_window_jni.h>
#include <qguiapplication.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
@ -102,6 +103,7 @@ QAndroidPlatformScreen::QAndroidPlatformScreen():QObject(),QPlatformScreen()
m_redrawTimer.setSingleShot(true);
m_redrawTimer.setInterval(0);
connect(&m_redrawTimer, SIGNAL(timeout()), this, SLOT(doRedraw()));
connect(qGuiApp, &QGuiApplication::applicationStateChanged, this, &QAndroidPlatformScreen::applicationStateChanged);
}
QAndroidPlatformScreen::~QAndroidPlatformScreen()
@ -109,8 +111,7 @@ QAndroidPlatformScreen::~QAndroidPlatformScreen()
if (m_id != -1) {
QtAndroid::destroySurface(m_id);
m_surfaceWaitCondition.wakeOne();
if (m_nativeSurface)
ANativeWindow_release(m_nativeSurface);
releaseSurface();
}
}
@ -133,7 +134,7 @@ QWindow *QAndroidPlatformScreen::topLevelAt(const QPoint &p) const
void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
{
if (window->parent())
if (window->parent() && window->isRaster())
return;
m_windowStack.prepend(window);
@ -149,10 +150,11 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
{
if (window->parent())
if (window->parent() && window->isRaster())
return;
m_windowStack.removeOne(window);
if (window->isRaster()) {
m_rasterSurfaces.deref();
setDirty(window->geometry());
@ -165,7 +167,7 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
{
if (window->parent())
if (window->parent() && window->isRaster())
return;
int index = m_windowStack.indexOf(window);
@ -182,7 +184,7 @@ void QAndroidPlatformScreen::raise(QAndroidPlatformWindow *window)
void QAndroidPlatformScreen::lower(QAndroidPlatformWindow *window)
{
if (window->parent())
if (window->parent() && window->isRaster())
return;
int index = m_windowStack.indexOf(window);
@ -247,14 +249,25 @@ void QAndroidPlatformScreen::setAvailableGeometry(const QRect &rect)
}
if (m_id != -1) {
if (m_nativeSurface) {
ANativeWindow_release(m_nativeSurface);
m_nativeSurface = 0;
}
releaseSurface();
QtAndroid::setSurfaceGeometry(m_id, rect);
}
}
void QAndroidPlatformScreen::applicationStateChanged(Qt::ApplicationState state)
{
foreach (QAndroidPlatformWindow *w, m_windowStack)
w->applicationStateChanged(state);
if (state <= Qt::ApplicationHidden && QtAndroid::blockEventLoopsWhenSuspended()) {
lockSurface();
QtAndroid::destroySurface(m_id);
m_id = -1;
releaseSurface();
unlockSurface();
}
}
void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
{
QtAndroidMenu::setActiveTopLevelWindow(w);
@ -365,18 +378,22 @@ void QAndroidPlatformScreen::surfaceChanged(JNIEnv *env, jobject surface, int w,
{
lockSurface();
if (surface && w && h) {
if (m_nativeSurface)
ANativeWindow_release(m_nativeSurface);
releaseSurface();
m_nativeSurface = ANativeWindow_fromSurface(env, surface);
QMetaObject::invokeMethod(this, "setDirty", Qt::QueuedConnection, Q_ARG(QRect, QRect(0, 0, w, h)));
} else {
if (m_nativeSurface) {
ANativeWindow_release(m_nativeSurface);
m_nativeSurface = 0;
}
releaseSurface();
}
unlockSurface();
m_surfaceWaitCondition.wakeOne();
}
void QAndroidPlatformScreen::releaseSurface()
{
if (m_nativeSurface) {
ANativeWindow_release(m_nativeSurface);
m_nativeSurface = 0;
}
}
QT_END_NAMESPACE

View File

@ -107,6 +107,8 @@ private:
Qt::ScreenOrientation orientation() const;
Qt::ScreenOrientation nativeOrientation() const;
void surfaceChanged(JNIEnv *env, jobject surface, int w, int h);
void releaseSurface();
void applicationStateChanged(Qt::ApplicationState);
private slots:
void doRedraw();

View File

@ -45,6 +45,8 @@
#include "qandroidplatformscreen.h"
#include "androidjnimain.h"
#include <qguiapplication.h>
#include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE
@ -160,5 +162,21 @@ void QAndroidPlatformWindow::updateStatusBarVisibility()
}
}
bool QAndroidPlatformWindow::isExposed() const
{
return qApp->applicationState() > Qt::ApplicationHidden
&& window()->isVisible()
&& !window()->geometry().isEmpty();
}
void QAndroidPlatformWindow::applicationStateChanged(Qt::ApplicationState)
{
QRegion region;
if (isExposed())
region = QRect(QPoint(), geometry().size());
QWindowSystemInterface::handleExposeEvent(window(), region);
QWindowSystemInterface::flushWindowSystemEvents();
}
QT_END_NAMESPACE

View File

@ -72,7 +72,9 @@ public:
void requestActivateWindow();
void updateStatusBarVisibility();
inline bool isRaster() const { return window()->surfaceType() == QSurface::RasterSurface; }
bool isExposed() const;
virtual void applicationStateChanged(Qt::ApplicationState);
protected:
void setGeometry(const QRect &rect);