diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt index 146396d82b..ff86480635 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/IApplicationLifecycleHandler.kt @@ -10,8 +10,13 @@ import android.app.Application.ActivityLifecycleCallbacks interface IApplicationLifecycleHandler { /** * Called when the application is brought into the foreground. + * This callback can be fired immediately on subscribing to the IApplicationService (when the + * IApplicationService itself is started too late to capture the application's early lifecycle events), + * or through natural application lifecycle callbacks. + * + * @param firedOnSubscribe Method is fired from subscribing or from application lifecycle callbacks */ - fun onFocus() + fun onFocus(firedOnSubscribe: Boolean) /** * Called when the application has been brought out of the foreground, to the background. @@ -24,7 +29,7 @@ interface IApplicationLifecycleHandler { * can use this if they only want to override a subset of the callbacks that make up this interface. */ open class ApplicationLifecycleHandlerBase : IApplicationLifecycleHandler { - override fun onFocus() {} + override fun onFocus(firedOnSubscribe: Boolean) {} override fun onUnfocused() {} } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt index 6b4247a6db..55f2612324 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/application/impl/ApplicationService.kt @@ -67,6 +67,9 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On private var activityReferences = 0 private var isActivityChangingConfigurations = false + private val wasInBackground: Boolean + get() = !isInForeground || nextResumeIsFirstActivity + /** * Call to "start" this service, expected to be called during initialization of the SDK. * @@ -117,6 +120,11 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On override fun addApplicationLifecycleHandler(handler: IApplicationLifecycleHandler) { applicationLifecycleNotifier.subscribe(handler) + if (current != null) { + // When a listener subscribes, fire its callback + // The listener is too late to receive the earlier onFocus call + handler.onFocus(true) + } } override fun removeApplicationLifecycleHandler(handler: IApplicationLifecycleHandler) { @@ -150,7 +158,7 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On current = activity - if ((!isInForeground || nextResumeIsFirstActivity) && !isActivityChangingConfigurations) { + if (wasInBackground && !isActivityChangingConfigurations) { activityReferences = 1 handleFocus() } else { @@ -170,7 +178,7 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On current = activity } - if ((!isInForeground || nextResumeIsFirstActivity) && !isActivityChangingConfigurations) { + if (wasInBackground && !isActivityChangingConfigurations) { activityReferences = 1 handleFocus() } @@ -373,7 +381,7 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On } private fun handleFocus() { - if (!isInForeground || nextResumeIsFirstActivity) { + if (wasInBackground) { Logging.debug( "ApplicationService.handleFocus: application is now in focus, nextResumeIsFirstActivity=$nextResumeIsFirstActivity", ) @@ -384,7 +392,7 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On entryState = AppEntryAction.APP_OPEN } - applicationLifecycleNotifier.fire { it.onFocus() } + applicationLifecycleNotifier.fire { it.onFocus(false) } } else { Logging.debug("ApplicationService.handleFocus: application never lost focus") } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt index 4cc37d3132..a210056104 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/background/impl/BackgroundManager.kt @@ -79,7 +79,7 @@ internal class BackgroundManager( _applicationService.addApplicationLifecycleHandler(this) } - override fun onFocus() { + override fun onFocus(firedOnSubscribe: Boolean) { cancelSyncTask() } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt index 16658ff4c0..98646a7c88 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackAmazonPurchase.kt @@ -115,7 +115,7 @@ internal class TrackAmazonPurchase( e.printStackTrace() } - override fun onFocus() { } + override fun onFocus(firedOnSubscribe: Boolean) { } override fun onUnfocused() { if (!canTrack) return diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt index 6d2f9e66ba..35f95fac5f 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/purchases/impl/TrackGooglePurchase.kt @@ -98,7 +98,7 @@ internal class TrackGooglePurchase( trackIAP() } - override fun onFocus() { + override fun onFocus(firedOnSubscribe: Boolean) { trackIAP() } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt index 439d22fe91..e49e96c26e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/SessionModel.kt @@ -19,13 +19,14 @@ class SessionModel : Model() { * Whether the session is valid. */ var isValid: Boolean - get() = getBooleanProperty(::isValid.name) { true } + get() = getBooleanProperty(::isValid.name) { false } set(value) { setBooleanProperty(::isValid.name, value) } /** * When this session started, in Unix time milliseconds. + * This is used by In-App Message triggers, and not used in detecting session time. */ var startTime: Long get() = getLongProperty(::startTime.name) { System.currentTimeMillis() } @@ -37,7 +38,7 @@ class SessionModel : Model() { * When this app was last focused, in Unix time milliseconds. */ var focusTime: Long - get() = getLongProperty(::focusTime.name) { 0 } + get() = getLongProperty(::focusTime.name) { System.currentTimeMillis() } set(value) { setLongProperty(::focusTime.name, value) } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt index 265be9f82e..9669e05de5 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionListener.kt @@ -4,6 +4,7 @@ import com.onesignal.common.threading.suspendifyOnThread import com.onesignal.core.internal.config.ConfigModelStore import com.onesignal.core.internal.operations.IOperationRepo import com.onesignal.core.internal.startup.IStartableService +import com.onesignal.debug.internal.logging.Logging import com.onesignal.session.internal.outcomes.IOutcomeEventsController import com.onesignal.session.internal.session.ISessionLifecycleHandler import com.onesignal.session.internal.session.ISessionService @@ -47,6 +48,12 @@ internal class SessionListener( override fun onSessionEnded(duration: Long) { val durationInSeconds = duration / 1000 + + // Time is erroneous if below 1 second or over a day + if (durationInSeconds < 1L || durationInSeconds > SECONDS_IN_A_DAY) { + Logging.error("SessionListener.onSessionEnded sending duration of $durationInSeconds seconds") + } + _operationRepo.enqueue( TrackSessionEndOperation(_configModelStore.model.appId, _identityModelStore.model.onesignalId, durationInSeconds), ) @@ -55,4 +62,8 @@ internal class SessionListener( _outcomeEventsController.sendSessionEndOutcomeEvent(durationInSeconds) } } + + companion object { + const val SECONDS_IN_A_DAY = 86_400L + } } diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt index 8f61196fee..d831ef54b1 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/session/internal/session/impl/SessionService.kt @@ -45,35 +45,42 @@ internal class SessionService( private val sessionLifeCycleNotifier: EventProducer = EventProducer() private var session: SessionModel? = null private var config: ConfigModel? = null + private var shouldFireOnSubscribe = false override fun start() { session = _sessionModelStore.model config = _configModelStore.model + // Reset the session validity property to drive a new session + session!!.isValid = false _applicationService.addApplicationLifecycleHandler(this) } override suspend fun backgroundRun() { - Logging.log(LogLevel.DEBUG, "SessionService.backgroundRun()") - - if (!session!!.isValid) { - return - } - + val activeDuration = session!!.activeDuration // end the session - Logging.debug("SessionService: Session ended. activeDuration: ${session!!.activeDuration}") + Logging.debug("SessionService.backgroundRun: Session ended. activeDuration: $activeDuration") session!!.isValid = false - sessionLifeCycleNotifier.fire { it.onSessionEnded(session!!.activeDuration) } + sessionLifeCycleNotifier.fire { it.onSessionEnded(activeDuration) } + session!!.activeDuration = 0L } - override fun onFocus() { - Logging.log(LogLevel.DEBUG, "SessionService.onFocus()") - + /** + * NOTE: When `firedOnSubscribe = true` + * + * Typically, the app foregrounding will trigger this callback via the IApplicationService. + * However, it is possible for OneSignal to initialize too late to capture the Android lifecycle callbacks. + * In this case, the app is already foregrounded, so this method is fired immediately on subscribing + * to the IApplicationService. Listeners of this service will not subscribe in time to capture + * the `onSessionStarted()` callback here, so fire it when they themselves subscribe. + */ + override fun onFocus(firedOnSubscribe: Boolean) { + Logging.log(LogLevel.DEBUG, "SessionService.onFocus() - fired from start: $firedOnSubscribe") if (!session!!.isValid) { // As the old session was made inactive, we need to create a new session + shouldFireOnSubscribe = firedOnSubscribe session!!.sessionId = UUID.randomUUID().toString() session!!.startTime = _time.currentTimeMillis session!!.focusTime = session!!.startTime - session!!.activeDuration = 0L session!!.isValid = true Logging.debug("SessionService: New session started at ${session!!.startTime}") @@ -87,14 +94,17 @@ internal class SessionService( } override fun onUnfocused() { - Logging.log(LogLevel.DEBUG, "SessionService.onUnfocused()") - // capture the amount of time the app was focused val dt = _time.currentTimeMillis - session!!.focusTime session!!.activeDuration += dt + Logging.log(LogLevel.DEBUG, "SessionService.onUnfocused adding time $dt for total: ${session!!.activeDuration}") } - override fun subscribe(handler: ISessionLifecycleHandler) = sessionLifeCycleNotifier.subscribe(handler) + override fun subscribe(handler: ISessionLifecycleHandler) { + sessionLifeCycleNotifier.subscribe(handler) + // If a handler subscribes too late to capture the initial onSessionStarted. + if (shouldFireOnSubscribe) handler.onSessionStarted() + } override fun unsubscribe(handler: ISessionLifecycleHandler) = sessionLifeCycleNotifier.unsubscribe(handler) diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt index 44f90cdffe..7b04d7981e 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/service/UserRefreshService.kt @@ -1,28 +1,32 @@ package com.onesignal.user.internal.service import com.onesignal.common.IDManager -import com.onesignal.core.internal.application.IApplicationLifecycleHandler import com.onesignal.core.internal.application.IApplicationService import com.onesignal.core.internal.config.ConfigModelStore import com.onesignal.core.internal.operations.IOperationRepo import com.onesignal.core.internal.startup.IStartableService +import com.onesignal.session.internal.session.ISessionLifecycleHandler +import com.onesignal.session.internal.session.ISessionService import com.onesignal.user.internal.identity.IdentityModelStore import com.onesignal.user.internal.operations.RefreshUserOperation -// Ensure cache for the user is refreshed once per cold start when app +// Ensure user is refreshed only when app // is in the foreground. This saves resources as there are a number of // events (such as push received or non-OneSignal events) that start // the app in the background but will never read/write any user // properties. class UserRefreshService( private val _applicationService: IApplicationService, + private val _sessionService: ISessionService, private val _operationRepo: IOperationRepo, private val _configModelStore: ConfigModelStore, private val _identityModelStore: IdentityModelStore, ) : IStartableService, - IApplicationLifecycleHandler { + ISessionLifecycleHandler { private fun refreshUser() { - if (IDManager.isLocalId(_identityModelStore.model.onesignalId)) return + if (IDManager.isLocalId(_identityModelStore.model.onesignalId) || !_applicationService.isInForeground) { + return + } _operationRepo.enqueue( RefreshUserOperation( @@ -32,21 +36,11 @@ class UserRefreshService( ) } - override fun start() { - if (_applicationService.isInForeground) { - refreshUser() - } else { - _applicationService.addApplicationLifecycleHandler(this) - } - } + override fun start() = _sessionService.subscribe(this) - private var onFocusCalled: Boolean = false + override fun onSessionStarted() = refreshUser() - override fun onFocus() { - if (onFocusCalled) return - onFocusCalled = true - refreshUser() - } + override fun onSessionActive() { } - override fun onUnfocused() { } + override fun onSessionEnded(duration: Long) { } } diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt index 39ae8251ce..cd9f3d1712 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/core/internal/application/ApplicationServiceTests.kt @@ -175,7 +175,27 @@ class ApplicationServiceTests : FunSpec({ // Then currentActivity shouldBe activity2 verify(exactly = 1) { mockApplicationLifecycleHandler.onUnfocused() } - verify(exactly = 1) { mockApplicationLifecycleHandler.onFocus() } + verify(exactly = 1) { mockApplicationLifecycleHandler.onFocus(false) } + } + + test("focus will occur on subscribe when activity is already started") { + // Given + val activity: Activity + + Robolectric.buildActivity(Activity::class.java).use { controller -> + controller.setup() // Moves Activity to RESUMED state + activity = controller.get() + } + + val applicationService = ApplicationService() + val mockApplicationLifecycleHandler = spyk() + + // When + applicationService.start(activity) + applicationService.addApplicationLifecycleHandler(mockApplicationLifecycleHandler) + + // Then + verify(exactly = 1) { mockApplicationLifecycleHandler.onFocus(true) } } test("wait until system condition returns false when there is no activity") { diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt index f1d3a1e1ea..2a912d69e6 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/session/internal/session/SessionServiceTests.kt @@ -7,60 +7,89 @@ import io.kotest.matchers.shouldBe import io.mockk.spyk import io.mockk.verify -class SessionServiceTests : FunSpec({ +// Mocks used by every test in this file +private class Mocks { + val currentTime = 1111L + + private val mockSessionModelStore = MockHelper.sessionModelStore() + + fun sessionModelStore(action: ((SessionModel) -> Unit)? = null): SessionModelStore { + if (action != null) action(mockSessionModelStore.model) + return mockSessionModelStore + } + val sessionService = SessionService(MockHelper.applicationService(), MockHelper.configModelStore(), mockSessionModelStore, MockHelper.time(currentTime)) + + val spyCallback = spyk() +} + +class SessionServiceTests : FunSpec({ test("session created on focus when current session invalid") { // Given - val currentTime = 1111L + val mocks = Mocks() + val sessionService = mocks.sessionService - val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = - MockHelper.sessionModelStore { - it.isValid = false - } - val spyCallback = spyk() + sessionService.start() + val sessionModelStore = mocks.sessionModelStore { it.isValid = false } + sessionService.subscribe(mocks.spyCallback) + + // When + sessionService.onFocus(false) + + // Then + sessionModelStore.model.isValid shouldBe true + sessionModelStore.model.startTime shouldBe mocks.currentTime + sessionModelStore.model.focusTime shouldBe mocks.currentTime + verify(exactly = 1) { mocks.spyCallback.onSessionStarted() } + } + + test("session created in start when application is in the foreground") { + // Given + val mocks = Mocks() + val sessionService = mocks.sessionService + val sessionModelStore = mocks.sessionModelStore() - val sessionService = - SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) + // When sessionService.start() - sessionService.subscribe(spyCallback) + sessionService.onFocus(true) + sessionService.subscribe(mocks.spyCallback) + + // Then + sessionModelStore.model.isValid shouldBe true + sessionModelStore.model.startTime shouldBe mocks.currentTime + sessionModelStore.model.focusTime shouldBe mocks.currentTime + verify(exactly = 1) { mocks.spyCallback.onSessionStarted() } // When - sessionService.onFocus() + sessionService.onFocus(false) // Should not trigger a second session // Then - sessionModelStoreMock.model.isValid shouldBe true - sessionModelStoreMock.model.startTime shouldBe currentTime - sessionModelStoreMock.model.focusTime shouldBe currentTime - verify(exactly = 1) { spyCallback.onSessionStarted() } + verify(exactly = 1) { mocks.spyCallback.onSessionStarted() } } test("session focus time updated when current session valid") { // Given - val currentTime = 1111L val startTime = 555L + val mocks = Mocks() + val sessionService = mocks.sessionService - val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = - MockHelper.sessionModelStore { - it.isValid = true + sessionService.start() + val sessionModelStore = + mocks.sessionModelStore { it.startTime = startTime + it.isValid = true } - val spyCallback = spyk() - - val sessionService = - SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) - sessionService.start() - sessionService.subscribe(spyCallback) + sessionService.subscribe(mocks.spyCallback) // When - sessionService.onFocus() + sessionService.onFocus(false) // Then - sessionModelStoreMock.model.isValid shouldBe true - sessionModelStoreMock.model.startTime shouldBe startTime - sessionModelStoreMock.model.focusTime shouldBe currentTime - verify(exactly = 1) { spyCallback.onSessionActive() } + sessionModelStore.model.isValid shouldBe true + sessionModelStore.model.startTime shouldBe startTime + sessionModelStore.model.focusTime shouldBe mocks.currentTime + verify(exactly = 1) { mocks.spyCallback.onSessionActive() } + verify(exactly = 0) { mocks.spyCallback.onSessionStarted() } } test("session active duration updated when unfocused") { @@ -68,53 +97,47 @@ class SessionServiceTests : FunSpec({ val startTime = 555L val focusTime = 666L val startingDuration = 1000L - val currentTime = 1111L - val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = - MockHelper.sessionModelStore { + val mocks = Mocks() + val sessionService = mocks.sessionService + + sessionService.start() + val sessionModelStore = + mocks.sessionModelStore { it.isValid = true it.startTime = startTime it.focusTime = focusTime it.activeDuration = startingDuration } - val sessionService = - SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) - sessionService.start() - // When sessionService.onUnfocused() // Then - sessionModelStoreMock.model.isValid shouldBe true - sessionModelStoreMock.model.startTime shouldBe startTime - sessionModelStoreMock.model.activeDuration shouldBe startingDuration + (currentTime - focusTime) + sessionModelStore.model.isValid shouldBe true + sessionModelStore.model.startTime shouldBe startTime + sessionModelStore.model.activeDuration shouldBe startingDuration + (mocks.currentTime - focusTime) } test("session ended when background run") { // Given val activeDuration = 555L - val currentTime = 1111L + val mocks = Mocks() + val sessionService = mocks.sessionService - val configModelStoreMock = MockHelper.configModelStore() - val sessionModelStoreMock = - MockHelper.sessionModelStore { + sessionService.start() + val sessionModelStore = + mocks.sessionModelStore { it.isValid = true it.activeDuration = activeDuration } - val spyCallback = spyk() - - val sessionService = - SessionService(MockHelper.applicationService(), configModelStoreMock, sessionModelStoreMock, MockHelper.time(currentTime)) - sessionService.start() - sessionService.subscribe(spyCallback) + sessionService.subscribe(mocks.spyCallback) // When sessionService.backgroundRun() // Then - sessionModelStoreMock.model.isValid shouldBe false - verify(exactly = 1) { spyCallback.onSessionEnded(activeDuration) } + sessionModelStore.model.isValid shouldBe false + verify(exactly = 1) { mocks.spyCallback.onSessionEnded(activeDuration) } } }) diff --git a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt index 978fb6ab2a..2e70f1c07a 100644 --- a/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt +++ b/OneSignalSDK/onesignal/in-app-messages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt @@ -881,15 +881,7 @@ internal class InAppMessagesManager( .show() } - private var onFocusCalled: Boolean = false - - override fun onFocus() { - if (onFocusCalled) return - onFocusCalled = true - suspendifyOnThread { - fetchMessages() - } - } + override fun onFocus(firedOnSubscribe: Boolean) { } override fun onUnfocused() { } } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt index 1c489f1670..2d1ad00402 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/GmsLocationController.kt @@ -175,7 +175,7 @@ internal class GmsLocationController( refreshRequest() } - override fun onFocus() { + override fun onFocus(firedOnSubscribe: Boolean) { Logging.log(LogLevel.DEBUG, "LocationUpdateListener.onFocus()") refreshRequest() } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt index 19adab61d3..98dd1dec80 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/controller/impl/HmsLocationController.kt @@ -161,7 +161,7 @@ internal class HmsLocationController( refreshRequest() } - override fun onFocus() { + override fun onFocus(firedOnSubscribe: Boolean) { Logging.log(LogLevel.DEBUG, "LocationUpdateListener.onFocus()") refreshRequest() } diff --git a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt index 4acc34278c..b3a5efa10f 100644 --- a/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt +++ b/OneSignalSDK/onesignal/location/src/main/java/com/onesignal/location/internal/permissions/LocationPermissionController.kt @@ -107,8 +107,12 @@ internal class LocationPermissionController( // wait for focus to be regained, and check the current permission status. _applicationService.addApplicationLifecycleHandler( object : ApplicationLifecycleHandlerBase() { - override fun onFocus() { - super.onFocus() + override fun onFocus(firedOnSubscribe: Boolean) { + // Triggered by subscribing, wait for lifecycle callback + if (firedOnSubscribe) { + return + } + super.onFocus(false) _applicationService.removeApplicationLifecycleHandler(this) val hasPermission = AndroidUtils.hasPermission(currPermission, true, _applicationService) waiter.wake(hasPermission) diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt index 99fe9d3dc1..96a6bad747 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/NotificationsManager.kt @@ -61,7 +61,7 @@ internal class NotificationsManager( } } - override fun onFocus() { + override fun onFocus(firedOnSubscribe: Boolean) { refreshNotificationState() } diff --git a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt index b60f7700ac..b3feab7320 100644 --- a/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt +++ b/OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/permissions/impl/NotificationPermissionController.kt @@ -150,8 +150,12 @@ internal class NotificationPermissionController( // wait for focus to be regained, and check the current permission status. _applicationService.addApplicationLifecycleHandler( object : ApplicationLifecycleHandlerBase() { - override fun onFocus() { - super.onFocus() + override fun onFocus(firedOnSubscribe: Boolean) { + // Triggered by subscribing, wait for lifecycle callback + if (firedOnSubscribe) { + return + } + super.onFocus(false) _applicationService.removeApplicationLifecycleHandler(this) val hasPermission = AndroidUtils.hasPermission(ANDROID_PERMISSION_STRING, true, _applicationService) waiter.wake(hasPermission)