diff options
author | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-03-23 21:06:47 +0200 |
---|---|---|
committer | Tarja Sundqvist <tarja.sundqvist@qt.io> | 2023-03-23 21:06:47 +0200 |
commit | 42e4ae042a4c86e58bcb8b6d2d59ba4a988285b4 (patch) | |
tree | a7f25b1d335a834a7c3ae104cee913ef3a4dd4fb /src/android/jar/src/org | |
parent | 4ee4fc18b4067b90efa46ca9baba74f53b54d9ec (diff) | |
parent | 168ff3419f256fdb35b586275d293fc0cd773fe1 (diff) | |
download | qtbase-5.15.tar.gz |
Merge remote-tracking branch 'origin/tqtc/lts-5.15.9' into tqtc/lts-5.15-opensourcev5.15.9-lts-lgpl5.15
Change-Id: Iaff6b55275e50d19973e1020853d8622587069f9
Diffstat (limited to 'src/android/jar/src/org')
6 files changed, 194 insertions, 52 deletions
diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index 16f3ea0c4d..9f7c040c17 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2017 BogDan Vatra <bogdan@kde.org> -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com> ** Contact: https://www.qt.io/licensing/ ** @@ -69,6 +69,7 @@ import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.Menu; @@ -675,10 +676,29 @@ public class QtActivityDelegate @Override public void onDisplayAdded(int 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) { - m_currentRotation = m_activity.getWindowManager().getDefaultDisplay().getRotation(); - QtNative.handleOrientationChanged(m_currentRotation, m_nativeOrientation); + 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); } @Override @@ -806,9 +826,15 @@ public class QtActivityDelegate else m_nativeOrientation = Configuration.ORIENTATION_PORTRAIT; + m_layout.setNativeOrientation(m_nativeOrientation); QtNative.handleOrientationChanged(rotation, m_nativeOrientation); m_currentRotation = rotation; + float refreshRate = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) + ? m_activity.getWindowManager().getDefaultDisplay().getRefreshRate() + : m_activity.getDisplay().getRefreshRate(); + QtNative.handleRefreshRateChanged(refreshRate); + m_layout.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { @@ -875,11 +901,11 @@ public class QtActivityDelegate m_accessibilityDelegate.notifyLocationChange(); } - public void notifyObjectHide(int viewId) + public void notifyObjectHide(int viewId, int parentId) { if (m_accessibilityDelegate == null) return; - m_accessibilityDelegate.notifyObjectHide(viewId); + m_accessibilityDelegate.notifyObjectHide(viewId, parentId); } public void notifyObjectFocus(int viewId) @@ -889,6 +915,13 @@ public class QtActivityDelegate m_accessibilityDelegate.notifyObjectFocus(viewId); } + public void notifyValueChanged(int viewId, String value) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyValueChanged(viewId, value); + } + public void notifyQtAndroidPluginRunning(boolean running) { m_isPluginRunning = running; diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java index e94ce60248..123c5bc248 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> ** Contact: https://www.qt.io/licensing/ ** @@ -42,16 +42,35 @@ package org.qtproject.qt5.android; import android.app.Activity; import android.content.Context; +import android.os.Build; import android.util.AttributeSet; import android.util.DisplayMetrics; +import android.view.Display; import android.view.View; import android.view.ViewGroup; -import android.graphics.Rect; public class QtLayout extends ViewGroup { private Runnable m_startApplicationRunnable; - private int m_bottomDisplayFrame = -1; + + private int m_activityDisplayRotation = -1; + private int m_ownDisplayRotation = -1; + private int m_nativeOrientation = -1; + + public void setActivityDisplayRotation(int rotation) + { + m_activityDisplayRotation = rotation; + } + + public void setNativeOrientation(int orientation) + { + m_nativeOrientation = orientation; + } + + public int displayRotation() + { + return m_ownDisplayRotation; + } public QtLayout(Context context, Runnable startRunnable) { @@ -69,31 +88,40 @@ public class QtLayout extends ViewGroup super(context, attrs, defStyle); } - private void handleSizeChanged (int w, int h, int oldw, int oldh) + @Override + protected void onSizeChanged (int w, int h, int oldw, int oldh) { DisplayMetrics metrics = new DisplayMetrics(); - ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(metrics); - - Rect r = new Rect(); - ((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(r); - - if (m_bottomDisplayFrame != r.bottom || oldh == -1) { - m_bottomDisplayFrame = r.bottom; - QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels, w, h, - metrics.xdpi, - metrics.ydpi, - metrics.scaledDensity, - metrics.density, - ((metrics.heightPixels == h) - || (metrics.heightPixels == h + r.top) - || (m_bottomDisplayFrame > metrics.heightPixels + r.top))); + Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) + ? ((Activity)getContext()).getWindowManager().getDefaultDisplay() + : ((Activity)getContext()).getDisplay(); + display.getMetrics(metrics); + + if ((metrics.widthPixels > metrics.heightPixels) != (w > h)) { + // This is an intermediate state during display rotation. + // The new size is still reported for old orientation, while + // metrics 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. + return; } - } - @Override - protected void onSizeChanged (int w, int h, int oldw, int oldh) - { - handleSizeChanged (w, h, oldw, oldh); + QtNative.setApplicationDisplayMetrics(metrics.widthPixels, metrics.heightPixels, w, h, + metrics.xdpi, metrics.ydpi, metrics.scaledDensity, + metrics.density, display.getRefreshRate()); + + int newRotation = display.getRotation(); + 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); + } + m_ownDisplayRotation = newRotation; if (m_startApplicationRunnable != null) { m_startApplicationRunnable.run(); @@ -172,8 +200,6 @@ public class QtLayout extends ViewGroup } } - - handleSizeChanged (r, b, 0, -1); } // Override to allow type-checking of LayoutParams. diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java index 5792b5b2f5..b077014b81 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java @@ -103,6 +103,7 @@ public class QtNative private static int m_displayMetricsScreenHeightPixels = 0; private static int m_displayMetricsDesktopWidthPixels = 0; private static int m_displayMetricsDesktopHeightPixels = 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; @@ -614,7 +615,7 @@ public class QtNative m_displayMetricsYDpi, m_displayMetricsScaledDensity, m_displayMetricsDensity, - true); + m_displayMetricsRefreshRate); } }); m_qtThread.post(new Runnable() { @@ -637,7 +638,7 @@ public class QtNative double YDpi, double scaledDensity, double density, - boolean forceUpdate) + float refreshRate) { /* Fix buggy dpi report */ if (XDpi < android.util.DisplayMetrics.DENSITY_LOW) @@ -647,15 +648,9 @@ public class QtNative synchronized (m_mainActivityMutex) { if (m_started) { - setDisplayMetrics(screenWidthPixels, - screenHeightPixels, - desktopWidthPixels, - desktopHeightPixels, - XDpi, - YDpi, - scaledDensity, - density, - forceUpdate); + setDisplayMetrics(screenWidthPixels, screenHeightPixels, desktopWidthPixels, + desktopHeightPixels, XDpi, YDpi, scaledDensity, density, + refreshRate); } else { m_displayMetricsScreenWidthPixels = screenWidthPixels; m_displayMetricsScreenHeightPixels = screenHeightPixels; @@ -665,6 +660,7 @@ public class QtNative m_displayMetricsYDpi = YDpi; m_displayMetricsScaledDensity = scaledDensity; m_displayMetricsDensity = density; + m_displayMetricsRefreshRate = refreshRate; } } } @@ -712,9 +708,11 @@ public class QtNative } return 1; } - if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { + if (action == MotionEvent.ACTION_DOWN + || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) { return 0; - } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { + } else if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) { return 3; } return 2; @@ -766,6 +764,10 @@ public class QtNative touchEnd(id, 2); break; + case MotionEvent.ACTION_CANCEL: + touchCancel(id); + break; + default: touchEnd(id, 1); } @@ -954,13 +956,13 @@ public class QtNative }); } - private static void notifyObjectHide(final int viewId) + private static void notifyObjectHide(final int viewId, final int parentId) { runAction(new Runnable() { @Override public void run() { if (m_activityDelegate != null) { - m_activityDelegate.notifyObjectHide(viewId); + m_activityDelegate.notifyObjectHide(viewId, parentId); } } }); @@ -978,6 +980,18 @@ public class QtNative }); } + private static void notifyValueChanged(final int viewId, final String value) + { + runAction(new Runnable() { + @Override + public void run() { + if (m_activityDelegate != null) { + m_activityDelegate.notifyValueChanged(viewId, value); + } + } + }); + } + public static void notifyQtAndroidPluginRunning(final boolean running) { m_activityDelegate.notifyQtAndroidPluginRunning(running); @@ -1344,8 +1358,9 @@ public class QtNative double YDpi, double scaledDensity, double density, - boolean forceUpdate); + float refreshRate); public static native void handleOrientationChanged(int newRotation, int nativeOrientation); + public static native void handleRefreshRateChanged(float refreshRate); // screen methods // pointer methods @@ -1356,6 +1371,7 @@ public class QtNative public static native void touchBegin(int winId); public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure); public static native void touchEnd(int winId, int action); + public static native void touchCancel(int winId); public static native void longPress(int winId, int x, int y); // pointer methods diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java index 68e79c273f..433c57f598 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java @@ -84,6 +84,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import java.util.Objects; public class QtServiceDelegate { @@ -115,10 +116,11 @@ public class QtServiceDelegate QtNative.setService(m_service, this); QtNative.setClassLoader(classLoader); - QtNative.setApplicationDisplayMetrics(10, 10, 10, 10, 120, 120, 1.0, 1.0, false); + QtNative.setApplicationDisplayMetrics(10, 10, 10, 10, 120, 120, 1.0, 1.0, 60.0f); if (loaderParams.containsKey(STATIC_INIT_CLASSES_KEY)) { - for (String className: loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY)) { + for (String className : + Objects.requireNonNull(loaderParams.getStringArray(STATIC_INIT_CLASSES_KEY))) { if (className.length() == 0) continue; try { @@ -128,9 +130,11 @@ public class QtServiceDelegate Method m = initClass.getMethod("setService", Service.class, Object.class); m.invoke(staticInitDataObject, m_service, this); } catch (Exception e) { - e.printStackTrace(); + Log.d(QtNative.QtTAG, + "Class " + className + " does not implement setService method"); } + // For modules that don't need/have setService try { Method m = initClass.getMethod("setContext", Context.class); m.invoke(staticInitDataObject, (Context)m_service); diff --git a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java index 360902c1db..90e38231fc 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java @@ -89,6 +89,8 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate // this is because the Android platform window does not take // the offset of the view on screen into account (eg status bar on top) private final int[] m_globalOffset = new int[2]; + private int m_oldOffsetX = 0; + private int m_oldOffsetY = 0; private class HoverEventListener implements View.OnHoverListener { @@ -196,20 +198,60 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate invalidateVirtualViewId(m_focusedVirtualViewId); } - public void notifyObjectHide(int viewId) + public void notifyObjectHide(int viewId, int parentId) { - invalidateVirtualViewId(viewId); + // If the object had accessibility focus, we need to clear it. + // Note: This code is mostly copied from + // AccessibilityNodeProvider::performAction, but we remove the + // focus only if the focused view id matches the one that was hidden. + if (m_focusedVirtualViewId == viewId) { + m_focusedVirtualViewId = INVALID_ID; + m_view.invalidate(); + sendEventForVirtualViewId(viewId, + AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); + } + // When the object is hidden, we need to notify its parent about + // content change, not the hidden object itself + invalidateVirtualViewId(parentId); } public void notifyObjectFocus(int viewId) { if (m_view == null) return; + m_focusedVirtualViewId = viewId; m_view.invalidate(); sendEventForVirtualViewId(viewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); } + public void notifyValueChanged(int viewId, String value) + { + // Send a TYPE_ANNOUNCEMENT event with the new value + if ((viewId == INVALID_ID) || !m_manager.isEnabled()) { + Log.w(TAG, "notifyValueChanged() for invalid view"); + return; + } + final ViewGroup group = (ViewGroup)m_view.getParent(); + if (group == null) { + Log.w(TAG, "Could not announce value because ViewGroup was null."); + return; + } + final AccessibilityEvent event = + AccessibilityEvent.obtain(AccessibilityEvent.TYPE_ANNOUNCEMENT); + event.setEnabled(true); + event.setClassName(m_view.getClass().getName() + DEFAULT_CLASS_NAME); + event.setContentDescription(value); + if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) { + Log.w(TAG, "No value to announce for " + event.getClassName()); + return; + } + event.setPackageName(m_view.getContext().getPackageName()); + event.setSource(m_view, viewId); + if (!group.requestSendAccessibilityEvent(m_view, event)) + Log.w(TAG, "Failed to send value change announcement for " + event.getClassName()); + } + public boolean sendEventForVirtualViewId(int virtualViewId, int eventType) { if ((virtualViewId == INVALID_ID) || !m_manager.isEnabled()) { @@ -314,6 +356,22 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate 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 + // focus frame + if ((m_oldOffsetX != offsetX) || (m_oldOffsetY != offsetY)) { + m_oldOffsetX = offsetX; + m_oldOffsetY = offsetY; + if (m_focusedVirtualViewId != INVALID_ID) { + m_nodeProvider.performAction(m_focusedVirtualViewId, + AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, + new Bundle()); + m_nodeProvider.performAction(m_focusedVirtualViewId, + AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, + new Bundle()); + } + } + return result; } @@ -356,6 +414,10 @@ public class QtAccessibilityDelegate extends View.AccessibilityDelegate node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); } + int[] ids = QtNativeAccessibility.childIdListForAccessibleObject(virtualViewId); + for (int i = 0; i < ids.length; ++i) + node.addChild(m_view, ids[i]); + return node; } diff --git a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java index a83174377d..448b29a98e 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java +++ b/src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java @@ -55,4 +55,5 @@ class QtNativeAccessibility static native boolean scrollBackward(int objectId); static native boolean populateNode(int objectId, AccessibilityNodeInfo node); + static native String valueForAccessibleObject(int objectId); } |