From 8457e63e2383bf73195e7aaa3f984c4c63b8c7fc Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Thu, 30 Nov 2023 13:22:08 -0500 Subject: [PATCH 1/2] Wait for activity to be set rather than immediately return --- .../application/impl/ApplicationService.kt | 21 +++++-- .../application/ApplicationServiceTests.kt | 55 +++++++++++++++++++ 2 files changed, 72 insertions(+), 4 deletions(-) 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 c1a7f5f45f..92e1893f0b 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 @@ -24,6 +24,7 @@ import com.onesignal.core.internal.application.IApplicationLifecycleHandler import com.onesignal.core.internal.application.IApplicationService import com.onesignal.debug.internal.logging.Logging import java.lang.ref.WeakReference +import kotlinx.coroutines.delay class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, OnGlobalLayoutListener { private val activityLifecycleNotifier = EventProducer() @@ -208,10 +209,22 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On } override suspend fun waitUntilSystemConditionsAvailable(): Boolean { - val currentActivity = current - if (currentActivity == null) { - Logging.warn("ApplicationService.waitUntilSystemConditionsAvailable: current is null") - return false + var currentActivity = current + + // if this is called just after focusing, it's possible the current activity has not yet + // been set up. So we check for up to 5 seconds, then bail if it doesn't happen. We only + // do this when called on a non-main thread, if we're running on the main thread the + // activity cannot be setup, so we don't wait around. + var waitForActivityRetryCount = if (AndroidUtils.isRunningOnMainThread()) { 50 } else { 0 } + while (currentActivity == null) { + waitForActivityRetryCount++ + if(waitForActivityRetryCount > 50) { + Logging.warn("ApplicationService.waitUntilSystemConditionsAvailable: current is null") + return false + } + delay(100) + + currentActivity = current } try { 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 9a0586b47b..900959ee1a 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 @@ -3,6 +3,8 @@ package com.onesignal.core.internal.application import android.app.Activity import android.content.Context import androidx.test.core.app.ApplicationProvider +import com.onesignal.common.threading.WaiterWithValue +import com.onesignal.common.threading.suspendifyOnThread import com.onesignal.core.internal.application.impl.ApplicationService import com.onesignal.debug.LogLevel import com.onesignal.debug.internal.logging.Logging @@ -12,6 +14,7 @@ import io.kotest.matchers.shouldBe import io.kotest.runner.junit4.KotestTestRunner import io.mockk.spyk import io.mockk.verify +import kotlinx.coroutines.delay import org.junit.runner.RunWith import org.robolectric.Robolectric @@ -189,6 +192,58 @@ class ApplicationServiceTests : FunSpec({ response shouldBe false } + test("wait until system condition returns false if activity not started within 5 seconds") { + // 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 waiter = WaiterWithValue() + + // When + suspendifyOnThread { + val response = applicationService.waitUntilSystemConditionsAvailable() + waiter.wake(response) + } + + delay(7000) + + applicationService.onActivityStarted(activity) + val response = waiter.waitForWake() + + // Then + response shouldBe false + } + + test("wait until system condition returns true when an activity is started within 5 seconds") { + // 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 waiter = WaiterWithValue() + + // When + suspendifyOnThread { + val response = applicationService.waitUntilSystemConditionsAvailable() + waiter.wake(response) + } + + delay(3000) + + applicationService.onActivityStarted(activity) + val response = waiter.waitForWake() + + // Then + response shouldBe true + } + test("wait until system condition returns true when there is no system condition") { // Given val activity: Activity From 586d7afb2e5379667dcf4510171bc6775ae2ad73 Mon Sep 17 00:00:00 2001 From: jinliu9508 Date: Mon, 4 Dec 2023 12:39:27 -0500 Subject: [PATCH 2/2] Fix linting problems --- .../internal/application/impl/ApplicationService.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 92e1893f0b..6b4247a6db 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 @@ -23,8 +23,8 @@ import com.onesignal.core.internal.application.IActivityLifecycleHandler import com.onesignal.core.internal.application.IApplicationLifecycleHandler import com.onesignal.core.internal.application.IApplicationService import com.onesignal.debug.internal.logging.Logging -import java.lang.ref.WeakReference import kotlinx.coroutines.delay +import java.lang.ref.WeakReference class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, OnGlobalLayoutListener { private val activityLifecycleNotifier = EventProducer() @@ -215,10 +215,15 @@ class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, On // been set up. So we check for up to 5 seconds, then bail if it doesn't happen. We only // do this when called on a non-main thread, if we're running on the main thread the // activity cannot be setup, so we don't wait around. - var waitForActivityRetryCount = if (AndroidUtils.isRunningOnMainThread()) { 50 } else { 0 } + var waitForActivityRetryCount = + if (AndroidUtils.isRunningOnMainThread()) { + 50 + } else { + 0 + } while (currentActivity == null) { waitForActivityRetryCount++ - if(waitForActivityRetryCount > 50) { + if (waitForActivityRetryCount > 50) { Logging.warn("ApplicationService.waitUntilSystemConditionsAvailable: current is null") return false }