summaryrefslogtreecommitdiffstats
path: root/src/android/jar/src/org/qtproject/qt5
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt5')
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java43
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtLayout.java78
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtNative.java48
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/QtServiceDelegate.java10
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/accessibility/QtAccessibilityDelegate.java66
-rw-r--r--src/android/jar/src/org/qtproject/qt5/android/accessibility/QtNativeAccessibility.java1
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);
}