Skip to content

Commit

Permalink
Add has user location consent flag (#469)
Browse files Browse the repository at this point in the history
* Add hasUserLocationConsent to DropInRequest

* Update changelog
  • Loading branch information
tdchow authored Mar 29, 2024
1 parent 247cede commit b19d746
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 13 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Braintree Android Drop-In Release Notes

## unreleased

* Fixes Google Play Store Rejection
* See [developer documentation](link) for required updates for user location data compliance
* Add `PayPalDataCollectorRequest` to pass in `hasUserLocationConsent`
* Add `hasUserLocationConsent` property to `DropInRequest`
* Deprecate existing constructor that does not pass in `hasUserLocationConsent`

## 6.15.0

* Refresh vaulted payment methods list after 3DS is canceled (fixes #455)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ private void onVaultedPaymentMethodSelected(DropInEvent event) {
} else {
final DropInResult dropInResult = new DropInResult();
dropInResult.setPaymentMethodNonce(paymentMethodNonce);
dropInInternalClient.collectDeviceData(DropInActivity.this, (deviceData, error) -> {
dropInInternalClient.collectDeviceData(DropInActivity.this, dropInRequest.hasUserLocationConsent(), (deviceData, error) -> {
if (deviceData != null) {
dropInResult.setDeviceData(deviceData);
animateBottomSheetClosedAndFinishDropInWithResult(dropInResult);
Expand Down Expand Up @@ -531,7 +531,7 @@ private void onPaymentMethodNonceCreated(final PaymentMethodNonce paymentMethod)
} else {
DropInResult dropInResult = new DropInResult();
dropInResult.setPaymentMethodNonce(paymentMethod);
dropInInternalClient.collectDeviceData(this, (deviceData, deviceDataError) -> {
dropInInternalClient.collectDeviceData(this, dropInRequest.hasUserLocationConsent(), (deviceData, deviceDataError) -> {
if (deviceData != null) {
dropInResult.setDeviceData(deviceData);
animateBottomSheetClosedAndFinishDropInWithResult(dropInResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,12 @@ void sendAnalyticsEvent(String eventName) {
braintreeClient.sendAnalyticsEvent(eventName);
}

void collectDeviceData(FragmentActivity activity, DataCollectorCallback callback) {
void collectDeviceData(
FragmentActivity activity,
boolean hasUserLocationConsent,
DataCollectorCallback callback
) {
// TODO: pass in hasUserLocationConsent
dataCollector.collectDeviceData(activity, callback);
}

Expand All @@ -106,7 +111,7 @@ void performThreeDSecureVerification(final FragmentActivity activity, PaymentMet
} else if (threeDSecureResult != null) {
final DropInResult dropInResult = new DropInResult();
dropInResult.setPaymentMethodNonce(threeDSecureResult.getTokenizedCard());
dataCollector.collectDeviceData(activity, (deviceData, dataCollectionError) -> {
collectDeviceData(activity, dropInRequest.hasUserLocationConsent(), (deviceData, dataCollectionError) -> {
if (deviceData != null) {
dropInResult.setDeviceData(deviceData);
callback.onResult(dropInResult, null);
Expand Down Expand Up @@ -145,6 +150,8 @@ void tokenizePayPalRequest(FragmentActivity activity, PayPalFlowStartedCallback
if (paypalRequest == null) {
paypalRequest = new PayPalVaultRequest();
}
// TODO: set hasUserLocationConsent on paypalRequest
dropInRequest.hasUserLocationConsent();
payPalClient.tokenizePayPalAccount(activity, paypalRequest, callback);
}

Expand Down Expand Up @@ -248,7 +255,7 @@ private void notifyDropInResult(FragmentActivity activity, PaymentMethodNonce pa

final DropInResult dropInResult = new DropInResult();
dropInResult.setPaymentMethodNonce(paymentMethodNonce);
dataCollector.collectDeviceData(activity, (deviceData, dataCollectionError) -> {
collectDeviceData(activity, dropInRequest.hasUserLocationConsent(), (deviceData, dataCollectionError) -> {
if (dataCollectionError != null) {
callback.onResult(null, dataCollectionError);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,21 @@ public class DropInRequest implements Parcelable {
private boolean allowVaultCardOverride = false;

private String customUrlScheme = null;
private final boolean hasUserLocationConsent;

private int cardholderNameStatus = CardForm.FIELD_DISABLED;

public DropInRequest() {}
/**
* Deprecated. Use {@link DropInRequest#DropInRequest(boolean)} instead.
**/
@Deprecated
public DropInRequest() {
hasUserLocationConsent = false;
}

public DropInRequest(boolean hasUserLocationConsent) {
this.hasUserLocationConsent = hasUserLocationConsent;
}

/**
* This method is optional.
Expand Down Expand Up @@ -311,6 +322,13 @@ public String getCustomUrlScheme() {
return customUrlScheme;
}

/**
* @return If the user has consented to sharing location data.
*/
boolean hasUserLocationConsent() {
return hasUserLocationConsent;
}

@Override
public int describeContents() {
return 0;
Expand All @@ -334,6 +352,7 @@ public void writeToParcel(Parcel dest, int flags) {
dest.writeByte(vaultCardDefaultValue ? (byte) 1 : (byte) 0);
dest.writeByte(allowVaultCardOverride ? (byte) 1 : (byte) 0);
dest.writeString(customUrlScheme);
dest.writeByte(hasUserLocationConsent ? (byte) 1 : (byte) 0);
}

protected DropInRequest(Parcel in) {
Expand All @@ -353,6 +372,7 @@ protected DropInRequest(Parcel in) {
vaultCardDefaultValue = in.readByte() != 0;
allowVaultCardOverride = in.readByte() != 0;
customUrlScheme = in.readString();
hasUserLocationConsent = in.readByte() != 0;
}

public static final Creator<DropInRequest> CREATOR = new Creator<DropInRequest>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public DataCollector build() {
callback.onResult(null, collectDeviceDataError);
}
return null;
// TODO: add hasUserLocationConsent argument
}).when(dataCollector).collectDeviceData(any(Context.class), any(DataCollectorCallback.class));

return dataCollector;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.braintreepayments.api;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
Expand Down Expand Up @@ -253,14 +254,14 @@ DropInInternalClient build() {
}).when(dropInClient).getSupportedCardTypes(any(GetSupportedCardTypesCallback.class));

doAnswer((Answer<Void>) invocation -> {
DataCollectorCallback callback = (DataCollectorCallback) invocation.getArguments()[1];
DataCollectorCallback callback = (DataCollectorCallback) invocation.getArguments()[2];
if (deviceDataSuccess != null) {
callback.onResult(deviceDataSuccess, null);
} else if (deviceDataError != null) {
callback.onResult(null, deviceDataError);
}
return null;
}).when(dropInClient).collectDeviceData(any(FragmentActivity.class), any(DataCollectorCallback.class));
}).when(dropInClient).collectDeviceData(any(FragmentActivity.class), anyBoolean(), any(DataCollectorCallback.class));

doAnswer((Answer<Void>) invocation -> {
DeletePaymentMethodNonceCallback callback = (DeletePaymentMethodNonceCallback) invocation.getArguments()[2];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class DropInActivityUnitTest {
@Before
fun beforeEach() {
authorization = Authorization.fromString(Fixtures.TOKENIZATION_KEY)
dropInRequest = DropInRequest()
dropInRequest = DropInRequest(true)
}

@After
Expand Down Expand Up @@ -425,6 +425,39 @@ class DropInActivityUnitTest {
)
}

@Test
fun threeDS_collectDeviceData_passes_in_hasUserLocationConsent() {
val dropInClient = MockDropInInternalClientBuilder()
.authorizationSuccess(authorization)
.shouldPerformThreeDSecureVerification(false)
.build()
setupDropInActivity(dropInClient, dropInRequest)

val cardNonce = CardNonce.fromJSON(JSONObject(Fixtures.VISA_CREDIT_CARD_RESPONSE))
activity.supportFragmentManager.setFragmentResult(
DropInEvent.REQUEST_KEY,
DropInEvent.createVaultedPaymentMethodSelectedEvent(cardNonce).toBundle()
)

verify(dropInClient).collectDeviceData(same(activity), eq(true), any())
}

@Test
fun card_collectDeviceData_passes_in_hasUserLocationConsent() {
val cardNonce = CardNonce.fromJSON(JSONObject(Fixtures.VISA_CREDIT_CARD_RESPONSE))
val dropInClient = MockDropInInternalClientBuilder()
.authorizationSuccess(authorization)
.shouldPerformThreeDSecureVerification(false)
.cardTokenizeSuccess(cardNonce)
.build()
setupDropInActivity(dropInClient, dropInRequest)

val event = DropInEvent.createCardDetailsSubmitEvent(Card())
activity.supportFragmentManager.setFragmentResult(DropInEvent.REQUEST_KEY, event.toBundle())

verify(dropInClient).collectDeviceData(same(activity), eq(true), any())
}

@Test
fun onVaultedPaymentMethodSelectedEvent_returnsDeviceData() {
val dropInClient = MockDropInInternalClientBuilder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ public void collectDeviceData_forwardsInvocationToDataCollector() {
DataCollectorCallback callback = mock(DataCollectorCallback.class);

DropInInternalClient sut = new DropInInternalClient(params);
sut.collectDeviceData(activity, callback);
sut.collectDeviceData(activity, true, callback);

// TODO: add hasUserLocationConsent to verify
verify(dataCollector).collectDeviceData(activity, callback);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;

@RunWith(RobolectricTestRunner.class)
Expand Down Expand Up @@ -58,7 +59,7 @@ public void includesAllOptions() {
additionalInformation.setShippingMethodIndicator("GEN");
threeDSecureRequest.setAdditionalInformation(additionalInformation);

DropInRequest dropInRequest = new DropInRequest();
DropInRequest dropInRequest = new DropInRequest(true);
dropInRequest.setGooglePayRequest(googlePayRequest);
dropInRequest.setGooglePayDisabled(true);
dropInRequest.setPayPalRequest(paypalRequest);
Expand Down Expand Up @@ -120,6 +121,7 @@ public void includesAllOptions() {
assertTrue(dropInRequest.getVaultCardDefaultValue());
assertTrue(dropInRequest.getAllowVaultCardOverride());
assertEquals(CardForm.FIELD_OPTIONAL, dropInRequest.getCardholderNameStatus());
assertTrue(dropInRequest.hasUserLocationConsent());
}

@Test
Expand Down Expand Up @@ -164,7 +166,7 @@ public void isParcelable() {
additionalInformation.setShippingMethodIndicator("GEN");
threeDSecureRequest.setAdditionalInformation(additionalInformation);

DropInRequest dropInRequest = new DropInRequest();
DropInRequest dropInRequest = new DropInRequest(true);
dropInRequest.setGooglePayRequest(googlePayRequest);
dropInRequest.setGooglePayDisabled(true);
dropInRequest.setPayPalRequest(paypalRequest);
Expand Down Expand Up @@ -229,13 +231,20 @@ public void isParcelable() {
assertTrue(parceledDropInRequest.getVaultCardDefaultValue());
assertTrue(parceledDropInRequest.getAllowVaultCardOverride());
assertEquals(CardForm.FIELD_OPTIONAL, parceledDropInRequest.getCardholderNameStatus());
assertTrue(parceledDropInRequest.hasUserLocationConsent());
}

@Test
public void getCardholderNameStatus_includesCardHolderNameStatus() {
DropInRequest dropInRequest = new DropInRequest();
DropInRequest dropInRequest = new DropInRequest(true);
dropInRequest.setCardholderNameStatus(CardForm.FIELD_REQUIRED);

assertEquals(CardForm.FIELD_REQUIRED, dropInRequest.getCardholderNameStatus());
}

@Test
public void no_argument_constructor_defaults_hasUserLocationConsent_to_false() {
DropInRequest request = new DropInRequest();
assertFalse(request.hasUserLocationConsent());
}
}

0 comments on commit b19d746

Please sign in to comment.