From aea816b1972c834b805876868829159d7c459c27 Mon Sep 17 00:00:00 2001 From: Assam Boudjelthia Date: Wed, 22 Nov 2023 01:22:12 +0200 Subject: Android: rework app state tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup 'isStarted' and state management logic and move it to QtNative. Currently, it's spread between QtActivityDelegate and QtNative where multiple variables are used for overlapping use cases. Task-number: QTBUG-118077 Change-Id: I2c98b48be78809c30636bfdf6d6640317470cec6 Reviewed-by: Tinja Paavoseppä --- src/android/jar/CMakeLists.txt | 1 - .../org/qtproject/qt/android/QtActivityBase.java | 25 ++++++----- .../qtproject/qt/android/QtActivityDelegate.java | 13 ------ .../src/org/qtproject/qt/android/QtConstants.java | 14 ------- .../jar/src/org/qtproject/qt/android/QtNative.java | 48 ++++++++++++++-------- .../org/qtproject/qt/android/QtServiceBase.java | 4 +- 6 files changed, 49 insertions(+), 56 deletions(-) delete mode 100644 src/android/jar/src/org/qtproject/qt/android/QtConstants.java diff --git a/src/android/jar/CMakeLists.txt b/src/android/jar/CMakeLists.txt index 7bef9679c2..729ea07013 100644 --- a/src/android/jar/CMakeLists.txt +++ b/src/android/jar/CMakeLists.txt @@ -26,7 +26,6 @@ set(java_sources src/org/qtproject/qt/android/extras/QtAndroidBinder.java src/org/qtproject/qt/android/extras/QtAndroidServiceConnection.java src/org/qtproject/qt/android/extras/QtNative.java - src/org/qtproject/qt/android/QtConstants.java src/org/qtproject/qt/android/QtClipboardManager.java src/org/qtproject/qt/android/QtDisplayManager.java src/org/qtproject/qt/android/UsedFromNativeCode.java 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 415c8f3a1a..159f31be9d 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityBase.java @@ -59,7 +59,7 @@ public class QtActivityBase extends Activity } private void handleActivityRestart() { - if (QtNative.isStarted()) { + if (QtNative.getStateDetails().isStarted) { boolean updated = m_delegate.updateActivityAfterRestart(this); if (!updated) { // could not update the activity so restart the application @@ -119,15 +119,15 @@ public class QtActivityBase extends Activity { super.onPause(); if (Build.VERSION.SDK_INT < 24 || !isInMultiWindowMode()) - QtNative.setApplicationState(QtConstants.ApplicationState.ApplicationInactive); + QtNative.setApplicationState(QtNative.ApplicationState.ApplicationInactive); } @Override protected void onResume() { super.onResume(); - QtNative.setApplicationState(QtConstants.ApplicationState.ApplicationActive); - if (m_delegate.isStarted()) { + QtNative.setApplicationState(QtNative.ApplicationState.ApplicationActive); + if (QtNative.getStateDetails().isStarted) { QtNative.updateWindow(); // Suspending the app clears the immersive mode, so we need to set it again. m_delegate.displayManager().updateFullScreen(this); @@ -138,7 +138,7 @@ public class QtActivityBase extends Activity protected void onStop() { super.onStop(); - QtNative.setApplicationState(QtConstants.ApplicationState.ApplicationSuspended); + QtNative.setApplicationState(QtNative.ApplicationState.ApplicationSuspended); } @Override @@ -187,7 +187,8 @@ public class QtActivityBase extends Activity @Override public boolean dispatchKeyEvent(KeyEvent event) { - if (m_delegate.isStarted() && m_delegate.getInputDelegate().handleDispatchKeyEvent(event)) + boolean handleResult = m_delegate.getInputDelegate().handleDispatchKeyEvent(event); + if (QtNative.getStateDetails().isStarted && handleResult) return true; return super.dispatchKeyEvent(event); @@ -197,7 +198,7 @@ public class QtActivityBase extends Activity public boolean dispatchGenericMotionEvent(MotionEvent event) { boolean handled = m_delegate.getInputDelegate().handleDispatchGenericMotionEvent(event); - if (m_delegate.isStarted() && handled) + if (QtNative.getStateDetails().isStarted && handled) return true; return super.dispatchGenericMotionEvent(event); @@ -206,7 +207,8 @@ public class QtActivityBase extends Activity @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (!m_delegate.isStarted() || !m_delegate.isPluginRunning()) + QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails(); + if (!stateDetails.isStarted || !m_delegate.isPluginRunning()) return false; return m_delegate.getInputDelegate().onKeyDown(keyCode, event); @@ -215,7 +217,8 @@ public class QtActivityBase extends Activity @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - if (!m_delegate.isStarted() || !m_delegate.isPluginRunning()) + QtNative.ApplicationStateDetails stateDetails = QtNative.getStateDetails(); + if (!stateDetails.isStarted || !m_delegate.isPluginRunning()) return false; return m_delegate.getInputDelegate().onKeyUp(keyCode, event); @@ -252,7 +255,7 @@ public class QtActivityBase extends Activity protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); - m_delegate.setStarted(savedInstanceState.getBoolean("Started")); + QtNative.setStarted(savedInstanceState.getBoolean("Started")); // FIXME restore all surfaces } @@ -269,7 +272,7 @@ public class QtActivityBase extends Activity { super.onSaveInstanceState(outState); outState.putInt("SystemUiVisibility", m_delegate.displayManager().systemUiVisibility()); - outState.putBoolean("Started", m_delegate.isStarted()); + outState.putBoolean("Started", QtNative.getStateDetails().isStarted); } @Override 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 79d00fac15..c154399911 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtActivityDelegate.java @@ -37,7 +37,6 @@ public class QtActivityDelegate { private Activity m_activity; - private boolean m_started = false; private boolean m_isPluginRunning = false; private HashMap m_surfaces = null; @@ -98,16 +97,6 @@ public class QtActivityDelegate }); } - void setStarted(boolean started) - { - m_started = started; - } - - boolean isStarted() - { - return m_started; - } - boolean isPluginRunning() { return m_isPluginRunning; @@ -153,13 +142,11 @@ public class QtActivityDelegate Runnable startApplication = () -> { try { QtNative.startApplication(appParams, mainLib); - m_started = true; } catch (Exception e) { e.printStackTrace(); m_activity.finish(); } }; - initMembers(startApplication); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtConstants.java b/src/android/jar/src/org/qtproject/qt/android/QtConstants.java deleted file mode 100644 index c3dfc3d9f9..0000000000 --- a/src/android/jar/src/org/qtproject/qt/android/QtConstants.java +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -package org.qtproject.qt.android; - -public class QtConstants { - // Application states - public static class ApplicationState { - public static final int ApplicationSuspended = 0x0; - public static final int ApplicationHidden = 0x1; - public static final int ApplicationInactive = 0x2; - public static final int ApplicationActive = 0x4; - } -} 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 7d48a4ea0f..8d39398837 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtNative.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtNative.java @@ -33,26 +33,21 @@ import javax.net.ssl.X509TrustManager; public class QtNative { private static WeakReference m_activity = null; - private static boolean m_activityPaused = false; private static WeakReference m_service = null; public 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"; // a list containing all actions which could not be performed (e.g. the main activity is destroyed, etc.) private static final ArrayList m_lostActions = new ArrayList<>(); - private static boolean m_started = false; private static final QtThread m_qtThread = new QtThread(); private static ClassLoader m_classLoader = null; private static final Runnable runPendingCppRunnablesRunnable = QtNative::runPendingCppRunnables; - public static boolean isStarted() - { - return m_started && (isActivityValid() || isServiceValid()); - } - @UsedFromNativeCode public static ClassLoader classLoader() { @@ -198,16 +193,37 @@ public class QtNative return m_qtThread; } + // Keep in sync with src/corelib/global/qnamespace.h + public 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 { + int state = ApplicationState.ApplicationSuspended; + boolean isStarted = false; + } + + public static ApplicationStateDetails getStateDetails() + { + return m_stateDetails; + } + + public static void setStarted(boolean started) + { + m_stateDetails.isStarted = started; + } + public static void setApplicationState(int state) { synchronized (m_mainActivityMutex) { - if (state == QtConstants.ApplicationState.ApplicationActive) { - m_activityPaused = false; + m_stateDetails.state = state; + if (state == ApplicationState.ApplicationActive) { for (Runnable mLostAction : m_lostActions) runAction(mLostAction); m_lostActions.clear(); - } else { - m_activityPaused = true; } } updateApplicationState(state); @@ -220,7 +236,8 @@ public class QtNative synchronized (m_mainActivityMutex) { final Looper mainLooper = Looper.getMainLooper(); final Handler handler = new Handler(mainLooper); - final boolean active = (isActivityValid() && !m_activityPaused) || isServiceValid(); + final boolean isStateActive = m_stateDetails.state == ApplicationState.ApplicationActive; + final boolean active = (isActivityValid() && isStateActive) || isServiceValid(); if (!active || !handler.post(action)) m_lostActions.add(action); } @@ -231,7 +248,7 @@ public class QtNative { synchronized (m_mainActivityMutex) { if (isActivityValid()) { - if (!m_activityPaused) + if (m_stateDetails.state == ApplicationState.ApplicationActive) m_activity.get().runOnUiThread(runPendingCppRunnablesRunnable); else runAction(runPendingCppRunnablesRunnable); @@ -264,7 +281,7 @@ public class QtNative }); m_qtThread.post(QtNative::startQtApplication); waitForServiceSetup(); - m_started = true; + m_stateDetails.isStarted = true; } } @@ -276,8 +293,7 @@ public class QtNative m_activity.get().finish(); if (isServiceValid()) m_service.get().stopSelf(); - - m_started = false; + m_stateDetails.isStarted = false; }); } diff --git a/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java b/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java index 3f2a82fd5e..8ecd8d5643 100644 --- a/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java +++ b/src/android/jar/src/org/qtproject/qt/android/QtServiceBase.java @@ -14,8 +14,10 @@ public class QtServiceBase extends Service { { super.onCreate(); + QtNative.setApplicationState(QtNative.ApplicationState.ApplicationHidden); + // the application has already started, do not reload everything again - if (QtNative.isStarted()) { + if (QtNative.getStateDetails().isStarted) { Log.w(QtNative.QtTAG, "A QtService tried to start in the same process as an initiated " + "QtActivity. That is not supported. This results in the service " + -- cgit v1.2.3