Android: don't call delegates outside of the Activity

The delegate classes shouldn't be used outside of the Activity/Service
classes, since they're practically private implementation, so don't use
them anywhere outside Activity/Service.

Since Qt Android apps still mainly support having one QtActivity/
QtService, QtNative heavily uses those objects to do various operations.
For that reason, we still need to use the delegate there. The aim is
to change that in future patches and do the operations where they make
more sense for example directly under QtActivityBase/QtActivityDelegate
or Service counterpart.

The QtServiceDelegate is used no where and have no special
implementation, so it's removed here.

Task-number: QTBUG-118077
Change-Id: I5e106318169be19fec8163e8e500ee573af0e1bc
Reviewed-by: Tinja Paavoseppä <tinja.paavoseppa@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Assam Boudjelthia 2023-09-17 23:13:04 +03:00
parent 19baa077d9
commit f5e2302851
15 changed files with 351 additions and 460 deletions

View File

@ -12,7 +12,6 @@ set(java_sources
src/org/qtproject/qt/android/QtActivityBase.java src/org/qtproject/qt/android/QtActivityBase.java
src/org/qtproject/qt/android/QtServiceBase.java src/org/qtproject/qt/android/QtServiceBase.java
src/org/qtproject/qt/android/QtActivityDelegate.java src/org/qtproject/qt/android/QtActivityDelegate.java
src/org/qtproject/qt/android/QtServiceDelegate.java
src/org/qtproject/qt/android/QtInputDelegate.java src/org/qtproject/qt/android/QtInputDelegate.java
src/org/qtproject/qt/android/QtLoader.java src/org/qtproject/qt/android/QtLoader.java
src/org/qtproject/qt/android/QtActivityLoader.java src/org/qtproject/qt/android/QtActivityLoader.java

View File

@ -173,7 +173,7 @@ public class QtActivityBase extends Activity
super.onDestroy(); super.onDestroy();
if (m_delegate.isQuitApp()) { if (m_delegate.isQuitApp()) {
QtNative.terminateQt(); QtNative.terminateQt();
QtNative.setActivity(null, null); QtNative.setActivity(null);
QtNative.m_qtThread.exit(); QtNative.m_qtThread.exit();
System.exit(0); System.exit(0);
} }
@ -325,6 +325,11 @@ public class QtActivityBase extends Activity
QtNative.sendRequestPermissionsResult(requestCode, permissions, grantResults); QtNative.sendRequestPermissionsResult(requestCode, permissions, grantResults);
} }
public void hideSplashScreen(final int duration)
{
m_delegate.hideSplashScreen(duration);
}
QtActivityDelegate getActivityDelegate() QtActivityDelegate getActivityDelegate()
{ {
return m_delegate; return m_delegate;

View File

@ -6,7 +6,6 @@
package org.qtproject.qt.android; package org.qtproject.qt.android;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration; import android.content.res.Configuration;
@ -27,7 +26,6 @@ import android.view.ViewConfiguration;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
import android.view.WindowInsetsController; import android.view.WindowInsetsController;
import android.view.inputmethod.InputMethodManager;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
@ -56,34 +54,36 @@ public class QtActivityDelegate
private QtAccessibilityDelegate m_accessibilityDelegate = null; private QtAccessibilityDelegate m_accessibilityDelegate = null;
private final QtDisplayManager m_displayManager = new QtDisplayManager(); private final QtDisplayManager m_displayManager = new QtDisplayManager();
private QtInputDelegate.KeyboardVisibilityListener m_keyboardVisibilityListener = private QtInputDelegate m_inputDelegate = null;
QtActivityDelegate(Activity activity)
{
m_activity = activity;
QtNative.setActivity(m_activity);
setActionBarVisibility(false);
m_displayManager.registerDisplayListener(m_activity, m_layout);
QtInputDelegate.KeyboardVisibilityListener keyboardVisibilityListener =
new QtInputDelegate.KeyboardVisibilityListener() { new QtInputDelegate.KeyboardVisibilityListener() {
@Override @Override
public void onKeyboardVisibilityChange() { public void onKeyboardVisibilityChange() {
m_displayManager.updateFullScreen(m_activity); m_displayManager.updateFullScreen(m_activity);
} }
}; };
private final QtInputDelegate m_inputDelegate = new QtInputDelegate(m_keyboardVisibilityListener); m_inputDelegate = new QtInputDelegate(m_activity, keyboardVisibilityListener);
QtActivityDelegate(Activity activity)
{
m_activity = activity;
QtNative.setActivity(m_activity, this);
setActionBarVisibility(false);
try { try {
m_inputDelegate.setSoftInputMode(m_activity.getPackageManager() PackageManager pm = m_activity.getPackageManager();
.getActivityInfo(m_activity.getComponentName(), 0).softInputMode); ActivityInfo activityInfo = pm.getActivityInfo(m_activity.getComponentName(), 0);
m_inputDelegate.setSoftInputMode(activityInfo.softInputMode);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
m_displayManager.registerDisplayListener(m_activity, m_layout);
} }
QtDisplayManager displayManager() QtDisplayManager displayManager() {
{
return m_displayManager; return m_displayManager;
} }
@ -147,7 +147,7 @@ public class QtActivityDelegate
try { try {
// set new activity // set new activity
m_activity = activity; m_activity = activity;
QtNative.setActivity(m_activity, this); QtNative.setActivity(m_activity);
// update the new activity content view to old layout // update the new activity content view to old layout
ViewGroup layoutParent = (ViewGroup) m_layout.getParent(); ViewGroup layoutParent = (ViewGroup) m_layout.getParent();
@ -220,8 +220,6 @@ public class QtActivityDelegate
e.printStackTrace(); e.printStackTrace();
} }
m_inputDelegate.setEditText(new QtEditText(m_activity));
m_inputDelegate.setInputMethodManager((InputMethodManager)m_activity.getSystemService(Context.INPUT_METHOD_SERVICE));
m_surfaces = new HashMap<Integer, QtSurface>(); m_surfaces = new HashMap<Integer, QtSurface>();
m_nativeViews = new HashMap<Integer, View>(); m_nativeViews = new HashMap<Integer, View>();
m_activity.registerForContextMenu(m_layout); m_activity.registerForContextMenu(m_layout);
@ -273,6 +271,9 @@ public class QtActivityDelegate
public void hideSplashScreen(final int duration) public void hideSplashScreen(final int duration)
{ {
QtNative.runAction(new Runnable() {
@Override
public void run() {
if (m_splashScreen == null) if (m_splashScreen == null)
return; return;
@ -288,17 +289,23 @@ public class QtActivityDelegate
fadeOut.setAnimationListener(new Animation.AnimationListener() { fadeOut.setAnimationListener(new Animation.AnimationListener() {
@Override @Override
public void onAnimationEnd(Animation animation) { hideSplashScreen(0); } public void onAnimationEnd(Animation animation) {
hideSplashScreen(0);
}
@Override @Override
public void onAnimationRepeat(Animation animation) {} public void onAnimationRepeat(Animation animation) {
}
@Override @Override
public void onAnimationStart(Animation animation) {} public void onAnimationStart(Animation animation) {
}
}); });
m_splashScreen.startAnimation(fadeOut); m_splashScreen.startAnimation(fadeOut);
} }
});
}
public void notifyLocationChange(int viewId) public void notifyLocationChange(int viewId)
{ {
@ -381,8 +388,23 @@ public class QtActivityDelegate
public void resetOptionsMenu() public void resetOptionsMenu()
{ {
QtNative.runAction(new Runnable() {
@Override
public void run() {
m_activity.invalidateOptionsMenu(); m_activity.invalidateOptionsMenu();
} }
});
}
public void openOptionsMenu()
{
QtNative.runAction(new Runnable() {
@Override
public void run() {
m_activity.openOptionsMenu();
}
});
}
private boolean m_contextMenuVisible = false; private boolean m_contextMenuVisible = false;
@ -419,8 +441,13 @@ public class QtActivityDelegate
public void closeContextMenu() public void closeContextMenu()
{ {
QtNative.runAction(new Runnable() {
@Override
public void run() {
m_activity.closeContextMenu(); m_activity.closeContextMenu();
} }
});
}
void setActionBarVisibility(boolean visible) void setActionBarVisibility(boolean visible)
{ {
@ -433,6 +460,9 @@ public class QtActivityDelegate
} }
public void insertNativeView(int id, View view, int x, int y, int w, int h) { public void insertNativeView(int id, View view, int x, int y, int w, int h) {
QtNative.runAction(new Runnable() {
@Override
public void run() {
if (m_dummyView != null) { if (m_dummyView != null) {
m_layout.removeView(m_dummyView); m_layout.removeView(m_dummyView);
m_dummyView = null; m_dummyView = null;
@ -452,8 +482,13 @@ public class QtActivityDelegate
m_layout.addView(view); m_layout.addView(view);
m_nativeViews.put(id, view); m_nativeViews.put(id, view);
} }
});
}
public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) { public void createSurface(int id, boolean onTop, int x, int y, int w, int h, int imageDepth) {
QtNative.runAction(new Runnable() {
@Override
public void run() {
if (m_surfaces.size() == 0) { if (m_surfaces.size() == 0) {
TypedValue attr = new TypedValue(); TypedValue attr = new TypedValue();
m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true); m_activity.getTheme().resolveAttribute(android.R.attr.windowBackground, attr, true);
@ -488,8 +523,13 @@ public class QtActivityDelegate
if (!m_splashScreenSticky) if (!m_splashScreenSticky)
hideSplashScreen(); hideSplashScreen();
} }
});
}
public void setSurfaceGeometry(int id, int x, int y, int w, int h) { public void setSurfaceGeometry(int id, int x, int y, int w, int h) {
QtNative.runAction(new Runnable() {
@Override
public void run() {
if (m_surfaces.containsKey(id)) { if (m_surfaces.containsKey(id)) {
QtSurface surface = m_surfaces.get(id); QtSurface surface = m_surfaces.get(id);
surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y)); surface.setLayoutParams(new QtLayout.LayoutParams(w, h, x, y));
@ -501,8 +541,13 @@ public class QtActivityDelegate
return; return;
} }
} }
});
}
public void destroySurface(int id) { public void destroySurface(int id) {
QtNative.runAction(new Runnable() {
@Override
public void run() {
View view = null; View view = null;
if (m_surfaces.containsKey(id)) { if (m_surfaces.containsKey(id)) {
@ -524,6 +569,8 @@ public class QtActivityDelegate
m_layout.removeView(view); m_layout.removeView(view);
} }
} }
});
}
public int getSurfaceCount() public int getSurfaceCount()
{ {
@ -532,6 +579,9 @@ public class QtActivityDelegate
public void bringChildToFront(int id) public void bringChildToFront(int id)
{ {
QtNative.runAction(new Runnable() {
@Override
public void run() {
View view = m_surfaces.get(id); View view = m_surfaces.get(id);
if (view != null) { if (view != null) {
final int surfaceCount = getSurfaceCount(); final int surfaceCount = getSurfaceCount();
@ -544,9 +594,14 @@ public class QtActivityDelegate
if (view != null) if (view != null)
m_layout.moveChild(view, -1); m_layout.moveChild(view, -1);
} }
});
}
public void bringChildToBack(int id) public void bringChildToBack(int id)
{ {
QtNative.runAction(new Runnable() {
@Override
public void run() {
View view = m_surfaces.get(id); View view = m_surfaces.get(id);
if (view != null) { if (view != null) {
m_layout.moveChild(view, 0); m_layout.moveChild(view, 0);
@ -559,4 +614,6 @@ public class QtActivityDelegate
m_layout.moveChild(view, index); m_layout.moveChild(view, index);
} }
} }
});
}
} }

View File

@ -10,6 +10,8 @@ import android.view.View;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnection;
import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
public class QtEditText extends View public class QtEditText extends View
{ {
int m_initialCapsMode = 0; int m_initialCapsMode = 0;
@ -17,6 +19,13 @@ public class QtEditText extends View
int m_inputType = InputType.TYPE_CLASS_TEXT; int m_inputType = InputType.TYPE_CLASS_TEXT;
boolean m_optionsChanged = false; boolean m_optionsChanged = false;
private QtInputConnectionListener m_qtInputConnectionListener;
public void setQtInputConnectionListener(QtInputConnectionListener listener)
{
m_qtInputConnectionListener = listener;
}
public void setImeOptions(int m_imeOptions) public void setImeOptions(int m_imeOptions)
{ {
if (m_imeOptions == this.m_imeOptions) if (m_imeOptions == this.m_imeOptions)
@ -56,7 +65,7 @@ public class QtEditText extends View
outAttrs.imeOptions = m_imeOptions; outAttrs.imeOptions = m_imeOptions;
outAttrs.initialCapsMode = m_initialCapsMode; outAttrs.initialCapsMode = m_initialCapsMode;
outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI; outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI;
return new QtInputConnection(this); return new QtInputConnection(this, m_qtInputConnectionListener);
} }
// // DEBUG CODE // // DEBUG CODE

View File

@ -51,9 +51,19 @@ class QtNativeInputConnection
static native boolean updateCursorPosition(); static native boolean updateCursorPosition();
} }
class HideKeyboardRunnable implements Runnable { public class QtInputConnection extends BaseInputConnection
private long m_hideTimeStamp = System.nanoTime(); {
private static final int ID_SELECT_ALL = android.R.id.selectAll;
private static final int ID_CUT = android.R.id.cut;
private static final int ID_COPY = android.R.id.copy;
private static final int ID_PASTE = android.R.id.paste;
private static final int ID_COPY_URL = android.R.id.copyUrl;
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
private final QtInputConnectionListener m_qtInputConnectionListener;
class HideKeyboardRunnable implements Runnable {
@Override @Override
public void run() { public void run() {
// Check that the keyboard is really no longer there. // Check that the keyboard is really no longer there.
@ -72,35 +82,31 @@ class HideKeyboardRunnable implements Runnable {
} }
final int kbHeight = screenHeight - r.bottom; final int kbHeight = screenHeight - r.bottom;
if (kbHeight < 100) if (kbHeight < 100)
QtNative.activityDelegate().getInputDelegate().setKeyboardVisibility(false, m_hideTimeStamp); m_qtInputConnectionListener.onHideKeyboardRunnableDone(false, System.nanoTime());
} }
} }
public class QtInputConnection extends BaseInputConnection public interface QtInputConnectionListener {
{ void onSetClosing(boolean closing);
private static final int ID_SELECT_ALL = android.R.id.selectAll; void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp);
private static final int ID_CUT = android.R.id.cut; void onSendKeyEventDefaultCase();
private static final int ID_COPY = android.R.id.copy; }
private static final int ID_PASTE = android.R.id.paste;
private static final int ID_COPY_URL = android.R.id.copyUrl;
private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod;
private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary;
private QtEditText m_view = null; private QtEditText m_view = null;
private void setClosing(boolean closing) private void setClosing(boolean closing)
{ {
if (closing) { if (closing)
m_view.postDelayed(new HideKeyboardRunnable(), 100); m_view.postDelayed(new HideKeyboardRunnable(), 100);
} else { else
QtNative.activityDelegate().getInputDelegate().setKeyboardVisibility(true, System.nanoTime()); m_qtInputConnectionListener.onSetClosing(false);
}
} }
public QtInputConnection(QtEditText targetView) public QtInputConnection(QtEditText targetView, QtInputConnectionListener listener)
{ {
super(targetView, true); super(targetView, true);
m_view = targetView; m_view = targetView;
m_qtInputConnectionListener = listener;
} }
@Override @Override
@ -256,7 +262,7 @@ public class QtInputConnection extends BaseInputConnection
break; break;
default: default:
QtNative.activityDelegate().getInputDelegate().hideSoftwareKeyboard(); m_qtInputConnectionListener.onSendKeyEventDefaultCase();
break; break;
} }
} }

View File

@ -4,6 +4,7 @@
package org.qtproject.qt.android; package org.qtproject.qt.android;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
@ -17,6 +18,8 @@ import android.view.MotionEvent;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import org.qtproject.qt.android.QtInputConnection.QtInputConnectionListener;
public class QtInputDelegate { public class QtInputDelegate {
// keyboard methods // keyboard methods
@ -96,7 +99,7 @@ public class QtInputDelegate {
private int m_lastChar = 0; private int m_lastChar = 0;
private boolean m_backKeyPressedSent = false; private boolean m_backKeyPressedSent = false;
// Note: because of the circular call to updateFullScreen() from QtActivityDelegate, we need // 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 // a listener to be able to do that call from the delegate, because that's where that
// logic lives // logic lives
public interface KeyboardVisibilityListener { public interface KeyboardVisibilityListener {
@ -105,9 +108,29 @@ public class QtInputDelegate {
private final KeyboardVisibilityListener m_keyboardVisibilityListener; private final KeyboardVisibilityListener m_keyboardVisibilityListener;
QtInputDelegate(KeyboardVisibilityListener listener) QtInputDelegate(Activity activity, KeyboardVisibilityListener listener)
{ {
this.m_keyboardVisibilityListener = listener; this.m_keyboardVisibilityListener = listener;
m_editText = new QtEditText(activity);
m_imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
QtInputConnectionListener inputConnectionListener = new QtInputConnectionListener() {
@Override
public void onSetClosing(boolean closing) {
if (!closing)
setKeyboardVisibility(true, System.nanoTime());
}
@Override
public void onHideKeyboardRunnableDone(boolean visibility, long hideTimeStamp) {
setKeyboardVisibility(visibility, hideTimeStamp);
}
@Override
public void onSendKeyEventDefaultCase() {
hideSoftwareKeyboard();
}
};
m_editText.setQtInputConnectionListener(inputConnectionListener);
} }
public boolean isKeyboardVisible() public boolean isKeyboardVisible()
@ -131,16 +154,6 @@ public class QtInputDelegate {
return m_editText; return m_editText;
} }
void setEditText(QtEditText editText)
{
m_editText = editText;
}
void setInputMethodManager(InputMethodManager inputMethodManager)
{
m_imm = inputMethodManager;
}
void setEditPopupMenu(EditPopupMenu editPopupMenu) void setEditPopupMenu(EditPopupMenu editPopupMenu)
{ {
m_editPopupMenu = editPopupMenu; m_editPopupMenu = editPopupMenu;

View File

@ -54,11 +54,10 @@ import android.graphics.Rect;
public class QtNative public class QtNative
{ {
// TODO get rid of the delegation from QtNative, call directly the Activity in c++
private static Activity m_activity = null; private static Activity m_activity = null;
private static boolean m_activityPaused = false; private static boolean m_activityPaused = false;
private static Service m_service = null; private static Service m_service = null;
private static QtActivityDelegate m_activityDelegate = null;
private static QtServiceDelegate m_serviceDelegate = null;
public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations public static Object m_mainActivityMutex = new Object(); // mutex used to synchronize runnable operations
public static final String QtTAG = "Qt JAVA"; // string used for Log.x public static final String QtTAG = "Qt JAVA"; // string used for Log.x
@ -81,8 +80,8 @@ public class QtNative
public static boolean isStarted() public static boolean isStarted()
{ {
boolean hasActivity = m_activity != null && m_activityDelegate != null; boolean hasActivity = m_activity != null;
boolean hasService = m_service != null && m_serviceDelegate != null; boolean hasService = m_service != null;
return m_started && (hasActivity || hasService); return m_started && (hasActivity || hasService);
} }
@ -111,21 +110,6 @@ public class QtNative
} }
} }
public static QtActivityDelegate activityDelegate()
{
synchronized (m_mainActivityMutex) {
return m_activityDelegate;
}
}
public static QtServiceDelegate serviceDelegate()
{
synchronized (m_mainActivityMutex) {
return m_serviceDelegate;
}
}
public static String[] getStringArray(String joinedString) public static String[] getStringArray(String joinedString)
{ {
return joinedString.split(","); return joinedString.split(",");
@ -204,19 +188,17 @@ public class QtNative
return m_qtThread; return m_qtThread;
} }
public static void setActivity(Activity qtMainActivity, QtActivityDelegate qtActivityDelegate) public static void setActivity(Activity qtMainActivity)
{ {
synchronized (m_mainActivityMutex) { synchronized (m_mainActivityMutex) {
m_activity = qtMainActivity; m_activity = qtMainActivity;
m_activityDelegate = qtActivityDelegate;
} }
} }
public static void setService(Service qtMainService, QtServiceDelegate qtServiceDelegate) public static void setService(Service qtMainService)
{ {
synchronized (m_mainActivityMutex) { synchronized (m_mainActivityMutex) {
m_service = qtMainService; m_service = qtMainService;
m_serviceDelegate = qtServiceDelegate;
} }
} }
@ -349,72 +331,6 @@ public class QtNative
return perm; return perm;
} }
// TODO get rid of the delegation from QtNative, call directly the Activity in c++
private static void setSystemUiVisibility(final int systemUiVisibility)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null) {
m_activityDelegate.setSystemUiVisibility(systemUiVisibility);
}
updateWindow();
}
});
}
public static void notifyQtAndroidPluginRunning(final boolean running)
{
if (m_activityDelegate != null)
m_activityDelegate.notifyQtAndroidPluginRunning(running);
}
private static void openContextMenu(final int x, final int y, final int w, final int h)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.openContextMenu(x, y, w, h);
}
});
}
private static void closeContextMenu()
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.closeContextMenu();
}
});
}
private static void resetOptionsMenu()
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.resetOptionsMenu();
}
});
}
private static void openOptionsMenu()
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activity != null)
m_activity.openOptionsMenu();
}
});
}
private static byte[][] getSSLCertificates() private static byte[][] getSSLCertificates()
{ {
ArrayList<byte[]> certificateList = new ArrayList<byte[]>(); ArrayList<byte[]> certificateList = new ArrayList<byte[]>();
@ -442,83 +358,6 @@ public class QtNative
return certificateArray; return certificateArray;
} }
private static void createSurface(final int id, final boolean onTop, final int x, final int y, final int w, final int h, final int imageDepth)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.createSurface(id, onTop, x, y, w, h, imageDepth);
}
});
}
private static void insertNativeView(final int id, final View view, final int x, final int y, final int w, final int h)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.insertNativeView(id, view, x, y, w, h);
}
});
}
private static void setSurfaceGeometry(final int id, final int x, final int y, final int w, final int h)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.setSurfaceGeometry(id, x, y, w, h);
}
});
}
private static void bringChildToFront(final int id)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.bringChildToFront(id);
}
});
}
private static void bringChildToBack(final int id)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.bringChildToBack(id);
}
});
}
private static void destroySurface(final int id)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.destroySurface(id);
}
});
}
private static void hideSplashScreen(final int duration)
{
runAction(new Runnable() {
@Override
public void run() {
if (m_activityDelegate != null)
m_activityDelegate.hideSplashScreen(duration);
}
});
}
private static String[] listAssetContent(android.content.res.AssetManager asset, String path) { private static String[] listAssetContent(android.content.res.AssetManager asset, String path) {
String [] list; String [] list;
ArrayList<String> res = new ArrayList<String>(); ArrayList<String> res = new ArrayList<String>();

View File

@ -9,15 +9,11 @@ import android.os.IBinder;
import android.util.Log; import android.util.Log;
public class QtServiceBase extends Service { public class QtServiceBase extends Service {
private QtServiceDelegate m_delegate;
@Override @Override
public void onCreate() public void onCreate()
{ {
super.onCreate(); super.onCreate();
m_delegate = new QtServiceDelegate(this);
// the application has already started, do not reload everything again // the application has already started, do not reload everything again
if (QtNative.isStarted()) { if (QtNative.isStarted()) {
Log.w(QtNative.QtTAG, Log.w(QtNative.QtTAG,
@ -38,7 +34,7 @@ public class QtServiceBase extends Service {
super.onDestroy(); super.onDestroy();
QtNative.quitQtCoreApplication(); QtNative.quitQtCoreApplication();
QtNative.terminateQt(); QtNative.terminateQt();
QtNative.setService(null, null); QtNative.setService(null);
QtNative.m_qtThread.exit(); QtNative.m_qtThread.exit();
System.exit(0); System.exit(0);
} }
@ -49,9 +45,4 @@ public class QtServiceBase extends Service {
return QtNative.onBind(intent); return QtNative.onBind(intent);
} }
} }
QtServiceDelegate getServiceDelegate()
{
return m_delegate;
}
} }

View File

@ -1,20 +0,0 @@
// Copyright (C) 2016 BogDan Vatra <bogdan@kde.org>
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
package org.qtproject.qt.android;
import android.app.Service;
public class QtServiceDelegate
{
private Service m_service = null;
QtServiceDelegate(Service service)
{
m_service = service;
// Set native context
QtNative.setService(m_service, this);
}
}

View File

@ -94,8 +94,7 @@ int QNativeInterface::QAndroidApplication::sdkVersion()
*/ */
void QNativeInterface::QAndroidApplication::hideSplashScreen(int duration) void QNativeInterface::QAndroidApplication::hideSplashScreen(int duration)
{ {
QJniObject::callStaticMethod<void>("org/qtproject/qt/android/QtNative", QtAndroidPrivate::activity().callMethod<void>("hideSplashScreen", duration);
"hideSplashScreen", "(I)V", duration);
} }
/*! /*!

View File

@ -45,9 +45,6 @@ static jmethodID m_loadClassMethodID = nullptr;
static AAssetManager *m_assetManager = nullptr; static AAssetManager *m_assetManager = nullptr;
static jobject m_assets = nullptr; static jobject m_assets = nullptr;
static jobject m_resourcesObj = nullptr; static jobject m_resourcesObj = nullptr;
static jmethodID m_createSurfaceMethodID = nullptr;
static jmethodID m_setSurfaceGeometryMethodID = nullptr;
static jmethodID m_destroySurfaceMethodID = nullptr;
static QtJniTypes::QtActivityDelegate m_activityDelegate = nullptr; static QtJniTypes::QtActivityDelegate m_activityDelegate = nullptr;
static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr; static QtJniTypes::QtInputDelegate m_inputDelegate = nullptr;
@ -165,7 +162,7 @@ namespace QtAndroid
// TODO move calls from here to where they logically belong // TODO move calls from here to where they logically belong
void setSystemUiVisibility(SystemUiVisibility uiVisibility) void setSystemUiVisibility(SystemUiVisibility uiVisibility)
{ {
QJniObject::callStaticMethod<void>(m_applicationClass, "setSystemUiVisibility", "(I)V", jint(uiVisibility)); qtActivityDelegate().callMethod<void>("setSystemUiVisibility", jint(uiVisibility));
} }
// FIXME: avoid direct access to QtActivityDelegate // FIXME: avoid direct access to QtActivityDelegate
@ -218,7 +215,7 @@ namespace QtAndroid
void notifyQtAndroidPluginRunning(bool running) void notifyQtAndroidPluginRunning(bool running)
{ {
QJniObject::callStaticMethod<void>(m_applicationClass, "notifyQtAndroidPluginRunning","(Z)V", running); qtActivityDelegate().callMethod<void>("notifyQtAndroidPluginRunning", running);
} }
jobject createBitmap(QImage img, JNIEnv *env) jobject createBitmap(QImage img, JNIEnv *env)
@ -338,12 +335,8 @@ namespace QtAndroid
w = std::max(geometry.width(), 1); w = std::max(geometry.width(), 1);
h = std::max(geometry.height(), 1); h = std::max(geometry.height(), 1);
} }
env->CallStaticVoidMethod(m_applicationClass, qtActivityDelegate().callMethod<void>("createSurface", surfaceId, jboolean(onTop),
m_createSurfaceMethodID, x, y, w, h, imageDepth);
surfaceId,
jboolean(onTop),
x, y, w, h,
imageDepth);
return surfaceId; return surfaceId;
} }
@ -358,9 +351,7 @@ namespace QtAndroid
if (!geometry.isNull()) if (!geometry.isNull())
geometry.getRect(&x, &y, &w, &h); geometry.getRect(&x, &y, &w, &h);
QJniObject::callStaticMethod<void>(m_applicationClass, qtActivityDelegate().callMethod<void>("insertNativeView",
"insertNativeView",
"(ILandroid/view/View;IIII)V",
surfaceId, surfaceId,
view, view,
x, x,
@ -395,10 +386,7 @@ namespace QtAndroid
w = geometry.width(); w = geometry.width();
h = geometry.height(); h = geometry.height();
} }
env->CallStaticVoidMethod(m_applicationClass, qtActivityDelegate().callMethod<void>("setSurfaceGeometry", surfaceId, x, y, w, h);
m_setSurfaceGeometryMethodID,
surfaceId,
x, y, w, h);
} }
@ -414,11 +402,7 @@ namespace QtAndroid
m_surfaces.erase(it); m_surfaces.erase(it);
} }
QJniEnvironment env; qtActivityDelegate().callMethod<void>("destroySurface", surfaceId);
if (env.jniEnv())
env->CallStaticVoidMethod(m_applicationClass,
m_destroySurfaceMethodID,
surfaceId);
} }
void bringChildToFront(int surfaceId) void bringChildToFront(int surfaceId)
@ -426,10 +410,7 @@ namespace QtAndroid
if (surfaceId == -1) if (surfaceId == -1)
return; return;
QJniObject::callStaticMethod<void>(m_applicationClass, qtActivityDelegate().callMethod<void>("bringChildToFront", surfaceId);
"bringChildToFront",
"(I)V",
surfaceId);
} }
void bringChildToBack(int surfaceId) void bringChildToBack(int surfaceId)
@ -437,10 +418,7 @@ namespace QtAndroid
if (surfaceId == -1) if (surfaceId == -1)
return; return;
QJniObject::callStaticMethod<void>(m_applicationClass, qtActivityDelegate().callMethod<void>("bringChildToBack", surfaceId);
"bringChildToBack",
"(I)V",
surfaceId);
} }
bool blockEventLoopsWhenSuspended() bool blockEventLoopsWhenSuspended()
@ -893,10 +871,6 @@ static bool registerNatives(QJniEnvironment &env)
return JNI_FALSE; return JNI_FALSE;
} }
GET_AND_CHECK_STATIC_METHOD(m_createSurfaceMethodID, m_applicationClass, "createSurface", "(IZIIIII)V");
GET_AND_CHECK_STATIC_METHOD(m_setSurfaceGeometryMethodID, m_applicationClass, "setSurfaceGeometry", "(IIIII)V");
GET_AND_CHECK_STATIC_METHOD(m_destroySurfaceMethodID, m_applicationClass, "destroySurface", "(I)V");
jmethodID methodID; jmethodID methodID;
GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;"); GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID); jobject contextObject = env->CallStaticObjectMethod(m_applicationClass, methodID);

View File

@ -31,8 +31,6 @@ namespace QtAndroidMenu
static QWindow *activeTopLevelWindow = nullptr; static QWindow *activeTopLevelWindow = nullptr;
Q_CONSTINIT static QRecursiveMutex menuBarMutex; Q_CONSTINIT static QRecursiveMutex menuBarMutex;
static jmethodID openContextMenuMethodID = 0;
static jmethodID clearMenuMethodID = 0; static jmethodID clearMenuMethodID = 0;
static jmethodID addMenuItemMethodID = 0; static jmethodID addMenuItemMethodID = 0;
static int menuNoneValue = 0; static int menuNoneValue = 0;
@ -46,29 +44,31 @@ namespace QtAndroidMenu
void resetMenuBar() void resetMenuBar()
{ {
QJniObject::callStaticMethod<void>(applicationClass(), "resetOptionsMenu"); qtActivityDelegate().callMethod<void>("resetOptionsMenu");
} }
void openOptionsMenu() void openOptionsMenu()
{ {
QJniObject::callStaticMethod<void>(applicationClass(), "openOptionsMenu"); qtActivityDelegate().callMethod<void>("openOptionsMenu");
} }
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env) void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect)
{ {
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu) if (visibleMenu)
pendingContextMenus.append(visibleMenu); pendingContextMenus.append(visibleMenu);
visibleMenu = menu; visibleMenu = menu;
menu->aboutToShow(); menu->aboutToShow();
env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height()); qtActivityDelegate().callMethod<void>("openContextMenu",
anchorRect.x(), anchorRect.y(),
anchorRect.width(), anchorRect.height());
} }
void hideContextMenu(QAndroidPlatformMenu *menu) void hideContextMenu(QAndroidPlatformMenu *menu)
{ {
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
if (visibleMenu == menu) { if (visibleMenu == menu) {
QJniObject::callStaticMethod<void>(applicationClass(), "closeContextMenu"); qtActivityDelegate().callMethod<void>("closeContextMenu");
pendingContextMenus.clear(); pendingContextMenus.clear();
} else { } else {
pendingContextMenus.removeOne(menu); pendingContextMenus.removeOne(menu);
@ -211,8 +211,10 @@ namespace QtAndroidMenu
return order; return order;
} }
static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu) static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject thiz, jobject menu)
{ {
Q_UNUSED(thiz)
env->CallVoidMethod(menu, clearMenuMethodID); env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&menuBarMutex); QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar) if (!visibleMenuBar)
@ -249,8 +251,11 @@ namespace QtAndroidMenu
return order ? JNI_TRUE : JNI_FALSE; return order ? JNI_TRUE : JNI_FALSE;
} }
static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked) static jboolean onOptionsItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{ {
Q_UNUSED(env)
Q_UNUSED(thiz)
QMutexLocker lock(&menuBarMutex); QMutexLocker lock(&menuBarMutex);
if (!visibleMenuBar) if (!visibleMenuBar)
return JNI_FALSE; return JNI_FALSE;
@ -260,7 +265,7 @@ namespace QtAndroidMenu
QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForId(menuId)); QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForId(menuId));
if (item) { if (item) {
if (item->menu()) { if (item->menu()) {
showContextMenu(item->menu(), QRect(), env); showContextMenu(item->menu(), QRect());
} else { } else {
if (item->isCheckable()) if (item->isCheckable())
item->setChecked(checked); item->setChecked(checked);
@ -270,18 +275,23 @@ namespace QtAndroidMenu
} else { } else {
QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForId(menuId)); QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForId(menuId));
if (menu) if (menu)
showContextMenu(menu, QRect(), env); showContextMenu(menu, QRect());
} }
return JNI_TRUE; return JNI_TRUE;
} }
static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/) static void onOptionsMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{ {
Q_UNUSED(env)
Q_UNUSED(thiz)
Q_UNUSED(menu)
} }
static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu) static void onCreateContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{ {
Q_UNUSED(thiz)
env->CallVoidMethod(menu, clearMenuMethodID); env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu) if (!visibleMenu)
@ -295,8 +305,9 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu); addAllMenuItemsToMenu(env, menu, visibleMenu);
} }
static void fillContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu) static void fillContextMenu(JNIEnv *env, jobject thiz, jobject menu)
{ {
Q_UNUSED(thiz)
env->CallVoidMethod(menu, clearMenuMethodID); env->CallVoidMethod(menu, clearMenuMethodID);
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu) if (!visibleMenu)
@ -305,13 +316,16 @@ namespace QtAndroidMenu
addAllMenuItemsToMenu(env, menu, visibleMenu); addAllMenuItemsToMenu(env, menu, visibleMenu);
} }
static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked) static jboolean onContextItemSelected(JNIEnv *env, jobject thiz, jint menuId, jboolean checked)
{ {
Q_UNUSED(env)
Q_UNUSED(thiz)
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForId(menuId)); QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForId(menuId));
if (item) { if (item) {
if (item->menu()) { if (item->menu()) {
showContextMenu(item->menu(), QRect(), env); showContextMenu(item->menu(), QRect());
} else { } else {
if (item->isCheckable()) if (item->isCheckable())
item->setChecked(checked); item->setChecked(checked);
@ -328,8 +342,12 @@ namespace QtAndroidMenu
return JNI_TRUE; return JNI_TRUE;
} }
static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/) static void onContextMenuClosed(JNIEnv *env, jobject thiz, jobject menu)
{ {
Q_UNUSED(env)
Q_UNUSED(thiz)
Q_UNUSED(menu)
QMutexLocker lock(&visibleMenuMutex); QMutexLocker lock(&visibleMenuMutex);
if (!visibleMenu) if (!visibleMenu)
return; return;
@ -337,7 +355,7 @@ namespace QtAndroidMenu
visibleMenu->aboutToHide(); visibleMenu->aboutToHide();
visibleMenu = 0; visibleMenu = 0;
if (!pendingContextMenus.empty()) if (!pendingContextMenus.empty())
showContextMenu(pendingContextMenus.takeLast(), QRect(), env); showContextMenu(pendingContextMenus.takeLast(), QRect());
} }
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
@ -387,8 +405,6 @@ namespace QtAndroidMenu
return false; return false;
} }
GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "(IIII)V");
jclass clazz; jclass clazz;
FIND_AND_CHECK_CLASS("android/view/Menu"); FIND_AND_CHECK_CLASS("android/view/Menu");
GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V"); GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");

View File

@ -21,7 +21,7 @@ namespace QtAndroidMenu
{ {
// Menu support // Menu support
void openOptionsMenu(); void openOptionsMenu();
void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect, JNIEnv *env); void showContextMenu(QAndroidPlatformMenu *menu, const QRect &anchorRect);
void hideContextMenu(QAndroidPlatformMenu *menu); void hideContextMenu(QAndroidPlatformMenu *menu);
void syncMenu(QAndroidPlatformMenu *menu); void syncMenu(QAndroidPlatformMenu *menu);
void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu); void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);

View File

@ -119,7 +119,7 @@ void QAndroidPlatformMenu::showPopup(const QWindow *parentWindow, const QRect &t
Q_UNUSED(parentWindow); Q_UNUSED(parentWindow);
Q_UNUSED(item); Q_UNUSED(item);
setVisible(true); setVisible(true);
QtAndroidMenu::showContextMenu(this, targetRect, QJniEnvironment().jniEnv()); QtAndroidMenu::showContextMenu(this, targetRect);
} }
QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const

View File

@ -199,11 +199,14 @@ void tst_Android::testRunOnAndroidMainThread()
} }
} }
Q_DECLARE_JNI_CLASS(QtActivityDelegate, "org/qtproject/qt/android/QtActivityDelegate")
void setSystemUiVisibility(int visibility) void setSystemUiVisibility(int visibility)
{ {
QNativeInterface::QAndroidApplication::runOnAndroidMainThread([visibility] { QNativeInterface::QAndroidApplication::runOnAndroidMainThread([visibility] {
QJniObject::callStaticMethod<void>("org/qtproject/qt/android/QtNative", auto context = QNativeInterface::QAndroidApplication::context();
"setSystemUiVisibility", "(I)V", visibility); auto activityDelegate = context.callMethod<QtJniTypes::QtActivityDelegate>("getActivityDelegate");
activityDelegate.callMethod<void>("setSystemUiVisibility", jint(visibility));
}).waitForFinished(); }).waitForFinished();
} }