diff --git a/modules/juce_core/native/juce_JNIHelpers_android.cpp b/modules/juce_core/native/juce_JNIHelpers_android.cpp index dd8d55147f..32bd98b18b 100644 --- a/modules/juce_core/native/juce_JNIHelpers_android.cpp +++ b/modules/juce_core/native/juce_JNIHelpers_android.cpp @@ -429,7 +429,22 @@ void juce_dispatchDelete (JNIEnv*, jobject /*object*/, jlong host) } //============================================================================== -jobject ActivityLifecycleCallbacks::invoke (jobject proxy, jobject method, jobjectArray args) +ActivityLifecycleCallbackForwarder::ActivityLifecycleCallbackForwarder (GlobalRef ctx, ActivityLifecycleCallbacks* cb) + : appContext (ctx), + myself (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")), + callbacks (cb) +{ + if (appContext != nullptr && myself != nullptr) + getEnv()->CallVoidMethod (appContext, AndroidApplication.registerActivityLifecycleCallbacks, myself.get()); +} + +ActivityLifecycleCallbackForwarder::~ActivityLifecycleCallbackForwarder() +{ + if (appContext != nullptr && myself != nullptr) + getEnv()->CallVoidMethod (appContext, AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get()); +} + +jobject ActivityLifecycleCallbackForwarder::invoke (jobject proxy, jobject method, jobjectArray args) { auto* env = getEnv(); @@ -475,7 +490,7 @@ jobject ActivityLifecycleCallbacks::invoke (jobject proxy, jobject method, jobje const auto activity = env->GetArrayLength (args) > 0 ? env->GetObjectArrayElement (args, 0) : (jobject) nullptr; const auto bundle = env->GetArrayLength (args) > 1 ? env->GetObjectArrayElement (args, 1) : (jobject) nullptr; - (iter->second) (*this, activity, bundle); + (iter->second) (*callbacks, activity, bundle); return nullptr; } diff --git a/modules/juce_core/native/juce_JNIHelpers_android.h b/modules/juce_core/native/juce_JNIHelpers_android.h index 543a11aed0..e4ab1591d3 100644 --- a/modules/juce_core/native/juce_JNIHelpers_android.h +++ b/modules/juce_core/native/juce_JNIHelpers_android.h @@ -1016,9 +1016,11 @@ LocalRef CreateJavaInterface (AndroidInterfaceImplementer* implementer, const String& interfaceName); //============================================================================== -class ActivityLifecycleCallbacks : public AndroidInterfaceImplementer +class ActivityLifecycleCallbacks { public: + virtual ~ActivityLifecycleCallbacks() = default; + virtual void onActivityPreCreated (jobject /*activity*/, jobject /*bundle*/) {} virtual void onActivityPreDestroyed (jobject /*activity*/) {} virtual void onActivityPrePaused (jobject /*activity*/) {} @@ -1044,15 +1046,27 @@ public: virtual void onActivityPostStopped (jobject /*activity*/) {} virtual void onActivityConfigurationChanged (jobject /*activity*/) {} +}; + +class ActivityLifecycleCallbackForwarder : private AndroidInterfaceImplementer +{ +public: + ActivityLifecycleCallbackForwarder (GlobalRef appContext, ActivityLifecycleCallbacks* callbacks); + + ~ActivityLifecycleCallbackForwarder() override; private: jobject invoke (jobject, jobject, jobjectArray) override; + + GlobalRef appContext; + GlobalRef myself; + ActivityLifecycleCallbacks* callbacks = nullptr; }; //============================================================================== -struct SurfaceHolderCallback : AndroidInterfaceImplementer +struct SurfaceHolderCallback : public AndroidInterfaceImplementer { - virtual ~SurfaceHolderCallback() override = default; + ~SurfaceHolderCallback() override = default; virtual void surfaceChanged (LocalRef holder, int format, int width, int height) = 0; virtual void surfaceCreated (LocalRef holder) = 0; diff --git a/modules/juce_core/native/juce_Threads_android.cpp b/modules/juce_core/native/juce_Threads_android.cpp index d17318e09a..d1e16bad22 100644 --- a/modules/juce_core/native/juce_Threads_android.cpp +++ b/modules/juce_core/native/juce_Threads_android.cpp @@ -111,33 +111,9 @@ class JuceActivityWatcher final : public ActivityLifecycleCallbacks public: JuceActivityWatcher() { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr) - { - auto* env = getEnv(); - - myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")); - env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get()); - } - checkActivityIsMain (androidApkContext); } - ~JuceActivityWatcher() override - { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr && myself != nullptr) - { - auto* env = getEnv(); - - env->CallVoidMethod (appContext.get(), AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get()); - clear(); - myself.clear(); - } - } - void onActivityStarted (jobject activity) override { auto* env = getEnv(); @@ -273,10 +249,10 @@ private: return mainActivityClassPath; } - GlobalRef myself; CriticalSection currentActivityLock; jweak currentActivity = nullptr; jweak mainActivity = nullptr; + ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this }; }; //============================================================================== diff --git a/modules/juce_events/native/juce_Messaging_android.cpp b/modules/juce_events/native/juce_Messaging_android.cpp index eb559d06ca..061bd52c1a 100644 --- a/modules/juce_events/native/juce_Messaging_android.cpp +++ b/modules/juce_events/native/juce_Messaging_android.cpp @@ -183,29 +183,6 @@ public: JuceAppLifecycle (juce::JUCEApplicationBase* (*initSymbolAddr)()) : createApplicationSymbol (initSymbolAddr) { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr) - { - auto* env = getEnv(); - - myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")); - env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get()); - } - } - - ~JuceAppLifecycle() override - { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr && myself != nullptr) - { - auto* env = getEnv(); - - clear(); - env->CallVoidMethod (appContext.get(), AndroidApplication.unregisterActivityLifecycleCallbacks, myself.get()); - myself.clear(); - } } void onActivityCreated (jobject, jobject) override @@ -292,6 +269,7 @@ private: GlobalRef myself; juce::JUCEApplicationBase* (*createApplicationSymbol)(); bool hasBeenInitialised = false; + ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this }; }; //============================================================================== diff --git a/modules/juce_gui_basics/native/juce_Windowing_android.cpp b/modules/juce_gui_basics/native/juce_Windowing_android.cpp index 961eebb4c6..da2befc2f9 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_android.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_android.cpp @@ -1308,7 +1308,8 @@ static constexpr int translateAndroidKeyboardFlags (int javaFlags) noexcept } //============================================================================== -class AndroidComponentPeer final : public ComponentPeer +class AndroidComponentPeer final : public ComponentPeer, + private ActivityLifecycleCallbacks { public: AndroidComponentPeer (Component& comp, int windowStyleFlags, void* nativeViewHandle) @@ -2097,20 +2098,12 @@ public: { void onActivityStarted (jobject /*activity*/) override { - auto* env = getEnv(); - LocalRef appContext (getAppContext()); + forceDisplayUpdate(); - if (appContext.get() != nullptr) - { - env->CallVoidMethod (appContext.get(), - AndroidApplication.unregisterActivityLifecycleCallbacks, - activityCallbackListener.get()); - clear(); - activityCallbackListener.clear(); - - forceDisplayUpdate(); - } + AndroidComponentPeer::startupActivityCallbackListener.reset(); } + + ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this }; }; class MainActivityWindowLayoutListener : public AndroidInterfaceImplementer @@ -2530,7 +2523,7 @@ private: //============================================================================== friend class Displays; inline static AndroidComponentPeer* frontWindow = nullptr; - inline static GlobalRef activityCallbackListener; + inline static std::optional startupActivityCallbackListener; static constexpr jint GRAVITY_LEFT = 0x3, GRAVITY_TOP = 0x30; static constexpr jint TYPE_APPLICATION = 0x2; @@ -2562,37 +2555,10 @@ bool Desktop::canUseSemiTransparentWindows() noexcept return true; } -class Desktop::NativeDarkModeChangeDetectorImpl : public ActivityLifecycleCallbacks +class Desktop::NativeDarkModeChangeDetectorImpl : private ActivityLifecycleCallbacks { public: - NativeDarkModeChangeDetectorImpl() - { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr) - { - auto* env = getEnv(); - - myself = GlobalRef (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")); - env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, myself.get()); - } - } - - ~NativeDarkModeChangeDetectorImpl() override - { - LocalRef appContext (getAppContext()); - - if (appContext != nullptr && myself != nullptr) - { - auto* env = getEnv(); - - env->CallVoidMethod (appContext.get(), - AndroidApplication.unregisterActivityLifecycleCallbacks, - myself.get()); - clear(); - myself.clear(); - } - } + NativeDarkModeChangeDetectorImpl() = default; bool isDarkModeEnabled() const noexcept { return darkModeEnabled; } @@ -2625,8 +2591,8 @@ private: UI_MODE_NIGHT_UNDEFINED = 0x00000000, UI_MODE_NIGHT_YES = 0x00000020; - GlobalRef myself; bool darkModeEnabled = getDarkModeSetting(); + ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this }; //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl) @@ -2972,20 +2938,9 @@ void Displays::findDisplays (float masterScale) } } } - else if (AndroidComponentPeer::activityCallbackListener == nullptr) + else if (! AndroidComponentPeer::startupActivityCallbackListener.has_value()) { - LocalRef appContext (getAppContext()); - - if (appContext.get() != nullptr) - { - AndroidComponentPeer::activityCallbackListener = GlobalRef (CreateJavaInterface ( - new AndroidComponentPeer::StartupActivityCallbackListener, - "android/app/Application$ActivityLifecycleCallbacks")); - - env->CallVoidMethod (appContext, - AndroidApplication.registerActivityLifecycleCallbacks, - AndroidComponentPeer::activityCallbackListener.get()); - } + AndroidComponentPeer::startupActivityCallbackListener.emplace(); } displays.add (d); diff --git a/modules/juce_video/native/juce_CameraDevice_android.h b/modules/juce_video/native/juce_CameraDevice_android.h index 125a2c1ec7..dcbaec988a 100644 --- a/modules/juce_video/native/juce_CameraDevice_android.h +++ b/modules/juce_video/native/juce_CameraDevice_android.h @@ -490,8 +490,7 @@ private: }; //============================================================================== -struct CameraDevice::Pimpl - : private ActivityLifecycleCallbacks +struct CameraDevice::Pimpl : private ActivityLifecycleCallbacks { using InternalOpenCameraResultCallback = std::function; @@ -504,7 +503,6 @@ struct CameraDevice::Pimpl maxWidth (maxWidthToUse), maxHeight (maxHeightToUse), cameraId (cameraIdToUse), - activityLifeListener (CreateJavaInterface (this, "android/app/Application$ActivityLifecycleCallbacks")), cameraManager (initialiseCameraManager()), cameraCharacteristics (initialiseCameraCharacteristics (cameraManager, cameraId)), streamConfigurationMap (cameraCharacteristics), @@ -516,10 +514,7 @@ struct CameraDevice::Pimpl ~Pimpl() override { - auto* env = getEnv(); - - env->CallVoidMethod (getAppContext().get(), AndroidApplication.unregisterActivityLifecycleCallbacks, activityLifeListener.get()); - activityLifeListener.clear(); + callbackForwarder.reset(); } JUCE_DECLARE_WEAK_REFERENCEABLE (Pimpl) @@ -551,7 +546,7 @@ struct CameraDevice::Pimpl { if (granted) { - getEnv()->CallVoidMethod (getAppContext().get(), AndroidApplication.registerActivityLifecycleCallbacks, activityLifeListener.get()); + callbackForwarder.emplace (GlobalRef { getAppContext() }, static_cast (this)); scopedCameraDevice.reset (new ScopedCameraDevice (*this, cameraId, cameraManager, handler, getAutoFocusModeToUse())); } else @@ -2809,7 +2804,7 @@ private: String cameraId; InternalOpenCameraResultCallback cameraOpenCallback; - GlobalRef activityLifeListener; + std::optional callbackForwarder; GlobalRef cameraManager; GlobalRef cameraCharacteristics; diff --git a/modules/juce_video/native/juce_Video_android.h b/modules/juce_video/native/juce_Video_android.h index 4c3e386b99..de869f092c 100644 --- a/modules/juce_video/native/juce_Video_android.h +++ b/modules/juce_video/native/juce_Video_android.h @@ -344,8 +344,9 @@ private: }; //============================================================================== -struct VideoComponent::Pimpl - : public AndroidViewComponent, private ActivityLifecycleCallbacks, private SurfaceHolderCallback +struct VideoComponent::Pimpl : public AndroidViewComponent, + private ActivityLifecycleCallbacks, + private SurfaceHolderCallback { Pimpl (VideoComponent& ownerToUse, bool) : owner (ownerToUse), @@ -360,14 +361,6 @@ struct VideoComponent::Pimpl LocalRef appContext (getAppContext()); - if (appContext != nullptr) - { - ActivityLifecycleCallbacks* callbacks = dynamic_cast (this); - - activityLifeListener = GlobalRef (CreateJavaInterface (callbacks, "android/app/Application$ActivityLifecycleCallbacks")); - env->CallVoidMethod (appContext.get(), AndroidApplication.registerActivityLifecycleCallbacks, activityLifeListener.get()); - } - { LocalRef surfaceView (env->NewObject (AndroidSurfaceView, AndroidSurfaceView.constructor, getAppContext().get())); LocalRef holder (env->CallObjectMethod (surfaceView.get(), AndroidSurfaceView.getHolder)); @@ -397,13 +390,6 @@ struct VideoComponent::Pimpl surfaceHolderCallback.clear(); } } - - if (activityLifeListener != nullptr) - { - env->CallVoidMethod (getAppContext().get(), AndroidApplication.unregisterActivityLifecycleCallbacks, activityLifeListener.get()); - ActivityLifecycleCallbacks::clear(); - activityLifeListener.clear(); - } } void loadAsync (const URL& url, std::function callback) @@ -1696,7 +1682,7 @@ private: VideoComponent& owner; MediaSession mediaSession; - GlobalRef activityLifeListener; + ActivityLifecycleCallbackForwarder forwarder { GlobalRef { getAppContext() }, this }; #if JUCE_SYNC_VIDEO_VOLUME_WITH_OS_MEDIA_VOLUME SystemVolumeListener systemVolumeListener; #endif