From 30433c1559b1a8b5c9faca26ca6b8fa4ff8ca124 Mon Sep 17 00:00:00 2001 From: Brian Smith <104789812+brismithers@users.noreply.github.com> Date: Tue, 5 Dec 2023 10:21:42 -0500 Subject: [PATCH] Wait for activity to be set rather than immediately return in waitUntilSystemConditionsAvailable (#1926) * Wait for activity to be set rather than immediately return * Fix linting problems --------- Co-authored-by: jinliu9508 --- .../application/impl/ApplicationService.kt | 26 +++++++-- .../application/ApplicationServiceTests.kt | 55 +++++++++++++++++++ 2 files changed, 77 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..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,6 +23,7 @@ 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 kotlinx.coroutines.delay import java.lang.ref.WeakReference class ApplicationService() : IApplicationService, ActivityLifecycleCallbacks, OnGlobalLayoutListener { @@ -208,10 +209,27 @@ 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