diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index b45b17c4832..37f5e346ab9 100644 --- a/src/android/jar/CMakeLists.txt +++ b/src/android/jar/CMakeLists.txt @@ -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 diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java index e067cf5de34..d68a838018d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java @@ -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 diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java index ad4931a1fcc..019b9244f14 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -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; } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java new file mode 100644 index 00000000000..16f90aa5457 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java @@ -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 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; + } +} diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java index d7207dc2c5d..2f2a3622c51 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java @@ -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; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/QtNative.java index 5f0bd1cd59a..f37228c562f 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -64,17 +64,7 @@ public class QtNative public static final String QtTAG = "Qt JAVA"; // string used for Log.x private static ArrayList m_lostActions = new ArrayList(); // 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 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(); - } - - 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 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 diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index bed3777d45d..f7de6fb3699 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -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(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::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"); diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 84ab311a11e..abe1a14c469 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -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::Traits::className(), - "getDisplay", - displayId); + const QJniObject display = QtJniTypes::QtDisplayManager::callStaticMethod( + "getDisplay", QtAndroidPrivate::context(), displayId); if (!display.isValid()) return nullptr; return new QAndroidPlatformScreen(display); @@ -187,12 +186,10 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ if (Q_UNLIKELY(!eglBindAPI(EGL_OPENGL_ES_API))) qFatal("Could not bind GL_ES API"); - m_primaryDisplayId = QJniObject::getStaticField( - QtJniTypes::Traits::className(), "DEFAULT_DISPLAY"); - - const QJniObject nativeDisplaysList = QJniObject::callStaticObjectMethod( - QtJniTypes::Traits::className(), - "getAvailableDisplays"); + using namespace QtJniTypes; + m_primaryDisplayId = Display::getStaticField("DEFAULT_DISPLAY"); + const QJniObject nativeDisplaysList = QtDisplayManager::callStaticMethod( + "getAvailableDisplays", QtAndroidPrivate::context()); const int numberOfAvailableDisplays = nativeDisplaysList.callMethod("size"); for (int i = 0; i < numberOfAvailableDisplays; ++i) { diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index b9e83907ba9..e31b6180089 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -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("createDisplayContext", displayObject.object()); - const auto sizeObj = QJniObject::callStaticMethod( - QtJniTypes::Traits::className(), - "getDisplaySize", - displayContext.object(), - displayObject.object()); + const auto sizeObj = QtJniTypes::QtDisplayManager::callStaticMethod( + "getDisplaySize", displayContext, + displayObject.object()); m_size = QSize(sizeObj.callMethod("getWidth"), sizeObj.callMethod("getHeight")); const auto resources = displayContext.callMethod("getResources");