Android: QtActivityDelegateBase listens to focus events from child views

In order to detect gaining/losing and moving focus between windows,
implement GlobalFocusChangeListener for the root View.

Add a surfaceFocusChanged native function in QAndroidPlatformWindow in
order to follow these focus changes.

Task-number: QTBUG-118139
Change-Id: Ia9bf6249c28a420f42793a9829aef31b12757630
Reviewed-by: Assam Boudjelthia <assam.boudjelthia@qt.io>
(cherry picked from commit 2c192c6f5fe08b014bfa90ea0452258e649d3183)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Petri Virkkunen 2024-01-25 14:11:22 +02:00 committed by Tinja Paavoseppä
parent 1712c4eeca
commit 17e546ac7f
6 changed files with 45 additions and 1 deletions

View File

@ -138,6 +138,7 @@ class QtActivityDelegate extends QtActivityDelegateBase
r.width(), kbHeight); r.width(), kbHeight);
return true; return true;
}); });
registerGlobalFocusChangeListener(m_layout);
m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout)); m_inputDelegate.setEditPopupMenu(new EditPopupMenu(m_activity, m_layout));
} }

View File

@ -133,6 +133,26 @@ abstract class QtActivityDelegateBase
setUpLayout(); setUpLayout();
} }
protected void registerGlobalFocusChangeListener(final View view) {
view.getViewTreeObserver().addOnGlobalFocusChangeListener(this::onGlobalFocusChanged);
}
private void onGlobalFocusChanged(View oldFocus, View newFocus) {
if (newFocus instanceof QtEditText) {
final QtWindow newWindow = (QtWindow) newFocus.getParent();
QtWindow.windowFocusChanged(true, newWindow.getId());
m_inputDelegate.setFocusedView((QtEditText) newFocus);
} else {
int id = -1;
if (oldFocus instanceof QtEditText) {
final QtWindow oldWindow = (QtWindow) oldFocus.getParent();
id = oldWindow.getId();
}
QtWindow.windowFocusChanged(false, id);
m_inputDelegate.setFocusedView(null);
}
}
public void hideSplashScreen() public void hideSplashScreen()
{ {
hideSplashScreen(0); hideSplashScreen(0);

View File

@ -135,6 +135,7 @@ class QtEmbeddedDelegate extends QtActivityDelegateBase implements QtNative.AppS
void setView(QtView view) { void setView(QtView view) {
m_view = view; m_view = view;
registerGlobalFocusChangeListener(m_view);
} }
public void setRootWindowRef(long ref) { public void setRootWindowRef(long ref) {

View File

@ -24,6 +24,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
private final QtEditText m_editText; private final QtEditText m_editText;
private static native void setSurface(int windowId, Surface surface); private static native void setSurface(int windowId, Surface surface);
static native void windowFocusChanged(boolean hasFocus, int id);
public QtWindow(Context context, QtWindow parentWindow) public QtWindow(Context context, QtWindow parentWindow)
{ {
@ -31,6 +32,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
setId(View.generateViewId()); setId(View.generateViewId());
m_editText = new QtEditText(context); m_editText = new QtEditText(context);
setParent(parentWindow); setParent(parentWindow);
setFocusableInTouchMode(true);
QtNative.runAction(() -> { QtNative.runAction(() -> {
m_gestureDetector = m_gestureDetector =

View File

@ -342,10 +342,28 @@ void QAndroidPlatformWindow::setSurface(JNIEnv *env, jobject object, jint window
} }
} }
void QAndroidPlatformWindow::windowFocusChanged(JNIEnv *env, jobject object,
jboolean focus, jint windowId)
{
Q_UNUSED(env)
Q_UNUSED(object)
QWindow* window = QtAndroid::windowFromId(windowId);
Q_ASSERT_X(window, "QAndroidPlatformWindow", "windowFocusChanged event window should exist");
if (focus) {
QWindowSystemInterface::handleFocusWindowChanged(window);
} else if (!focus && window == qGuiApp->focusWindow()) {
// Clear focus if current window has lost focus
QWindowSystemInterface::handleFocusWindowChanged(nullptr);
}
}
bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env) bool QAndroidPlatformWindow::registerNatives(QJniEnvironment &env)
{ {
if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(), if (!env.registerNativeMethods(QtJniTypes::Traits<QtJniTypes::QtWindow>::className(),
{Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow)})) { {
Q_JNI_NATIVE_SCOPED_METHOD(setSurface, QAndroidPlatformWindow),
Q_JNI_NATIVE_SCOPED_METHOD(windowFocusChanged, QAndroidPlatformWindow)
})) {
qCCritical(lcQpaWindow) << "RegisterNatives failed for" qCCritical(lcQpaWindow) << "RegisterNatives failed for"
<< QtJniTypes::Traits<QtJniTypes::QtWindow>::className(); << QtJniTypes::Traits<QtJniTypes::QtWindow>::className();
return false; return false;

View File

@ -93,6 +93,8 @@ protected:
private: private:
static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface); static void setSurface(JNIEnv *env, jobject obj, jint windowId, QtJniTypes::Surface surface);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface) Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(setSurface)
static void windowFocusChanged(JNIEnv *env, jobject object, jboolean focus, jint windowId);
Q_DECLARE_JNI_NATIVE_METHOD_IN_CURRENT_SCOPE(windowFocusChanged)
}; };
QT_END_NAMESPACE QT_END_NAMESPACE