Android: move display and screen management to new QtDisplayManager

Have all or most of Android code dealing with displays in
QtDisplayManager. Also, simplify setApplicationDisplayMetrics()
call and avoid caching any uneccessary members.

Task-number: QTBUG-118077
Change-Id: I943069c24bb40ae3016db5896e553b501e700a6b
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
This commit is contained in:
Assam Boudjelthia 2023-09-24 13:10:17 +01:00
parent 7b77a1c2a6
commit 58c7249ee8
9 changed files with 370 additions and 303 deletions

View File

@ -29,6 +29,7 @@ set(java_sources
src/org/qtproject/qt/android/extras/QtNative.java
src/org/qtproject/qt/android/QtConstants.java
src/org/qtproject/qt/android/QtClipboardManager.java
src/org/qtproject/qt/android/QtDisplayManager.java
)
qt_internal_add_jar(Qt${QtBase_VERSION_MAJOR}Android

View File

@ -155,7 +155,8 @@ public class QtActivityBase extends Activity
QtNative.setApplicationState(QtConstants.ApplicationState.ApplicationActive);
if (m_delegate.isStarted()) {
QtNative.updateWindow();
m_delegate.updateFullScreen(); // Suspending the app clears the immersive mode, so we need to set it again.
// Suspending the app clears the immersive mode, so we need to set it again.
m_delegate.displayManager().updateFullScreen(this);
}
}
@ -294,7 +295,7 @@ public class QtActivityBase extends Activity
protected void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putInt("SystemUiVisibility", m_delegate.systemUiVisibility());
outState.putInt("SystemUiVisibility", m_delegate.displayManager().systemUiVisibility());
outState.putBoolean("Started", m_delegate.isStarted());
}
@ -303,7 +304,7 @@ public class QtActivityBase extends Activity
{
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
m_delegate.updateFullScreen();
m_delegate.displayManager().updateFullScreen(this);
}
@Override

View File

@ -20,21 +20,17 @@ import android.util.TypedValue;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.Display;
import android.view.Menu;
import android.view.MenuItem;
import android.view.Surface;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowInsetsController;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.hardware.display.DisplayManager;
import java.util.ArrayList;
import java.util.HashMap;
@ -45,15 +41,6 @@ public class QtActivityDelegate
{
private Activity m_activity = null;
// Keep in sync with QtAndroid::SystemUiVisibility in androidjnimain.h
public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
public static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2;
private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
private int m_currentRotation = -1; // undefined
private int m_nativeOrientation = Configuration.ORIENTATION_UNDEFINED;
private boolean m_started = false;
private boolean m_quitApp = true;
private boolean m_isPluginRunning = false;
@ -64,16 +51,16 @@ public class QtActivityDelegate
private ImageView m_splashScreen = null;
private boolean m_splashScreenSticky = false;
private View m_dummyView = null;
private QtAccessibilityDelegate m_accessibilityDelegate = null;
private final QtDisplayManager m_displayManager = new QtDisplayManager();
private QtInputDelegate.KeyboardVisibilityListener m_keyboardVisibilityListener =
new QtInputDelegate.KeyboardVisibilityListener() {
@Override
public void onKeyboardVisibilityChange() {
updateFullScreen();
m_displayManager.updateFullScreen(m_activity);
}
};
private final QtInputDelegate m_inputDelegate = new QtInputDelegate(m_keyboardVisibilityListener);
@ -92,8 +79,12 @@ public class QtActivityDelegate
e.printStackTrace();
}
DisplayManager displayManager = (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(m_displayListener, null);
m_displayManager.registerDisplayListener(m_activity, m_layout);
}
QtDisplayManager displayManager()
{
return m_displayManager;
}
QtInputDelegate getInputDelegate() {
@ -107,56 +98,14 @@ public class QtActivityDelegate
public void setSystemUiVisibility(int systemUiVisibility)
{
if (m_systemUiVisibility == systemUiVisibility)
return;
m_systemUiVisibility = systemUiVisibility;
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);
setDisplayCutoutLayout(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER);
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;
setDisplayCutoutLayout(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT);
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);
setDisplayCutoutLayout(WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
break;
};
m_activity.getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
m_layout.requestLayout();
}
private void setDisplayCutoutLayout(int cutoutLayout)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
m_activity.getWindow().getAttributes().layoutInDisplayCutoutMode = cutoutLayout;
}
public void updateFullScreen()
{
if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) {
m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
setSystemUiVisibility(SYSTEM_UI_VISIBILITY_FULLSCREEN);
}
QtNative.runAction(new Runnable() {
@Override
public void run() {
m_displayManager.setSystemUiVisibility(m_activity, systemUiVisibility);
m_layout.requestLayout();
QtNative.updateWindow();
}
});
}
void setStarted(boolean started)
@ -184,11 +133,6 @@ public class QtActivityDelegate
return m_isPluginRunning;
}
int systemUiVisibility()
{
return m_systemUiVisibility;
}
void setContextMenuVisible(boolean contextMenuVisible)
{
m_contextMenuVisible = contextMenuVisible;
@ -199,47 +143,6 @@ public class QtActivityDelegate
return m_contextMenuVisible;
}
private final DisplayManager.DisplayListener m_displayListener = new DisplayManager.DisplayListener()
{
@Override
public void onDisplayAdded(int displayId) {
QtNative.handleScreenAdded(displayId);
}
private boolean isSimilarRotation(int r1, int r2)
{
return (r1 == r2)
|| (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180)
|| (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0)
|| (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270)
|| (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90);
}
@Override
public void onDisplayChanged(int displayId)
{
Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
? m_activity.getWindowManager().getDefaultDisplay()
: m_activity.getDisplay();
m_currentRotation = display.getRotation();
m_layout.setActivityDisplayRotation(m_currentRotation);
// Process orientation change only if it comes after the size
// change, or if the screen is rotated by 180 degrees.
// Otherwise it will be processed in QtLayout.
if (isSimilarRotation(m_currentRotation, m_layout.displayRotation()))
QtNative.handleOrientationChanged(m_currentRotation, m_nativeOrientation);
float refreshRate = display.getRefreshRate();
QtNative.handleRefreshRateChanged(refreshRate);
QtNative.handleScreenChanged(displayId);
}
@Override
public void onDisplayRemoved(int displayId) {
QtNative.handleScreenRemoved(displayId);
}
};
public boolean updateActivityAfterRestart(Activity activity) {
try {
// set new activity
@ -327,23 +230,16 @@ public class QtActivityDelegate
ViewGroup.LayoutParams.MATCH_PARENT));
int rotation = m_activity.getWindowManager().getDefaultDisplay().getRotation();
boolean rot90 = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
boolean currentlyLandscape = (orientation == Configuration.ORIENTATION_LANDSCAPE);
if ((currentlyLandscape && !rot90) || (!currentlyLandscape && rot90))
m_nativeOrientation = Configuration.ORIENTATION_LANDSCAPE;
else
m_nativeOrientation = Configuration.ORIENTATION_PORTRAIT;
m_layout.setNativeOrientation(m_nativeOrientation);
QtNative.handleOrientationChanged(rotation, m_nativeOrientation);
m_currentRotation = rotation;
int nativeOrientation = QtDisplayManager.getNativeOrientation(m_activity, rotation);
m_layout.setNativeOrientation(nativeOrientation);
QtDisplayManager.handleOrientationChanged(rotation, nativeOrientation);
handleUiModeChange(m_activity.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK);
float refreshRate = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
? m_activity.getWindowManager().getDefaultDisplay().getRefreshRate()
: m_activity.getDisplay().getRefreshRate();
QtNative.handleRefreshRateChanged(refreshRate);
QtDisplayManager.handleRefreshRateChanged(refreshRate);
m_layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
@ -467,11 +363,11 @@ public class QtActivityDelegate
switch (uiMode) {
case Configuration.UI_MODE_NIGHT_NO:
ExtractStyle.runIfNeeded(m_activity, false);
QtNative.handleUiDarkModeChanged(0);
QtDisplayManager.handleUiDarkModeChanged(0);
break;
case Configuration.UI_MODE_NIGHT_YES:
ExtractStyle.runIfNeeded(m_activity, true);
QtNative.handleUiDarkModeChanged(1);
QtDisplayManager.handleUiDarkModeChanged(1);
break;
}
}

View File

@ -0,0 +1,299 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Size;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.WindowMetrics;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class QtDisplayManager {
// screen methods
public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
int availableLeftPixels, int availableTopPixels,
int availableWidthPixels, int availableHeightPixels,
double XDpi, double YDpi, double scaledDensity,
double density, float refreshRate);
public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
public static native void handleRefreshRateChanged(float refreshRate);
public static native void handleUiDarkModeChanged(int newUiMode);
public static native void handleScreenAdded(int displayId);
public static native void handleScreenChanged(int displayId);
public static native void handleScreenRemoved(int displayId);
// screen methods
private static int m_widthBeforeStart = 0;
private static int m_heightBeforeStart = 0;
// Keep in sync with QtAndroid::SystemUiVisibility in androidjnimain.h
public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0;
public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1;
public static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2;
private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
// FIXME: some methods here make more sense as non-static, fix that
QtDisplayManager() {}
// TODO: unregister the listener upon activity destruction as well
public void registerDisplayListener(Activity activity, QtLayout layout)
{
DisplayManager.DisplayListener displayListener = new DisplayManager.DisplayListener()
{
@Override
public void onDisplayAdded(int displayId) {
QtDisplayManager.handleScreenAdded(displayId);
}
private boolean isSimilarRotation(int r1, int r2)
{
return (r1 == r2)
|| (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180)
|| (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0)
|| (r1 == Surface.ROTATION_90 && r2 == Surface.ROTATION_270)
|| (r1 == Surface.ROTATION_270 && r2 == Surface.ROTATION_90);
}
@Override
public void onDisplayChanged(int displayId)
{
Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
? activity.getWindowManager().getDefaultDisplay()
: activity.getDisplay();
int rotation = display.getRotation();
layout.setActivityDisplayRotation(rotation);
// Process orientation change only if it comes after the size
// change, or if the screen is rotated by 180 degrees.
// Otherwise it will be processed in QtLayout.
if (isSimilarRotation(rotation, layout.displayRotation())) {
QtDisplayManager.handleOrientationChanged(rotation,
getNativeOrientation(activity, rotation));
}
float refreshRate = display.getRefreshRate();
QtDisplayManager.handleRefreshRateChanged(refreshRate);
QtDisplayManager.handleScreenChanged(displayId);
}
@Override
public void onDisplayRemoved(int displayId) {
QtDisplayManager.handleScreenRemoved(displayId);
}
};
DisplayManager displayManager = (DisplayManager) activity.getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(displayListener, null);
}
public static int getNativeOrientation(Activity activity, int rotation)
{
int nativeOrientation;
int orientation = activity.getResources().getConfiguration().orientation;
boolean rot90 = (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270);
boolean isLandscape = (orientation == Configuration.ORIENTATION_LANDSCAPE);
if ((isLandscape && !rot90) || (!isLandscape && rot90))
nativeOrientation = Configuration.ORIENTATION_LANDSCAPE;
else
nativeOrientation = Configuration.ORIENTATION_PORTRAIT;
return nativeOrientation;
}
public void setSystemUiVisibility(Activity activity, int systemUiVisibility)
{
if (m_systemUiVisibility == systemUiVisibility)
return;
m_systemUiVisibility = systemUiVisibility;
int systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_VISIBLE;
switch (m_systemUiVisibility) {
case SYSTEM_UI_VISIBILITY_NORMAL:
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setDisplayCutoutLayout(activity,
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER);
break;
case SYSTEM_UI_VISIBILITY_FULLSCREEN:
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
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;
setDisplayCutoutLayout(activity,
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT);
break;
case SYSTEM_UI_VISIBILITY_TRANSLUCENT:
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setDisplayCutoutLayout(activity,
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS);
break;
}
}
public int systemUiVisibility()
{
return m_systemUiVisibility;
}
private void setDisplayCutoutLayout(Activity activity, int cutoutLayout)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
activity.getWindow().getAttributes().layoutInDisplayCutoutMode = cutoutLayout;
}
public void updateFullScreen(Activity activity)
{
if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) {
m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL;
setSystemUiVisibility(activity, SYSTEM_UI_VISIBILITY_FULLSCREEN);
}
}
public static Display getDisplay(Context context, int displayId)
{
DisplayManager displayManager =
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (displayManager != null) {
return displayManager.getDisplay(displayId);
}
return null;
}
public static List<Display> getAvailableDisplays(Context context)
{
DisplayManager displayManager =
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (displayManager != null) {
Display[] displays = displayManager.getDisplays();
return Arrays.asList(displays);
}
return new ArrayList<>();
}
public static Size getDisplaySize(Context displayContext, Display display)
{
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
return new Size(realMetrics.widthPixels, realMetrics.heightPixels);
}
Context windowsContext = displayContext.createWindowContext(
WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowManager windowManager =
(WindowManager) windowsContext.getSystemService(Context.WINDOW_SERVICE);
WindowMetrics windowsMetrics = windowManager.getCurrentWindowMetrics();
Rect bounds = windowsMetrics.getBounds();
return new Size(bounds.width(), bounds.height());
}
public static void setApplicationDisplayMetrics(Activity activity, int width, int height)
{
if (activity == null)
return;
final WindowInsets rootInsets = activity.getWindow().getDecorView().getRootWindowInsets();
final WindowManager windowManager = activity.getWindowManager();
Display display;
int insetLeft;
int insetTop;
int maxWidth;
int maxHeight;
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
display = windowManager.getDefaultDisplay();
final DisplayMetrics maxMetrics = new DisplayMetrics();
display.getRealMetrics(maxMetrics);
maxWidth = maxMetrics.widthPixels;
maxHeight = maxMetrics.heightPixels;
insetLeft = rootInsets.getStableInsetLeft();
insetTop = rootInsets.getStableInsetTop();
} else {
display = activity.getDisplay();
final WindowMetrics maxMetrics = windowManager.getMaximumWindowMetrics();
maxWidth = maxMetrics.getBounds().width();
maxHeight = maxMetrics.getBounds().height();
insetLeft = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).left;
insetTop = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).top;
}
final DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
double xdpi = displayMetrics.xdpi;
double ydpi = displayMetrics.ydpi;
/* Fix buggy dpi report */
if (xdpi < android.util.DisplayMetrics.DENSITY_LOW)
xdpi = android.util.DisplayMetrics.DENSITY_LOW;
if (ydpi < android.util.DisplayMetrics.DENSITY_LOW)
ydpi = android.util.DisplayMetrics.DENSITY_LOW;
double density = displayMetrics.density;
double scaledDensity = displayMetrics.scaledDensity;
float refreshRate = 60.0f;
if (display != null) {
refreshRate = display.getRefreshRate();
}
m_widthBeforeStart = width;
m_heightBeforeStart = height;
setDisplayMetrics(maxWidth, maxHeight, insetLeft, insetTop,
m_widthBeforeStart, m_heightBeforeStart, xdpi, ydpi,
scaledDensity, density, refreshRate);
}
public static void setApplicationDisplayMetrics(Activity activity)
{
setApplicationDisplayMetrics(activity, m_widthBeforeStart, m_heightBeforeStart);
}
public static int getDisplayRotation(Activity activity) {
Display display;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
final WindowManager windowManager = activity.getWindowManager();
display = windowManager.getDefaultDisplay();
} else {
display = activity.getDisplay();
}
int newRotation = 0;
if (display != null) {
newRotation = display.getRotation();
}
return newRotation;
}
}

View File

@ -67,58 +67,16 @@ public class QtLayout extends ViewGroup
if (activity == null)
return;
final WindowManager windowManager = activity.getWindowManager();
Display display;
QtDisplayManager.setApplicationDisplayMetrics(activity, w, h);
final WindowInsets rootInsets = getRootWindowInsets();
int insetLeft = 0;
int insetTop = 0;
int maxWidth = 0;
int maxHeight = 0;
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
display = windowManager.getDefaultDisplay();
final DisplayMetrics maxMetrics = new DisplayMetrics();
display.getRealMetrics(maxMetrics);
maxWidth = maxMetrics.widthPixels;
maxHeight = maxMetrics.heightPixels;
insetLeft = rootInsets.getStableInsetLeft();
insetTop = rootInsets.getStableInsetTop();
} else {
display = activity.getDisplay();
final WindowMetrics maxMetrics = windowManager.getMaximumWindowMetrics();
maxWidth = maxMetrics.getBounds().width();
maxHeight = maxMetrics.getBounds().height();
insetLeft = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).left;
insetTop = rootInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()).top;
}
final DisplayMetrics displayMetrics = activity.getResources().getDisplayMetrics();
double xdpi = displayMetrics.xdpi;
double ydpi = displayMetrics.ydpi;
double density = displayMetrics.density;
double scaledDensity = displayMetrics.scaledDensity;
float refreshRate = display.getRefreshRate();
QtNative.setApplicationDisplayMetrics(maxWidth, maxHeight, insetLeft,
insetTop, w, h,
xdpi,ydpi,scaledDensity, density,
refreshRate);
int newRotation = display.getRotation();
int newRotation = QtDisplayManager.getDisplayRotation(activity);
if (m_ownDisplayRotation != m_activityDisplayRotation
&& newRotation == m_activityDisplayRotation) {
// If the saved rotation value does not match the one from the
// activity, it means that we got orientation change before size
// change, and the value was cached. So we need to notify about
// orientation change now.
QtNative.handleOrientationChanged(newRotation, m_nativeOrientation);
QtDisplayManager.handleOrientationChanged(newRotation, m_nativeOrientation);
}
m_ownDisplayRotation = newRotation;

View File

@ -64,17 +64,7 @@ public class QtNative
public static final String QtTAG = "Qt JAVA"; // string used for Log.x
private static ArrayList<Runnable> m_lostActions = new ArrayList<Runnable>(); // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.)
private static boolean m_started = false;
private static int m_displayMetricsScreenWidthPixels = 0;
private static int m_displayMetricsScreenHeightPixels = 0;
private static int m_displayMetricsAvailableLeftPixels = 0;
private static int m_displayMetricsAvailableTopPixels = 0;
private static int m_displayMetricsAvailableWidthPixels = 0;
private static int m_displayMetricsAvailableHeightPixels = 0;
private static float m_displayMetricsRefreshRate = 60;
private static double m_displayMetricsXDpi = .0;
private static double m_displayMetricsYDpi = .0;
private static double m_displayMetricsScaledDensity = 1.0;
private static double m_displayMetricsDensity = 1.0;
private static final int m_moveThreshold = 0;
private static Method m_checkSelfPermissionMethod = null;
@ -291,46 +281,6 @@ public class QtNative
});
}
public static Display getDisplay(int displayId)
{
Context context = getContext();
DisplayManager displayManager =
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (displayManager != null) {
return displayManager.getDisplay(displayId);
}
return null;
}
public static List<Display> getAvailableDisplays()
{
Context context = getContext();
DisplayManager displayManager =
(DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
if (displayManager != null) {
Display[] displays = displayManager.getDisplays();
return Arrays.asList(displays);
}
return new ArrayList<Display>();
}
public static Size getDisplaySize(Context displayContext, Display display)
{
if (Build.VERSION.SDK_INT < 31) {
DisplayMetrics realMetrics = new DisplayMetrics();
display.getRealMetrics(realMetrics);
return new Size(realMetrics.widthPixels, realMetrics.heightPixels);
}
Context windowsContext = displayContext.createWindowContext(
WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowManager displayMgr =
(WindowManager) windowsContext.getSystemService(Context.WINDOW_SERVICE);
WindowMetrics windowsMetrics = displayMgr.getCurrentWindowMetrics();
Rect bounds = windowsMetrics.getBounds();
return new Size(bounds.width(), bounds.height());
}
public static boolean startApplication(ArrayList<String> params, String mainLib)
{
final boolean[] res = new boolean[1];
@ -341,13 +291,7 @@ public class QtNative
@Override
public void run() {
res[0] = startQtAndroidPlugin(qtParams);
setDisplayMetrics(
m_displayMetricsScreenWidthPixels, m_displayMetricsScreenHeightPixels,
m_displayMetricsAvailableLeftPixels, m_displayMetricsAvailableTopPixels,
m_displayMetricsAvailableWidthPixels,
m_displayMetricsAvailableHeightPixels, m_displayMetricsXDpi,
m_displayMetricsYDpi, m_displayMetricsScaledDensity,
m_displayMetricsDensity, m_displayMetricsRefreshRate);
QtDisplayManager.setApplicationDisplayMetrics(m_activity);
}
});
m_qtThread.post(new Runnable() {
@ -362,40 +306,6 @@ public class QtNative
return res[0];
}
public static void setApplicationDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
int availableLeftPixels, int availableTopPixels,
int availableWidthPixels,
int availableHeightPixels, double XDpi,
double YDpi, double scaledDensity,
double density, float refreshRate)
{
/* Fix buggy dpi report */
if (XDpi < android.util.DisplayMetrics.DENSITY_LOW)
XDpi = android.util.DisplayMetrics.DENSITY_LOW;
if (YDpi < android.util.DisplayMetrics.DENSITY_LOW)
YDpi = android.util.DisplayMetrics.DENSITY_LOW;
synchronized (m_mainActivityMutex) {
if (m_started) {
setDisplayMetrics(screenWidthPixels, screenHeightPixels, availableLeftPixels,
availableTopPixels, availableWidthPixels, availableHeightPixels,
XDpi, YDpi, scaledDensity, density, refreshRate);
} else {
m_displayMetricsScreenWidthPixels = screenWidthPixels;
m_displayMetricsScreenHeightPixels = screenHeightPixels;
m_displayMetricsAvailableLeftPixels = availableLeftPixels;
m_displayMetricsAvailableTopPixels = availableTopPixels;
m_displayMetricsAvailableWidthPixels = availableWidthPixels;
m_displayMetricsAvailableHeightPixels = availableHeightPixels;
m_displayMetricsXDpi = XDpi;
m_displayMetricsYDpi = YDpi;
m_displayMetricsScaledDensity = scaledDensity;
m_displayMetricsDensity = density;
m_displayMetricsRefreshRate = refreshRate;
}
}
}
// application methods
public static native boolean startQtAndroidPlugin(String params);
public static native void startQtApplication();
@ -704,20 +614,6 @@ public class QtNative
return res.toArray(new String[res.size()]);
}
// screen methods
public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels,
int availableLeftPixels, int availableTopPixels,
int availableWidthPixels, int availableHeightPixels,
double XDpi, double YDpi, double scaledDensity,
double density, float refreshRate);
public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
public static native void handleRefreshRateChanged(float refreshRate);
public static native void handleScreenAdded(int displayId);
public static native void handleScreenChanged(int displayId);
public static native void handleScreenRemoved(int displayId);
// screen methods
public static native void handleUiDarkModeChanged(int newUiMode);
// surface methods
public static native void setSurface(int id, Object surface, int w, int h);
// surface methods

View File

@ -159,6 +159,7 @@ namespace QtAndroid
return m_applicationClass;
}
// TODO move calls from here to where they logically belong
void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{
QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility));
@ -632,6 +633,7 @@ static void setDisplayMetrics(JNIEnv * /*env*/, jclass /*clazz*/, jint screenWid
m_androidPlatformIntegration->setRefreshRate(refreshRate);
}
}
Q_DECLARE_JNI_NATIVE_METHOD(setDisplayMetrics)
static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
{
@ -733,36 +735,42 @@ static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint new
}
}
}
Q_DECLARE_JNI_NATIVE_METHOD(handleOrientationChanged)
static void handleRefreshRateChanged(JNIEnv */*env*/, jclass /*cls*/, jfloat refreshRate)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->setRefreshRate(refreshRate);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleRefreshRateChanged)
static void handleScreenAdded(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenAdded(displayId);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleScreenAdded)
static void handleScreenChanged(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenChanged(displayId);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleScreenChanged)
static void handleScreenRemoved(JNIEnv */*env*/, jclass /*cls*/, jint displayId)
{
if (m_androidPlatformIntegration)
m_androidPlatformIntegration->handleScreenRemoved(displayId);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleScreenRemoved)
static void handleUiDarkModeChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newUiMode)
{
QAndroidPlatformIntegration::setColorScheme(
(newUiMode == 1 ) ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light);
}
Q_DECLARE_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
static void onActivityResult(JNIEnv */*env*/, jclass /*cls*/,
jint requestCode,
@ -789,19 +797,12 @@ static JNINativeMethod methods[] = {
{ "quitQtCoreApplication", "()V", (void *)quitQtCoreApplication },
{ "terminateQt", "()V", (void *)terminateQt },
{ "waitForServiceSetup", "()V", (void *)waitForServiceSetup },
{ "setDisplayMetrics", "(IIIIIIDDDDF)V", (void *)setDisplayMetrics },
{ "setSurface", "(ILjava/lang/Object;II)V", (void *)setSurface },
{ "updateWindow", "()V", (void *)updateWindow },
{ "updateApplicationState", "(I)V", (void *)updateApplicationState },
{ "handleUiDarkModeChanged", "(I)V", (void *)handleUiDarkModeChanged },
{ "handleOrientationChanged", "(II)V", (void *)handleOrientationChanged },
{ "onActivityResult", "(IILandroid/content/Intent;)V", (void *)onActivityResult },
{ "onNewIntent", "(Landroid/content/Intent;)V", (void *)onNewIntent },
{ "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind },
{ "handleRefreshRateChanged", "(F)V", (void *)handleRefreshRateChanged },
{ "handleScreenAdded", "(I)V", (void *)handleScreenAdded },
{ "handleScreenChanged", "(I)V", (void *)handleScreenChanged },
{ "handleScreenRemoved", "(I)V", (void *)handleScreenRemoved }
{ "onBind", "(Landroid/content/Intent;)Landroid/os/IBinder;", (void *)onBind }
};
#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
@ -839,6 +840,8 @@ if (!VAR) { \
return false; \
}
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
static bool registerNatives(QJniEnvironment &env)
{
jclass clazz;
@ -851,6 +854,23 @@ static bool registerNatives(QJniEnvironment &env)
return false;
}
bool success = env.registerNativeMethods(
QtJniTypes::Traits<QtJniTypes::QtDisplayManager>::className(),
{
Q_JNI_NATIVE_METHOD(setDisplayMetrics),
Q_JNI_NATIVE_METHOD(handleOrientationChanged),
Q_JNI_NATIVE_METHOD(handleRefreshRateChanged),
Q_JNI_NATIVE_METHOD(handleScreenAdded),
Q_JNI_NATIVE_METHOD(handleScreenChanged),
Q_JNI_NATIVE_METHOD(handleScreenRemoved),
Q_JNI_NATIVE_METHOD(handleUiDarkModeChanged)
});
if (!success) {
qCritical() << "QtDisplayManager: registerNativeMethods() failed";
return JNI_FALSE;
}
GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIIII)V");
GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V");
GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V");

View File

@ -57,6 +57,7 @@ bool QAndroidPlatformIntegration::m_showPasswordEnabled = false;
static bool m_running = false;
Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
Q_DECLARE_JNI_CLASS(Display, "android/view/Display")
Q_DECLARE_JNI_CLASS(List, "java/util/List")
@ -65,10 +66,8 @@ namespace {
QAndroidPlatformScreen* createScreenForDisplayId(int displayId)
{
const QJniObject display = QJniObject::callStaticObjectMethod<QtJniTypes::Display>(
QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getDisplay",
displayId);
const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Display>(
"getDisplay", QtAndroidPrivate::context(), displayId);
if (!display.isValid())
return nullptr;
return new QAndroidPlatformScreen(display);
@ -187,12 +186,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API)))
qFatal("Could not bind GL_ES API");
m_primaryDisplayId = QJniObject::getStaticField<jint>(
QtJniTypes::Traits<QtJniTypes::Display>::className(), "DEFAULT_DISPLAY");
const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod<QtJniTypes::List>(
QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getAvailableDisplays");
using namespace QtJniTypes;
m_primaryDisplayId = Display::getStaticField<jint>("DEFAULT_DISPLAY");
const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod<List>(
"getAvailableDisplays", QtAndroidPrivate::context());
const int numberOfAvailableDisplays = nativeDisplaysList.callMethod<jint>("size");
for (int i = 0; i < numberOfAvailableDisplays; ++i) {

View File

@ -57,6 +57,7 @@ Q_DECLARE_JNI_CLASS(DisplayMetrics, "android/util/DisplayMetrics")
Q_DECLARE_JNI_CLASS(Resources, "android/content/res/Resources")
Q_DECLARE_JNI_CLASS(Size, "android/util/Size")
Q_DECLARE_JNI_CLASS(QtNative, "org/qtproject/qt/android/QtNative")
Q_DECLARE_JNI_CLASS(QtDisplayManager, "org/qtproject/qt/android/QtDisplayManager")
Q_DECLARE_JNI_CLASS(DisplayMode, "android/view/Display$Mode")
@ -91,11 +92,9 @@ QAndroidPlatformScreen::QAndroidPlatformScreen(const QJniObject &displayObject)
const auto displayContext = context.callMethod<QtJniTypes::Context>("createDisplayContext",
displayObject.object<QtJniTypes::Display>());
const auto sizeObj = QJniObject::callStaticMethod<QtJniTypes::Size>(
QtJniTypes::Traits<QtJniTypes::QtNative>::className(),
"getDisplaySize",
displayContext.object<QtJniTypes::Context>(),
displayObject.object<QtJniTypes::Display>());
const auto sizeObj = QtJniTypes::QtDisplayManager::callStaticMethod<QtJniTypes::Size>(
"getDisplaySize", displayContext,
displayObject.object<QtJniTypes::Display>());
m_size = QSize(sizeObj.callMethod<int>("getWidth"), sizeObj.callMethod<int>("getHeight"));
const auto resources = displayContext.callMethod<QtJniTypes::Resources>("getResources");