Android: improve fullscreen and maximized states handling
Rework fullscreen and maximized/expanded states handling by simplifying and re-organizing the code, removing some unnecessary code. Also, use newer APIs and handling the cutout regions. For expanded mode, use transparent instead of translucent so that the user can decide what color to use if needed, and in any case using the translucent flags is deprecated. You might still notice some artifacts as in QTBUG-88676, a fix for that is outside the scope of this patch. When going off of fullscreen mode one some cases you might notice a white/black black at the bottom and that's because QtRootLayout.onSizeChanged() is reporting wrong available size which is also an existing issue and outside of this scope. Fixes: QTBUG-96105 Fixes: QTBUG-101968 Fixes: QTBUG-127394 Fixes: QTBUG-121820 Task-number: QTBUG-109878 Task-number: QTBUG-119594 Change-Id: I586775a1d0414ec0adbc968d50b9c1a1ce466422 Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io> (cherry picked from commit 0abcb9bef8a7cb85df006adfed51bc9258868ed2) Reviewed-by: Petri Virkkunen <petri.virkkunen@qt.io>
This commit is contained in:
parent
b9c61b0f68
commit
6e32a2e065
@ -157,7 +157,7 @@ public class QtActivityBase extends Activity
|
||||
m_delegate.displayManager().registerDisplayListener();
|
||||
QtNative.updateWindow();
|
||||
// Suspending the app clears the immersive mode, so we need to set it again.
|
||||
m_delegate.displayManager().updateFullScreen();
|
||||
m_delegate.displayManager().reinstateFullScreen();
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,8 +290,9 @@ public class QtActivityBase extends Activity
|
||||
{
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
QtNative.setStarted(savedInstanceState.getBoolean("Started"));
|
||||
int savedSystemUiVisibility = savedInstanceState.getInt("SystemUiVisibility");
|
||||
m_delegate.displayManager().setSystemUiVisibility(savedSystemUiVisibility);
|
||||
boolean isFullScreen = savedInstanceState.getBoolean("isFullScreen");
|
||||
boolean expandedToCutout = savedInstanceState.getBoolean("expandedToCutout");
|
||||
m_delegate.displayManager().setSystemUiVisibility(isFullScreen, expandedToCutout);
|
||||
// FIXME restore all surfaces
|
||||
}
|
||||
|
||||
@ -307,7 +308,8 @@ public class QtActivityBase extends Activity
|
||||
protected void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt("SystemUiVisibility", m_delegate.displayManager().systemUiVisibility());
|
||||
outState.putBoolean("isFullScreen", m_delegate.displayManager().isFullScreen());
|
||||
outState.putBoolean("expandedToCutout", m_delegate.displayManager().expandedToCutout());
|
||||
outState.putBoolean("Started", QtNative.getStateDetails().isStarted);
|
||||
}
|
||||
|
||||
@ -316,7 +318,7 @@ public class QtActivityBase extends Activity
|
||||
{
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus)
|
||||
m_delegate.displayManager().updateFullScreen();
|
||||
m_delegate.displayManager().reinstateFullScreen();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -88,14 +88,14 @@ class QtActivityDelegate extends QtActivityDelegateBase
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSystemUiVisibility(int systemUiVisibility)
|
||||
public void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout)
|
||||
{
|
||||
if (m_layout == null)
|
||||
return;
|
||||
|
||||
QtNative.runAction(() -> {
|
||||
if (m_layout != null) {
|
||||
m_displayManager.setSystemUiVisibility(systemUiVisibility);
|
||||
m_displayManager.setSystemUiVisibility(isFullScreen, expandedToCutout);
|
||||
m_layout.requestLayout();
|
||||
QtNative.updateWindow();
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ abstract class QtActivityDelegateBase
|
||||
m_activity = activity;
|
||||
QtNative.setActivity(m_activity);
|
||||
m_displayManager = new QtDisplayManager(m_activity);
|
||||
m_inputDelegate = new QtInputDelegate(m_displayManager::updateFullScreen);
|
||||
m_inputDelegate = new QtInputDelegate(m_displayManager::reinstateFullScreen);
|
||||
m_accessibilityDelegate = new QtAccessibilityDelegate();
|
||||
}
|
||||
|
||||
|
@ -16,12 +16,19 @@ import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.WindowMetrics;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.view.Window;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.util.TypedValue;
|
||||
import android.content.res.Resources.Theme;
|
||||
|
||||
class QtDisplayManager {
|
||||
|
||||
// screen methods
|
||||
@ -38,11 +45,8 @@ class QtDisplayManager {
|
||||
static native void handleScreenRemoved(int displayId);
|
||||
// screen methods
|
||||
|
||||
// Keep in sync with QtAndroid::SystemUiVisibility in androidjnimain.h
|
||||
static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
|
||||
static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
|
||||
static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2;
|
||||
private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
|
||||
private boolean m_isFullScreen = false;
|
||||
private boolean m_expandedToCutout = false;
|
||||
|
||||
private static int m_previousRotation = -1;
|
||||
|
||||
@ -123,62 +127,96 @@ class QtDisplayManager {
|
||||
displayManager.unregisterDisplayListener(m_displayListener);
|
||||
}
|
||||
|
||||
void setSystemUiVisibility(int systemUiVisibility)
|
||||
void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout)
|
||||
{
|
||||
if (m_systemUiVisibility == systemUiVisibility)
|
||||
if (m_isFullScreen == isFullScreen && m_expandedToCutout == expandedToCutout)
|
||||
return;
|
||||
|
||||
m_systemUiVisibility = systemUiVisibility;
|
||||
m_isFullScreen = isFullScreen;
|
||||
m_expandedToCutout = expandedToCutout;
|
||||
Window window = m_activity.getWindow();
|
||||
View decorView = window.getDecorView();
|
||||
|
||||
int systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
switch (m_systemUiVisibility) {
|
||||
case SYSTEM_UI_VISIBILITY_NORMAL:
|
||||
m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
int cutoutMode;
|
||||
if (m_isFullScreen || m_expandedToCutout) {
|
||||
window.setDecorFitsSystemWindows(false);
|
||||
cutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||
} else {
|
||||
window.setDecorFitsSystemWindows(true);
|
||||
cutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
||||
}
|
||||
LayoutParams layoutParams = window.getAttributes();
|
||||
layoutParams.layoutInDisplayCutoutMode = cutoutMode;
|
||||
window.setAttributes(layoutParams);
|
||||
|
||||
final WindowInsetsController insetsControl = window.getInsetsController();
|
||||
if (insetsControl != null) {
|
||||
int sysBarsBehavior;
|
||||
if (m_isFullScreen) {
|
||||
insetsControl.hide(WindowInsets.Type.systemBars());
|
||||
sysBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
|
||||
} else {
|
||||
insetsControl.show(WindowInsets.Type.systemBars());
|
||||
sysBarsBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
|
||||
}
|
||||
break;
|
||||
case SYSTEM_UI_VISIBILITY_FULLSCREEN:
|
||||
m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
|
||||
systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
| View.INVISIBLE;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
|
||||
insetsControl.setSystemBarsBehavior(sysBarsBehavior);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
int systemUiVisibility;
|
||||
|
||||
if (m_isFullScreen || m_expandedToCutout) {
|
||||
systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
|
||||
if (m_isFullScreen) {
|
||||
systemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
}
|
||||
break;
|
||||
case SYSTEM_UI_VISIBILITY_TRANSLUCENT:
|
||||
m_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
|
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
|
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
m_activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode =
|
||||
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
|
||||
}
|
||||
|
||||
decorView.setSystemUiVisibility(systemUiVisibility);
|
||||
}
|
||||
|
||||
// Handle transparent status and navigation bars
|
||||
if (m_expandedToCutout) {
|
||||
window.setStatusBarColor(Color.TRANSPARENT);
|
||||
window.setNavigationBarColor(Color.TRANSPARENT);
|
||||
} else {
|
||||
// Restore theme's system bars colors
|
||||
Theme theme = m_activity.getTheme();
|
||||
TypedValue typedValue = new TypedValue();
|
||||
|
||||
theme.resolveAttribute(android.R.attr.statusBarColor, typedValue, true);
|
||||
int defaultStatusBarColor = typedValue.data;
|
||||
window.setStatusBarColor(defaultStatusBarColor);
|
||||
|
||||
theme.resolveAttribute(android.R.attr.navigationBarColor, typedValue, true);
|
||||
int defaultNavigationBarColor = typedValue.data;
|
||||
window.setNavigationBarColor(defaultNavigationBarColor);
|
||||
}
|
||||
m_activity.getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
|
||||
}
|
||||
|
||||
int systemUiVisibility()
|
||||
boolean isFullScreen()
|
||||
{
|
||||
return m_systemUiVisibility;
|
||||
return m_isFullScreen;
|
||||
}
|
||||
|
||||
void updateFullScreen()
|
||||
boolean expandedToCutout()
|
||||
{
|
||||
if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) {
|
||||
m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
|
||||
setSystemUiVisibility(SYSTEM_UI_VISIBILITY_FULLSCREEN);
|
||||
return m_expandedToCutout;
|
||||
}
|
||||
|
||||
void reinstateFullScreen()
|
||||
{
|
||||
if (m_isFullScreen) {
|
||||
m_isFullScreen = false;
|
||||
setSystemUiVisibility(true, m_expandedToCutout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,5 +7,5 @@ interface QtWindowInterface {
|
||||
default void removeTopLevelWindow(final int id) { }
|
||||
default void bringChildToFront(final int id) { }
|
||||
default void bringChildToBack(int id) { }
|
||||
default void setSystemUiVisibility(int systemUiVisibility) { }
|
||||
default void setSystemUiVisibility(boolean isFullScreen, boolean expandedToCutout) { }
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#include "qandroidplatformwindow.h"
|
||||
#include "androidbackendregister.h"
|
||||
#include "qandroidplatformopenglcontext.h"
|
||||
#include "qandroidplatformscreen.h"
|
||||
|
||||
@ -255,19 +256,13 @@ void QAndroidPlatformWindow::requestActivateWindow()
|
||||
|
||||
void QAndroidPlatformWindow::updateSystemUiVisibility()
|
||||
{
|
||||
Qt::WindowFlags flags = window()->flags();
|
||||
bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
|
||||
const int flags = window()->flags();
|
||||
const bool isNonRegularWindow = flags & (Qt::Popup | Qt::Dialog | Qt::Sheet) & ~Qt::Window;
|
||||
if (!isNonRegularWindow) {
|
||||
SystemUiVisibility visibility;
|
||||
if (m_windowState & Qt::WindowFullScreen)
|
||||
visibility = SYSTEM_UI_VISIBILITY_FULLSCREEN;
|
||||
else if (flags & Qt::MaximizeUsingFullscreenGeometryHint)
|
||||
visibility = SYSTEM_UI_VISIBILITY_TRANSLUCENT;
|
||||
else
|
||||
visibility = SYSTEM_UI_VISIBILITY_NORMAL;
|
||||
|
||||
const bool isFullScreen = (m_windowState & Qt::WindowFullScreen);
|
||||
const bool expandedToCutout = (flags & Qt::MaximizeUsingFullscreenGeometryHint);
|
||||
QtAndroid::backendRegister()->callInterface<QtJniTypes::QtWindowInterface, void>(
|
||||
"setSystemUiVisibility", jint(visibility));
|
||||
"setSystemUiVisibility", isFullScreen, expandedToCutout);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,13 +31,6 @@ public:
|
||||
TextureView
|
||||
};
|
||||
|
||||
// Keep synchronized with flags in ActivityDelegate.java
|
||||
enum SystemUiVisibility {
|
||||
SYSTEM_UI_VISIBILITY_NORMAL = 0,
|
||||
SYSTEM_UI_VISIBILITY_FULLSCREEN = 1,
|
||||
SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2
|
||||
};
|
||||
|
||||
explicit QAndroidPlatformWindow(QWindow *window);
|
||||
void initialize() override;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user