Skip to content

Commit

Permalink
Create PurchasesStateProvider (#1502)
Browse files Browse the repository at this point in the history
This will help removing `appInForeground` as a parameter of many
functions, specially in the `BillingWrapper`

Since this could become a very big refactor I decided to just go with
changing the getter of `PurchasesOrchestrator.state` for now to get the
state held by a `PurchasesStateProvider`.

Future PRs will remove the `appInForeground` parameter and access the
state directly.
  • Loading branch information
vegaro authored Nov 30, 2023
1 parent 6708f96 commit ba4d880
Show file tree
Hide file tree
Showing 15 changed files with 98 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ internal object BillingFactory {
cache: DeviceCache,
observerMode: Boolean,
diagnosticsTrackerIfEnabled: DiagnosticsTracker?,
stateProvider: PurchasesStateProvider,
) = when (store) {
Store.PLAY_STORE -> BillingWrapper(
BillingWrapper.ClientFactory(application),
Handler(application.mainLooper),
cache,
diagnosticsTrackerIfEnabled,
stateProvider,
)
Store.AMAZON -> {
try {
Expand All @@ -34,6 +36,7 @@ internal object BillingFactory {
observerMode,
Handler(application.mainLooper),
backendHelper,
stateProvider,
)
} catch (e: NoClassDefFoundError) {
errorLog("Make sure purchases-amazon is added as dependency", e)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ internal class PurchasesFactory(
backendHelper,
)

val purchasesStateProvider = PurchasesStateCache(PurchasesState())

// Override used for integration tests.
val billing: BillingAbstract = overrideBillingAbstract ?: BillingFactory.createBilling(
store,
Expand All @@ -134,6 +136,7 @@ internal class PurchasesFactory(
cache,
observerMode,
diagnosticsTracker,
purchasesStateProvider,
)

val subscriberAttributesPoster = SubscriberAttributesPoster(backendHelper)
Expand Down Expand Up @@ -268,6 +271,7 @@ internal class PurchasesFactory(
offeringsManager,
createPaywallEventsManager(application, identityManager, eventsDispatcher, backend),
paywallPresentedCache,
purchasesStateProvider,
)

return Purchases(purchasesOrchestrator)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,16 @@ internal class PurchasesOrchestrator constructor(
private val offeringsManager: OfferingsManager,
private val paywallEventsManager: PaywallEventsManager?,
private val paywallPresentedCache: PaywallPresentedCache,
private val purchasesStateCache: PurchasesStateCache,
// This is nullable due to: https://github.com/RevenueCat/purchases-flutter/issues/408
private val mainHandler: Handler? = Handler(Looper.getMainLooper()),
) : LifecycleDelegate, CustomActivityLifecycleHandler {

/** @suppress */
@Suppress("RedundantGetter", "RedundantSetter")
@Volatile
internal var state = PurchasesState()
@Synchronized
get() = field
internal var state: PurchasesState
get() = purchasesStateCache.purchasesState

@Synchronized
set(value) {
field = value
purchasesStateCache.purchasesState = value
}

var finishTransactions: Boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.revenuecat.purchases

internal data class PurchasesStateCache(
@get:Synchronized
@set:Synchronized
override var purchasesState: PurchasesState,
) : PurchasesStateProvider
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.revenuecat.purchases

internal interface PurchasesStateProvider {
val purchasesState: PurchasesState
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.revenuecat.purchases.PostReceiptInitiationSource
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCallback
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.amazon.handler.ProductDataHandler
import com.revenuecat.purchases.amazon.handler.PurchaseHandler
import com.revenuecat.purchases.amazon.handler.PurchaseUpdatesHandler
Expand Down Expand Up @@ -50,13 +51,14 @@ import com.revenuecat.purchases.ProductType as RevenueCatProductType

private const val TERM_SKU_JSON_KEY = "termSku"

@SuppressWarnings("LongParameterList")
@SuppressWarnings("LongParameterList", "TooManyFunctions")
internal class AmazonBilling constructor(
private val applicationContext: Context,
private val amazonBackend: AmazonBackend,
private val cache: AmazonCache,
private val observerMode: Boolean,
private val mainHandler: Handler,
stateProvider: PurchasesStateProvider,
private val purchasingServiceProvider: PurchasingServiceProvider = DefaultPurchasingServiceProvider(),
private val productDataHandler: ProductDataResponseListener =
ProductDataHandler(purchasingServiceProvider, mainHandler),
Expand All @@ -67,7 +69,7 @@ internal class AmazonBilling constructor(
),
private val userDataHandler: UserDataResponseListener = UserDataHandler(purchasingServiceProvider, mainHandler),
private val dateProvider: DateProvider = DefaultDateProvider(),
) : BillingAbstract(),
) : BillingAbstract(stateProvider),
ProductDataResponseListener by productDataHandler,
PurchaseResponseListener by purchaseHandler,
PurchaseUpdatesResponseListener by purchaseUpdatesHandler,
Expand All @@ -81,9 +83,17 @@ internal class AmazonBilling constructor(
observerMode: Boolean,
mainHandler: Handler,
backendHelper: BackendHelper,
) : this(applicationContext, AmazonBackend(backendHelper), AmazonCache(cache), observerMode, mainHandler)

var connected = false
stateProvider: PurchasesStateProvider,
) : this(
applicationContext,
AmazonBackend(backendHelper),
AmazonCache(cache),
observerMode,
mainHandler,
stateProvider,
)

private var connected = false

override fun startConnection() {
if (checkObserverMode()) return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.revenuecat.purchases.PostReceiptInitiationSource
import com.revenuecat.purchases.ProductType
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCallback
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.models.InAppMessageType
import com.revenuecat.purchases.models.PurchasingData
import com.revenuecat.purchases.models.StoreProduct
Expand All @@ -13,7 +14,9 @@ import com.revenuecat.purchases.models.StoreTransaction
internal typealias StoreProductsCallback = (List<StoreProduct>) -> Unit

@SuppressWarnings("TooManyFunctions")
internal abstract class BillingAbstract {
internal abstract class BillingAbstract(
protected val purchasesStateProvider: PurchasesStateProvider,
) {

@get:Synchronized
@set:Synchronized
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.revenuecat.purchases.ProductType
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCallback
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.common.BillingAbstract
import com.revenuecat.purchases.common.DateProvider
import com.revenuecat.purchases.common.DefaultDateProvider
Expand Down Expand Up @@ -81,8 +82,9 @@ internal class BillingWrapper(
private val deviceCache: DeviceCache,
@Suppress("unused")
private val diagnosticsTrackerIfEnabled: DiagnosticsTracker?,
purchasesStateProvider: PurchasesStateProvider,
private val dateProvider: DateProvider = DefaultDateProvider(),
) : BillingAbstract(), PurchasesUpdatedListener, BillingClientStateListener {
) : BillingAbstract(purchasesStateProvider), PurchasesUpdatedListener, BillingClientStateListener {

@get:Synchronized
@set:Synchronized
Expand All @@ -101,6 +103,9 @@ internal class BillingWrapper(
@set:Synchronized
private var reconnectionAlreadyScheduled = false

val appInBackground: Boolean
get() = purchasesStateProvider.purchasesState.appInBackground

class ClientFactory(private val context: Context) {
@UiThread
fun buildClient(listener: com.android.billingclient.api.PurchasesUpdatedListener): BillingClient {
Expand Down Expand Up @@ -523,7 +528,7 @@ internal class BillingWrapper(
QueryPurchasesByTypeUseCaseParams(
dateProvider,
diagnosticsTrackerIfEnabled,
appInBackground = false,
appInBackground = appInBackground,
productType = productType,
),
onSuccess = { purchases ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ internal open class BasePurchasesTest {
internal val mockSyncPurchasesHelper = mockk<SyncPurchasesHelper>()
protected val mockOfferingsManager = mockk<OfferingsManager>()
internal val mockPaywallEventsManager = mockk<PaywallEventsManager>()
private val purchasesStateProvider = PurchasesStateCache(PurchasesState())

protected var capturedPurchasesUpdatedListener = slot<BillingAbstract.PurchasesUpdatedListener>()
protected var capturedBillingWrapperStateListener = slot<BillingAbstract.StateListener>()
Expand Down Expand Up @@ -407,6 +408,7 @@ internal open class BasePurchasesTest {
offeringsManager = mockOfferingsManager,
paywallEventsManager = mockPaywallEventsManager,
paywallPresentedCache = paywallPresentedCache,
purchasesStateCache = purchasesStateProvider,
)
purchases = Purchases(purchasesOrchestrator)
Purchases.sharedInstance = purchases
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class BillingFactoryTest {
mockBackendHelper,
mockCache,
observerMode = false,
mockDiagnosticsTracker
mockDiagnosticsTracker,
PurchasesStateCache(PurchasesState())
)
}

Expand All @@ -41,7 +42,8 @@ class BillingFactoryTest {
mockBackendHelper,
mockCache,
observerMode = false,
diagnosticsTrackerIfEnabled = null
diagnosticsTrackerIfEnabled = null,
PurchasesStateCache(PurchasesState())
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import com.revenuecat.purchases.PostReceiptInitiationSource
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCallback
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.PurchasesState
import com.revenuecat.purchases.PurchasesStateCache
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.amazon.handler.ProductDataHandler
import com.revenuecat.purchases.amazon.handler.PurchaseHandler
import com.revenuecat.purchases.amazon.handler.PurchaseUpdatesHandler
Expand Down Expand Up @@ -70,7 +73,8 @@ class AmazonBillingTest {
purchaseHandler = mockPurchaseHandler,
purchaseUpdatesHandler = mockPurchaseUpdatesHandler,
userDataHandler = mockUserDataHandler,
mainHandler = handler
mainHandler = handler,
stateProvider = PurchasesStateCache(PurchasesState())
)

mockSetupFunctions()
Expand All @@ -90,7 +94,8 @@ class AmazonBillingTest {
productDataHandler = mockProductDataHandler,
purchaseHandler = mockPurchaseHandler,
purchaseUpdatesHandler = mockPurchaseUpdatesHandler,
userDataHandler = mockUserDataHandler
userDataHandler = mockUserDataHandler,
stateProvider = PurchasesStateCache(PurchasesState())
)

mockSetupFunctions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ package com.revenuecat.purchases.amazon
import android.app.Application
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.revenuecat.purchases.BillingFactory
import com.revenuecat.purchases.PurchasesState
import com.revenuecat.purchases.PurchasesStateCache
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.Store
import com.revenuecat.purchases.common.BackendHelper
import com.revenuecat.purchases.common.caching.DeviceCache
Expand All @@ -27,7 +30,8 @@ class BillingFactoryAmazonTest {
mockBackendHelper,
mockCache,
observerMode = false,
mockDiagnosticsTracker
mockDiagnosticsTracker,
stateProvider = PurchasesStateCache(PurchasesState())
)
}

Expand All @@ -43,7 +47,8 @@ class BillingFactoryAmazonTest {
mockBackendHelper,
mockCache,
observerMode = false,
diagnosticsTrackerIfEnabled = null
diagnosticsTrackerIfEnabled = null,
stateProvider = PurchasesStateCache(PurchasesState())
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import com.revenuecat.purchases.PostReceiptInitiationSource
import com.revenuecat.purchases.ProductType
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.PurchasesState
import com.revenuecat.purchases.PurchasesStateCache
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.assertDebugLog
import com.revenuecat.purchases.assertErrorLog
import com.revenuecat.purchases.assertVerboseLog
Expand Down Expand Up @@ -110,6 +113,7 @@ class BillingWrapperTest {

private val subsGoogleProductType = ProductType.SUBS.toGoogleProductType()!!
private val inAppGoogleProductType = ProductType.INAPP.toGoogleProductType()!!
private val purchasesStateProvider = PurchasesStateCache(PurchasesState())

@Before
fun setup() {
Expand Down Expand Up @@ -153,7 +157,14 @@ class BillingWrapperTest {

mockDetailsList = listOf(mockProductDetails())

wrapper = BillingWrapper(mockClientFactory, handler, mockDeviceCache, mockDiagnosticsTracker, mockDateProvider)
wrapper = BillingWrapper(
mockClientFactory,
handler,
mockDeviceCache,
mockDiagnosticsTracker,
purchasesStateProvider,
mockDateProvider
)
wrapper.purchasesUpdatedListener = mockPurchasesListener
wrapper.startConnectionOnMainThread()
onConnectedCalled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.BillingClientStateListener
import com.android.billingclient.api.BillingResult
import com.android.billingclient.api.PurchasesUpdatedListener
import com.revenuecat.purchases.PurchasesState
import com.revenuecat.purchases.PurchasesStateCache
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.common.BillingAbstract
import com.revenuecat.purchases.common.DateProvider
import com.revenuecat.purchases.common.caching.DeviceCache
Expand Down Expand Up @@ -45,6 +48,7 @@ internal open class BaseBillingUseCaseTest {

private var onConnectedCalled: Boolean = false
private var mockPurchasesListener: BillingAbstract.PurchasesUpdatedListener = mockk()
private val purchasesStateProvider = PurchasesStateCache(PurchasesState())

@Before
open fun setup() {
Expand Down Expand Up @@ -75,7 +79,14 @@ internal open class BaseBillingUseCaseTest {
mockClient.isReady
} returns false andThen true

wrapper = BillingWrapper(mockClientFactory, handler, mockDeviceCache, mockDiagnosticsTracker, mockDateProvider)
wrapper = BillingWrapper(
mockClientFactory,
handler,
mockDeviceCache,
mockDiagnosticsTracker,
purchasesStateProvider,
mockDateProvider
)
wrapper.purchasesUpdatedListener = mockPurchasesListener
wrapper.startConnectionOnMainThread()
onConnectedCalled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import com.revenuecat.purchases.PostReceiptHelper
import com.revenuecat.purchases.PostTransactionWithProductDetailsHelper
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.PurchasesOrchestrator
import com.revenuecat.purchases.PurchasesState
import com.revenuecat.purchases.PurchasesStateCache
import com.revenuecat.purchases.PurchasesStateProvider
import com.revenuecat.purchases.Store
import com.revenuecat.purchases.common.AppConfig
import com.revenuecat.purchases.common.Backend
Expand Down Expand Up @@ -98,7 +101,8 @@ class SubscriberAttributesPurchasesTests {
syncPurchasesHelper = mockk(),
offeringsManager = offeringsManagerMock,
paywallEventsManager = null,
paywallPresentedCache = PaywallPresentedCache()
paywallPresentedCache = PaywallPresentedCache(),
purchasesStateCache = PurchasesStateCache(PurchasesState()),
)

underTest = Purchases(purchasesOrchestrator)
Expand Down

0 comments on commit ba4d880

Please sign in to comment.