diff options
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt/android')
8 files changed, 202 insertions, 271 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java b/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java index b6d054d600..87257adb3d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java +++ b/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java @@ -88,8 +88,7 @@ public class CursorHandle implements ViewTreeObserver.OnPreDrawListener m_id = id; m_attr = attr; m_layout = layout; - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); + DisplayMetrics metrics = activity.getResources().getDisplayMetrics(); m_yShift = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, metrics); tolerance = Math.min(1, (int)(m_yShift / 2f)); m_lastX = m_lastY = -1 - tolerance; diff --git a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java index 6792247eeb..672a2e28d3 100644 --- a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java @@ -34,6 +34,7 @@ import android.graphics.drawable.ScaleDrawable; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.VectorDrawable; import android.os.Build; +import android.os.Bundle; import android.util.AttributeSet; import android.util.Log; import android.util.TypedValue; @@ -135,6 +136,42 @@ public class ExtractStyle { Context m_context; private final HashMap<String, DrawableCache> m_drawableCache = new HashMap<>(); + private static final String EXTRACT_STYLE_KEY = "extract.android.style"; + private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option"; + + private static boolean m_missingNormalStyle = false; + private static boolean m_missingDarkStyle = false; + private static String m_stylePath = null; + private static boolean m_extractMinimal = false; + + public static void setup(Bundle loaderParams) { + if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) { + m_stylePath = loaderParams.getString(EXTRACT_STYLE_KEY); + + boolean darkModeFileMissing = !(new File(m_stylePath + "darkUiMode/style.json").exists()); + m_missingDarkStyle = Build.VERSION.SDK_INT > 28 && darkModeFileMissing; + + m_missingNormalStyle = !(new File(m_stylePath + "style.json").exists()); + + m_extractMinimal = loaderParams.containsKey(EXTRACT_STYLE_MINIMAL_KEY) && + loaderParams.getBoolean(EXTRACT_STYLE_MINIMAL_KEY); + } + } + + public static void runIfNeeded(Context context, boolean extractDarkMode) { + if (m_stylePath == null) + return; + if (extractDarkMode) { + if (m_missingDarkStyle) { + new ExtractStyle(context, m_stylePath + "darkUiMode/", m_extractMinimal); + m_missingDarkStyle = false; + } + } else if (m_missingNormalStyle) { + new ExtractStyle(context, m_stylePath, m_extractMinimal); + m_missingNormalStyle = false; + } + } + public ExtractStyle(Context context, String extractPath, boolean minimal) { m_minimal = minimal; m_extractPath = extractPath + "/"; 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 c36459ad3a..87ee760f4b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -14,6 +14,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.AssetManager; import android.content.res.Configuration; +import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.Rect; @@ -43,6 +44,8 @@ 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; @@ -84,8 +87,6 @@ public class QtActivityDelegate private static final String ENVIRONMENT_VARIABLES_KEY = "environment.variables"; private static final String APPLICATION_PARAMETERS_KEY = "application.parameters"; private static final String STATIC_INIT_CLASSES_KEY = "static.init.classes"; - private static final String EXTRACT_STYLE_KEY = "extract.android.style"; - private static final String EXTRACT_STYLE_MINIMAL_KEY = "extract.android.style.option"; public static final int SYSTEM_UI_VISIBILITY_NORMAL = 0; public static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1; @@ -707,11 +708,8 @@ public class QtActivityDelegate libraries.remove(libraries.size() - 1); } - if (loaderParams.containsKey(EXTRACT_STYLE_KEY)) { - String path = loaderParams.getString(EXTRACT_STYLE_KEY); - new ExtractStyle(m_activity, path, loaderParams.containsKey(EXTRACT_STYLE_MINIMAL_KEY) && - loaderParams.getBoolean(EXTRACT_STYLE_MINIMAL_KEY)); - } + ExtractStyle.setup(loaderParams); + ExtractStyle.runIfNeeded(m_activity, isUiModeDark(m_activity.getResources().getConfiguration())); QtNative.setEnvironmentVariables(loaderParams.getString(ENVIRONMENT_VARIABLES_KEY)); QtNative.setEnvironmentVariable("QT_ANDROID_FONTS_MONOSPACE", @@ -849,6 +847,8 @@ public class QtActivityDelegate QtNative.handleOrientationChanged(rotation, m_nativeOrientation); m_currentRotation = rotation; + 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(); @@ -941,6 +941,14 @@ public class QtActivityDelegate m_accessibilityDelegate.notifyValueChanged(viewId, value); } + public void notifyScrolledEvent(int viewId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyScrolledEvent(viewId); + } + + public void notifyQtAndroidPluginRunning(boolean running) { m_isPluginRunning = running; @@ -961,6 +969,38 @@ public class QtActivityDelegate updateFullScreen(); } + boolean isUiModeDark(Configuration config) + { + return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; + } + + private void handleUiModeChange(int uiMode) + { + // QTBUG-108365 + if (Build.VERSION.SDK_INT >= 30) { + // Since 29 version we are using Theme_DeviceDefault_DayNight + Window window = m_activity.getWindow(); + WindowInsetsController controller = window.getInsetsController(); + if (controller != null) { + // set APPEARANCE_LIGHT_STATUS_BARS if needed + int appearanceLight = Color.luminance(window.getStatusBarColor()) > 0.5 ? + WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS : 0; + controller.setSystemBarsAppearance(appearanceLight, + WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); + } + } + switch (uiMode) { + case Configuration.UI_MODE_NIGHT_NO: + ExtractStyle.runIfNeeded(m_activity, false); + QtNative.handleUiDarkModeChanged(0); + break; + case Configuration.UI_MODE_NIGHT_YES: + ExtractStyle.runIfNeeded(m_activity, true); + QtNative.handleUiDarkModeChanged(1); + break; + } + } + public void onConfigurationChanged(Configuration configuration) { try { @@ -968,6 +1008,7 @@ public class QtActivityDelegate } catch (Exception e) { e.printStackTrace(); } + handleUiModeChange(configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK); } public void onDestroy() diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java index c7401ee342..abcc76da17 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java @@ -5,6 +5,8 @@ package org.qtproject.qt.android; import android.content.Context; +import android.os.Build; +import android.view.WindowMetrics; import android.view.inputmethod.BaseInputConnection; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.ExtractedText; @@ -58,9 +60,17 @@ class HideKeyboardRunnable implements Runnable { Activity activity = QtNative.activity(); Rect r = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); - DisplayMetrics metrics = new DisplayMetrics(); - activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); - final int kbHeight = metrics.heightPixels - r.bottom; + + int screenHeight = 0; + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + DisplayMetrics metrics = new DisplayMetrics(); + activity.getWindowManager().getDefaultDisplay().getMetrics(metrics); + screenHeight = metrics.heightPixels; + } else { + final WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics(); + screenHeight = maximumWindowMetrics.getBounds().height(); + } + final int kbHeight = screenHeight - r.bottom; if (kbHeight < 100) QtNative.activityDelegate().setKeyboardVisibility(false, m_hideTimeStamp); } @@ -242,7 +252,11 @@ public class QtInputConnection extends BaseInputConnection KeyEvent.META_SHIFT_ON); return super.sendKeyEvent(fakeEvent); + case android.view.inputmethod.EditorInfo.IME_FLAG_NO_ENTER_ACTION: + break; + default: + QtNative.activityDelegate().hideSoftwareKeyboard(); break; } } 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 a0c1f4b2af..d7207dc2c5 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java @@ -6,7 +6,9 @@ package org.qtproject.qt.android; import android.app.Activity; import android.content.Context; +import android.graphics.Rect; import android.os.Build; +import android.util.Log; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.Display; @@ -14,6 +16,10 @@ import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; import android.view.WindowManager; +import android.graphics.Insets; +import android.view.WindowMetrics; +import android.content.res.Configuration; +import android.content.res.Resources; public class QtLayout extends ViewGroup { @@ -57,53 +63,53 @@ public class QtLayout extends ViewGroup @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) { - WindowInsets insets = getRootWindowInsets(); - - DisplayMetrics realMetrics = new DisplayMetrics(); - Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) - ? ((Activity)getContext()).getWindowManager().getDefaultDisplay() - : ((Activity)getContext()).getDisplay(); - display.getRealMetrics(realMetrics); - - if ((realMetrics.widthPixels > realMetrics.heightPixels) != (w > h)) { - // This is an intermediate state during display rotation. - // The new size is still reported for old orientation, while - // realMetrics contain sizes for new orientation. Setting - // such parameters will produce inconsistent results, so - // we just skip them. - // We will have another onSizeChanged() with normal values - // a bit later. + Activity activity = (Activity)getContext(); + if (activity == null) return; + + final WindowManager windowManager = activity.getWindowManager(); + Display display; + + 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; } - boolean isFullScreenView = h == realMetrics.heightPixels; - // The code uses insets for fullscreen mode only. However in practice - // the insets can be reported incorrectly. Both on Android 6 and Android 11 - // a non-zero bottom inset is reported even when the - // WindowManager.LayoutParams.FLAG_FULLSCREEN flag is set. - // To avoid that, add an extra check for the fullscreen mode. - // The insets-related logic is not removed for the case when - // isFullScreenView == true, but hasFlagFullscreen == false, although - // I can't get such case in my tests. - final int windowFlags = ((Activity)getContext()).getWindow().getAttributes().flags; - final boolean hasFlagFullscreen = - (windowFlags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; - int insetLeft = - (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetLeft() : 0; - int insetTop = - (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetTop() : 0; - int insetRight = - (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetRight() : 0; - int insetBottom = - (isFullScreenView && !hasFlagFullscreen) ? insets.getSystemWindowInsetBottom() : 0; - - int usableAreaWidth = w - insetLeft - insetRight; - int usableAreaHeight = h - insetTop - insetBottom; - - QtNative.setApplicationDisplayMetrics( - realMetrics.widthPixels, realMetrics.heightPixels, insetLeft, insetTop, - usableAreaWidth, usableAreaHeight, realMetrics.xdpi, realMetrics.ydpi, - realMetrics.scaledDensity, realMetrics.density, display.getRefreshRate()); + 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(); if (m_ownDisplayRotation != m_activityDisplayRotation diff --git a/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java b/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java index 5680c068aa..58bcbf0627 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java @@ -73,7 +73,8 @@ public class QtMessageDialogHelper try { TypedValue typedValue = new TypedValue(); m_theme.resolveAttribute(android.R.attr.alertDialogIcon, typedValue, true); - return m_activity.getResources().getDrawable(typedValue.resourceId); + return m_activity.getResources().getDrawable(typedValue.resourceId, + m_activity.getTheme()); } catch (Exception e) { e.printStackTrace(); } @@ -83,7 +84,8 @@ public class QtMessageDialogHelper { case 1: // Information try { - return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_info); + return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_info, + m_activity.getTheme()); } catch (Exception e) { e.printStackTrace(); } @@ -97,14 +99,16 @@ public class QtMessageDialogHelper // break; case 3: // Critical try { - return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert); + return m_activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert, + m_activity.getTheme()); } catch (Exception e) { e.printStackTrace(); } break; case 4: // Question try { - return m_activity.getResources().getDrawable(android.R.drawable.ic_menu_help); + return m_activity.getResources().getDrawable(android.R.drawable.ic_menu_help, + m_activity.getTheme()); } catch (Exception e) { e.printStackTrace(); } 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 8140a46f11..b4116f3e5b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -10,7 +10,6 @@ import java.io.FileNotFoundException; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Semaphore; -import java.util.HashMap; import android.app.Activity; import android.app.Service; @@ -80,8 +79,6 @@ public class QtNative private static Boolean m_tabletEventSupported = null; private static boolean m_usePrimaryClip = false; public static QtThread m_qtThread = new QtThread(); - private static HashMap<String, Uri> m_cachedUris = new HashMap<String, Uri>(); - private static ArrayList<String> m_knownDirs = new ArrayList<String>(); private static final int KEYBOARD_HEIGHT_THRESHOLD = 100; private static final String INVALID_OR_NULL_URI_ERROR_MESSAGE = "Received invalid/null Uri"; @@ -214,209 +211,6 @@ public class QtNative } } - public static ParcelFileDescriptor openParcelFdForContentUrl(Context context, String contentUrl, - String openMode) - { - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, openMode); - - if (uri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return null; - } - - try { - final ContentResolver resolver = context.getContentResolver(); - return resolver.openFileDescriptor(uri, openMode); - } catch (FileNotFoundException | IllegalArgumentException | SecurityException e) { - Log.e(QtTAG, getCurrentMethodNameLog() + e.toString()); - } - - return null; - } - - public static FileDescriptor openFdObjectForContentUrl(Context context, String contentUrl, - String openMode) - { - final ParcelFileDescriptor pfd = openParcelFdForContentUrl(context, contentUrl, openMode); - if (pfd != null) - return pfd.getFileDescriptor(); - return null; - } - - public static int openFdForContentUrl(Context context, String contentUrl, String openMode) - { - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, openMode); - - int fileDescriptor = -1; - if (uri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return fileDescriptor; - } - - try { - final ContentResolver resolver = context.getContentResolver(); - fileDescriptor = resolver.openFileDescriptor(uri, openMode).detachFd(); - } catch (IllegalArgumentException | SecurityException | FileNotFoundException e) { - Log.e(QtTAG, getCurrentMethodNameLog() + e.toString()); - } - - return fileDescriptor; - } - - public static long getSize(Context context, String contentUrl) - { - long size = -1; - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, "r"); - - if (uri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return size; - } else if (!m_cachedUris.containsKey(contentUrl)) { - m_cachedUris.put(contentUrl, uri); - } - - try { - ContentResolver resolver = context.getContentResolver(); - Cursor cur = resolver.query(uri, new String[] { - DocumentsContract.Document.COLUMN_SIZE }, - null, null, null); - if (cur != null) { - if (cur.moveToFirst()) - size = cur.getLong(0); - cur.close(); - } - return size; - } catch (IllegalArgumentException | SecurityException | UnsupportedOperationException e) { - Log.e(QtTAG, getCurrentMethodNameLog() + e.toString()); - } - return size; - } - - public static boolean checkFileExists(Context context, String contentUrl) - { - boolean exists = false; - Uri uri = m_cachedUris.get(contentUrl); - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, "r"); - if (uri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return exists; - } else { - if (!m_cachedUris.containsKey(contentUrl)) - m_cachedUris.put(contentUrl, uri); - } - - try { - ContentResolver resolver = context.getContentResolver(); - Cursor cur = resolver.query(uri, null, null, null, null); - if (cur != null) { - exists = true; - cur.close(); - } - return exists; - } catch (IllegalArgumentException | SecurityException | UnsupportedOperationException e) { - Log.e(QtTAG, getCurrentMethodNameLog() + e.toString()); - } - return exists; - } - - public static boolean checkIfWritable(Context context, String contentUrl) - { - return getUriWithValidPermission(context, contentUrl, "w") != null; - } - - public static boolean checkIfDir(Context context, String contentUrl) - { - boolean isDir = false; - Uri uri = m_cachedUris.get(contentUrl); - if (m_knownDirs.contains(contentUrl)) - return true; - if (uri == null) - uri = getUriWithValidPermission(context, contentUrl, "r"); - - if (uri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return isDir; - } else { - if (!m_cachedUris.containsKey(contentUrl)) - m_cachedUris.put(contentUrl, uri); - } - - try { - final List<String> paths = uri.getPathSegments(); - // getTreeDocumentId will throw an exception if it is not a directory so check manually - if (!paths.get(0).equals("tree")) - return false; - ContentResolver resolver = context.getContentResolver(); - Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri, - DocumentsContract.getTreeDocumentId(uri)); - if (!docUri.toString().startsWith(uri.toString())) - return false; - Cursor cur = resolver.query(docUri, new String[] { - DocumentsContract.Document.COLUMN_MIME_TYPE }, - null, null, null); - if (cur != null) { - if (cur.moveToFirst()) { - final String dirStr = new String(DocumentsContract.Document.MIME_TYPE_DIR); - isDir = cur.getString(0).equals(dirStr); - if (isDir) - m_knownDirs.add(contentUrl); - } - cur.close(); - } - return isDir; - } catch (IllegalArgumentException | SecurityException | UnsupportedOperationException e) { - Log.e(QtTAG, getCurrentMethodNameLog() + e.toString()); - } - return false; - } - - public static String[] listContentsFromTreeUri(Context context, String contentUrl) - { - Uri treeUri = Uri.parse(contentUrl); - final ArrayList<String> results = new ArrayList<>(); - if (treeUri == null) { - Log.e(QtTAG, getCurrentMethodNameLog() + INVALID_OR_NULL_URI_ERROR_MESSAGE); - return results.toArray(new String[results.size()]); - } - final ContentResolver resolver = context.getContentResolver(); - final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, - DocumentsContract.getTreeDocumentId(treeUri)); - final Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(docUri, - DocumentsContract.getDocumentId(docUri)); - Cursor c; - final String dirStr = DocumentsContract.Document.MIME_TYPE_DIR; - try { - c = resolver.query(childrenUri, new String[] { - DocumentsContract.Document.COLUMN_DOCUMENT_ID, - DocumentsContract.Document.COLUMN_DISPLAY_NAME, - DocumentsContract.Document.COLUMN_MIME_TYPE }, - null, null, null); - while (c.moveToNext()) { - final String fileString = c.getString(1); - if (!m_cachedUris.containsKey(contentUrl + "/" + fileString)) { - m_cachedUris.put(contentUrl + "/" + fileString, - DocumentsContract.buildDocumentUriUsingTree(treeUri, - c.getString(0))); - } - results.add(fileString); - if (c.getString(2).equals(dirStr)) - m_knownDirs.add(contentUrl + "/" + fileString); - } - c.close(); - } catch (Exception e) { - Log.w(QtTAG, "Failed query: " + e); - return results.toArray(new String[results.size()]); - } - return results.toArray(new String[results.size()]); - } - // this method loads full path libs public static void loadQtLibraries(final ArrayList<String> libraries) { @@ -985,6 +779,18 @@ public class QtNative }); } + private static void notifyScrolledEvent(final int viewId) + { + runAction(new Runnable() { + @Override + public void run() { + if (m_activityDelegate != null) { + m_activityDelegate.notifyScrolledEvent(viewId); + } + } + }); + } + public static void notifyQtAndroidPluginRunning(final boolean running) { m_activityDelegate.notifyQtAndroidPluginRunning(running); @@ -1392,6 +1198,7 @@ public class QtNative public static native void handleOrientationChanged(int newRotation, int nativeOrientation); public static native void handleRefreshRateChanged(float refreshRate); // screen methods + public static native void handleUiDarkModeChanged(int newUiMode); // pointer methods public static native void mouseDown(int winId, int x, int y); diff --git a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java index 84cbc0b456..74d5ce5dde 100644 --- a/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/accessibility/QtAccessibilityDelegate.java @@ -7,6 +7,7 @@ package org.qtproject.qt.android.accessibility; import android.accessibilityservice.AccessibilityService; import android.app.Activity; import android.graphics.Rect; +import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.View; @@ -15,10 +16,12 @@ import android.view.ViewParent; import android.text.TextUtils; import android.view.accessibility.*; +import android.view.accessibility.AccessibilityNodeInfo.CollectionInfo; import android.view.MotionEvent; import android.view.View.OnHoverListener; import android.content.Context; +import android.system.Os; import java.util.LinkedList; import java.util.List; @@ -86,6 +89,8 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate @Override public void onAccessibilityStateChanged(boolean enabled) { + if (Os.getenv("QT_ANDROID_DISABLE_ACCESSIBILITY") != null) + return; if (enabled) { try { View view = m_view; @@ -157,6 +162,11 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate return true; } + public void notifyScrolledEvent(int viewId) + { + sendEventForVirtualViewId(viewId, AccessibilityEvent.TYPE_VIEW_SCROLLED); + } + public void notifyLocationChange(int viewId) { if (m_focusedVirtualViewId == viewId) @@ -275,6 +285,9 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate return null; } + if (m_activityDelegate.getSurfaceCount() == 0) + return null; + final AccessibilityEvent event = AccessibilityEvent.obtain(eventType); event.setEnabled(true); @@ -337,9 +350,11 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate // Spit out the entire hierarchy for debugging purposes // dumpNodes(-1); - int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1); - for (int i = 0; i < ids.length; ++i) - result.addChild(m_view, ids[i]); + if (m_activityDelegate.getSurfaceCount() != 0) { + int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(-1); + for (int i = 0; i < ids.length; ++i) + result.addChild(m_view, ids[i]); + } // The offset values have changed, so we need to re-focus the // currently focused item, otherwise it will have an incorrect @@ -367,8 +382,9 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate node.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); node.setPackageName(m_view.getContext().getPackageName()); - if (!QtNativeAccessibility.populateNode(virtualViewId, node)) + if (m_activityDelegate.getSurfaceCount() == 0 || !QtNativeAccessibility.populateNode(virtualViewId, node)) { return node; + } // set only if valid, otherwise we return a node that is invalid and will crash when accessed node.setSource(m_view, virtualViewId); @@ -402,6 +418,13 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId); for (int i = 0; i < ids.length; ++i) node.addChild(m_view, ids[i]); + if (node.isScrollable()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + node.setCollectionInfo(new CollectionInfo(ids.length, 1, false)); + } else { + node.setCollectionInfo(CollectionInfo.obtain(ids.length, 1, false)); + } + } return node; } @@ -411,7 +434,7 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate @Override public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { - if (virtualViewId == View.NO_ID) { + if (virtualViewId == View.NO_ID || m_activityDelegate.getSurfaceCount() == 0) { return getNodeForView(); } return getNodeForVirtualViewId(virtualViewId); |