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; return;
m_surfaces.remove(surfaceId); m_surfaces.remove(surfaceId);
if (m_surfaces.isEmpty())
m_surfaceId = 1;
QJNIEnvironmentPrivate env; QJNIEnvironmentPrivate env;
if (!env) if (!env)
return; return;

View File

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

View File

@ -57,10 +57,6 @@ QT_BEGIN_NAMESPACE
QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display) QAndroidPlatformOpenGLWindow::QAndroidPlatformOpenGLWindow(QWindow *window, EGLDisplay display)
:QAndroidPlatformWindow(window), m_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() QAndroidPlatformOpenGLWindow::~QAndroidPlatformOpenGLWindow()
@ -97,6 +93,13 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config) EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
{ {
QMutexLocker lock(&m_surfaceMutex); 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) { if (m_eglSurface == EGL_NO_SURFACE) {
m_surfaceMutex.unlock(); m_surfaceMutex.unlock();
checkNativeSurface(config); checkNativeSurface(config);
@ -120,6 +123,20 @@ void QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); 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) void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
{ {
clearEgl(); clearEgl();

View File

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

View File

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

View File

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

View File

@ -45,6 +45,8 @@
#include "qandroidplatformscreen.h" #include "qandroidplatformscreen.h"
#include "androidjnimain.h" #include "androidjnimain.h"
#include <qguiapplication.h>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
QT_BEGIN_NAMESPACE 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 QT_END_NAMESPACE

View File

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