diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/IDManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/IDManager.kt index d0e168a787..8bb997c601 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/IDManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/common/IDManager.kt @@ -7,7 +7,7 @@ import java.util.UUID * and detect whether a provided ID was generated locally. */ object IDManager { - private const val LOCAL_PREFIX = "local-" + internal const val LOCAL_PREFIX = "local-" /** * Create a new local ID to be used temporarily prior to backend generation. diff --git a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt index c119ab62d0..57bc9f175b 100644 --- a/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt +++ b/OneSignalSDK/onesignal/core/src/main/java/com/onesignal/user/internal/subscriptions/impl/SubscriptionManager.kt @@ -157,7 +157,10 @@ internal class SubscriptionManager( args: ModelChangedArgs, tag: String, ) { - val subscription = subscriptions.collection.firstOrNull { it.id == args.model.id } + val subscription = + subscriptions.collection.firstOrNull { + args.model == (it as Subscription).model + } if (subscription == null) { // this shouldn't happen, but create a new subscription if a model was updated and we diff --git a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt index 0ee0af81c1..f753d01db8 100644 --- a/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt +++ b/OneSignalSDK/onesignal/core/src/test/java/com/onesignal/user/internal/subscriptions/SubscriptionManagerTests.kt @@ -1,9 +1,11 @@ package com.onesignal.user.internal.subscriptions +import com.onesignal.common.IDManager.LOCAL_PREFIX import com.onesignal.common.modeling.ModelChangeTags import com.onesignal.common.modeling.ModelChangedArgs import com.onesignal.core.internal.application.IApplicationService import com.onesignal.session.internal.session.ISessionService +import com.onesignal.user.internal.Subscription import com.onesignal.user.internal.subscriptions.impl.SubscriptionManager import com.onesignal.user.subscriptions.ISmsSubscription import io.kotest.core.spec.style.FunSpec @@ -11,6 +13,7 @@ import io.kotest.matchers.should import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.beInstanceOf +import io.kotest.matchers.types.shouldBeSameInstanceAs import io.mockk.every import io.mockk.just import io.mockk.mockk @@ -328,6 +331,53 @@ class SubscriptionManagerTests : FunSpec({ verify(exactly = 1) { spySubscriptionChangedHandler.onSubscriptionChanged(any(), any()) } } + // This is a common case where updates (such as optedIn) should + // still propagate even if we haven't sent the POST /users create + // call yet. Motivation for this test was a bug was discovered + // where calling OneSignal.User.pushSubscription.optIn() was not + // prompting for notification permission if it was called before + // the create User network call finished. + test("subscription modified when model updated, but with local-id") { + // Given + val pushSubscriptionModel = SubscriptionModel() + pushSubscriptionModel.id = "${LOCAL_PREFIX}subscription1" + pushSubscriptionModel.type = SubscriptionType.PUSH + pushSubscriptionModel.optedIn = true + pushSubscriptionModel.address = "my_push_token-org" + + val mockSubscriptionModelStore = mockk() + val mockApplicationService = mockk() + val mockSessionService = mockk(relaxed = true) + val listOfSubscriptions = listOf(pushSubscriptionModel) + + every { mockSubscriptionModelStore.subscribe(any()) } just runs + every { mockSubscriptionModelStore.list() } returns listOfSubscriptions + + val spySubscriptionChangedHandler = spyk() + + val subscriptionManager = SubscriptionManager(mockApplicationService, mockSessionService, mockSubscriptionModelStore) + subscriptionManager.subscribe(spySubscriptionChangedHandler) + + // When + pushSubscriptionModel.address = "my_push_token-new" + subscriptionManager.onModelUpdated( + ModelChangedArgs( + pushSubscriptionModel, + SubscriptionModel::address.name, + SubscriptionModel::address.name, + "my_push_token-org", + "my_push_token-new", + ), + ModelChangeTags.NORMAL, + ) + val subscriptions = subscriptionManager.subscriptions + + // Then + (subscriptions.push as Subscription).model shouldBeSameInstanceAs pushSubscriptionModel + subscriptions.push.token shouldBe "my_push_token-new" + verify(exactly = 1) { spySubscriptionChangedHandler.onSubscriptionChanged(any(), any()) } + } + test("subscription removed when model removed") { // Given val smsSubscription = SubscriptionModel()