Android: Fix flashing on startup/shutdown

There were several issues on startup of the application which
were caused by the fact that we would get the wrong
available screen geometry on startup, set this as the
initial surface size and then expose native windows with this
size. This would cause first a flicker of white on the early
expose and the window contents to jump around as the window was
resized to the actual available space on screen.

The fix for this is to postpone the first expose until we have
actually got a proper screen size from the main layout. We use
width,height = 0 as an indicator that the available geometry
is not yet known, and we skip posting any expose events before
this is set by the layout.

In addition, since we removed the surface before we shut down
the application, it was by a white rectangle before the
shutdown transition happens, and this white rectangle will
be animated instead of application contents.

To rectify this, we make sure the last surface in the stack
remains in the layout until it is either replaced by a different
surface or until the application has shut down. This way, the
shutdown animation will work on this surface instead.

[ChangeLog][Android] Fixed regression where there would be flickering
on startup and shutdown of the application.

Task-number: QTBUG-38960
Change-Id: Ia1579ca8c522d8beeab066f78070ad49009d0238
Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2014-05-22 14:10:53 +02:00 committed by The Qt Project
parent ac7bf97f51
commit 90808ead98
6 changed files with 74 additions and 12 deletions

View File

@ -118,6 +118,7 @@ public class QtActivityDelegate
private InputMethodManager m_imm = null;
private boolean m_quitApp = true;
private Process m_debuggerProcess = null; // debugger process
private View m_dummyView = null;
private boolean m_keyboardIsVisible = false;
public boolean m_backKeyPressedSent = false;
@ -667,7 +668,7 @@ public class QtActivityDelegate
DisplayMetrics metrics = new DisplayMetrics();
m_activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels,
metrics.widthPixels, metrics.heightPixels,
0, 0,
metrics.xdpi, metrics.ydpi, metrics.scaledDensity);
}
m_layout = new QtLayout(m_activity);
@ -677,6 +678,10 @@ public class QtActivityDelegate
m_nativeViews = new HashMap<Integer, View>();
m_activity.registerForContextMenu(m_layout);
m_activity.setContentView(m_layout,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
int orientation = m_activity.getResources().getConfiguration().orientation;
int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
boolean rot90 = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
@ -1001,6 +1006,11 @@ public class QtActivityDelegate
}
public void insertNativeView(int id, View view, int x, int y, int w, int h) {
if (m_dummyView != null) {
m_layout.removeView(m_dummyView);
m_dummyView = null;
}
if (m_nativeViews.containsKey(id))
m_layout.removeView(m_nativeViews.remove(id));
@ -1026,9 +1036,10 @@ public class QtActivityDelegate
m_activity.getWindow().setBackgroundDrawable(m_activity.getResources().getDrawable(attr.resourceId));
}
m_activity.setContentView(m_layout,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
if (m_dummyView != null) {
m_layout.removeView(m_dummyView);
m_dummyView = null;
}
}
if (m_surfaces.containsKey(id))
@ -1065,12 +1076,22 @@ public class QtActivityDelegate
}
public void destroySurface(int id) {
View view = null;
if (m_surfaces.containsKey(id)) {
m_layout.removeView(m_surfaces.remove(id));
view = m_surfaces.remove(id);
} else if (m_nativeViews.containsKey(id)) {
m_layout.removeView(m_nativeViews.remove(id));
view = m_nativeViews.remove(id);
} else {
Log.e(QtNative.QtTAG, "Surface " + id +" not found!");
}
// Keep last frame in stack until it is replaced to get correct
// shutdown transition
if (m_surfaces.size() == 0 && m_nativeViews.size() == 0) {
m_dummyView = view;
} else if (view != null) {
m_layout.removeView(view);
}
}
}

View File

@ -69,6 +69,7 @@ import android.content.res.Resources.Theme;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@ -874,6 +875,8 @@ public class QtActivity extends Activity
// if splash screen is defined, then show it
if (m_activityInfo.metaData.containsKey("android.app.splash_screen_drawable"))
getWindow().setBackgroundDrawableResource(m_activityInfo.metaData.getInt("android.app.splash_screen_drawable"));
else
getWindow().setBackgroundDrawable(new ColorDrawable(0xff000000));
startApp(true);
}
}

View File

@ -573,8 +573,11 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
return;
if (QGuiApplication::instance() != 0) {
foreach (QWindow *w, QGuiApplication::topLevelWindows())
QWindowSystemInterface::handleExposeEvent(w, QRegion(w->geometry()));
foreach (QWindow *w, QGuiApplication::topLevelWindows()) {
QRect availableGeometry = w->screen()->availableGeometry();
if (w->geometry().width() > 0 && w->geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(w, QRegion(w->geometry()));
}
}
QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());

View File

@ -47,7 +47,8 @@
#include <QSurfaceFormat>
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformscreen.h>
#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <android/native_window.h>
#include <android/native_window_jni.h>
@ -77,8 +78,20 @@ void QAndroidPlatformOpenGLWindow::setGeometry(const QRect &rect)
if (rect == geometry())
return;
QRect oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
QtAndroid::setSurfaceGeometry(m_nativeSurfaceId, rect);
QRect availableGeometry = screen()->availableGeometry();
if (oldGeometry.width() == 0
&& oldGeometry.height() == 0
&& rect.width() > 0
&& rect.height() > 0
&& availableGeometry.width() > 0
&& availableGeometry.height() > 0) {
QWindowSystemInterface::handleExposeEvent(window(), QRegion(rect));
}
}
EGLSurface QAndroidPlatformOpenGLWindow::eglSurface(EGLConfig config)
@ -100,8 +113,11 @@ void QAndroidPlatformOpenGLWindow::checkNativeSurface(EGLConfig config)
createEgl(config);
// we've create another surface, the window should be repainted
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
}
void QAndroidPlatformOpenGLWindow::createEgl(EGLConfig config)
@ -143,7 +159,9 @@ void QAndroidPlatformOpenGLWindow::surfaceChanged(JNIEnv *jniEnv, jobject surfac
unlockSurface();
// repaint the window
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry()));
}
QT_END_NAMESPACE

View File

@ -55,6 +55,9 @@
#include <android/bitmap.h>
#include <android/native_window_jni.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QWindow>
QT_BEGIN_NAMESPACE
#ifdef QANDROIDPLATFORMSCREEN_DEBUG
@ -217,11 +220,23 @@ void QAndroidPlatformScreen::setGeometry(const QRect &rect)
if (m_geometry == rect)
return;
QRect oldGeometry = m_geometry;
m_geometry = rect;
QWindowSystemInterface::handleScreenGeometryChange(QPlatformScreen::screen(), geometry());
QWindowSystemInterface::handleScreenAvailableGeometryChange(QPlatformScreen::screen(), availableGeometry());
resizeMaximizedWindows();
if (oldGeometry.width() == 0 && oldGeometry.height() == 0 && rect.width() > 0 && rect.height() > 0) {
QList<QWindow *> windows = QGuiApplication::allWindows();
for (int i = 0; i < windows.size(); ++i) {
QWindow *w = windows.at(i);
QRect geometry = w->handle()->geometry();
if (geometry.width() > 0 && geometry.height() > 0)
QWindowSystemInterface::handleExposeEvent(w, QRegion(geometry));
}
}
if (m_id != -1) {
if (m_nativeSurface) {
ANativeWindow_release(m_nativeSurface);

View File

@ -88,7 +88,9 @@ void QAndroidPlatformWindow::setVisible(bool visible)
setGeometry(platformScreen()->availableGeometry());
}
QPlatformWindow::setVisible(visible);
QRect availableGeometry = screen()->availableGeometry();
if (geometry().width() > 0 && geometry().height() > 0 && availableGeometry.width() > 0 && availableGeometry.height() > 0)
QPlatformWindow::setVisible(visible);
if (visible)
platformScreen()->addWindow(this);