diff --git a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTracker.kt b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTracker.kt index 2a12e56c67..d94eb817cd 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTracker.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTracker.kt @@ -26,132 +26,156 @@ import org.json.JSONException import org.json.JSONObject object InAppPurchaseActivityLifecycleTracker { - private val TAG = InAppPurchaseActivityLifecycleTracker::class.java.canonicalName - private const val SERVICE_INTERFACE_NAME = - "com.android.vending.billing.IInAppBillingService\$Stub" - private const val BILLING_ACTIVITY_NAME = "com.android.billingclient.api.ProxyBillingActivity" - private val isTracking = AtomicBoolean(false) - private var hasBillingService: Boolean? = null - private var hasBillingActivity: Boolean? = null - private lateinit var serviceConnection: ServiceConnection - private lateinit var callbacks: Application.ActivityLifecycleCallbacks - private lateinit var intent: Intent - private var inAppBillingObj: Any? = null - - /** Start iap logging if enable, initialize billing service if not */ - @JvmStatic - fun startIapLogging() { - initializeIfNotInitialized() - if (hasBillingService == false) { - return - } - if (isImplicitPurchaseLoggingEnabled()) { - startTracking() - } - } + private val TAG = InAppPurchaseActivityLifecycleTracker::class.java.canonicalName + private const val SERVICE_INTERFACE_NAME = + "com.android.vending.billing.IInAppBillingService\$Stub" + private const val BILLING_ACTIVITY_NAME = "com.android.billingclient.api.ProxyBillingActivity" + private val isTracking = AtomicBoolean(false) + private var hasBillingService: Boolean? = null + private var hasBillingActivity: Boolean? = null + private lateinit var serviceConnection: ServiceConnection + private lateinit var callbacks: Application.ActivityLifecycleCallbacks + private lateinit var intent: Intent + private var inAppBillingObj: Any? = null + private var billingClientVersion: InAppPurchaseUtils.BillingClientVersion? = null - private fun initializeIfNotInitialized() { - if (hasBillingService != null) { - return + /** Start iap logging if enable, initialize billing service if not */ + @JvmStatic + fun startIapLogging(billingClientVersion: InAppPurchaseUtils.BillingClientVersion) { + initializeIfNotInitialized() + if (hasBillingService == false) { + return + } + if (isImplicitPurchaseLoggingEnabled()) { + this.billingClientVersion = billingClientVersion + startTracking() + } } - hasBillingService = InAppPurchaseUtils.getClass(SERVICE_INTERFACE_NAME) != null - if (hasBillingService == false) { - return - } + private fun initializeIfNotInitialized() { + if (hasBillingService != null) { + return + } + + hasBillingService = InAppPurchaseUtils.getClass(SERVICE_INTERFACE_NAME) != null + if (hasBillingService == false) { + return + } - hasBillingActivity = InAppPurchaseUtils.getClass(BILLING_ACTIVITY_NAME) != null + hasBillingActivity = InAppPurchaseUtils.getClass(BILLING_ACTIVITY_NAME) != null - InAppPurchaseEventManager.clearSkuDetailsCache() + InAppPurchaseEventManager.clearSkuDetailsCache() - intent = - Intent("com.android.vending.billing.InAppBillingService.BIND") - .setPackage("com.android.vending") - serviceConnection = - object : ServiceConnection { - override fun onServiceConnected(name: ComponentName, service: IBinder) { - inAppBillingObj = - InAppPurchaseEventManager.asInterface(getApplicationContext(), service) - } + intent = + Intent("com.android.vending.billing.InAppBillingService.BIND") + .setPackage("com.android.vending") + serviceConnection = + object : ServiceConnection { + override fun onServiceConnected(name: ComponentName, service: IBinder) { + inAppBillingObj = + InAppPurchaseEventManager.asInterface(getApplicationContext(), service) + } - override fun onServiceDisconnected(name: ComponentName) = Unit - } - callbacks = - object : Application.ActivityLifecycleCallbacks { - override fun onActivityResumed(activity: Activity) { - try { - getExecutor().execute { - val context = getApplicationContext() - val purchasesInapp = - InAppPurchaseEventManager.getPurchasesInapp(context, inAppBillingObj) - logPurchase(context, purchasesInapp, false) - val purchasesSubs = - InAppPurchaseEventManager.getPurchasesSubs(context, inAppBillingObj) - logPurchase(context, purchasesSubs, true) - } - } catch (ep: Exception) { - /*no op*/ + override fun onServiceDisconnected(name: ComponentName) = Unit } - } + callbacks = + object : Application.ActivityLifecycleCallbacks { + override fun onActivityResumed(activity: Activity) { + try { + getExecutor().execute { + val context = getApplicationContext() + val purchasesInapp = + InAppPurchaseEventManager.getPurchasesInapp( + context, + inAppBillingObj + ) + logPurchase(context, purchasesInapp, false) + val purchasesSubs = + InAppPurchaseEventManager.getPurchasesSubs(context, inAppBillingObj) + logPurchase(context, purchasesSubs, true) + } + } catch (ep: Exception) { + /*no op*/ + } + } - override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = Unit - override fun onActivityStarted(activity: Activity) = Unit - override fun onActivityPaused(activity: Activity) = Unit - override fun onActivityStopped(activity: Activity) { - try { - if (hasBillingActivity == true && activity.localClassName == BILLING_ACTIVITY_NAME) { - getExecutor().execute { - val context = getApplicationContext() - var purchases = - InAppPurchaseEventManager.getPurchasesInapp(context, inAppBillingObj) - if (purchases.isEmpty()) { - purchases = - InAppPurchaseEventManager.getPurchaseHistoryInapp(context, inAppBillingObj) - } - logPurchase(context, purchases, false) + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = + Unit + + override fun onActivityStarted(activity: Activity) = Unit + override fun onActivityPaused(activity: Activity) = Unit + override fun onActivityStopped(activity: Activity) { + try { + if (hasBillingActivity == true && activity.localClassName == BILLING_ACTIVITY_NAME) { + getExecutor().execute { + val context = getApplicationContext() + var purchases = + InAppPurchaseEventManager.getPurchasesInapp( + context, + inAppBillingObj + ) + if (purchases.isEmpty()) { + purchases = + InAppPurchaseEventManager.getPurchaseHistoryInapp( + context, + inAppBillingObj + ) + } + logPurchase(context, purchases, false) + } + } + } catch (ep: Exception) { + /*no op*/ + } } - } - } catch (ep: Exception) { - /*no op*/ - } - } - override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = Unit - override fun onActivityDestroyed(activity: Activity) = Unit - } - } + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) = + Unit - private fun startTracking() { - if (!isTracking.compareAndSet(false, true)) { - return - } - val context = getApplicationContext() - if (context is Application) { - context.registerActivityLifecycleCallbacks(callbacks) - context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + override fun onActivityDestroyed(activity: Activity) = Unit + } } - } - private fun logPurchase(context: Context, purchases: ArrayList, isSubscription: Boolean) { - if (purchases.isEmpty()) { - return - } - val purchaseMap = hashMapOf() - val skuList = arrayListOf() - for (purchase in purchases) { - try { - val purchaseJson = JSONObject(purchase) - val sku = purchaseJson.getString("productId") - purchaseMap[sku] = purchase - skuList.add(sku) - } catch (e: JSONException) { - Log.e(TAG, "Error parsing in-app purchase data.", e) - } + private fun startTracking() { + if (!isTracking.compareAndSet(false, true)) { + return + } + val context = getApplicationContext() + if (context is Application) { + context.registerActivityLifecycleCallbacks(callbacks) + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE) + } } - val skuDetailsMap = - InAppPurchaseEventManager.getSkuDetails(context, skuList, inAppBillingObj, isSubscription) - for ((key, value) in skuDetailsMap) { - purchaseMap[key]?.let { logPurchase(it, value, isSubscription) } + + private fun logPurchase( + context: Context, + purchases: ArrayList, + isSubscription: Boolean + ) { + if (purchases.isEmpty()) { + return + } + val purchaseMap = hashMapOf() + val skuList = arrayListOf() + for (purchase in purchases) { + try { + val purchaseJson = JSONObject(purchase) + val sku = purchaseJson.getString("productId") + purchaseMap[sku] = purchase + skuList.add(sku) + } catch (e: JSONException) { + Log.e(TAG, "Error parsing in-app purchase data.", e) + } + } + val skuDetailsMap = + InAppPurchaseEventManager.getSkuDetails( + context, + skuList, + inAppBillingObj, + isSubscription + ) + for ((key, value) in skuDetailsMap) { + purchaseMap[key]?.let { logPurchase(it, value, isSubscription, billingClientVersion) } + } } - } } diff --git a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseAutoLogger.kt b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseAutoLogger.kt index ed9077aadb..fc097140af 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseAutoLogger.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseAutoLogger.kt @@ -9,7 +9,7 @@ package com.facebook.appevents.iap import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V2_V4 -import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_Plus +import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_V7 import com.facebook.appevents.iap.InAppPurchaseUtils.IAPProductType.INAPP import android.content.Context import androidx.annotation.RestrictTo @@ -35,7 +35,7 @@ object InAppPurchaseAutoLogger { if (billingClientVersion == V2_V4) { billingClientWrapper = InAppPurchaseBillingClientWrapperV2V4.getOrCreateInstance(context) - } else if (billingClientVersion == V5_Plus) { + } else if (billingClientVersion == V5_V7) { billingClientWrapper = InAppPurchaseBillingClientWrapperV5V7.getOrCreateInstance(context) } @@ -59,13 +59,15 @@ object InAppPurchaseAutoLogger { InAppPurchaseBillingClientWrapperV2V4.iapPurchaseDetailsMap, InAppPurchaseBillingClientWrapperV2V4.skuDetailsMap, false, - packageName + packageName, + billingClientVersion ) InAppPurchaseLoggerManager.filterPurchaseLogging( InAppPurchaseBillingClientWrapperV2V4.subsPurchaseDetailsMap, InAppPurchaseBillingClientWrapperV2V4.skuDetailsMap, true, - packageName + packageName, + billingClientVersion ) InAppPurchaseBillingClientWrapperV2V4.iapPurchaseDetailsMap.clear() InAppPurchaseBillingClientWrapperV2V4.subsPurchaseDetailsMap.clear() @@ -74,13 +76,15 @@ object InAppPurchaseAutoLogger { InAppPurchaseBillingClientWrapperV5V7.iapPurchaseDetailsMap, InAppPurchaseBillingClientWrapperV5V7.productDetailsMap, false, - packageName + packageName, + billingClientVersion ) InAppPurchaseLoggerManager.filterPurchaseLogging( InAppPurchaseBillingClientWrapperV5V7.subsPurchaseDetailsMap, InAppPurchaseBillingClientWrapperV5V7.productDetailsMap, true, - packageName + packageName, + billingClientVersion ) InAppPurchaseBillingClientWrapperV5V7.iapPurchaseDetailsMap.clear() InAppPurchaseBillingClientWrapperV5V7.subsPurchaseDetailsMap.clear() diff --git a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseLoggerManager.kt b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseLoggerManager.kt index 1a777cb496..68d267baa5 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseLoggerManager.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseLoggerManager.kt @@ -69,7 +69,8 @@ object InAppPurchaseLoggerManager { purchaseDetailsMap: MutableMap, skuDetailsMap: Map, isSubscription: Boolean, - packageName: String + packageName: String, + billingClientVersion: InAppPurchaseUtils.BillingClientVersion ) { readPurchaseCache() @@ -79,12 +80,16 @@ object InAppPurchaseLoggerManager { skuDetailsMap, packageName ) - logPurchases(loggingReadyMap, isSubscription) + logPurchases(loggingReadyMap, isSubscription, billingClientVersion) } - private fun logPurchases(purchaseDetailsMap: Map, isSubscription: Boolean) { + private fun logPurchases( + purchaseDetailsMap: Map, + isSubscription: Boolean, + billingClientVersion: InAppPurchaseUtils.BillingClientVersion + ) { for ((purchaseDetails, skuDetails) in purchaseDetailsMap) { - logPurchase(purchaseDetails, skuDetails, isSubscription) + logPurchase(purchaseDetails, skuDetails, isSubscription, billingClientVersion) } } diff --git a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseManager.kt b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseManager.kt index c4693dce2d..fc50cbf8bf 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseManager.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseManager.kt @@ -13,7 +13,7 @@ import androidx.annotation.RestrictTo import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.NONE import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V1 import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V2_V4 -import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_Plus +import com.facebook.appevents.iap.InAppPurchaseUtils.BillingClientVersion.V5_V7 import com.facebook.FacebookSdk.getApplicationContext import com.facebook.internal.FeatureManager import com.facebook.internal.FeatureManager.isEnabled @@ -40,7 +40,7 @@ object InAppPurchaseManager { // Delegate IAP logic to separate handler based on Google Play Billing Library version when (val billingClientVersion = getBillingClientVersion()) { NONE -> return - V1 -> InAppPurchaseActivityLifecycleTracker.startIapLogging() + V1 -> InAppPurchaseActivityLifecycleTracker.startIapLogging(V1) V2_V4 -> { if (isEnabled(FeatureManager.Feature.IapLoggingLib2)) { InAppPurchaseAutoLogger.startIapLogging( @@ -48,11 +48,11 @@ object InAppPurchaseManager { billingClientVersion ) } else { - InAppPurchaseActivityLifecycleTracker.startIapLogging() + InAppPurchaseActivityLifecycleTracker.startIapLogging(V2_V4) } } - V5_Plus -> InAppPurchaseAutoLogger.startIapLogging( + V5_V7 -> InAppPurchaseAutoLogger.startIapLogging( getApplicationContext(), billingClientVersion ) @@ -76,20 +76,20 @@ object InAppPurchaseManager { ) if (version.isEmpty()) { // Default to newest version - return V5_Plus + return V5_V7 } val majorVersion = - versionArray[0].toIntOrNull() ?: return V5_Plus + versionArray[0].toIntOrNull() ?: return V5_V7 return if (majorVersion == 1) { V1 } else if (majorVersion < 5) { V2_V4 } else { - V5_Plus + V5_V7 } } catch (e: Exception) { // Default to newest version - return V5_Plus + return V5_V7 } } } diff --git a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseUtils.kt b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseUtils.kt index 81bd091bfc..0f8dae2a1a 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseUtils.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/iap/InAppPurchaseUtils.kt @@ -84,11 +84,11 @@ object InAppPurchaseUtils { } } - enum class BillingClientVersion { - NONE, - V1, - V2_V4, - V5_Plus + enum class BillingClientVersion(val type: String) { + NONE("none"), + V1("Android-GPBL-V1"), + V2_V4("Android-GPBL-V2-V4"), + V5_V7("Android-GPBL-V5-V7") } enum class IAPProductType(val type: String) { diff --git a/facebook-core/src/main/java/com/facebook/appevents/internal/AutomaticAnalyticsLogger.kt b/facebook-core/src/main/java/com/facebook/appevents/internal/AutomaticAnalyticsLogger.kt index 4d82baf485..06eb4c1be2 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/internal/AutomaticAnalyticsLogger.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/internal/AutomaticAnalyticsLogger.kt @@ -78,11 +78,17 @@ object AutomaticAnalyticsLogger { } @JvmStatic - fun logPurchase(purchase: String, skuDetails: String, isSubscription: Boolean) { + fun logPurchase( + purchase: String, + skuDetails: String, + isSubscription: Boolean, + billingClientVersion: InAppPurchaseUtils.BillingClientVersion? + ) { if (!isImplicitPurchaseLoggingEnabled()) { return } - val loggingParameters = getPurchaseLoggingParameters(purchase, skuDetails) ?: return + val loggingParameters = + getPurchaseLoggingParameters(purchase, skuDetails, billingClientVersion) ?: return val logAsSubs = isSubscription && getGateKeeperForKey( @@ -123,9 +129,10 @@ object AutomaticAnalyticsLogger { private fun getPurchaseLoggingParameters( purchase: String, - skuDetails: String + skuDetails: String, + billingClientVersion: InAppPurchaseUtils.BillingClientVersion? ): PurchaseLoggingParameters? { - return getPurchaseLoggingParameters(purchase, skuDetails, HashMap()) + return getPurchaseLoggingParameters(purchase, skuDetails, HashMap(), billingClientVersion) } private fun getPurchaseParametersGPBLV2V4( @@ -224,12 +231,19 @@ object AutomaticAnalyticsLogger { private fun getPurchaseLoggingParameters( purchase: String, skuDetails: String, - extraParameter: Map + extraParameter: Map, + billingClientVersion: InAppPurchaseUtils.BillingClientVersion? ): PurchaseLoggingParameters? { try { val purchaseJSON = JSONObject(purchase) val skuDetailsJSON = JSONObject(skuDetails) val params = Bundle(1) + if (billingClientVersion != null) { + params.putCharSequence( + Constants.IAP_AUTOLOG_IMPLEMENTATION, + billingClientVersion.type + ) + } params.putCharSequence( Constants.IAP_PRODUCT_ID, purchaseJSON.getString(Constants.GP_IAP_PRODUCT_ID) diff --git a/facebook-core/src/main/java/com/facebook/appevents/internal/Constants.kt b/facebook-core/src/main/java/com/facebook/appevents/internal/Constants.kt index adf9fee886..3cee38c327 100644 --- a/facebook-core/src/main/java/com/facebook/appevents/internal/Constants.kt +++ b/facebook-core/src/main/java/com/facebook/appevents/internal/Constants.kt @@ -29,6 +29,7 @@ object Constants { const val IAP_FREE_TRIAL_PERIOD = "fb_free_trial_period" const val IAP_INTRO_PRICE_AMOUNT_MICROS = "fb_intro_price_amount_micros" const val IAP_INTRO_PRICE_CYCLES = "fb_intro_price_cycles" + const val IAP_AUTOLOG_IMPLEMENTATION = "fb_iap_sdk_supported_library_versions" // The following are in app purchase parameters returned by Google Play const val GP_IAP_PRODUCT_ID = "productId" diff --git a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTrackerTest.kt b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTrackerTest.kt index 482f796889..9e9b655e18 100644 --- a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTrackerTest.kt +++ b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseActivityLifecycleTrackerTest.kt @@ -34,59 +34,69 @@ import org.powermock.reflect.Whitebox AutomaticAnalyticsLogger::class, InternalAppEventsLogger::class, InAppPurchaseEventManager::class, - InAppPurchaseUtils::class) + InAppPurchaseUtils::class +) class InAppPurchaseActivityLifecycleTrackerTest : FacebookPowerMockTestCase() { - private lateinit var applicationContext: Application + private lateinit var applicationContext: Application - override fun setup() { - super.setup() - PowerMockito.whenNew(InternalAppEventsLogger::class.java).withAnyArguments().thenReturn(mock()) - applicationContext = mock() - whenever(applicationContext.registerActivityLifecycleCallbacks(any())).thenAnswer {} - whenever(applicationContext.bindService(any(), any(), any())) - .thenReturn(true) - PowerMockito.mockStatic(FacebookSdk::class.java) - whenever(FacebookSdk.isInitialized()).thenReturn(true) - whenever(FacebookSdk.getApplicationId()).thenReturn("123456789") - whenever(FacebookSdk.getApplicationContext()).thenReturn(applicationContext) - PowerMockito.mockStatic(AutomaticAnalyticsLogger::class.java) - PowerMockito.mockStatic(InAppPurchaseEventManager::class.java) + override fun setup() { + super.setup() + PowerMockito.whenNew(InternalAppEventsLogger::class.java).withAnyArguments() + .thenReturn(mock()) + applicationContext = mock() + whenever(applicationContext.registerActivityLifecycleCallbacks(any())).thenAnswer {} + whenever( + applicationContext.bindService( + any(), + any(), + any() + ) + ) + .thenReturn(true) + PowerMockito.mockStatic(FacebookSdk::class.java) + whenever(FacebookSdk.isInitialized()).thenReturn(true) + whenever(FacebookSdk.getApplicationId()).thenReturn("123456789") + whenever(FacebookSdk.getApplicationContext()).thenReturn(applicationContext) + PowerMockito.mockStatic(AutomaticAnalyticsLogger::class.java) + PowerMockito.mockStatic(InAppPurchaseEventManager::class.java) - Whitebox.setInternalState( - InAppPurchaseActivityLifecycleTracker::class.java, "hasBillingService", null as Boolean?) - Whitebox.setInternalState( - InAppPurchaseActivityLifecycleTracker::class.java, "isTracking", AtomicBoolean(false)) - PowerMockito.spy(InAppPurchaseActivityLifecycleTracker::class.java) - PowerMockito.mockStatic(InAppPurchaseUtils::class.java) - PowerMockito.doAnswer { this.javaClass } - .`when`(InAppPurchaseUtils::class.java, "getClass", any()) - } + Whitebox.setInternalState( + InAppPurchaseActivityLifecycleTracker::class.java, "hasBillingService", null as Boolean? + ) + Whitebox.setInternalState( + InAppPurchaseActivityLifecycleTracker::class.java, "isTracking", AtomicBoolean(false) + ) + PowerMockito.spy(InAppPurchaseActivityLifecycleTracker::class.java) + PowerMockito.mockStatic(InAppPurchaseUtils::class.java) + PowerMockito.doAnswer { this.javaClass } + .`when`(InAppPurchaseUtils::class.java, "getClass", any()) + } - @Test - fun `test startIapLogging will bind iap intent and lifecycle callback`() { - val intentCaptor = argumentCaptor() - whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(true) - InAppPurchaseActivityLifecycleTracker.startIapLogging() - verify(applicationContext).registerActivityLifecycleCallbacks(any()) - verify(applicationContext) - .bindService(intentCaptor.capture(), any(), any()) - assertThat(intentCaptor.firstValue.action) - .isEqualTo("com.android.vending.billing.InAppBillingService.BIND") - assertThat(intentCaptor.firstValue.`package`).isEqualTo("com.android.vending") - } + @Test + fun `test startIapLogging will bind iap intent and lifecycle callback`() { + val intentCaptor = argumentCaptor() + whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(true) + InAppPurchaseActivityLifecycleTracker.startIapLogging(InAppPurchaseUtils.BillingClientVersion.V1) + verify(applicationContext).registerActivityLifecycleCallbacks(any()) + verify(applicationContext) + .bindService(intentCaptor.capture(), any(), any()) + assertThat(intentCaptor.firstValue.action) + .isEqualTo("com.android.vending.billing.InAppBillingService.BIND") + assertThat(intentCaptor.firstValue.`package`).isEqualTo("com.android.vending") + } - @Test - fun `test startIapLogging will only register once`() { - whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(true) - InAppPurchaseActivityLifecycleTracker.startIapLogging() - InAppPurchaseActivityLifecycleTracker.startIapLogging() - verify(applicationContext, times(1)).registerActivityLifecycleCallbacks(any()) - } + @Test + fun `test startIapLogging will only register once`() { + whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(true) + InAppPurchaseActivityLifecycleTracker.startIapLogging(InAppPurchaseUtils.BillingClientVersion.V1) + InAppPurchaseActivityLifecycleTracker.startIapLogging(InAppPurchaseUtils.BillingClientVersion.V1) + verify(applicationContext, times(1)).registerActivityLifecycleCallbacks(any()) + } - @Test - fun `test startIapLogging will not register if implicit purchase disabled`() { - whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(false) - InAppPurchaseActivityLifecycleTracker.startIapLogging() - verify(applicationContext, never()).registerActivityLifecycleCallbacks(any()) - } + @Test + fun `test startIapLogging will not register if implicit purchase disabled`() { + whenever(AutomaticAnalyticsLogger.isImplicitPurchaseLoggingEnabled()).thenReturn(false) + InAppPurchaseActivityLifecycleTracker.startIapLogging(InAppPurchaseUtils.BillingClientVersion.V1) + verify(applicationContext, never()).registerActivityLifecycleCallbacks(any()) + } } diff --git a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseAutoLoggerTest.kt b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseAutoLoggerTest.kt index aabac36018..ead48a4910 100644 --- a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseAutoLoggerTest.kt +++ b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseAutoLoggerTest.kt @@ -97,12 +97,12 @@ class InAppPurchaseAutoLoggerTest : FacebookPowerMockTestCase() { } InAppPurchaseAutoLogger.startIapLogging( mockContext, - InAppPurchaseUtils.BillingClientVersion.V5_Plus + InAppPurchaseUtils.BillingClientVersion.V5_V7 ) assertThat(InAppPurchaseAutoLogger.failedToCreateWrapper.get()).isTrue() InAppPurchaseAutoLogger.startIapLogging( mockContext, - InAppPurchaseUtils.BillingClientVersion.V5_Plus + InAppPurchaseUtils.BillingClientVersion.V5_V7 ) assertThat(queryCount).isEqualTo(0) assertThat(InAppPurchaseAutoLogger.failedToCreateWrapper.get()).isTrue() @@ -125,6 +125,7 @@ class InAppPurchaseAutoLoggerTest : FacebookPowerMockTestCase() { any(), any(), any(), + any(), any() ) ).thenAnswer { @@ -183,6 +184,7 @@ class InAppPurchaseAutoLoggerTest : FacebookPowerMockTestCase() { any(), any(), any(), + any(), any() ) ).thenAnswer { @@ -212,7 +214,7 @@ class InAppPurchaseAutoLoggerTest : FacebookPowerMockTestCase() { InAppPurchaseAutoLogger.startIapLogging( mockContext, - InAppPurchaseUtils.BillingClientVersion.V5_Plus + InAppPurchaseUtils.BillingClientVersion.V5_V7 ) assertThat(querySubsRunnable).isNotNull querySubsRunnable?.run() diff --git a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseManagerTest.kt b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseManagerTest.kt index 782bc223da..9409da32cd 100644 --- a/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseManagerTest.kt +++ b/facebook-core/src/test/kotlin/com/facebook/appevents/iap/InAppPurchaseManagerTest.kt @@ -55,7 +55,7 @@ class InAppPurchaseManagerTest : FacebookPowerMockTestCase() { ) .toReturn(InAppPurchaseUtils.BillingClientVersion.V1) var isStartIapLoggingCalled = false - whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging()).thenAnswer { + whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging(eq(InAppPurchaseUtils.BillingClientVersion.V1))).thenAnswer { isStartIapLoggingCalled = true Unit } @@ -70,7 +70,7 @@ class InAppPurchaseManagerTest : FacebookPowerMockTestCase() { ) .toReturn(InAppPurchaseUtils.BillingClientVersion.NONE) var isStartIapLoggingCalled = false - whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging()).thenAnswer { + whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging(eq(InAppPurchaseUtils.BillingClientVersion.NONE))).thenAnswer { isStartIapLoggingCalled = true Unit } @@ -86,7 +86,7 @@ class InAppPurchaseManagerTest : FacebookPowerMockTestCase() { .toReturn(InAppPurchaseUtils.BillingClientVersion.V2_V4) whenever(FeatureManager.isEnabled(FeatureManager.Feature.IapLoggingLib2)).thenReturn(false) var isStartIapLoggingCalled = false - whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging()).thenAnswer { + whenever(InAppPurchaseActivityLifecycleTracker.startIapLogging(InAppPurchaseUtils.BillingClientVersion.V2_V4)).thenAnswer { isStartIapLoggingCalled = true Unit } @@ -145,7 +145,7 @@ class InAppPurchaseManagerTest : FacebookPowerMockTestCase() { whenever( InAppPurchaseAutoLogger.startIapLogging( any(), - eq(InAppPurchaseUtils.BillingClientVersion.V5_Plus) + eq(InAppPurchaseUtils.BillingClientVersion.V5_V7) ) ).thenAnswer { isStartIapLoggingCalled = true diff --git a/facebook-core/src/test/kotlin/com/facebook/appevents/internal/AutomaticAnalyticsLoggerTest.kt b/facebook-core/src/test/kotlin/com/facebook/appevents/internal/AutomaticAnalyticsLoggerTest.kt index d93e013057..4786c58132 100644 --- a/facebook-core/src/test/kotlin/com/facebook/appevents/internal/AutomaticAnalyticsLoggerTest.kt +++ b/facebook-core/src/test/kotlin/com/facebook/appevents/internal/AutomaticAnalyticsLoggerTest.kt @@ -17,6 +17,7 @@ import com.facebook.FacebookSdk import com.facebook.appevents.AppEventsConstants import com.facebook.appevents.AppEventsLogger import com.facebook.appevents.InternalAppEventsLogger +import com.facebook.appevents.iap.InAppPurchaseUtils import com.facebook.internal.FetchedAppGateKeepersManager import com.facebook.internal.FetchedAppSettings import com.facebook.internal.FetchedAppSettingsManager @@ -224,7 +225,12 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { } whenever(FacebookSdk.getAutoLogAppEventsEnabled()).thenReturn(false) - AutomaticAnalyticsLogger.logPurchase(oneTimePurchase, oneTimePurchaseDetailsGPBLV2V4, true) + AutomaticAnalyticsLogger.logPurchase( + oneTimePurchase, + oneTimePurchaseDetailsGPBLV2V4, + true, + InAppPurchaseUtils.BillingClientVersion.V2_V4 + ) assertEquals(0, appGateKeepersManagerCallCount) } @@ -234,7 +240,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { AutomaticAnalyticsLogger.logPurchase( subscriptionPurchase, subscriptionDetailsGPBLV2V4, - true + true, + InAppPurchaseUtils.BillingClientVersion.V2_V4 ) verify(mockInternalAppEventsLogger) .logEventImplicitly( @@ -245,6 +252,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { ) Assertions.assertThat(bundle).isNotNull + Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_AUTOLOG_IMPLEMENTATION)) + .isEqualTo(InAppPurchaseUtils.BillingClientVersion.V2_V4.type) Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PRODUCT_ID)).isEqualTo("id123") Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PURCHASE_TIME)) .isEqualTo("12345") @@ -275,7 +284,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { AutomaticAnalyticsLogger.logPurchase( subscriptionPurchase, subscriptionDetailsWithNoFreeTrialGPBLV2V4, - true + true, + InAppPurchaseUtils.BillingClientVersion.V2_V4 ) verify(mockInternalAppEventsLogger) .logEventImplicitly( @@ -286,6 +296,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { ) Assertions.assertThat(bundle).isNotNull + Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_AUTOLOG_IMPLEMENTATION)) + .isEqualTo(InAppPurchaseUtils.BillingClientVersion.V2_V4.type) Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PRODUCT_ID)).isEqualTo("id123") Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PURCHASE_TIME)) .isEqualTo("12345") @@ -316,7 +328,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { AutomaticAnalyticsLogger.logPurchase( subscriptionPurchase, subscriptionDetailsGPBLV5V7, - true + true, + InAppPurchaseUtils.BillingClientVersion.V5_V7 ) verify(mockInternalAppEventsLogger) .logEventImplicitly( @@ -327,6 +340,8 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { ) Assertions.assertThat(bundle).isNotNull + Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_AUTOLOG_IMPLEMENTATION)) + .isEqualTo(InAppPurchaseUtils.BillingClientVersion.V5_V7.type) Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PRODUCT_ID)).isEqualTo("id123") Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PURCHASE_TIME)) .isEqualTo("12345") @@ -355,11 +370,14 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { AutomaticAnalyticsLogger.logPurchase( oneTimePurchase, oneTimePurchaseDetailsGPBLV2V4, - false + false, + InAppPurchaseUtils.BillingClientVersion.V2_V4 ) verify(mockInternalAppEventsLogger) .logPurchaseImplicitly(any(), any(), any()) Assertions.assertThat(bundle).isNotNull + Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_AUTOLOG_IMPLEMENTATION)) + .isEqualTo(InAppPurchaseUtils.BillingClientVersion.V2_V4.type) Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PRODUCT_ID)).isEqualTo("id123") Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PURCHASE_TIME)) .isEqualTo("12345") @@ -379,10 +397,17 @@ class AutomaticAnalyticsLoggerTest : FacebookPowerMockTestCase() { @Test fun `test log purchase when implicit purchase logging enable & not subscribed with GPBL v5 - v7`() { - AutomaticAnalyticsLogger.logPurchase(oneTimePurchase, oneTimePurchaseDetailsGPBLV5V7, false) + AutomaticAnalyticsLogger.logPurchase( + oneTimePurchase, + oneTimePurchaseDetailsGPBLV5V7, + false, + InAppPurchaseUtils.BillingClientVersion.V5_V7 + ) verify(mockInternalAppEventsLogger) .logPurchaseImplicitly(any(), any(), any()) Assertions.assertThat(bundle).isNotNull + Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_AUTOLOG_IMPLEMENTATION)) + .isEqualTo(InAppPurchaseUtils.BillingClientVersion.V5_V7.type) Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PRODUCT_ID)).isEqualTo("id123") Assertions.assertThat(bundle?.getCharSequence(Constants.IAP_PURCHASE_TIME)) .isEqualTo("12345")