diff options
Diffstat (limited to 'src/android/jar/src/org/qtproject/qt')
39 files changed, 722 insertions, 664 deletions
diff --git a/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java b/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java new file mode 100644 index 0000000000..b66a593ec6 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/BackendRegister.java @@ -0,0 +1,9 @@ +// Copyright (C) 2024 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; + +class BackendRegister +{ + static native void registerBackend(Class interfaceType, Object interfaceObject); + static native void unregisterBackend(Class interfaceType); +} 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 7e601c0551..015ff9349c 100644 --- a/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java +++ b/src/android/jar/src/org/qtproject/qt/android/CursorHandle.java @@ -33,7 +33,7 @@ class CursorView extends ImageView } // Called when the handle was moved programmatically , with the delta amount in pixels - public void adjusted(int dx, int dy) { + void adjusted(int dx, int dy) { m_offsetX += dx; m_offsetY += dy; } @@ -83,7 +83,7 @@ class CursorHandle implements ViewTreeObserver.OnPreDrawListener private final boolean m_rtl; int m_yShift; - public CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) { + CursorHandle(Activity activity, View layout, int id, int attr, boolean rtl) { m_activity = activity; m_id = id; m_attr = attr; @@ -123,7 +123,7 @@ class CursorHandle implements ViewTreeObserver.OnPreDrawListener } // Show the handle at a given position (or move it if it is already shown) - public void setPosition(final int x, final int y){ + void setPosition(final int x, final int y){ initOverlay(); final int[] layoutLocation = new int[2]; @@ -157,7 +157,7 @@ class CursorHandle implements ViewTreeObserver.OnPreDrawListener m_posY = y; } - public int bottom() + int bottom() { initOverlay(); final int[] location = new int[2]; @@ -165,19 +165,19 @@ class CursorHandle implements ViewTreeObserver.OnPreDrawListener return location[1] + m_cursorView.getHeight(); } - public void hide() { + void hide() { if (m_popup != null) { m_popup.dismiss(); } } - public int width() + int width() { return m_cursorView.getDrawable().getIntrinsicWidth(); } // The handle was dragged by a given relative position - public void updatePosition(int x, int y) { + void updatePosition(int x, int y) { y -= m_yShift; if (Math.abs(m_lastX - x) > tolerance || Math.abs(m_lastY - y) > tolerance) { QtInputDelegate.handleLocationChanged(m_id, x + m_posX, y + m_posY); diff --git a/src/android/jar/src/org/qtproject/qt/android/EditContextView.java b/src/android/jar/src/org/qtproject/qt/android/EditContextView.java index fbd32ed98b..fc34b41e94 100644 --- a/src/android/jar/src/org/qtproject/qt/android/EditContextView.java +++ b/src/android/jar/src/org/qtproject/qt/android/EditContextView.java @@ -19,23 +19,23 @@ import java.util.HashMap; @SuppressLint("ViewConstructor") class EditContextView extends LinearLayout implements View.OnClickListener { - public static final int CUT_BUTTON = 1; - public static final int COPY_BUTTON = 1 << 1; - public static final int PASTE_BUTTON = 1 << 2; - public static final int SELECT_ALL_BUTTON = 1 << 3; + static final int CUT_BUTTON = 1; + static final int COPY_BUTTON = 1 << 1; + static final int PASTE_BUTTON = 1 << 2; + static final int SELECT_ALL_BUTTON = 1 << 3; HashMap<Integer, ContextButton> m_buttons = new HashMap<>(4); OnClickListener m_onClickListener; - public interface OnClickListener + interface OnClickListener { void contextButtonClicked(int buttonId); } private class ContextButton extends TextView { - public int m_buttonId; - public ContextButton(Context context, int stringId) { + int m_buttonId; + ContextButton(Context context, int stringId) { super(context); m_buttonId = stringId; setText(stringId); @@ -70,7 +70,7 @@ class EditContextView extends LinearLayout implements View.OnClickListener addView(button); } - public void updateButtons(int buttonsLayout) + void updateButtons(int buttonsLayout) { ContextButton button = m_buttons.get(android.R.string.cut); if (button != null) @@ -89,7 +89,7 @@ class EditContextView extends LinearLayout implements View.OnClickListener button.setVisibility((buttonsLayout & SELECT_ALL_BUTTON) != 0 ? View.VISIBLE : View.GONE); } - public Point getCalculatedSize() + Point getCalculatedSize() { Point size = new Point(0, 0); for (ContextButton b : m_buttons.values()) { @@ -106,7 +106,7 @@ class EditContextView extends LinearLayout implements View.OnClickListener return size; } - public EditContextView(Context context, OnClickListener onClickListener) { + EditContextView(Context context, OnClickListener onClickListener) { super(context); m_onClickListener = onClickListener; setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)); diff --git a/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java b/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java index 25be522c48..00097f4003 100644 --- a/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java +++ b/src/android/jar/src/org/qtproject/qt/android/EditPopupMenu.java @@ -27,7 +27,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout private CursorHandle m_leftSelectionHandle; private CursorHandle m_rightSelectionHandle; - public EditPopupMenu(Activity activity, View layout) + EditPopupMenu(Activity activity, View layout) { m_activity = activity; m_view = new EditContextView(activity, this); @@ -53,7 +53,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout } // Show the handle at a given position (or move it if it is already shown) - public void setPosition(final int x, final int y, final int buttons, + void setPosition(final int x, final int y, final int buttons, CursorHandle cursorHandle, CursorHandle leftSelectionHandle, CursorHandle rightSelectionHandle) { initOverlay(); @@ -105,7 +105,7 @@ class EditPopupMenu implements ViewTreeObserver.OnPreDrawListener, View.OnLayout m_rightSelectionHandle = rightSelectionHandle; } - public void hide() { + void hide() { if (m_popup != null) { m_popup.dismiss(); m_popup = null; 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 6780634317..50722e54de 100644 --- a/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java +++ b/src/android/jar/src/org/qtproject/qt/android/ExtractStyle.java @@ -149,7 +149,7 @@ class ExtractStyle { return (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } - public static String setup(Context context, String extractOption, int dpi) { + static String setup(Context context, String extractOption, int dpi) { String dataDir = context.getApplicationInfo().dataDir; m_stylePath = dataDir + "/qt-reserved-files/android-style/" + dpi + "/"; @@ -189,7 +189,7 @@ class ExtractStyle { return m_stylePath; } - public static void runIfNeeded(Context context, boolean extractDarkMode) { + static void runIfNeeded(Context context, boolean extractDarkMode) { if (m_stylePath == null) return; if (extractDarkMode) { @@ -203,7 +203,7 @@ class ExtractStyle { } } - public ExtractStyle(Context context, String extractPath, boolean minimal) { + ExtractStyle(Context context, String extractPath, boolean minimal) { m_minimal = minimal; m_extractPath = extractPath + "/"; boolean dirCreated = new File(m_extractPath).mkdirs(); @@ -770,7 +770,7 @@ class ExtractStyle { return json; } - public JSONObject getDrawable(Object drawable, String filename, Rect padding) { + JSONObject getDrawable(Object drawable, String filename, Rect padding) { if (drawable == null || m_minimal) return null; @@ -951,11 +951,11 @@ class ExtractStyle { return sortedAttrs; } - public void extractViewInformation(int styleName, JSONObject json, String qtClassName) { + void extractViewInformation(int styleName, JSONObject json, String qtClassName) { extractViewInformation(styleName, json, qtClassName, null); } - public void extractViewInformation(int styleName, JSONObject json, String qtClassName, AttributeSet attributeSet) { + void extractViewInformation(int styleName, JSONObject json, String qtClassName, AttributeSet attributeSet) { try { TypedValue typedValue = new TypedValue(); Context ctx = new ContextThemeWrapper(m_context, m_theme); @@ -1077,13 +1077,13 @@ class ExtractStyle { } } - public JSONObject extractTextAppearance(int styleName) + JSONObject extractTextAppearance(int styleName) { return extractTextAppearance(styleName, false); } @SuppressLint("ResourceType") - public JSONObject extractTextAppearance(int styleName, boolean subStyle) + JSONObject extractTextAppearance(int styleName, boolean subStyle) { final int[] attributes = new int[]{ android.R.attr.textSize, @@ -1135,11 +1135,11 @@ class ExtractStyle { return json; } - public JSONObject extractTextAppearanceInformation(int styleName, String qtClass) { + JSONObject extractTextAppearanceInformation(int styleName, String qtClass) { return extractTextAppearanceInformation(styleName, qtClass, android.R.attr.textAppearance, null); } - public JSONObject extractTextAppearanceInformation(int styleName, String qtClass, int textAppearance, AttributeSet attributeSet) { + JSONObject extractTextAppearanceInformation(int styleName, String qtClass, int textAppearance, AttributeSet attributeSet) { JSONObject json = new JSONObject(); extractViewInformation(styleName, json, qtClass, attributeSet); @@ -1371,7 +1371,7 @@ class ExtractStyle { return json; } - public JSONObject extractImageViewInformation(int styleName, String qtClassName) { + JSONObject extractImageViewInformation(int styleName, String qtClassName) { JSONObject json = new JSONObject(); try { extractViewInformation(styleName, json, qtClassName); @@ -1805,11 +1805,11 @@ class ExtractStyle { private boolean m_addComma = false; private int m_indentLevel = 0; - public SimpleJsonWriter(String filePath) throws FileNotFoundException { + SimpleJsonWriter(String filePath) throws FileNotFoundException { m_writer = new OutputStreamWriter(new FileOutputStream(filePath)); } - public void close() throws IOException { + void close() throws IOException { m_writer.close(); } @@ -1850,7 +1850,7 @@ class ExtractStyle { static class DrawableCache { JSONObject object; Object drawable; - public DrawableCache(JSONObject json, Object drawable) { + DrawableCache(JSONObject json, Object drawable) { object = json; this.drawable = drawable; } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java index d23c87e792..2c25febb4d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityDelegate.java @@ -28,7 +28,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate // Qt uses the upper half of the unsigned integers // all low positive ints should be fine. - public static final int INVALID_ID = 333; // half evil + static final int INVALID_ID = 333; // half evil // The platform might ask for the class implementing the "view". // Pretend to be an inner class of the QtSurface. @@ -61,7 +61,9 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate } // TODO do we want to have one QtAccessibilityDelegate for the whole app (QtRootLayout) or // e.g. one per window? - public QtAccessibilityDelegate(QtLayout layout) + // FIXME make QtAccessibilityDelegate window based or verify current way works + // also for child windows: QTBUG-120685 + QtAccessibilityDelegate(QtLayout layout) { m_layout = layout; @@ -154,13 +156,13 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate return true; } - public void notifyScrolledEvent(int viewId) + void notifyScrolledEvent(int viewId) { QtNative.runAction(() -> sendEventForVirtualViewId(viewId, AccessibilityEvent.TYPE_VIEW_SCROLLED)); } - public void notifyLocationChange(int viewId) + void notifyLocationChange(int viewId) { QtNative.runAction(() -> { if (m_focusedVirtualViewId == viewId) @@ -168,7 +170,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate }); } - public void notifyObjectHide(int viewId, int parentId) + void notifyObjectHide(int viewId, int parentId) { QtNative.runAction(() -> { // If the object had accessibility focus, we need to clear it. @@ -187,7 +189,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate }); } - public void notifyObjectShow(int parentId) + void notifyObjectShow(int parentId) { QtNative.runAction(() -> { // When the object is shown, we need to notify its parent about @@ -196,7 +198,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate }); } - public void notifyObjectFocus(int viewId) + void notifyObjectFocus(int viewId) { QtNative.runAction(() -> { if (m_view == null) @@ -208,7 +210,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate }); } - public void notifyValueChanged(int viewId, String value) + void notifyValueChanged(int viewId, String value) { QtNative.runAction(() -> { // Send a TYPE_ANNOUNCEMENT event with the new value @@ -245,13 +247,13 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate }); } - public void sendEventForVirtualViewId(int virtualViewId, int eventType) + void sendEventForVirtualViewId(int virtualViewId, int eventType) { final AccessibilityEvent event = getEventForVirtualViewId(virtualViewId, eventType); sendAccessibilityEvent(event); } - public void sendAccessibilityEvent(AccessibilityEvent event) + void sendAccessibilityEvent(AccessibilityEvent event) { if (event == null) return; @@ -265,7 +267,7 @@ class QtAccessibilityDelegate extends View.AccessibilityDelegate group.requestSendAccessibilityEvent(m_view, event); } - public void invalidateVirtualViewId(int virtualViewId) + void invalidateVirtualViewId(int virtualViewId) { final AccessibilityEvent event = getEventForVirtualViewId(virtualViewId, AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityInterface.java new file mode 100644 index 0000000000..690b1ae248 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtAccessibilityInterface.java @@ -0,0 +1,14 @@ +// Copyright (C) 2024 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; + +@UsedFromNativeCode +interface QtAccessibilityInterface { + default void initializeAccessibility() { } + default void notifyLocationChange(int viewId) { } + default void notifyObjectHide(int viewId, int parentId) { } + default void notifyObjectFocus(int viewId) { } + default void notifyScrolledEvent(int viewId) { } + default void notifyValueChanged(int viewId, String value) { } + default void notifyObjectShow(int parentId) { } +} 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 3cb6ba220e..dccaf45a05 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java @@ -19,7 +19,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.Window; -public class QtActivityBase extends Activity +public class QtActivityBase extends Activity implements QtNative.AppStateDetailsListener { private String m_applicationParams = ""; private boolean m_isCustomThemeSet = false; @@ -63,25 +63,19 @@ public class QtActivityBase extends Activity m_applicationParams += params; } - private void handleActivityRestart() { - if (QtNative.getStateDetails().isStarted) { - boolean updated = m_delegate.updateActivityAfterRestart(this); - if (!updated) { - // could not update the activity so restart the application - Intent intent = Intent.makeRestartActivityTask(getComponentName()); - startActivity(intent); - QtNative.quitApp(); - Runtime.getRuntime().exit(0); - } - } - } - @Override public void setTheme(int resId) { super.setTheme(resId); m_isCustomThemeSet = true; } + private void restartApplication() { + Intent intent = Intent.makeRestartActivityTask(getComponentName()); + startActivity(intent); + QtNative.quitApp(); + Runtime.getRuntime().exit(0); + } + @Override protected void onCreate(Bundle savedInstanceState) { @@ -94,9 +88,17 @@ public class QtActivityBase extends Activity android.R.style.Theme_Holo_Light); } + if (QtNative.getStateDetails().isStarted) { + // We don't yet have a reliable way to keep the app + // running properly in case of an Activity only restart, + // so for now restart the whole app. + restartApplication(); + } + m_delegate = new QtActivityDelegate(this); - handleActivityRestart(); + QtNative.registerAppStateListener(this); + addReferrer(getIntent()); QtActivityLoader loader = new QtActivityLoader(this); @@ -108,6 +110,14 @@ public class QtActivityBase extends Activity } @Override + public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) { + if (details.isStarted) + m_delegate.registerBackends(); + else + m_delegate.unregisterBackends(); + } + + @Override protected void onStart() { super.onStart(); @@ -153,6 +163,7 @@ public class QtActivityBase extends Activity { super.onDestroy(); if (!m_retainNonConfigurationInstance) { + QtNative.unregisterAppStateListener(this); QtNative.terminateQt(); QtNative.setActivity(null); QtNative.getQtThread().exit(); @@ -295,6 +306,7 @@ public class QtActivityBase extends Activity @Override protected void onNewIntent(Intent intent) { + addReferrer(intent); QtNative.onNewIntent(intent); } 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 1e1a36be3c..1096ccf1b7 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -9,7 +9,6 @@ import android.app.Activity; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.Rect; @@ -26,24 +25,24 @@ import android.view.Menu; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowInsetsController; import android.widget.ImageView; import android.widget.PopupMenu; import java.util.HashMap; class QtActivityDelegate extends QtActivityDelegateBase + implements QtWindowInterface, QtAccessibilityInterface, QtMenuInterface, QtLayoutInterface { private static final String QtTAG = "QtActivityDelegate"; private QtRootLayout m_layout = null; private ImageView m_splashScreen = null; private boolean m_splashScreenSticky = false; + private boolean m_backendsRegistered = false; private View m_dummyView = null; - private HashMap<Integer, View> m_nativeViews = new HashMap<Integer, View>(); - + private final HashMap<Integer, View> m_nativeViews = new HashMap<>(); + private QtAccessibilityDelegate m_accessibilityDelegate = null; QtActivityDelegate(Activity activity) { @@ -53,17 +52,43 @@ class QtActivityDelegate extends QtActivityDelegateBase setActivityBackgroundDrawable(); } + void registerBackends() + { + if (!m_backendsRegistered) { + m_backendsRegistered = true; + BackendRegister.registerBackend(QtWindowInterface.class, + (QtWindowInterface)QtActivityDelegate.this); + BackendRegister.registerBackend(QtAccessibilityInterface.class, + (QtAccessibilityInterface)QtActivityDelegate.this); + BackendRegister.registerBackend(QtMenuInterface.class, + (QtMenuInterface)QtActivityDelegate.this); + BackendRegister.registerBackend(QtLayoutInterface.class, + (QtLayoutInterface)QtActivityDelegate.this); + BackendRegister.registerBackend(QtInputInterface.class, + (QtInputInterface)m_inputDelegate); + } + } + + void unregisterBackends() + { + if (m_backendsRegistered) { + m_backendsRegistered = false; + BackendRegister.unregisterBackend(QtWindowInterface.class); + BackendRegister.unregisterBackend(QtAccessibilityInterface.class); + BackendRegister.unregisterBackend(QtMenuInterface.class); + BackendRegister.unregisterBackend(QtLayoutInterface.class); + BackendRegister.unregisterBackend(QtInputInterface.class); + } + } - @UsedFromNativeCode @Override - QtLayout getQtLayout() + public QtLayout getQtLayout() { return m_layout; } - @UsedFromNativeCode @Override - void setSystemUiVisibility(int systemUiVisibility) + public void setSystemUiVisibility(int systemUiVisibility) { QtNative.runAction(() -> { m_displayManager.setSystemUiVisibility(systemUiVisibility); @@ -73,21 +98,6 @@ class QtActivityDelegate extends QtActivityDelegateBase } @Override - public boolean updateActivityAfterRestart(Activity activity) { - boolean updated = super.updateActivityAfterRestart(activity); - // TODO verify whether this is even needed, the last I checked the initMembers - // recreates the layout anyway - // update the new activity content view to old layout - ViewGroup layoutParent = (ViewGroup)m_layout.getParent(); - if (layoutParent != null) - layoutParent.removeView(m_layout); - - m_activity.setContentView(m_layout); - - return updated; - } - - @Override void startNativeApplicationImpl(String appParams, String mainLib) { m_layout.getViewTreeObserver().addOnGlobalLayoutListener( @@ -212,7 +222,55 @@ class QtActivityDelegate extends QtActivityDelegateBase }); } - @UsedFromNativeCode + @Override + public void notifyLocationChange(int viewId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyLocationChange(viewId); + } + + @Override + public void notifyObjectHide(int viewId, int parentId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyObjectHide(viewId, parentId); + } + + @Override + public void notifyObjectShow(int parentId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyObjectShow(parentId); + } + + @Override + public void notifyObjectFocus(int viewId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyObjectFocus(viewId); + } + + @Override + public void notifyValueChanged(int viewId, String value) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyValueChanged(viewId, value); + } + + @Override + public void notifyScrolledEvent(int viewId) + { + if (m_accessibilityDelegate == null) + return; + m_accessibilityDelegate.notifyScrolledEvent(viewId); + } + + @Override public void initializeAccessibility() { QtNative.runAction(() -> { @@ -224,27 +282,25 @@ class QtActivityDelegate extends QtActivityDelegateBase }); } - @UsedFromNativeCode + // QtMenuInterface implementation begin + @Override public void resetOptionsMenu() { QtNative.runAction(() -> m_activity.invalidateOptionsMenu()); } - @UsedFromNativeCode + @Override public void openOptionsMenu() { QtNative.runAction(() -> m_activity.openOptionsMenu()); } - private boolean m_contextMenuVisible = false; - - public void onCreatePopupMenu(Menu menu) + @Override + public void closeContextMenu() { - QtNative.fillContextMenu(menu); - m_contextMenuVisible = true; + QtNative.runAction(() -> m_activity.closeContextMenu()); } - @UsedFromNativeCode @Override public void openContextMenu(final int x, final int y, final int w, final int h) { @@ -264,11 +320,14 @@ class QtActivityDelegate extends QtActivityDelegateBase popup.show(); }, 100); } + // QtMenuInterface implementation end - @UsedFromNativeCode - public void closeContextMenu() + private boolean m_contextMenuVisible = false; + + void onCreatePopupMenu(Menu menu) { - QtNative.runAction(() -> m_activity.closeContextMenu()); + QtNative.fillContextMenu(menu); + m_contextMenuVisible = true; } @Override @@ -310,7 +369,7 @@ class QtActivityDelegate extends QtActivityDelegateBase @UsedFromNativeCode @Override - void removeTopLevelWindow(final int id) + public void removeTopLevelWindow(final int id) { QtNative.runAction(()-> { if (m_topLevelWindows.containsKey(id)) { @@ -328,7 +387,7 @@ class QtActivityDelegate extends QtActivityDelegateBase @UsedFromNativeCode @Override - void bringChildToFront(final int id) + public void bringChildToFront(final int id) { QtNative.runAction(() -> { QtWindow window = m_topLevelWindows.get(id); @@ -339,7 +398,7 @@ class QtActivityDelegate extends QtActivityDelegateBase @UsedFromNativeCode @Override - void bringChildToBack(int id) + public void bringChildToBack(int id) { QtNative.runAction(() -> { QtWindow window = m_topLevelWindows.get(id); @@ -348,16 +407,6 @@ class QtActivityDelegate extends QtActivityDelegateBase }); } - @Override - QtAccessibilityDelegate createAccessibilityDelegate() - { - if (m_layout != null) - return new QtAccessibilityDelegate(m_layout); - - Log.w(QtTAG, "Null layout, failed to initialize accessibility delegate."); - return null; - } - private void setActivityBackgroundDrawable() { TypedValue attr = new TypedValue(); @@ -377,7 +426,7 @@ class QtActivityDelegate extends QtActivityDelegateBase // TODO: QTBUG-122761 To be removed after QtAndroidAutomotive does not depend on it. @UsedFromNativeCode - public void insertNativeView(int id, View view, int x, int y, int w, int h) + void insertNativeView(int id, View view, int x, int y, int w, int h) { QtNative.runAction(()-> { if (m_dummyView != null) { @@ -403,12 +452,13 @@ class QtActivityDelegate extends QtActivityDelegateBase // TODO: QTBUG-122761 To be removed after QtAndroidAutomotive does not depend on it. @UsedFromNativeCode - public void setNativeViewGeometry(int id, int x, int y, int w, int h) + void setNativeViewGeometry(int id, int x, int y, int w, int h) { QtNative.runAction(() -> { if (m_nativeViews.containsKey(id)) { View view = m_nativeViews.get(id); - view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); + if (view != null) + view.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); } else { Log.e(QtTAG, "View " + id + " not found!"); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java index 6fd539d8dd..0e74884a77 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegateBase.java @@ -37,7 +37,6 @@ abstract class QtActivityDelegateBase { protected Activity m_activity; protected HashMap<Integer, QtWindow> m_topLevelWindows; - protected QtAccessibilityDelegate m_accessibilityDelegate = null; protected QtDisplayManager m_displayManager = null; protected QtInputDelegate m_inputDelegate = null; @@ -46,20 +45,12 @@ abstract class QtActivityDelegateBase // Subclass must implement these abstract void startNativeApplicationImpl(String appParams, String mainLib); - abstract QtAccessibilityDelegate createAccessibilityDelegate(); - abstract QtLayout getQtLayout(); // With these we are okay with default implementation doing nothing void setUpLayout() {} void setUpSplashScreen(int orientation) {} void hideSplashScreen(final int duration) {} - void openContextMenu(final int x, final int y, final int w, final int h) {} void setActionBarVisibility(boolean visible) {} - void addTopLevelWindow(final QtWindow window) {} - void removeTopLevelWindow(final int id) {} - void bringChildToFront(final int id) {} - void bringChildToBack(int id) {} - void setSystemUiVisibility(int systemUiVisibility) {} QtActivityDelegateBase(Activity activity) { @@ -72,7 +63,6 @@ abstract class QtActivityDelegateBase return m_displayManager; } - @UsedFromNativeCode QtInputDelegate getInputDelegate() { return m_inputDelegate; } @@ -87,22 +77,7 @@ abstract class QtActivityDelegateBase return m_contextMenuVisible; } - public boolean updateActivityAfterRestart(Activity activity) { - try { - // set new activity - m_activity = activity; - QtNative.setActivity(m_activity); - - // force c++ native activity object to update - return QtNative.updateNativeActivity(); - } catch (Exception e) { - Log.w(QtNative.QtTAG, "Failed to update the activity."); - e.printStackTrace(); - return false; - } - } - - public void startNativeApplication(String appParams, String mainLib) + void startNativeApplication(String appParams, String mainLib) { if (m_membersInitialized) return; @@ -153,67 +128,11 @@ abstract class QtActivityDelegateBase } } - public void hideSplashScreen() + void hideSplashScreen() { hideSplashScreen(0); } - @UsedFromNativeCode - public void notifyLocationChange(int viewId) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyLocationChange(viewId); - } - - @UsedFromNativeCode - public void notifyObjectHide(int viewId, int parentId) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectHide(viewId, parentId); - } - - @UsedFromNativeCode - public void notifyObjectShow(int parentId) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectShow(parentId); - } - - @UsedFromNativeCode - public void notifyObjectFocus(int viewId) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyObjectFocus(viewId); - } - - @UsedFromNativeCode - public void notifyValueChanged(int viewId, String value) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyValueChanged(viewId, value); - } - - @UsedFromNativeCode - public void notifyScrolledEvent(int viewId) - { - if (m_accessibilityDelegate == null) - return; - m_accessibilityDelegate.notifyScrolledEvent(viewId); - } - - @UsedFromNativeCode - public void initializeAccessibility() - { - QtNative.runAction(() -> { - m_accessibilityDelegate = createAccessibilityDelegate(); - }); - } - void handleUiModeChange(int uiMode) { // QTBUG-108365 @@ -240,28 +159,4 @@ abstract class QtActivityDelegateBase break; } } - - @UsedFromNativeCode - public void resetOptionsMenu() - { - QtNative.runAction(() -> m_activity.invalidateOptionsMenu()); - } - - @UsedFromNativeCode - public void openOptionsMenu() - { - QtNative.runAction(() -> m_activity.openOptionsMenu()); - } - - public void onCreatePopupMenu(Menu menu) - { - QtNative.fillContextMenu(menu); - m_contextMenuVisible = true; - } - - @UsedFromNativeCode - public void closeContextMenu() - { - QtNative.runAction(() -> m_activity.closeContextMenu()); - } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java index 1b2e8e49a0..93f28756b7 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityLoader.java @@ -26,7 +26,7 @@ import java.nio.charset.StandardCharsets; class QtActivityLoader extends QtLoader { private final Activity m_activity; - public QtActivityLoader(Activity activity) + QtActivityLoader(Activity activity) { super(new ContextWrapper(activity)); m_activity = activity; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java b/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java index ac0d4e1890..9c3e9aff76 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtClipboardManager.java @@ -18,14 +18,14 @@ import java.util.concurrent.Semaphore; class QtClipboardManager { - public static native void onClipboardDataChanged(long nativePointer); + static native void onClipboardDataChanged(long nativePointer); private final static String TAG = "QtClipboardManager"; private ClipboardManager m_clipboardManager = null; private boolean m_usePrimaryClip = false; private final long m_nativePointer; - public QtClipboardManager(Context context, long nativePointer) + QtClipboardManager(Context context, long nativePointer) { m_nativePointer = nativePointer; registerClipboardManager(context); @@ -53,7 +53,7 @@ class QtClipboardManager } @UsedFromNativeCode - public void clearClipData() + void clearClipData() { if (m_clipboardManager != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { @@ -68,7 +68,7 @@ class QtClipboardManager } @UsedFromNativeCode - public void setClipboardText(Context context, String text) + void setClipboardText(Context context, String text) { if (m_clipboardManager != null) { ClipData clipData = ClipData.newPlainText("text/plain", text); @@ -76,7 +76,7 @@ class QtClipboardManager } } - public static boolean hasClipboardText(Context context) + static boolean hasClipboardText(Context context) { ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); @@ -98,13 +98,13 @@ class QtClipboardManager } @UsedFromNativeCode - public boolean hasClipboardText() + boolean hasClipboardText() { return hasClipboardMimeType("text/(.*)"); } @UsedFromNativeCode - public String getClipboardText() + String getClipboardText() { try { if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { @@ -143,7 +143,7 @@ class QtClipboardManager } @UsedFromNativeCode - public void setClipboardHtml(Context context, String text, String html) + void setClipboardHtml(Context context, String text, String html) { if (m_clipboardManager != null) { ClipData clipData = ClipData.newHtmlText("text/html", text, html); @@ -170,13 +170,13 @@ class QtClipboardManager } @UsedFromNativeCode - public boolean hasClipboardHtml() + boolean hasClipboardHtml() { return hasClipboardMimeType("text/html"); } @UsedFromNativeCode - public String getClipboardHtml() + String getClipboardHtml() { try { if (m_clipboardManager != null && m_clipboardManager.hasPrimaryClip()) { @@ -194,7 +194,7 @@ class QtClipboardManager } @UsedFromNativeCode - public void setClipboardUri(Context context, String uriString) + void setClipboardUri(Context context, String uriString) { if (m_clipboardManager != null) { ClipData clipData = ClipData.newUri(context.getContentResolver(), "text/uri-list", @@ -204,7 +204,7 @@ class QtClipboardManager } @UsedFromNativeCode - public boolean hasClipboardUri() + boolean hasClipboardUri() { return hasClipboardMimeType("text/uri-list"); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java index b6a52fb22f..e4de2434e2 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtDisplayManager.java @@ -25,23 +25,23 @@ import java.util.List; class QtDisplayManager { // screen methods - public static native void setDisplayMetrics(int screenWidthPixels, int screenHeightPixels, + 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); + static native void handleOrientationChanged(int newRotation, int nativeOrientation); + static native void handleRefreshRateChanged(float refreshRate); + static native void handleUiDarkModeChanged(int newUiMode); + static native void handleScreenAdded(int displayId); + static native void handleScreenChanged(int displayId); + static native void handleScreenRemoved(int displayId); // screen methods // 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; + static final int SYSTEM_UI_VISIBILITY_NORMAL = 0; + static final int SYSTEM_UI_VISIBILITY_FULLSCREEN = 1; + static final int SYSTEM_UI_VISIBILITY_TRANSLUCENT = 2; private int m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL; private static int m_previousRotation = -1; @@ -89,7 +89,7 @@ class QtDisplayManager { m_previousRotation = currentRotation; } - public static int getDisplayRotation(Activity activity) { + static int getDisplayRotation(Activity activity) { Display display = Build.VERSION.SDK_INT < Build.VERSION_CODES.R ? activity.getWindowManager().getDefaultDisplay() : activity.getDisplay(); @@ -113,21 +113,21 @@ class QtDisplayManager { return display != null ? display.getRefreshRate() : 60.0f; } - public void registerDisplayListener() + void registerDisplayListener() { DisplayManager displayManager = (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE); displayManager.registerDisplayListener(m_displayListener, null); } - public void unregisterDisplayListener() + void unregisterDisplayListener() { DisplayManager displayManager = (DisplayManager) m_activity.getSystemService(Context.DISPLAY_SERVICE); displayManager.unregisterDisplayListener(m_displayListener); } - public void setSystemUiVisibility(int systemUiVisibility) + void setSystemUiVisibility(int systemUiVisibility) { if (m_systemUiVisibility == systemUiVisibility) return; @@ -173,12 +173,12 @@ class QtDisplayManager { m_activity.getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags); } - public int systemUiVisibility() + int systemUiVisibility() { return m_systemUiVisibility; } - public void updateFullScreen() + void updateFullScreen() { if (m_systemUiVisibility == SYSTEM_UI_VISIBILITY_FULLSCREEN) { m_systemUiVisibility = SYSTEM_UI_VISIBILITY_NORMAL; @@ -187,7 +187,7 @@ class QtDisplayManager { } @UsedFromNativeCode - public static Display getDisplay(Context context, int displayId) + static Display getDisplay(Context context, int displayId) { DisplayManager displayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); @@ -198,7 +198,7 @@ class QtDisplayManager { } @UsedFromNativeCode - public static List<Display> getAvailableDisplays(Context context) + static List<Display> getAvailableDisplays(Context context) { DisplayManager displayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); @@ -210,7 +210,7 @@ class QtDisplayManager { } @UsedFromNativeCode - public static Size getDisplaySize(Context displayContext, Display display) + static Size getDisplaySize(Context displayContext, Display display) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { DisplayMetrics realMetrics = new DisplayMetrics(); @@ -227,7 +227,7 @@ class QtDisplayManager { return new Size(bounds.width(), bounds.height()); } - public static void setApplicationDisplayMetrics(Activity activity, int width, int height) + static void setApplicationDisplayMetrics(Activity activity, int width, int height) { if (activity == null) return; @@ -273,13 +273,13 @@ class QtDisplayManager { scaledDensity, density, getRefreshRate(display)); } - public static float getXDpi(final DisplayMetrics metrics) { + static float getXDpi(final DisplayMetrics metrics) { if (metrics.xdpi < android.util.DisplayMetrics.DENSITY_LOW) return android.util.DisplayMetrics.DENSITY_LOW; return metrics.xdpi; } - public static float getYDpi(final DisplayMetrics metrics) { + static float getYDpi(final DisplayMetrics metrics) { if (metrics.ydpi < android.util.DisplayMetrics.DENSITY_LOW) return android.util.DisplayMetrics.DENSITY_LOW; return metrics.ydpi; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEditText.java b/src/android/jar/src/org/qtproject/qt/android/QtEditText.java index 4524887242..e4fa4b9942 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtEditText.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtEditText.java @@ -49,7 +49,7 @@ class QtEditText extends View private final QtInputConnectionListener m_qtInputConnectionListener; - public QtEditText(Context context, QtInputConnectionListener listener) + QtEditText(Context context, QtInputConnectionListener listener) { super(context); setFocusable(true); @@ -61,7 +61,7 @@ class QtEditText extends View { if (m_imeOptions == imeOptions) return; - m_imeOptions = m_imeOptions; + m_imeOptions = imeOptions; m_optionsChanged = true; } @@ -78,7 +78,7 @@ class QtEditText extends View { if (m_inputType == inputType) return; - m_inputType = m_inputType; + m_inputType = inputType; m_optionsChanged = true; } @@ -115,7 +115,7 @@ class QtEditText extends View } - public void setEditTextOptions(int enterKeyType, int inputHints) + void setEditTextOptions(int enterKeyType, int inputHints) { int initialCapsMode = 0; int imeOptions = imeOptionsFromEnterKeyType(enterKeyType); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java index ff694777d5..7a460ccc17 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegate.java @@ -15,21 +15,26 @@ import android.os.Handler; import android.os.Looper; import android.util.DisplayMetrics; import android.util.Log; +import android.view.Menu; import android.view.View; import android.view.ViewGroup; +import android.widget.PopupMenu; import java.util.ArrayList; import java.util.HashMap; class QtEmbeddedDelegate extends QtActivityDelegateBase - implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface + implements QtNative.AppStateDetailsListener, QtEmbeddedViewInterface, QtWindowInterface, + QtMenuInterface, QtLayoutInterface { + private static final String QtTAG = "QtEmbeddedDelegate"; // TODO simplistic implementation with one QtView, expand to support multiple views QTBUG-117649 private QtView m_view; private QtNative.ApplicationStateDetails m_stateDetails; private boolean m_windowLoaded = false; + private boolean m_backendsRegistered = false; - public QtEmbeddedDelegate(Activity context) { + QtEmbeddedDelegate(Activity context) { super(context); m_stateDetails = QtNative.getStateDetails(); @@ -76,7 +81,7 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase if (m_activity == activity && m_stateDetails.isStarted) { m_activity.getApplication().unregisterActivityLifecycleCallbacks(this); QtNative.unregisterAppStateListener(QtEmbeddedDelegate.this); - QtEmbeddedDelegateFactory.remove(m_activity); + QtEmbeddedViewInterfaceFactory.remove(m_activity); QtNative.terminateQt(); QtNative.setActivity(null); QtNative.getQtThread().exit(); @@ -89,6 +94,18 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase public void onAppStateDetailsChanged(QtNative.ApplicationStateDetails details) { synchronized (this) { m_stateDetails = details; + if (details.isStarted && !m_backendsRegistered) { + m_backendsRegistered = true; + BackendRegister.registerBackend(QtWindowInterface.class, (QtWindowInterface)this); + BackendRegister.registerBackend(QtMenuInterface.class, (QtMenuInterface)this); + BackendRegister.registerBackend(QtLayoutInterface.class, (QtLayoutInterface)this); + } else if (!details.isStarted && m_backendsRegistered) { + m_backendsRegistered = false; + BackendRegister.unregisterBackend(QtWindowInterface.class); + BackendRegister.unregisterBackend(QtMenuInterface.class); + BackendRegister.unregisterBackend(QtLayoutInterface.class); + } + updateInputDelegate(); } } @@ -115,16 +132,7 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase } @Override - QtAccessibilityDelegate createAccessibilityDelegate() - { - // FIXME make QtAccessibilityDelegate window based or verify current way works - // also for child windows: QTBUG-120685 - return null; - } - - @UsedFromNativeCode - @Override - QtLayout getQtLayout() + public QtLayout getQtLayout() { // TODO verify if returning m_view here works, this is used by the androidjniinput // when e.g. showing a keyboard, so depends on getting the keyboard focus working @@ -161,11 +169,14 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase // QtEmbeddedViewInterface implementation end private void updateInputDelegate() { - if (m_view == null) { - m_inputDelegate.setEditPopupMenu(null); + // If the QtView has attached to the window before Qt libs have been loaded, + // the input delegate will be null + if (m_inputDelegate == null) return; - } - m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_view)); + if (m_view == null) + m_inputDelegate.setEditPopupMenu(null); + else + m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_view)); } private void createRootWindow() { @@ -175,4 +186,36 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase m_windowLoaded = true; } } + + // QtMenuInterface implementation begin + @Override + public void resetOptionsMenu() { QtNative.runAction(() -> m_activity.invalidateOptionsMenu()); } + + @Override + public void openOptionsMenu() { QtNative.runAction(() -> m_activity.openOptionsMenu()); } + + @Override + public void closeContextMenu() { QtNative.runAction(() -> m_activity.closeContextMenu()); } + + @Override + public void openContextMenu(final int x, final int y, final int w, final int h) + { + QtLayout layout = getQtLayout(); + layout.postDelayed(() -> { + final QtEditText focusedEditText = m_inputDelegate.getCurrentQtEditText(); + if (focusedEditText == null) { + Log.w(QtTAG, "No focused view when trying to open context menu"); + return; + } + layout.setLayoutParams(focusedEditText, new QtLayout.LayoutParams(w, h, x, y), false); + PopupMenu popup = new PopupMenu(m_activity, focusedEditText); + QtNative.fillContextMenu(popup.getMenu()); + popup.setOnMenuItemClickListener(menuItem -> + m_activity.onContextItemSelected(menuItem)); + popup.setOnDismissListener(popupMenu -> + m_activity.onContextMenuClosed(popupMenu.getMenu())); + popup.show(); + }, 100); + } + // QtMenuInterface implementation end } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java deleted file mode 100644 index 8cf89e5bc3..0000000000 --- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedDelegateFactory.java +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2024 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.app.Application; -import android.os.Bundle; - -import java.util.HashMap; - -class QtEmbeddedDelegateFactory { - private static final HashMap<Activity, QtEmbeddedDelegate> m_delegates = new HashMap<>(); - private static final Object m_delegateLock = new Object(); - - @UsedFromNativeCode - public static QtActivityDelegateBase getActivityDelegate(Activity activity) { - synchronized (m_delegateLock) { - return m_delegates.get(activity); - } - } - - public static QtEmbeddedDelegate create(Activity activity) { - synchronized (m_delegateLock) { - if (!m_delegates.containsKey(activity)) - m_delegates.put(activity, new QtEmbeddedDelegate(activity)); - - return m_delegates.get(activity); - } - } - - public static void remove(Activity activity) { - synchronized (m_delegateLock) { - m_delegates.remove(activity); - } - } -} diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java index 0c6c4b49f0..7599a3ab27 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedLoader.java @@ -34,7 +34,7 @@ import android.content.res.Resources; class QtEmbeddedLoader extends QtLoader { private static final String TAG = "QtEmbeddedLoader"; - public QtEmbeddedLoader(Context context) { + QtEmbeddedLoader(Context context) { super(new ContextWrapper(context)); // TODO Service context handling QTBUG-118874 int displayDensity = m_context.getResources().getDisplayMetrics().densityDpi; @@ -48,6 +48,6 @@ class QtEmbeddedLoader extends QtLoader { protected void finish() { // Called when loading fails - clear the delegate to make sure we don't hold reference // to the embedding Context - QtEmbeddedDelegateFactory.remove((Activity)m_context.getBaseContext()); + QtEmbeddedViewInterfaceFactory.remove((Activity)m_context.getBaseContext()); } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterfaceFactory.java b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterfaceFactory.java new file mode 100644 index 0000000000..4ba337e19f --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtEmbeddedViewInterfaceFactory.java @@ -0,0 +1,34 @@ +// Copyright (C) 2024 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.content.Context; +import android.app.Activity; +import android.app.Service; + +import java.util.HashMap; + +class QtEmbeddedViewInterfaceFactory { + private static final HashMap<Context, QtEmbeddedViewInterface> m_interfaces = new HashMap<>(); + private static final Object m_interfaceLock = new Object(); + + static QtEmbeddedViewInterface create(Context context) { + synchronized (m_interfaceLock) { + if (!m_interfaces.containsKey(context)) { + if (context instanceof Activity) + m_interfaces.put(context, new QtEmbeddedDelegate((Activity)context)); + else if (context instanceof Service) + m_interfaces.put(context, new QtServiceEmbeddedDelegate((Service)context)); + } + + return m_interfaces.get(context); + } + } + + static void remove(Context context) { + synchronized (m_interfaceLock) { + m_interfaces.remove(context); + } + } +} 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 1bfe05e7ac..845f7c5e8d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtInputConnection.java @@ -20,12 +20,12 @@ import android.util.DisplayMetrics; class QtExtractedText { - public int partialEndOffset; - public int partialStartOffset; - public int selectionEnd; - public int selectionStart; - public int startOffset; - public String text; + int partialEndOffset; + int partialStartOffset; + int selectionEnd; + int selectionStart; + int startOffset; + String text; } class QtNativeInputConnection @@ -77,6 +77,10 @@ class QtInputConnection extends BaseInputConnection Log.w(QtTAG, "HideKeyboardRunnable: The activity reference is null"); return; } + if (m_qtInputConnectionListener == null) { + Log.w(QtTAG, "HideKeyboardRunnable: QtInputConnectionListener is null"); + return; + } Rect r = new Rect(); activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r); @@ -96,7 +100,7 @@ class QtInputConnection extends BaseInputConnection } } - public interface QtInputConnectionListener { + interface QtInputConnectionListener { void onSetClosing(boolean closing); void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp); void onSendKeyEventDefaultCase(); @@ -109,11 +113,11 @@ class QtInputConnection extends BaseInputConnection { if (closing) m_view.postDelayed(new HideKeyboardRunnable(), 100); - else + else if (m_qtInputConnectionListener != null) m_qtInputConnectionListener.onSetClosing(false); } - public QtInputConnection(QtEditText targetView, QtInputConnectionListener listener) + QtInputConnection(QtEditText targetView, QtInputConnectionListener listener) { super(targetView, true); m_view = targetView; @@ -122,7 +126,7 @@ class QtInputConnection extends BaseInputConnection m_qtInputConnectionListener = listener; } - public void restartImmInput() + void restartImmInput() { if (QtNativeInputConnection.fullscreenMode()) { if (m_imm != null) @@ -297,7 +301,8 @@ class QtInputConnection extends BaseInputConnection restartImmInput(); break; default: - m_qtInputConnectionListener.onSendKeyEventDefaultCase(); + if (m_qtInputConnectionListener != null) + m_qtInputConnectionListener.onSendKeyEventDefaultCase(); break; } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java index cfa273e410..3a879776c2 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtInputDelegate.java @@ -21,22 +21,23 @@ import android.view.inputmethod.InputMethodManager; import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener; /** @noinspection FieldCanBeLocal*/ -class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { +class QtInputDelegate implements QtInputConnection.QtInputConnectionListener, QtInputInterface +{ // keyboard methods - public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat); - public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat); - public static native void keyboardVisibilityChanged(boolean visibility); - public static native void keyboardGeometryChanged(int x, int y, int width, int height); + static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat); + static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat); + static native void keyboardVisibilityChanged(boolean visibility); + static native void keyboardGeometryChanged(int x, int y, int width, int height); // keyboard methods // dispatch events methods - public static native boolean dispatchGenericMotionEvent(MotionEvent event); - public static native boolean dispatchKeyEvent(KeyEvent event); + static native boolean dispatchGenericMotionEvent(MotionEvent event); + static native boolean dispatchKeyEvent(KeyEvent event); // dispatch events methods // handle methods - public static native void handleLocationChanged(int id, int x, int y); + static native void handleLocationChanged(int id, int x, int y); // handle methods private QtEditText m_currentEditText = null; @@ -62,9 +63,9 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { private static final int CursorHandleShowEdit = 0x100; // Handle IDs - public static final int IdCursorHandle = 1; - public static final int IdLeftHandle = 2; - public static final int IdRightHandle = 3; + static final int IdCursorHandle = 1; + static final int IdLeftHandle = 2; + static final int IdRightHandle = 3; private static Boolean m_tabletEventSupported = null; @@ -78,7 +79,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { // Note: because of the circular call to updateFullScreen() from the delegate, we need // a listener to be able to do that call from the delegate, because that's where that // logic lives - public interface KeyboardVisibilityListener { + interface KeyboardVisibilityListener { void onKeyboardVisibilityChange(); } @@ -90,6 +91,140 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); } + // QtInputInterface implementation begin + @Override + public void updateSelection(final int selStart, final int selEnd, + final int candidatesStart, final int candidatesEnd) + { + QtNative.runAction(() -> { + if (m_imm == null) + return; + + m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd); + }); + } + + @Override + public void showSoftwareKeyboard(Activity activity, QtLayout layout, + final int x, final int y, final int width, final int height, + final int inputHints, final int enterKeyType) + { + QtNative.runAction(() -> { + if (m_imm == null || m_currentEditText == null) + return; + + if (updateSoftInputMode(activity, height)) + return; + + m_currentEditText.setEditTextOptions(enterKeyType, inputHints); + + m_currentEditText.postDelayed(() -> { + m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + switch (resultCode) { + case InputMethodManager.RESULT_SHOWN: + QtNativeInputConnection.updateCursorPosition(); + //FALLTHROUGH + case InputMethodManager.RESULT_UNCHANGED_SHOWN: + setKeyboardVisibility(true, System.nanoTime()); + if (m_softInputMode == 0) { + probeForKeyboardHeight(layout, activity, + x, y, width, height, inputHints, enterKeyType); + } + break; + case InputMethodManager.RESULT_HIDDEN: + case InputMethodManager.RESULT_UNCHANGED_HIDDEN: + setKeyboardVisibility(false, System.nanoTime()); + break; + } + } + }); + if (m_currentEditText.m_optionsChanged) { + m_imm.restartInput(m_currentEditText); + m_currentEditText.m_optionsChanged = false; + } + }, 15); + }); + } + + @Override + public int getSelectHandleWidth() + { + int width = 0; + if (m_leftSelectionHandle != null && m_rightSelectionHandle != null) { + width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width()); + } else if (m_cursorHandle != null) { + width = m_cursorHandle.width(); + } + return width; + } + + /* called from the C++ code when the position of the cursor or selection handles needs to + be adjusted. + mode is one of QAndroidInputContext::CursorHandleShowMode + */ + @Override + public void updateHandles(Activity activity, QtLayout layout, int mode, + int editX, int editY, int editButtons, + int x1, int y1, int x2, int y2, boolean rtl) + { + QtNative.runAction(() -> updateHandleImpl(activity, layout, mode, editX, editY, editButtons, + x1, y1, x2, y2, rtl)); + } + + @Override + public QtInputConnection.QtInputConnectionListener getInputConnectionListener() + { + return this; + } + + @Override + public void resetSoftwareKeyboard() + { + if (m_imm == null || m_currentEditText == null) + return; + m_currentEditText.postDelayed(() -> { + m_imm.restartInput(m_currentEditText); + m_currentEditText.m_optionsChanged = false; + }, 5); + } + + @Override + public void hideSoftwareKeyboard() + { + m_isKeyboardHidingAnimationOngoing = true; + QtNative.runAction(() -> { + if (m_imm == null || m_currentEditText == null) + return; + + m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0, + new ResultReceiver(new Handler()) { + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + switch (resultCode) { + case InputMethodManager.RESULT_SHOWN: + case InputMethodManager.RESULT_UNCHANGED_SHOWN: + setKeyboardVisibility(true, System.nanoTime()); + break; + case InputMethodManager.RESULT_HIDDEN: + case InputMethodManager.RESULT_UNCHANGED_HIDDEN: + setKeyboardVisibility(false, System.nanoTime()); + break; + } + } + }); + }); + } + + // Is the keyboard fully visible i.e. visible and no ongoing animation + @Override + public boolean isSoftwareKeyboardVisible() + { + return isKeyboardVisible() && !m_isKeyboardHidingAnimationOngoing; + } + // QtInputInterface implementation end + // QtInputConnectionListener methods @Override public void onSetClosing(boolean closing) { @@ -108,18 +243,11 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { } // QtInputConnectionListener methods - public boolean isKeyboardVisible() + boolean isKeyboardVisible() { return m_keyboardIsVisible; } - // Is the keyboard fully visible i.e. visible and no ongoing animation - @UsedFromNativeCode - public boolean isSoftwareKeyboardVisible() - { - return isKeyboardVisible() && !m_isKeyboardHidingAnimationOngoing; - } - void setSoftInputMode(int inputMode) { m_softInputMode = inputMode; @@ -141,7 +269,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { QtInputDelegate.keyboardVisibilityChanged(visibility); } - public void setKeyboardVisibility(boolean visibility, long timeStamp) + void setKeyboardVisibility(boolean visibility, long timeStamp) { if (m_showHideTimeStamp > timeStamp) return; @@ -158,65 +286,11 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { } - @UsedFromNativeCode - public void resetSoftwareKeyboard() - { - if (m_imm == null || m_currentEditText == null) - return; - m_currentEditText.postDelayed(() -> { - m_imm.restartInput(m_currentEditText); - m_currentEditText.m_optionsChanged = false; - }, 5); - } - void setFocusedView(QtEditText currentEditText) { m_currentEditText = currentEditText; } - public void showSoftwareKeyboard(Activity activity, QtLayout layout, - final int x, final int y, final int width, final int height, - final int inputHints, final int enterKeyType) - { - QtNative.runAction(() -> { - if (m_imm == null || m_currentEditText == null) - return; - - if (updateSoftInputMode(activity, height)) - return; - - m_currentEditText.setEditTextOptions(enterKeyType, inputHints); - - m_currentEditText.postDelayed(() -> { - m_imm.showSoftInput(m_currentEditText, 0, new ResultReceiver(new Handler()) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - switch (resultCode) { - case InputMethodManager.RESULT_SHOWN: - QtNativeInputConnection.updateCursorPosition(); - //FALLTHROUGH - case InputMethodManager.RESULT_UNCHANGED_SHOWN: - setKeyboardVisibility(true, System.nanoTime()); - if (m_softInputMode == 0) { - probeForKeyboardHeight(layout, activity, - x, y, width, height, inputHints, enterKeyType); - } - break; - case InputMethodManager.RESULT_HIDDEN: - case InputMethodManager.RESULT_UNCHANGED_HIDDEN: - setKeyboardVisibility(false, System.nanoTime()); - break; - } - } - }); - if (m_currentEditText.m_optionsChanged) { - m_imm.restartInput(m_currentEditText); - m_currentEditText.m_optionsChanged = false; - } - }, 15); - }); - } - private boolean updateSoftInputMode(Activity activity, int height) { DisplayMetrics metrics = new DisplayMetrics(); @@ -284,69 +358,6 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { }, m_probeKeyboardHeightDelayMs); } - public void hideSoftwareKeyboard() - { - m_isKeyboardHidingAnimationOngoing = true; - QtNative.runAction(() -> { - if (m_imm == null || m_currentEditText == null) - return; - - m_imm.hideSoftInputFromWindow(m_currentEditText.getWindowToken(), 0, - new ResultReceiver(new Handler()) { - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - switch (resultCode) { - case InputMethodManager.RESULT_SHOWN: - case InputMethodManager.RESULT_UNCHANGED_SHOWN: - setKeyboardVisibility(true, System.nanoTime()); - break; - case InputMethodManager.RESULT_HIDDEN: - case InputMethodManager.RESULT_UNCHANGED_HIDDEN: - setKeyboardVisibility(false, System.nanoTime()); - break; - } - } - }); - }); - } - - @UsedFromNativeCode - public void updateSelection(final int selStart, final int selEnd, - final int candidatesStart, final int candidatesEnd) - { - QtNative.runAction(() -> { - if (m_imm == null) - return; - - m_imm.updateSelection(m_currentEditText, selStart, selEnd, candidatesStart, candidatesEnd); - }); - } - - @UsedFromNativeCode - public int getSelectHandleWidth() - { - int width = 0; - if (m_leftSelectionHandle != null && m_rightSelectionHandle != null) { - width = Math.max(m_leftSelectionHandle.width(), m_rightSelectionHandle.width()); - } else if (m_cursorHandle != null) { - width = m_cursorHandle.width(); - } - return width; - } - - /* called from the C++ code when the position of the cursor or selection handles needs to - be adjusted. - mode is one of QAndroidInputContext::CursorHandleShowMode - */ - @UsedFromNativeCode - public void updateHandles(Activity activity, QtLayout layout, int mode, - int editX, int editY, int editButtons, - int x1, int y1, int x2, int y2, boolean rtl) - { - QtNative.runAction(() -> updateHandleImpl(activity, layout, mode, editX, editY, editButtons, - x1, y1, x2, y2, rtl)); - } - private void updateHandleImpl(Activity activity, QtLayout layout, int mode, int editX, int editY, int editButtons, int x1, int y1, int x2, int y2, boolean rtl) @@ -416,7 +427,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { } } - public boolean onKeyDown(int keyCode, KeyEvent event) + boolean onKeyDown(int keyCode, KeyEvent event) { m_metaState = MetaKeyKeyListener.handleKeyDown(m_metaState, keyCode, event); int metaState = MetaKeyKeyListener.getMetaState(m_metaState) | event.getMetaState(); @@ -448,7 +459,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { return true; } - public boolean onKeyUp(int keyCode, KeyEvent event) + boolean onKeyUp(int keyCode, KeyEvent event) { if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN @@ -470,7 +481,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { return true; } - public boolean handleDispatchKeyEvent(KeyEvent event) + boolean handleDispatchKeyEvent(KeyEvent event) { if (event.getAction() == KeyEvent.ACTION_MULTIPLE && event.getCharacters() != null @@ -485,7 +496,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { return dispatchKeyEvent(event); } - public boolean handleDispatchGenericMotionEvent(MotionEvent event) + boolean handleDispatchGenericMotionEvent(MotionEvent event) { return dispatchGenericMotionEvent(event); } @@ -495,24 +506,24 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { ////////////////////////////// // tablet methods - public static native boolean isTabletEventSupported(); - public static native void tabletEvent(int winId, int deviceId, long time, int action, + static native boolean isTabletEventSupported(); + static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure); // tablet methods // pointer methods - public static native void mouseDown(int winId, int x, int y, int mouseButtonState); - public static native void mouseUp(int winId, int x, int y, int mouseButtonState); - public static native void mouseMove(int winId, int x, int y); - public static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta); - public static native void touchBegin(int winId); - public static native void touchAdd(int winId, int pointerId, int action, boolean primary, + static native void mouseDown(int winId, int x, int y, int mouseButtonState); + static native void mouseUp(int winId, int x, int y, int mouseButtonState); + static native void mouseMove(int winId, int x, int y); + static native void mouseWheel(int winId, int x, int y, float hDelta, float vDelta); + static native void touchBegin(int winId); + 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); + static native void touchEnd(int winId, int action); + static native void touchCancel(int winId); + static native void longPress(int winId, int x, int y); // pointer methods static private int getAction(int index, MotionEvent event) @@ -542,7 +553,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { return 2; } - static public void sendTouchEvent(MotionEvent event, int id) + static void sendTouchEvent(MotionEvent event, int id) { int pointerType = 0; @@ -598,12 +609,12 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { } } - static public void sendTrackballEvent(MotionEvent event, int id) + static void sendTrackballEvent(MotionEvent event, int id) { sendMouseEvent(event,id); } - static public boolean sendGenericMotionEvent(MotionEvent event, int id) + static boolean sendGenericMotionEvent(MotionEvent event, int id) { int scrollOrHoverMove = MotionEvent.ACTION_SCROLL | MotionEvent.ACTION_HOVER_MOVE; int pointerDeviceModifier = (event.getSource() & InputDevice.SOURCE_CLASS_POINTER); @@ -615,7 +626,7 @@ class QtInputDelegate implements QtInputConnection.QtInputConnectionListener { return sendMouseEvent(event, id); } - static public boolean sendMouseEvent(MotionEvent event, int id) + static boolean sendMouseEvent(MotionEvent event, int id) { switch (event.getActionMasked()) { case MotionEvent.ACTION_UP: diff --git a/src/android/jar/src/org/qtproject/qt/android/QtInputInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtInputInterface.java new file mode 100644 index 0000000000..1dc4d5fd7f --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtInputInterface.java @@ -0,0 +1,21 @@ +// Copyright (C) 2024 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; + +@UsedFromNativeCode +interface QtInputInterface { + void updateSelection(final int selStart, final int selEnd, final int candidatesStart, + final int candidatesEnd); + void showSoftwareKeyboard(Activity activity, QtLayout layout, final int x, final int y, + final int width, final int height, final int inputHints, + final int enterKeyType); + void resetSoftwareKeyboard(); + void hideSoftwareKeyboard(); + boolean isSoftwareKeyboardVisible(); + int getSelectHandleWidth(); + void updateHandles(Activity activity, QtLayout layout, int mode, int editX, int editY, + int editButtons, int x1, int y1, int x2, int y2, boolean rtl); + QtInputConnection.QtInputConnectionListener getInputConnectionListener(); +} 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 aedc845014..95c62d58c4 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayout.java @@ -16,17 +16,17 @@ import android.view.ViewGroup; class QtLayout extends ViewGroup { - public QtLayout(Context context) + QtLayout(Context context) { super(context); } - public QtLayout(Context context, AttributeSet attrs) + QtLayout(Context context, AttributeSet attrs) { super(context, attrs); } - public QtLayout(Context context, AttributeSet attrs, int defStyle) + QtLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @@ -126,16 +126,16 @@ class QtLayout extends ViewGroup { * See {android.R.styleable#AbsoluteLayout_Layout Absolute Layout Attributes} * for a list of all child view attributes that this class supports. */ - public static class LayoutParams extends ViewGroup.LayoutParams + static class LayoutParams extends ViewGroup.LayoutParams { /** * The horizontal, or X, location of the child within the view group. */ - public int x; + int x; /** * The vertical, or Y, location of the child within the view group. */ - public int y; + int y; /** * Creates a new set of layout parameters with the specified width, @@ -148,14 +148,14 @@ class QtLayout extends ViewGroup { * @param x the X location of the child * @param y the Y location of the child */ - public LayoutParams(int width, int height, int x, int y) + LayoutParams(int width, int height, int x, int y) { super(width, height); this.x = x; this.y = y; } - public LayoutParams(int width, int height) + LayoutParams(int width, int height) { super(width, height); } @@ -163,13 +163,13 @@ class QtLayout extends ViewGroup { /** * {@inheritDoc} */ - public LayoutParams(ViewGroup.LayoutParams source) + LayoutParams(ViewGroup.LayoutParams source) { super(source); } } - public void moveChild(View view, int index) + void moveChild(View view, int index) { if (view == null) return; @@ -189,7 +189,7 @@ class QtLayout extends ViewGroup { * Note: This function adds the child view if it's not in the * layout already. */ - public void setLayoutParams(final View childView, + void setLayoutParams(final View childView, final ViewGroup.LayoutParams params, final boolean forceRedraw) { diff --git a/src/android/jar/src/org/qtproject/qt/android/QtLayoutInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtLayoutInterface.java new file mode 100644 index 0000000000..8444266893 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtLayoutInterface.java @@ -0,0 +1,8 @@ +// Copyright (C) 2024 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; + +@UsedFromNativeCode +interface QtLayoutInterface { + QtLayout getQtLayout(); +} diff --git a/src/android/jar/src/org/qtproject/qt/android/QtMenuInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtMenuInterface.java new file mode 100644 index 0000000000..556b9a57b9 --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtMenuInterface.java @@ -0,0 +1,11 @@ +// Copyright (C) 2024 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; + +@UsedFromNativeCode +interface QtMenuInterface { + void resetOptionsMenu(); + void openOptionsMenu(); + void closeContextMenu(); + void openContextMenu(final int x, final int y, final int w, final int h); +} 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 e13abbbadd..068b6b9904 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtMessageDialogHelper.java @@ -52,13 +52,13 @@ class ButtonStruct implements View.OnClickListener class QtMessageDialogHelper { - public QtMessageDialogHelper(Activity activity) + QtMessageDialogHelper(Activity activity) { m_activity = activity; } @UsedFromNativeCode - public void setStandardIcon(int icon) + void setStandardIcon(int icon) { m_standardIcon = icon; @@ -89,31 +89,31 @@ class QtMessageDialogHelper } @UsedFromNativeCode - public void setTile(String title) + void setTile(String title) { m_title = Html.fromHtml(title); } @UsedFromNativeCode - public void setText(String text) + void setText(String text) { m_text = Html.fromHtml(text); } @UsedFromNativeCode - public void setInformativeText(String informativeText) + void setInformativeText(String informativeText) { m_informativeText = Html.fromHtml(informativeText); } @UsedFromNativeCode - public void setDetailedText(String text) + void setDetailedText(String text) { m_detailedText = Html.fromHtml(text); } @UsedFromNativeCode - public void addButton(int id, String text) + void addButton(int id, String text) { if (m_buttonsList == null) m_buttonsList = new ArrayList<>(); @@ -130,7 +130,7 @@ class QtMessageDialogHelper } @UsedFromNativeCode - public void show(long handler) + void show(long handler) { m_handler = handler; m_activity.runOnUiThread(() -> { @@ -299,7 +299,7 @@ class QtMessageDialogHelper } @UsedFromNativeCode - public void hide() + void hide() { m_activity.runOnUiThread(() -> { if (m_dialog != null && m_dialog.isShowing()) @@ -308,12 +308,12 @@ class QtMessageDialogHelper }); } - public long handler() + long handler() { return m_handler; } - public void reset() + void reset() { m_standardIcon = 0; m_title = null; 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 b2a2887ad5..17e1386efb 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -30,15 +30,16 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -class QtNative +// ### Qt7: make private and find new API for onNewIntent() +public class QtNative { private static WeakReference<Activity> m_activity = null; private static WeakReference<Service> m_service = null; - public static final Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations + private static final Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations private static final ApplicationStateDetails m_stateDetails = new ApplicationStateDetails(); - public static final String QtTAG = "Qt JAVA"; + static final String QtTAG = "Qt JAVA"; // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.) private static final ArrayList<Runnable> m_lostActions = new ArrayList<>(); @@ -51,24 +52,24 @@ class QtNative private static final Object m_appStateListenersLock = new Object(); @UsedFromNativeCode - public static ClassLoader classLoader() + static ClassLoader classLoader() { return m_classLoader; } - public static void setClassLoader(ClassLoader classLoader) + static void setClassLoader(ClassLoader classLoader) { m_classLoader = classLoader; } - public static void setActivity(Activity qtMainActivity) + static void setActivity(Activity qtMainActivity) { synchronized (m_mainActivityMutex) { m_activity = new WeakReference<>(qtMainActivity); } } - public static void setService(Service qtMainService) + static void setService(Service qtMainService) { synchronized (m_mainActivityMutex) { m_service = new WeakReference<>(qtMainService); @@ -76,40 +77,40 @@ class QtNative } @UsedFromNativeCode - public static Activity activity() + static Activity activity() { synchronized (m_mainActivityMutex) { return m_activity != null ? m_activity.get() : null; } } - public static boolean isActivityValid() + static boolean isActivityValid() { return m_activity != null && m_activity.get() != null; } @UsedFromNativeCode - public static Service service() + static Service service() { synchronized (m_mainActivityMutex) { return m_service != null ? m_service.get() : null; } } - public static boolean isServiceValid() + static boolean isServiceValid() { return m_service != null && m_service.get() != null; } @UsedFromNativeCode - public static Context getContext() { + static Context getContext() { if (isActivityValid()) return m_activity.get(); return service(); } @UsedFromNativeCode - public static String[] getStringArray(String joinedString) + static String[] getStringArray(String joinedString) { return joinedString.split(","); } @@ -162,7 +163,7 @@ class QtNative } @UsedFromNativeCode - public static boolean openURL(Context context, String url, String mime) + static boolean openURL(Context context, String url, String mime) { final Uri uri = getUriWithValidPermission(context, url, "r"); if (uri == null) { @@ -201,39 +202,39 @@ class QtNative } // Keep in sync with src/corelib/global/qnamespace.h - public static class ApplicationState { + static class ApplicationState { static final int ApplicationSuspended = 0x0; static final int ApplicationHidden = 0x1; static final int ApplicationInactive = 0x2; static final int ApplicationActive = 0x4; } - public static class ApplicationStateDetails { + static class ApplicationStateDetails { int state = ApplicationState.ApplicationSuspended; boolean nativePluginIntegrationReady = false; boolean isStarted = false; } - public static ApplicationStateDetails getStateDetails() + static ApplicationStateDetails getStateDetails() { return m_stateDetails; } - public static void setStarted(boolean started) + static void setStarted(boolean started) { m_stateDetails.isStarted = started; notifyAppStateDetailsChanged(m_stateDetails); } @UsedFromNativeCode - public static void notifyNativePluginIntegrationReady(boolean ready) + static void notifyNativePluginIntegrationReady(boolean ready) { m_stateDetails.nativePluginIntegrationReady = ready; notifyNativePluginIntegrationReadyChanged(ready); notifyAppStateDetailsChanged(m_stateDetails); } - public static void setApplicationState(int state) + static void setApplicationState(int state) { synchronized (m_mainActivityMutex) { m_stateDetails.state = state; @@ -276,12 +277,12 @@ class QtNative // Post a runnable to Main (UI) Thread if the app is active, // otherwise, queue it to be posted when the the app is active again - public static void runAction(Runnable action) + static void runAction(Runnable action) { runAction(action, true); } - public static void runAction(Runnable action, boolean queueWhenInactive) + static void runAction(Runnable action, boolean queueWhenInactive) { synchronized (m_mainActivityMutex) { final Looper mainLooper = Looper.getMainLooper(); @@ -328,7 +329,7 @@ class QtNative runAction(() -> view.setVisibility(visible ? View.VISIBLE : View.GONE)); } - public static void startApplication(String params, String mainLib) + static void startApplication(String params, String mainLib) { synchronized (m_mainActivityMutex) { m_qtThread.run(() -> { @@ -343,7 +344,7 @@ class QtNative } } - public static void quitApp() + static void quitApp() { runAction(() -> { quitQtAndroidPlugin(); @@ -357,7 +358,7 @@ class QtNative } @UsedFromNativeCode - public static int checkSelfPermission(String permission) + static int checkSelfPermission(String permission) { synchronized (m_mainActivityMutex) { Context context = getContext(); @@ -419,47 +420,43 @@ class QtNative } // application methods - public static native boolean startQtAndroidPlugin(String params); - public static native void startQtApplication(); - public static native void waitForServiceSetup(); - public static native void quitQtCoreApplication(); - public static native void quitQtAndroidPlugin(); - public static native void terminateQt(); - public static native boolean updateNativeActivity(); + static native boolean startQtAndroidPlugin(String params); + static native void startQtApplication(); + static native void waitForServiceSetup(); + static native void quitQtCoreApplication(); + static native void quitQtAndroidPlugin(); + static native void terminateQt(); + static native boolean updateNativeActivity(); // application methods - // surface methods - public static native void setSurface(int id, Object surface); - // surface methods - // window methods - public static native void updateWindow(); + static native void updateWindow(); // window methods // application methods - public static native void updateApplicationState(int state); + static native void updateApplicationState(int state); // menu methods - public static native boolean onPrepareOptionsMenu(Menu menu); - public static native boolean onOptionsItemSelected(int itemId, boolean checked); - public static native void onOptionsMenuClosed(Menu menu); - - public static native void onCreateContextMenu(ContextMenu menu); - public static native void fillContextMenu(Menu menu); - public static native boolean onContextItemSelected(int itemId, boolean checked); - public static native void onContextMenuClosed(Menu menu); + static native boolean onPrepareOptionsMenu(Menu menu); + static native boolean onOptionsItemSelected(int itemId, boolean checked); + static native void onOptionsMenuClosed(Menu menu); + + static native void onCreateContextMenu(ContextMenu menu); + static native void fillContextMenu(Menu menu); + static native boolean onContextItemSelected(int itemId, boolean checked); + static native void onContextMenuClosed(Menu menu); // menu methods // activity methods - public static native void onActivityResult(int requestCode, int resultCode, Intent data); + static native void onActivityResult(int requestCode, int resultCode, Intent data); public static native void onNewIntent(Intent data); - public static native void runPendingCppRunnables(); + static native void runPendingCppRunnables(); - public static native void sendRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults); + static native void sendRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults); // activity methods // service methods - public static native IBinder onBind(Intent intent); + static native IBinder onBind(Intent intent); // service methods } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java index 3dae587a71..21f4e635d1 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtRootLayout.java @@ -16,33 +16,15 @@ import android.view.Surface; A layout which corresponds to one Activity, i.e. is the root layout where the top level window and handles orientation changes. */ -public class QtRootLayout extends QtLayout +class QtRootLayout extends QtLayout { - private int m_activityDisplayRotation = -1; - private int m_ownDisplayRotation = -1; - private int m_nativeOrientation = -1; private int m_previousRotation = -1; - public QtRootLayout(Context context) + QtRootLayout(Context context) { super(context); } - public void setActivityDisplayRotation(int rotation) - { - m_activityDisplayRotation = rotation; - } - - public void setNativeOrientation(int orientation) - { - m_nativeOrientation = orientation; - } - - public int displayRotation() - { - return m_ownDisplayRotation; - } - @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) { @@ -50,25 +32,6 @@ public class QtRootLayout extends QtLayout if (activity == null) return; - DisplayMetrics realMetrics = new DisplayMetrics(); - Display display = (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) - ? activity.getWindowManager().getDefaultDisplay() - : activity.getDisplay(); - - if (display == null) - return; - - 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. - return; - } QtDisplayManager.setApplicationDisplayMetrics(activity, w, h); QtDisplayManager.handleOrientationChanges(activity); } @@ -88,7 +51,7 @@ public class QtRootLayout extends QtLayout } } - public boolean isSameSizeForOrientations(int r1, int r2) { + boolean isSameSizeForOrientations(int r1, int r2) { return (r1 == r2) || (r1 == Surface.ROTATION_0 && r2 == Surface.ROTATION_180) || (r1 == Surface.ROTATION_180 && r2 == Surface.ROTATION_0) diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java index 29f1d1790f..d8af626ca0 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceEmbeddedDelegate.java @@ -28,13 +28,8 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App m_service = service; QtNative.registerAppStateListener(this); QtNative.setService(service); - } - - @UsedFromNativeCode - QtInputDelegate getInputDelegate() - { - // TODO Implement text input (QTBUG-122552) - return null; + // QTBUG-122920 TODO Implement accessibility for service UIs + // QTBUG-122552 TODO Implement text input } @Override @@ -107,6 +102,7 @@ class QtServiceEmbeddedDelegate implements QtEmbeddedViewInterface, QtNative.App { QtNative.setApplicationState(ApplicationSuspended); QtNative.unregisterAppStateListener(QtServiceEmbeddedDelegate.this); + QtEmbeddedViewInterfaceFactory.remove(m_service); QtNative.terminateQt(); QtNative.setService(null); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java index ce74ec21e7..751519f045 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceLoader.java @@ -11,7 +11,7 @@ import android.util.Log; class QtServiceLoader extends QtLoader { private final Service m_service; - public QtServiceLoader(Service service) { + QtServiceLoader(Service service) { super(new ContextWrapper(service)); m_service = service; diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java index 3165de4811..f4ca3947d4 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtSurface.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtSurface.java @@ -14,9 +14,9 @@ import android.view.SurfaceView; @SuppressLint("ViewConstructor") class QtSurface extends SurfaceView implements SurfaceHolder.Callback { - private QtSurfaceInterface m_surfaceCallback; + private final QtSurfaceInterface m_surfaceCallback; - public QtSurface(Context context, QtSurfaceInterface surfaceCallback, boolean onTop, int imageDepth) + QtSurface(Context context, QtSurfaceInterface surfaceCallback, boolean onTop, int imageDepth) { super(context); setFocusable(false); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java index 8df442f730..5850f2e3a1 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtSurfaceInterface.java @@ -6,8 +6,7 @@ package org.qtproject.qt.android; import android.view.Surface; - -public interface QtSurfaceInterface +interface QtSurfaceInterface { void onSurfaceChanged(Surface surface); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java b/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java index 828838a9f0..67a533b55b 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtTextureView.java @@ -5,19 +5,18 @@ package org.qtproject.qt.android; import android.content.Context; -import android.graphics.PixelFormat; import android.graphics.SurfaceTexture; import android.util.Log; import android.view.Surface; import android.view.TextureView; -public class QtTextureView extends TextureView implements TextureView.SurfaceTextureListener +class QtTextureView extends TextureView implements TextureView.SurfaceTextureListener { - private QtSurfaceInterface m_surfaceCallback; + private final QtSurfaceInterface m_surfaceCallback; private boolean m_staysOnTop; private Surface m_surface; - public QtTextureView(Context context, QtSurfaceInterface surfaceCallback, boolean isOpaque) + QtTextureView(Context context, QtSurfaceInterface surfaceCallback, boolean isOpaque) { super(context); setFocusable(false); diff --git a/src/android/jar/src/org/qtproject/qt/android/QtThread.java b/src/android/jar/src/org/qtproject/qt/android/QtThread.java index 0943ad3265..aacefe0ee1 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtThread.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtThread.java @@ -35,14 +35,14 @@ class QtThread { m_qtThread.start(); } - public void post(final Runnable runnable) { + void post(final Runnable runnable) { synchronized (m_qtThread) { m_pendingRunnables.add(runnable); m_qtThread.notify(); } } - public void sleep(int milliseconds) { + void sleep(int milliseconds) { try { m_qtThread.sleep(milliseconds); } catch (InterruptedException e) { @@ -50,7 +50,7 @@ class QtThread { } } - public void run(final Runnable runnable) { + void run(final Runnable runnable) { final Semaphore sem = new Semaphore(0); synchronized (m_qtThread) { m_pendingRunnables.add(() -> { @@ -66,7 +66,7 @@ class QtThread { } } - public void exit() + void exit() { m_exit = true; synchronized (m_qtThread) { diff --git a/src/android/jar/src/org/qtproject/qt/android/QtView.java b/src/android/jar/src/org/qtproject/qt/android/QtView.java index ddf70b3b5b..cf06ce5e3d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtView.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtView.java @@ -21,7 +21,7 @@ import java.util.ArrayList; abstract class QtView extends ViewGroup { private final static String TAG = "QtView"; - public interface QtWindowListener { + interface QtWindowListener { // Called when the QWindow has been created and it's Java counterpart embedded into // QtView void onQtWindowLoaded(); @@ -44,24 +44,15 @@ abstract class QtView extends ViewGroup { private static native void resizeWindow(long windowReference, int x, int y, int width, int height); - /** - * Create QtView for embedding a QWindow. Instantiating a QtView will load the Qt libraries - * if they have not already been loaded, including the app library specified by appName, and - * starting the said Qt app. - * @param context the hosting Context - * @param appLibName the name of the Qt app library to load and start. This corresponds to the - target name set in Qt app's CMakeLists.txt - **/ - public QtView(Context context, String appLibName) throws InvalidParameterException { + /** + * Create a QtView for embedding a QWindow without loading the Qt libraries or starting + * the Qt app. + * @param context the hosting Context + **/ + QtView(Context context) { super(context); - if (appLibName == null || appLibName.isEmpty()) { - throw new InvalidParameterException("QtView: argument 'appLibName' may not be empty "+ - "or null"); - } - QtEmbeddedLoader loader = new QtEmbeddedLoader(context); - m_viewInterface = QtEmbeddedDelegateFactory.create((Activity)context); - loader.setMainLibraryName(appLibName); + m_viewInterface = QtEmbeddedViewInterfaceFactory.create(context); addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, @@ -78,10 +69,22 @@ abstract class QtView extends ViewGroup { } } }); - loader.loadQtLibraries(); - // Start Native Qt application - m_viewInterface.startQtApplication(loader.getApplicationParameters(), - loader.getMainLibraryPath()); + } + /** + * Create a QtView for embedding a QWindow, and load the Qt libraries if they have not already + * been loaded, including the app library specified by appName, and starting the said Qt app. + * @param context the hosting Context + * @param appLibName the name of the Qt app library to load and start. This corresponds to the + target name set in Qt app's CMakeLists.txt + **/ + QtView(Context context, String appLibName) throws InvalidParameterException { + this(context); + if (appLibName == null || appLibName.isEmpty()) { + throw new InvalidParameterException("QtView: argument 'appLibName' may not be empty "+ + "or null"); + } + + loadQtLibraries(appLibName); } @Override @@ -135,10 +138,19 @@ abstract class QtView extends ViewGroup { } - public void setQtWindowListener(QtWindowListener listener) { + void setQtWindowListener(QtWindowListener listener) { m_windowListener = listener; } + void loadQtLibraries(String appLibName) { + QtEmbeddedLoader loader = new QtEmbeddedLoader(getContext()); + loader.setMainLibraryName(appLibName); + loader.loadQtLibraries(); + // Start Native Qt application + m_viewInterface.startQtApplication(loader.getApplicationParameters(), + loader.getMainLibraryPath()); + } + void setWindowReference(long windowReference) { m_windowReference = windowReference; } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java index d72e69d32a..3b8fe4b1e9 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java @@ -6,7 +6,6 @@ package org.qtproject.qt.android; import android.content.Context; import android.view.GestureDetector; import android.view.MotionEvent; -import android.util.Log; import android.view.Surface; import android.view.View; import android.view.ViewGroup; @@ -14,11 +13,9 @@ import android.view.ViewGroup; import java.util.HashMap; class QtWindow extends QtLayout implements QtSurfaceInterface { - private final static String TAG = "QtWindow"; - private View m_surfaceContainer; private View m_nativeView; - private HashMap<Integer, QtWindow> m_childWindows = new HashMap<Integer, QtWindow>(); + private final HashMap<Integer, QtWindow> m_childWindows = new HashMap<>(); private QtWindow m_parentWindow; private GestureDetector m_gestureDetector; private final QtEditText m_editText; @@ -26,11 +23,12 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { private static native void setSurface(int windowId, Surface surface); static native void windowFocusChanged(boolean hasFocus, int id); - public QtWindow(Context context, QtWindow parentWindow, QtInputDelegate delegate) + QtWindow(Context context, QtWindow parentWindow, + QtInputConnection.QtInputConnectionListener listener) { super(context); setId(View.generateViewId()); - m_editText = new QtEditText(context, delegate); + m_editText = new QtEditText(context, listener); setParent(parentWindow); setFocusableInTouchMode(true); addView(m_editText, new QtLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, @@ -39,6 +37,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { QtNative.runAction(() -> { m_gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override public void onLongPress(MotionEvent event) { QtInputDelegate.longPress(getId(), (int) event.getX(), (int) event.getY()); } @@ -47,6 +46,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } + @UsedFromNativeCode void setVisible(boolean visible) { QtNative.runAction(() -> { if (visible) @@ -85,13 +85,15 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { return QtInputDelegate.sendGenericMotionEvent(event, getId()); } - public void removeWindow() + @UsedFromNativeCode + void removeWindow() { if (m_parentWindow != null) m_parentWindow.removeChildWindow(getId()); } - public void createSurface(final boolean onTop, + @UsedFromNativeCode + void createSurface(final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth, final boolean isOpaque, final int surfaceContainerType) // TODO constant for type @@ -116,7 +118,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void destroySurface() + @UsedFromNativeCode + void destroySurface() { QtNative.runAction(()-> { if (m_surfaceContainer != null) { @@ -126,7 +129,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }, false); } - public void setGeometry(final int x, final int y, final int w, final int h) + @UsedFromNativeCode + void setGeometry(final int x, final int y, final int w, final int h) { QtNative.runAction(()-> { if (getContext() instanceof QtActivityBase) @@ -134,7 +138,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void addChildWindow(QtWindow window) + void addChildWindow(QtWindow window) { QtNative.runAction(()-> { m_childWindows.put(window.getId(), window); @@ -142,7 +146,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void removeChildWindow(int id) + void removeChildWindow(int id) { QtNative.runAction(()-> { if (m_childWindows.containsKey(id)) @@ -150,7 +154,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void setNativeView(final View view, + @UsedFromNativeCode + void setNativeView(final View view, final int x, final int y, final int w, final int h) { QtNative.runAction(()-> { @@ -165,7 +170,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void bringChildToFront(int id) + @UsedFromNativeCode + void bringChildToFront(int id) { QtNative.runAction(()-> { View view = m_childWindows.get(id); @@ -176,7 +182,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void bringChildToBack(int id) { + @UsedFromNativeCode + void bringChildToBack(int id) { QtNative.runAction(()-> { View view = m_childWindows.get(id); if (view != null) { @@ -185,7 +192,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { }); } - public void removeNativeView() + @UsedFromNativeCode + void removeNativeView() { QtNative.runAction(()-> { if (m_nativeView != null) { @@ -207,9 +215,4 @@ class QtWindow extends QtLayout implements QtSurfaceInterface { if (m_parentWindow != null) m_parentWindow.addChildWindow(this); } - - QtWindow parent() - { - return m_parentWindow; - } } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java b/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java new file mode 100644 index 0000000000..1fb312786f --- /dev/null +++ b/src/android/jar/src/org/qtproject/qt/android/QtWindowInterface.java @@ -0,0 +1,11 @@ +// Copyright (C) 2024 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; +@UsedFromNativeCode +interface QtWindowInterface { + default void addTopLevelWindow(final QtWindow window) { } + default void removeTopLevelWindow(final int id) { } + default void bringChildToFront(final int id) { } + default void bringChildToBack(int id) { } + default void setSystemUiVisibility(int systemUiVisibility) { } +} diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java index bd837570fe..31a0d68c0a 100644 --- a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java +++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidBinder.java @@ -11,12 +11,12 @@ import org.qtproject.qt.android.UsedFromNativeCode; class QtAndroidBinder extends Binder { @UsedFromNativeCode - public QtAndroidBinder(long id) + QtAndroidBinder(long id) { m_id = id; } - public void setId(long id) + void setId(long id) { synchronized(this) { diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java index b70b64e3ac..fbf9232204 100644 --- a/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java +++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java @@ -12,12 +12,12 @@ import org.qtproject.qt.android.UsedFromNativeCode; class QtAndroidServiceConnection implements ServiceConnection { @UsedFromNativeCode - public QtAndroidServiceConnection(long id) + QtAndroidServiceConnection(long id) { m_id = id; } - public void setId(long id) + void setId(long id) { synchronized(this) { diff --git a/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java b/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java index f7ba8dd9b4..bec30c7e7e 100644 --- a/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/extras/QtNative.java @@ -8,10 +8,10 @@ import android.os.Parcel; class QtNative { // Binder - public static native boolean onTransact(long id, int code, Parcel data, Parcel reply, int flags); + static native boolean onTransact(long id, int code, Parcel data, Parcel reply, int flags); // ServiceConnection - public static native void onServiceConnected(long id, String name, IBinder service); - public static native void onServiceDisconnected(long id, String name); + static native void onServiceConnected(long id, String name, IBinder service); + static native void onServiceDisconnected(long id, String name); } |