From 96f0ff4f28c92b529a4d79afa669917734ec1192 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 21 Jul 2014 17:09:31 +0300 Subject: Android: Release all windows when the application is suspended. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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ø --- src/plugins/platforms/android/androidjnimain.cpp | 3 ++ .../android/qandroidplatformopenglcontext.cpp | 4 +- .../android/qandroidplatformopenglwindow.cpp | 25 +++++++++-- .../android/qandroidplatformopenglwindow.h | 2 + .../platforms/android/qandroidplatformscreen.cpp | 49 +++++++++++++++------- .../platforms/android/qandroidplatformscreen.h | 2 + .../platforms/android/qandroidplatformwindow.cpp | 18 ++++++++ .../platforms/android/qandroidplatformwindow.h | 2 + 8 files changed, 83 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 4ee32d79c2..7b99b29132 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -418,6 +418,9 @@ namespace QtAndroid return; m_surfaces.remove(surfaceId); + if (m_surfaces.isEmpty()) + m_surfaceId = 1; + QJNIEnvironmentPrivate env; if (!env) return; diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index f27bea8863..2c6e8370ce 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -58,10 +58,10 @@ QAndroidPlatformOpenGLContext::QAndroidPlatformOpenGLContext(const QSurfaceForma void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface) { - QEGLPlatformContext::swapBuffers(surface); - if (surface->surface()->surfaceClass() == QSurface::Window) static_cast(surface)->checkNativeSurface(eglConfig()); + + QEGLPlatformContext::swapBuffers(surface); } bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud() diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp index f0c4a1de2a..d14426d595 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.cpp @@ -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(); diff --git a/src/plugins/platforms/android/qandroidplatformopenglwindow.h b/src/plugins/platforms/android/qandroidplatformopenglwindow.h index 83df15a524..713f943bc5 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglwindow.h +++ b/src/plugins/platforms/android/qandroidplatformopenglwindow.h @@ -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); diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index af184cde02..529ae0a80d 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -54,6 +54,7 @@ #include #include +#include #include #include @@ -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 diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index cd9cf2ca71..311752c7b4 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -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(); diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index 558525b78c..d07573fb88 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -45,6 +45,8 @@ #include "qandroidplatformscreen.h" #include "androidjnimain.h" + +#include #include 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 diff --git a/src/plugins/platforms/android/qandroidplatformwindow.h b/src/plugins/platforms/android/qandroidplatformwindow.h index 764dd3ab86..91e32fa2ac 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.h +++ b/src/plugins/platforms/android/qandroidplatformwindow.h @@ -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); -- cgit v1.2.3