Skip to content

Commit c32ddfc

Browse files
committed
Merge branch 'main' into fix-error-desc
# Conflicts: # BraintreeCore/src/main/java/com/braintreepayments/api/core/AnalyticsApi.kt
2 parents baabdcc + c4be3b4 commit c32ddfc

File tree

22 files changed

+173
-30
lines changed

22 files changed

+173
-30
lines changed

BraintreeCore/src/main/java/com/braintreepayments/api/core/AnalyticsApi.kt

+4
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ internal class AnalyticsApi(
8181
.putOpt(FPTI_KEY_BUTTON_TYPE, event.buttonType)
8282
.putOpt(FPTI_KEY_BUTTON_POSITION, event.buttonOrder)
8383
.putOpt(FPTI_KEY_PAGE_TYPE, event.pageType)
84+
.putOpt(FPTI_KEY_MERCHANT_ENABLED_APP_SWITCH, event.didEnablePayPalAppSwitch)
85+
.putOpt(FPTI_KEY_PAYPAL_ATTEMPTED_APP_SWITCH, event.didPayPalServerAttemptAppSwitch)
8486
.putOpt(FPTI_KEY_ERROR_DESC, event.errorDescription)
8587
}
8688

@@ -134,6 +136,8 @@ internal class AnalyticsApi(
134136
private const val FPTI_KEY_BUTTON_TYPE = "button_type"
135137
private const val FPTI_KEY_BUTTON_POSITION = "button_position"
136138
private const val FPTI_KEY_PAGE_TYPE = "page_type"
139+
private const val FPTI_KEY_MERCHANT_ENABLED_APP_SWITCH = "merchant_enabled_app_switch"
140+
private const val FPTI_KEY_PAYPAL_ATTEMPTED_APP_SWITCH = "attempted_app_switch"
137141
private const val FPTI_KEY_ERROR_DESC = "error_desc"
138142

139143
private const val FPTI_BATCH_KEY_VENMO_INSTALLED = "venmo_installed"

BraintreeCore/src/main/java/com/braintreepayments/api/core/AnalyticsClient.kt

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ class AnalyticsClient internal constructor(
3434
buttonType = analyticsEventParams.buttonType,
3535
buttonOrder = analyticsEventParams.buttonOrder,
3636
pageType = analyticsEventParams.pageType,
37-
errorDescription = analyticsEventParams.errorDescription
37+
errorDescription = analyticsEventParams.errorDescription,
38+
didEnablePayPalAppSwitch = analyticsParamRepository.didEnablePayPalAppSwitch,
39+
didPayPalServerAttemptAppSwitch = analyticsParamRepository.didPayPalServerAttemptAppSwitch
3840
)
3941
if (sendImmediately) {
4042
configurationLoader.loadConfiguration { result ->

BraintreeCore/src/main/java/com/braintreepayments/api/core/AnalyticsEvent.kt

+2
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@ internal data class AnalyticsEvent(
2121
val buttonOrder: String? = null,
2222
val pageType: String? = null,
2323
val errorDescription: String? = null,
24+
val didEnablePayPalAppSwitch: Boolean? = null,
25+
val didPayPalServerAttemptAppSwitch: Boolean? = null,
2426
)

BraintreeCore/src/main/java/com/braintreepayments/api/core/AnalyticsParamRepository.kt

+22-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,21 @@ class AnalyticsParamRepository(
1010
private val uuidHelper: UUIDHelper = UUIDHelper()
1111
) {
1212

13+
/**
14+
* Link type used for navigating back to the merchant app. See [LinkType].
15+
*/
1316
var linkType: LinkType? = null
1417

18+
/**
19+
* App switch enabled by the merchant request
20+
*/
21+
var didEnablePayPalAppSwitch: Boolean? = null
22+
23+
/**
24+
* App switch attempted based on the server side response
25+
*/
26+
var didPayPalServerAttemptAppSwitch: Boolean? = null
27+
1528
private lateinit var _sessionId: String
1629

1730
/**
@@ -26,10 +39,17 @@ class AnalyticsParamRepository(
2639
}
2740

2841
/**
29-
* Clears the session ID value from the repository
42+
* Resets the [sessionId] and clears all other repository values.
43+
*
44+
* Note that this function is called in different spots of the SDK lifecycle for different payment modules. Some
45+
* modules call reset during launch of the SDK. The PayPal module calls reset at the end of the payment flow to
46+
* persist the [sessionId] value set from the Shopper Insights module.
3047
*/
31-
fun resetSessionId() {
48+
fun reset() {
3249
_sessionId = uuidHelper.formattedUUID
50+
linkType = null
51+
didEnablePayPalAppSwitch = null
52+
didPayPalServerAttemptAppSwitch = null
3353
}
3454

3555
companion object {

BraintreeCore/src/main/java/com/braintreepayments/api/core/LinkType.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ import androidx.annotation.RestrictTo
99
*/
1010
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
1111
enum class LinkType(val stringValue: String) {
12-
APP_LINK("universal"),
12+
APP_LINK("applink"),
1313
DEEP_LINK("deeplink")
1414
}

BraintreeCore/src/test/java/com/braintreepayments/api/core/AnalyticsApiUnitTest.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ class AnalyticsApiUnitTest {
5555
shopperSessionId = "shopper-session-id",
5656
buttonType = "button-type",
5757
buttonOrder = "button-order",
58-
pageType = "page-type"
58+
pageType = "page-type",
59+
didEnablePayPalAppSwitch = true,
60+
didPayPalServerAttemptAppSwitch = true
5961
)
6062

6163
@Before
@@ -158,7 +160,9 @@ class AnalyticsApiUnitTest {
158160
"event_params": [
159161
{
160162
"tenant_name": "Braintree",
163+
"attempted_app_switch": ${event.didPayPalServerAttemptAppSwitch},
161164
"page_type": "${event.pageType}",
165+
"merchant_enabled_app_switch": ${event.didEnablePayPalAppSwitch},
162166
"button_type": "${event.buttonType}",
163167
"end_time": ${event.endTime},
164168
"is_vault": ${event.isVaultRequest},
@@ -209,7 +213,9 @@ class AnalyticsApiUnitTest {
209213
"event_params": [
210214
{
211215
"tenant_name": "Braintree",
216+
"attempted_app_switch": ${event.didPayPalServerAttemptAppSwitch},
212217
"page_type": "${event.pageType}",
218+
"merchant_enabled_app_switch": ${event.didEnablePayPalAppSwitch},
213219
"button_type": "${event.buttonType}",
214220
"end_time": ${event.endTime},
215221
"is_vault": ${event.isVaultRequest},

BraintreeCore/src/test/java/com/braintreepayments/api/core/AnalyticsClientUnitTest.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,18 @@ class AnalyticsClientUnitTest {
5757
shopperSessionId = analyticsEventParams.shopperSessionId,
5858
buttonType = analyticsEventParams.buttonType,
5959
buttonOrder = analyticsEventParams.buttonOrder,
60-
pageType = analyticsEventParams.pageType
60+
pageType = analyticsEventParams.pageType,
61+
didEnablePayPalAppSwitch = true,
62+
didPayPalServerAttemptAppSwitch = true,
6163
)
6264

6365
@Before
6466
@Throws(InvalidArgumentException::class, GeneralSecurityException::class, IOException::class)
6567
fun beforeEach() {
6668
every { time.currentTime } returns timestamp
6769
every { analyticsParamRepository.linkType } returns linkType
70+
every { analyticsParamRepository.didEnablePayPalAppSwitch } returns true
71+
every { analyticsParamRepository.didPayPalServerAttemptAppSwitch } returns true
6872

6973
configurationLoader = MockkConfigurationLoaderBuilder()
7074
.configuration(configuration)

BraintreeCore/src/test/java/com/braintreepayments/api/core/AnalyticsParamRepositoryUnitTest.kt

+10-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.mockk.mockk
55
import org.junit.Before
66
import org.junit.Test
77
import kotlin.test.assertEquals
8+
import kotlin.test.assertNull
89

910
class AnalyticsParamRepositoryUnitTest {
1011

@@ -20,6 +21,9 @@ class AnalyticsParamRepositoryUnitTest {
2021
sut = AnalyticsParamRepository(uuidHelper)
2122

2223
every { uuidHelper.formattedUUID } returnsMany listOf(uuid, newUuid)
24+
25+
sut.didPayPalServerAttemptAppSwitch = true
26+
sut.didEnablePayPalAppSwitch = true
2327
}
2428

2529
@Test
@@ -34,11 +38,15 @@ class AnalyticsParamRepositoryUnitTest {
3438
}
3539

3640
@Test
37-
fun `resetSessionId resets the session ID`() {
41+
fun `invoking reset resets all of the repository's values`() {
3842
assertEquals(uuid, sut.sessionId)
43+
assertEquals(true, sut.didPayPalServerAttemptAppSwitch)
44+
assertEquals(true, sut.didEnablePayPalAppSwitch)
3945

40-
sut.resetSessionId()
46+
sut.reset()
4147

4248
assertEquals(newUuid, sut.sessionId)
49+
assertNull(sut.didPayPalServerAttemptAppSwitch)
50+
assertNull(sut.didEnablePayPalAppSwitch)
4351
}
4452
}

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* PayPal
66
* Add `error_desc` tag to the analytics events we are sending to FPTI.
7+
* Send `merchant_enabled_app_switch` and `attempted_app_switch` in `event_params` for App Switch events to PayPal's analytics service (FPTI)
78
* ThreeDSecure
89
* Bump Cardinal version to `2.2.7-7` (fixes #1236).
910

Card/src/main/java/com/braintreepayments/api/card/CardClient.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class CardClient internal constructor(
6161
* @param callback [CardTokenizeCallback]
6262
*/
6363
fun tokenize(card: Card, callback: CardTokenizeCallback) {
64-
analyticsParamRepository.resetSessionId()
64+
analyticsParamRepository.reset()
6565
braintreeClient.sendAnalyticsEvent(CardAnalytics.CARD_TOKENIZE_STARTED)
6666
braintreeClient.getConfiguration { configuration: Configuration?, error: Exception? ->
6767
if (error != null) {

Card/src/test/java/com/braintreepayments/api/card/CardClientUnitTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public void tokenize_resetsSessionId() {
6060
CardClient sut = new CardClient(braintreeClient, apiClient, analyticsParamRepository);
6161
sut.tokenize(card, cardTokenizeCallback);
6262

63-
verify(analyticsParamRepository).resetSessionId();
63+
verify(analyticsParamRepository).reset();
6464
}
6565

6666
@Test

GooglePay/src/main/java/com/braintreepayments/api/googlepay/GooglePayClient.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class GooglePayClient internal constructor(
185185
request: GooglePayRequest,
186186
callback: GooglePayPaymentAuthRequestCallback
187187
) {
188-
analyticsParamRepository.resetSessionId()
188+
analyticsParamRepository.reset()
189189
braintreeClient.sendAnalyticsEvent(GooglePayAnalytics.PAYMENT_REQUEST_STARTED)
190190

191191
if (!validateManifest()) {

GooglePay/src/test/java/com/braintreepayments/api/googlepay/GooglePayClientUnitTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ public void createPaymentAuthRequest_resetsSessionId() {
210210

211211
sut.createPaymentAuthRequest(mock(), mock());
212212

213-
verify(analyticsParamRepository).resetSessionId();
213+
verify(analyticsParamRepository).reset();
214214
}
215215

216216
@Test

LocalPayment/src/main/java/com/braintreepayments/api/localpayment/LocalPaymentClient.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class LocalPaymentClient internal constructor(
5858
request: LocalPaymentRequest,
5959
callback: LocalPaymentAuthCallback
6060
) {
61-
analyticsParamRepository.resetSessionId()
61+
analyticsParamRepository.reset()
6262
braintreeClient.sendAnalyticsEvent(LocalPaymentAnalytics.PAYMENT_STARTED)
6363

6464
var exception: Exception? = null

LocalPayment/src/test/java/com/braintreepayments/api/localpayment/LocalPaymentClientUnitTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public void createPaymentAuthRequest_resetsSessionId() {
8181
LocalPaymentClient sut = new LocalPaymentClient(braintreeClient, dataCollector, localPaymentApi, analyticsParamRepository);
8282
sut.createPaymentAuthRequest(getIdealLocalPaymentRequest(), localPaymentAuthCallback);
8383

84-
verify(analyticsParamRepository).resetSessionId();
84+
verify(analyticsParamRepository).reset();
8585
}
8686

8787
@Test

PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalClient.kt

+6-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class PayPalClient internal constructor(
3434
getReturnLinkTypeUseCase: GetReturnLinkTypeUseCase = GetReturnLinkTypeUseCase(merchantRepository),
3535
private val getReturnLinkUseCase: GetReturnLinkUseCase = GetReturnLinkUseCase(merchantRepository),
3636
private val getAppSwitchUseCase: GetAppSwitchUseCase = GetAppSwitchUseCase(AppSwitchRepository.instance),
37-
analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance
37+
private val analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance
3838
) {
3939
/**
4040
* Used for linking events from the client to server side request
@@ -105,6 +105,7 @@ class PayPalClient internal constructor(
105105
) {
106106
shopperSessionId = payPalRequest.shopperSessionId
107107
isVaultRequest = payPalRequest is PayPalVaultRequest
108+
analyticsParamRepository.didEnablePayPalAppSwitch = payPalRequest.enablePayPalAppSwitch
108109

109110
braintreeClient.sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_STARTED, analyticsParams)
110111

@@ -327,6 +328,7 @@ class PayPalClient internal constructor(
327328
analyticsParams.copy(errorDescription = failure.error.message)
328329
)
329330
callback.onPayPalPaymentAuthRequest(failure)
331+
analyticsParamRepository.reset()
330332
}
331333

332334
private fun callbackBrowserSwitchCancel(
@@ -341,6 +343,7 @@ class PayPalClient internal constructor(
341343
}
342344

343345
callback.onPayPalResult(cancel)
346+
analyticsParamRepository.reset()
344347
}
345348

346349
private fun callbackTokenizeFailure(
@@ -364,6 +367,7 @@ class PayPalClient internal constructor(
364367
}
365368

366369
callback.onPayPalResult(failure)
370+
analyticsParamRepository.reset()
367371
}
368372

369373
private fun callbackTokenizeSuccess(
@@ -381,6 +385,7 @@ class PayPalClient internal constructor(
381385
}
382386

383387
callback.onPayPalResult(success)
388+
analyticsParamRepository.reset()
384389
}
385390

386391
private val analyticsParams: AnalyticsEventParams

PayPal/src/main/java/com/braintreepayments/api/paypal/PayPalInternalClient.kt

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.braintreepayments.api.paypal
22

33
import android.content.Context
44
import android.net.Uri
5+
import com.braintreepayments.api.core.AnalyticsParamRepository
56
import com.braintreepayments.api.core.ApiClient
67
import com.braintreepayments.api.core.AppSwitchRepository
78
import com.braintreepayments.api.core.BraintreeClient
@@ -24,6 +25,7 @@ internal class PayPalInternalClient(
2425
private val merchantRepository: MerchantRepository = MerchantRepository.instance,
2526
private val getReturnLinkUseCase: GetReturnLinkUseCase = GetReturnLinkUseCase(merchantRepository),
2627
private val setAppSwitchUseCase: SetAppSwitchUseCase = SetAppSwitchUseCase(AppSwitchRepository.instance),
28+
private val analyticsParamRepository: AnalyticsParamRepository = AnalyticsParamRepository.instance,
2729
private val payPalTokenResponseRepository: PayPalTokenResponseRepository = PayPalTokenResponseRepository.instance,
2830
private val payPalSetPaymentTokenUseCase: PayPalSetPaymentTokenUseCase = PayPalSetPaymentTokenUseCase(
2931
payPalTokenResponseRepository
@@ -128,6 +130,8 @@ internal class PayPalInternalClient(
128130
try {
129131
val paypalPaymentResource = PayPalPaymentResource.fromJson(responseBody)
130132
val parsedRedirectUri = Uri.parse(paypalPaymentResource.redirectUrl)
133+
analyticsParamRepository.didPayPalServerAttemptAppSwitch = paypalPaymentResource.isAppSwitchFlow
134+
131135
setAppSwitchUseCase(paypalPaymentResource.isAppSwitchFlow)
132136
val paypalContextId = extractPayPalContextId(parsedRedirectUri)
133137
payPalSetPaymentTokenUseCase.setPaymentToken(paypalContextId)

PayPal/src/test/java/com/braintreepayments/api/paypal/PayPalClientUnitTest.java

+37-12
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ public void createPaymentAuthRequest_whenPayPalNotEnabled_returnsError() {
379379
PAYPAL_NOT_ENABLED_MESSAGE
380380
);
381381
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params, true);
382+
verify(analyticsParamRepository).reset();
382383
}
383384

384385
@Test
@@ -457,6 +458,27 @@ public void requestBillingAgreement_whenConfigError_forwardsErrorToListener() {
457458
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params, true);
458459
}
459460

461+
@Test
462+
public void createPaymentAuthRequest_sets_analyticsParamRepository_didEnablePayPalAppSwitch() {
463+
PayPalInternalClient payPalInternalClient = new MockPayPalInternalClientBuilder().build();
464+
465+
BraintreeClient braintreeClient =
466+
new MockBraintreeClientBuilder().configuration(payPalEnabledConfig).build();
467+
468+
PayPalVaultRequest payPalRequest = new PayPalVaultRequest(
469+
true,
470+
false,
471+
null,
472+
null,
473+
true
474+
);
475+
476+
PayPalClient sut = new PayPalClient(braintreeClient, payPalInternalClient, merchantRepository, getReturnLinkTypeUseCase, getReturnLinkUseCase, getAppSwitchUseCase, analyticsParamRepository);
477+
sut.createPaymentAuthRequest(activity, payPalRequest, paymentAuthCallback);
478+
479+
verify(analyticsParamRepository).setDidEnablePayPalAppSwitch(true);
480+
}
481+
460482
@Test
461483
public void createPaymentAuthRequest_whenVaultRequest_sendsPayPalRequestViaInternalClient() {
462484
PayPalInternalClient payPalInternalClient = new MockPayPalInternalClientBuilder().build();
@@ -664,6 +686,7 @@ public void tokenize_whenCancelUriReceived_notifiesCancellationAndSendsAnalytics
664686
false
665687
);
666688
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.BROWSER_LOGIN_CANCELED, params, true);
689+
verify(analyticsParamRepository).reset();
667690
}
668691

669692
@Test
@@ -707,6 +730,7 @@ public void tokenize_whenPayPalInternalClientTokenizeResult_callsBackResult()
707730
false
708731
);
709732
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_SUCCEEDED, params, true);
733+
verify(analyticsParamRepository).reset();
710734
}
711735

712736
@Test
@@ -802,20 +826,21 @@ public void tokenize_whenPayPalNotEnabled_sendsAppSwitchFailedEvents() throws JS
802826
);
803827
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.TOKENIZATION_FAILED, params, true);
804828
AnalyticsEventParams appSwitchParams = new AnalyticsEventParams(
805-
"SOME-BA",
806-
false,
807-
null,
808-
null,
809-
null,
810-
null,
811-
"https://some-scheme/onetouch/v1/cancel?token=SOME-BA&switch_initiated_time=17166111926211",
812-
null,
813-
null,
814-
null,
815-
null,
816-
BROWSER_SWITCH_EXCEPTION_MESSAGE
829+
"SOME-BA",
830+
false,
831+
null,
832+
null,
833+
null,
834+
null,
835+
"https://some-scheme/onetouch/v1/cancel?token=SOME-BA&switch_initiated_time=17166111926211",
836+
null,
837+
null,
838+
null,
839+
null,
840+
BROWSER_SWITCH_EXCEPTION_MESSAGE
817841
);
818842
verify(braintreeClient).sendAnalyticsEvent(PayPalAnalytics.APP_SWITCH_FAILED, appSwitchParams, true);
843+
verify(analyticsParamRepository).reset();
819844
}
820845

821846
@Test

0 commit comments

Comments
 (0)