mirror of https://github.com/qt/qtbase.git
Destroy window surface after exit transition for Qt for Android apps
Splash screen (or blank launch screen) is shown when exiting the Android application caused by hiding shown windows and destroying it's surface before application exit. On application exit all windows are first set to invisible then surfaces destroyed and finally removed from layout. Also window opacity change can show underlying splash screen as it is set as theme for the application. When pressing Android device's back button application either should hide current window or exit the application. When exiting current window should be visible during application exit. Add AtomicBoolean m_canBeDestroyed to QtWindow for blocking normal surface removal. Set false by default from QtActivityDelegate.addTopLevelWindow and changed from QAndroidPlatformWindow::setVisible() dependent on if there are more visible windows present. Destroy last window with delay so it can be shown during app exit. In QtActivityDelegate.setUpSplashScreen() set layout to use android device's DayNight theme colors to not show splash screen theme if window opacity is changed. Fixes: QTBUG-127705 Fixes: QTBUG-124140 Pickt-to: 6.8 6.9 6.10 Change-Id: I74adf693dac599c0b46b1f427e563683c1033565 Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
This commit is contained in:
parent
3cb3e84843
commit
e40d9d4361
|
@ -9,6 +9,7 @@ import android.app.Activity;
|
|||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.Rect;
|
||||
|
@ -25,7 +26,7 @@ import android.view.ViewConfiguration;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import android.graphics.Color;
|
||||
import java.util.HashMap;
|
||||
|
||||
class QtActivityDelegate extends QtActivityDelegateBase
|
||||
|
@ -39,7 +40,6 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
|||
private boolean m_splashScreenSticky = false;
|
||||
private boolean m_backendsRegistered = false;
|
||||
|
||||
private View m_dummyView = null;
|
||||
private final HashMap<Integer, View> m_nativeViews = new HashMap<>();
|
||||
|
||||
QtActivityDelegate(Activity activity)
|
||||
|
@ -197,6 +197,19 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
|||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
m_layout.addView(m_splashScreen);
|
||||
|
||||
// Set DayNight theme as layout background so splash screen
|
||||
// is not visible with opaque windows.
|
||||
TypedArray typedArray = m_activity.getTheme().obtainStyledAttributes(
|
||||
android.R.style.Theme_DeviceDefault_DayNight,
|
||||
new int[]{ android.R.attr.colorBackground });
|
||||
try {
|
||||
int backgroundColor = typedArray.getColor(0, 0);
|
||||
Drawable background = new ColorDrawable(backgroundColor);
|
||||
m_layout.setBackground(background);
|
||||
} finally {
|
||||
typedArray.recycle();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -368,15 +381,9 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
|||
if (m_layout == null)
|
||||
return;
|
||||
|
||||
if (m_topLevelWindows.isEmpty()) {
|
||||
if (m_dummyView != null) {
|
||||
m_layout.removeView(m_dummyView);
|
||||
m_dummyView = null;
|
||||
}
|
||||
}
|
||||
|
||||
m_layout.addView(window, m_topLevelWindows.size());
|
||||
m_topLevelWindows.put(window.getId(), window);
|
||||
window.setToDestroy(false);
|
||||
if (!m_splashScreenSticky)
|
||||
hideSplashScreen();
|
||||
});
|
||||
|
@ -390,13 +397,13 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
|||
if (m_topLevelWindows.containsKey(id)) {
|
||||
QtWindow window = m_topLevelWindows.remove(id);
|
||||
window.setOnApplyWindowInsetsListener(null); // Set in QtWindow for safe margins
|
||||
if (m_topLevelWindows.isEmpty()) {
|
||||
// Keep last frame in stack until it is replaced to get correct
|
||||
// shutdown transition
|
||||
m_dummyView = window;
|
||||
} else if (m_layout != null) {
|
||||
m_layout.removeView(window);
|
||||
}
|
||||
if (window.isFrontmostVisibleWindow()) {
|
||||
window.setToDestroy(true);
|
||||
// Keep current shown window open during shutdown transition
|
||||
m_layout.postDelayed(() -> { window.destroySurface(); }, 500);
|
||||
} else if (m_layout != null) {
|
||||
m_layout.removeView(window);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -452,11 +459,6 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
|||
return;
|
||||
|
||||
QtNative.runAction(()-> {
|
||||
if (m_dummyView != null) {
|
||||
m_layout.removeView(m_dummyView);
|
||||
m_dummyView = null;
|
||||
}
|
||||
|
||||
if (m_nativeViews.containsKey(id))
|
||||
m_layout.removeView(m_nativeViews.remove(id));
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.view.WindowInsets;
|
|||
import android.os.Build;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class QtWindow extends QtLayout implements QtSurfaceInterface {
|
||||
|
@ -30,6 +31,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
|||
private GestureDetector m_gestureDetector;
|
||||
private final QtEditText m_editText;
|
||||
private final QtInputConnection.QtInputConnectionListener m_inputConnectionListener;
|
||||
private final AtomicBoolean m_canBeDestroyed = new AtomicBoolean(true);
|
||||
|
||||
private static native void setSurface(int windowId, Surface surface);
|
||||
private static native void safeAreaMarginsChanged(Insets insets, int id);
|
||||
|
@ -127,6 +129,60 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
|||
QtNative.runAction(() -> setVisibility(visible ? View.VISIBLE : View.INVISIBLE));
|
||||
}
|
||||
|
||||
// Use only for Qt for Android and not Qt Quick for Android
|
||||
@UsedFromNativeCode
|
||||
public void setToDestroy(boolean destroy)
|
||||
{
|
||||
m_canBeDestroyed.set(destroy);
|
||||
}
|
||||
|
||||
// Use only for Qt for Android and not Qt Quick for Android
|
||||
private QtLayout getParentContainer()
|
||||
{
|
||||
if (!(getParent() instanceof QtLayout))
|
||||
return null;
|
||||
return (QtLayout) getParent();
|
||||
}
|
||||
|
||||
// Use only for Qt for Android and not Qt Quick for Android
|
||||
public boolean isFrontmostVisibleWindow()
|
||||
{
|
||||
QtLayout parent = getParentContainer();
|
||||
if (getVisibility() != View.VISIBLE || parent == null )
|
||||
return false;
|
||||
|
||||
for (int index = parent.indexOfChild(this) + 1; index < parent.getChildCount(); index ++) {
|
||||
View child = parent.getChildAt(index);
|
||||
if (child instanceof QtWindow && child.isShown())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use only for Qt for Android and not Qt Quick for Android
|
||||
@UsedFromNativeCode
|
||||
public boolean isLastVisibleTopLevelWindow()
|
||||
{
|
||||
QtLayout parent = getParentContainer();
|
||||
if (getVisibility() != View.VISIBLE || parent == null)
|
||||
return false;
|
||||
|
||||
for (int index = parent.indexOfChild(this) - 1; index >= 0; index--) {
|
||||
View child = parent.getChildAt(index);
|
||||
if (child instanceof QtWindow) {
|
||||
QtWindow childWindow = (QtWindow) child;
|
||||
if (child.getVisibility() == View.VISIBLE && !childWindow.m_canBeDestroyed.get())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent.getChildCount() > 1 && !isFrontmostVisibleWindow())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceChanged(Surface surface)
|
||||
{
|
||||
|
@ -193,10 +249,10 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
|
|||
void destroySurface()
|
||||
{
|
||||
QtNative.runAction(()-> {
|
||||
if (m_surfaceContainer != null) {
|
||||
if (m_surfaceContainer != null && m_canBeDestroyed.get()) {
|
||||
removeView(m_surfaceContainer);
|
||||
m_surfaceContainer = null;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,16 @@ void QAndroidPlatformWindow::setVisible(bool visible)
|
|||
return;
|
||||
|
||||
if (window()->isTopLevel()) {
|
||||
// Do not hide last Qt for Android window.
|
||||
// We don't want the splash screen to be shown during the app's
|
||||
// exit because it would be the foremost visible screen.
|
||||
if (QtAndroid::isQtApplication() && !visible) {
|
||||
bool lastVisibleWindow =
|
||||
m_nativeQtWindow.callMethod<bool>("isLastVisibleTopLevelWindow");
|
||||
m_nativeQtWindow.callMethod<void>("setToDestroy", !lastVisibleWindow);
|
||||
if (lastVisibleWindow)
|
||||
return;
|
||||
}
|
||||
if (!visible && window() == qGuiApp->focusWindow()) {
|
||||
platformScreen()->topVisibleWindowChanged();
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue