Commit 62726b73 authored by Liquan (Max) Gu's avatar Liquan (Max) Gu Committed by Chromium LUCI CQ

[Payments] Simplify JourneyLogger.recordTransactionAmount()

Behavioural changes:
* Before the CL, JourneyLogger.recordTransactionAmount() was triggered
  only when Event.SHOWN or Event.SKIPPED_SHOW is recorded. This was
  different from the desktop's behaviour(read crbug.com/1149936#c5 for
  more context).
* After the CL, the method is triggered whenever all of the following
  conditions are met:
  (1) show() has been called,
  (2) apps have been queried,
  (3) payment details has stabilized.
  Regardless of Event.SHOWN and Event.SKIPPED_SHOW, which are recorded
  when UI is shown or skipped. The new behaviour is consistent with the
  desktop one.

Changes:
* Moved the calling of recordTransactionAmount() into the hook
  onShowCalledAndAppsQueriedAndDetailsFinalized().

Bug: 1149936
Change-Id: I4fc72e2289ab95303165622e395f9d499ebf338d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2581218
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarSahel Sharify <sahel@chromium.org>
Cr-Commit-Position: refs/heads/master@{#835672}
parent 1467592e
...@@ -309,11 +309,6 @@ public class ChromePaymentRequestService ...@@ -309,11 +309,6 @@ public class ChromePaymentRequestService
dimBackgroundIfNotBottomSheetPaymentHandler(selectedApp); dimBackgroundIfNotBottomSheetPaymentHandler(selectedApp);
mDidRecordShowEvent = true; mDidRecordShowEvent = true;
mJourneyLogger.setEventOccurred(Event.SKIPPED_SHOW); mJourneyLogger.setEventOccurred(Event.SKIPPED_SHOW);
assert mSpec.getRawTotal() != null;
// The total amount in details should be finalized at this point. So it is safe to
// record the triggered transaction amount.
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, false /*completed*/);
invokePaymentApp(null /* selectedShippingAddress */, null /* selectedShippingOption */, invokePaymentApp(null /* selectedShippingAddress */, null /* selectedShippingOption */,
selectedApp); selectedApp);
} else { } else {
...@@ -346,8 +341,6 @@ public class ChromePaymentRequestService ...@@ -346,8 +341,6 @@ public class ChromePaymentRequestService
} }
private void onMinimalUiConfirmed(PaymentApp app) { private void onMinimalUiConfirmed(PaymentApp app) {
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, false /*completed*/);
app.disableShowingOwnUI(); app.disableShowingOwnUI();
invokePaymentApp( invokePaymentApp(
null /* selectedShippingAddress */, null /* selectedShippingOption */, app); null /* selectedShippingAddress */, null /* selectedShippingOption */, app);
...@@ -419,18 +412,6 @@ public class ChromePaymentRequestService ...@@ -419,18 +412,6 @@ public class ChromePaymentRequestService
mPaymentUiService.updateDetailsOnPaymentRequestUI(mSpec.getPaymentDetails()); mPaymentUiService.updateDetailsOnPaymentRequestUI(mSpec.getPaymentDetails());
// Triggered transaction amount gets recorded when both of the following conditions are met:
// 1- Either Event.Shown or Event.SKIPPED_SHOW bits are set showing that transaction is
// triggered (mDidRecordShowEvent == true). 2- The total amount in details won't change
// (mPaymentRequestService.isShowWaitingForUpdatedDetails() == false). Record the
// transaction amount only when the triggered condition is already met. Otherwise it will
// get recorded when triggered condition becomes true.
if (mDidRecordShowEvent) {
assert mSpec.getRawTotal() != null;
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, /*completed=*/false);
}
if (isFinishedQueryingPaymentApps && !mHasSkippedAppSelector) { if (isFinishedQueryingPaymentApps && !mHasSkippedAppSelector) {
boolean providedInformationToPaymentRequestUI = boolean providedInformationToPaymentRequestUI =
mPaymentUiService.enableAndUpdatePaymentRequestUIWithPaymentInfo(); mPaymentUiService.enableAndUpdatePaymentRequestUIWithPaymentInfo();
...@@ -461,15 +442,6 @@ public class ChromePaymentRequestService ...@@ -461,15 +442,6 @@ public class ChromePaymentRequestService
if (mDidRecordShowEvent) return; if (mDidRecordShowEvent) return;
mDidRecordShowEvent = true; mDidRecordShowEvent = true;
mJourneyLogger.setEventOccurred(Event.SHOWN); mJourneyLogger.setEventOccurred(Event.SHOWN);
// Record the triggered transaction amount only when the total amount in details is
// finalized (i.e. mPaymentRequestService.isShowWaitingForUpdatedDetails() == false).
// Otherwise it will get recorded when the updated details become available.
if (mPaymentRequestService != null
&& !mPaymentRequestService.isShowWaitingForUpdatedDetails()) {
assert mSpec.getRawTotal() != null;
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, false /*completed*/);
}
} }
// Implements BrowserPaymentRequest: // Implements BrowserPaymentRequest:
......
...@@ -810,8 +810,7 @@ public class PaymentRequestService ...@@ -810,8 +810,7 @@ public class PaymentRequestService
} }
if (mIsShowWaitingForUpdatedDetails) return null; if (mIsShowWaitingForUpdatedDetails) return null;
String error = mBrowserPaymentRequest.onShowCalledAndAppsQueriedAndDetailsFinalized( String error = onShowCalledAndAppsQueriedAndDetailsFinalized();
mIsUserGestureShow);
if (error != null) { if (error != null) {
return new PaymentNotShownError( return new PaymentNotShownError(
NotShownReason.OTHER, error, PaymentErrorReason.NOT_SUPPORTED); NotShownReason.OTHER, error, PaymentErrorReason.NOT_SUPPORTED);
...@@ -820,6 +819,16 @@ public class PaymentRequestService ...@@ -820,6 +819,16 @@ public class PaymentRequestService
return null; return null;
} }
// Returns the error if any.
@Nullable
private String onShowCalledAndAppsQueriedAndDetailsFinalized() {
assert mSpec.getRawTotal() != null;
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, false /*completed*/);
return mBrowserPaymentRequest.onShowCalledAndAppsQueriedAndDetailsFinalized(
mIsUserGestureShow);
}
private void onShowFailed(String error) { private void onShowFailed(String error) {
onShowFailed(NotShownReason.OTHER, error, PaymentErrorReason.USER_CANCEL); onShowFailed(NotShownReason.OTHER, error, PaymentErrorReason.USER_CANCEL);
} }
...@@ -1187,8 +1196,7 @@ public class PaymentRequestService ...@@ -1187,8 +1196,7 @@ public class PaymentRequestService
if (error != null) return error; if (error != null) return error;
if (!mIsFinishedQueryingPaymentApps) return null; if (!mIsFinishedQueryingPaymentApps) return null;
return mBrowserPaymentRequest.onShowCalledAndAppsQueriedAndDetailsFinalized( return onShowCalledAndAppsQueriedAndDetailsFinalized();
mIsUserGestureShow);
} }
/** /**
......
...@@ -12,6 +12,7 @@ import org.chromium.components.payments.BrowserPaymentRequest.Factory; ...@@ -12,6 +12,7 @@ import org.chromium.components.payments.BrowserPaymentRequest.Factory;
import org.chromium.components.payments.PaymentRequestService.Delegate; import org.chromium.components.payments.PaymentRequestService.Delegate;
import org.chromium.content_public.browser.RenderFrameHost; import org.chromium.content_public.browser.RenderFrameHost;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.payments.mojom.PaymentCurrencyAmount;
import org.chromium.payments.mojom.PaymentDetails; import org.chromium.payments.mojom.PaymentDetails;
import org.chromium.payments.mojom.PaymentItem; import org.chromium.payments.mojom.PaymentItem;
import org.chromium.payments.mojom.PaymentMethodData; import org.chromium.payments.mojom.PaymentMethodData;
...@@ -50,13 +51,14 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg ...@@ -50,13 +51,14 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg
/* package */ static PaymentRequestServiceBuilder defaultBuilder(Runnable onClosedListener, /* package */ static PaymentRequestServiceBuilder defaultBuilder(Runnable onClosedListener,
PaymentRequestClient client, PaymentAppService appService, PaymentRequestClient client, PaymentAppService appService,
BrowserPaymentRequest browserPaymentRequest) { BrowserPaymentRequest browserPaymentRequest, JourneyLogger journeyLogger) {
return new PaymentRequestServiceBuilder( return new PaymentRequestServiceBuilder(
onClosedListener, client, appService, browserPaymentRequest); onClosedListener, client, appService, browserPaymentRequest, journeyLogger);
} }
private PaymentRequestServiceBuilder(Runnable onClosedListener, PaymentRequestClient client, private PaymentRequestServiceBuilder(Runnable onClosedListener, PaymentRequestClient client,
PaymentAppService appService, BrowserPaymentRequest browserPaymentRequest) { PaymentAppService appService, BrowserPaymentRequest browserPaymentRequest,
JourneyLogger journeyLogger) {
mDelegate = this; mDelegate = this;
mWebContents = Mockito.mock(WebContents.class); mWebContents = Mockito.mock(WebContents.class);
setTopLevelOrigin("https://top.level.origin"); setTopLevelOrigin("https://top.level.origin");
...@@ -64,7 +66,7 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg ...@@ -64,7 +66,7 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg
setFrameOrigin("https://frame.origin"); setFrameOrigin("https://frame.origin");
Origin origin = Mockito.mock(Origin.class); Origin origin = Mockito.mock(Origin.class);
Mockito.doReturn(origin).when(mRenderFrameHost).getLastCommittedOrigin(); Mockito.doReturn(origin).when(mRenderFrameHost).getLastCommittedOrigin();
mJourneyLogger = Mockito.mock(JourneyLogger.class); mJourneyLogger = journeyLogger;
mMethodData = new PaymentMethodData[1]; mMethodData = new PaymentMethodData[1];
mMethodData[0] = new PaymentMethodData(); mMethodData[0] = new PaymentMethodData();
mMethodData[0].supportedMethod = "https://www.chromium.org"; mMethodData[0].supportedMethod = "https://www.chromium.org";
...@@ -74,7 +76,12 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg ...@@ -74,7 +76,12 @@ public class PaymentRequestServiceBuilder implements PaymentRequestService.Deleg
mOptions = new PaymentOptions(); mOptions = new PaymentOptions();
mOptions.requestShipping = true; mOptions.requestShipping = true;
mSpec = Mockito.mock(PaymentRequestSpec.class); mSpec = Mockito.mock(PaymentRequestSpec.class);
Mockito.doReturn(new PaymentItem()).when(mSpec).getRawTotal(); PaymentCurrencyAmount amount = new PaymentCurrencyAmount();
amount.currency = "CNY";
amount.value = "123";
PaymentItem total = new PaymentItem();
total.amount = amount;
Mockito.doReturn(total).when(mSpec).getRawTotal();
Map<String, PaymentMethodData> methodDataMap = new HashMap<>(); Map<String, PaymentMethodData> methodDataMap = new HashMap<>();
Mockito.doReturn(methodDataMap).when(mSpec).getMethodData(); Mockito.doReturn(methodDataMap).when(mSpec).getMethodData();
mBrowserPaymentRequestFactory = (paymentRequestService) -> browserPaymentRequest; mBrowserPaymentRequestFactory = (paymentRequestService) -> browserPaymentRequest;
......
...@@ -70,6 +70,7 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -70,6 +70,7 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
private boolean mWaitForUpdatedDetailsDefaultValue; private boolean mWaitForUpdatedDetailsDefaultValue;
private PaymentAppService mPaymentAppService; private PaymentAppService mPaymentAppService;
private PaymentAppFactoryDelegate mPaymentAppFactoryDelegate; private PaymentAppFactoryDelegate mPaymentAppFactoryDelegate;
private JourneyLogger mJourneyLogger;
/** The shadow of PaymentFeatureList. Not to use outside the test. */ /** The shadow of PaymentFeatureList. Not to use outside the test. */
@Implements(PaymentFeatureList.class) @Implements(PaymentFeatureList.class)
...@@ -144,6 +145,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -144,6 +145,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
List<PaymentApp> apps = new ArrayList(); List<PaymentApp> apps = new ArrayList();
apps.add(app); apps.add(app);
Mockito.doReturn(apps).when(mBrowserPaymentRequest).getPaymentApps(); Mockito.doReturn(apps).when(mBrowserPaymentRequest).getPaymentApps();
mJourneyLogger = Mockito.mock(JourneyLogger.class);
} }
@Before @Before
...@@ -251,7 +254,7 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -251,7 +254,7 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
return PaymentRequestServiceBuilder.defaultBuilder( return PaymentRequestServiceBuilder.defaultBuilder(
() ()
-> mIsOnCloseListenerInvoked = true, -> mIsOnCloseListenerInvoked = true,
/*client=*/this, mPaymentAppService, mBrowserPaymentRequest); /*client=*/this, mPaymentAppService, mBrowserPaymentRequest, mJourneyLogger);
} }
private PaymentApp createDefaultPaymentApp() { private PaymentApp createDefaultPaymentApp() {
...@@ -276,6 +279,11 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -276,6 +279,11 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
.showOrSkipAppSelector(Mockito.anyBoolean(), Mockito.any(), Mockito.anyBoolean()); .showOrSkipAppSelector(Mockito.anyBoolean(), Mockito.any(), Mockito.anyBoolean());
} }
private void verifyJourneyLoggerRecordedTransactionAmount() {
Mockito.verify(mJourneyLogger, Mockito.times(1))
.recordTransactionAmount(Mockito.eq("CNY"), Mockito.eq("123"), Mockito.eq(false));
}
@Test @Test
@Feature({"Payments"}) @Feature({"Payments"})
public void testNullFrameOriginFailsCreation() { public void testNullFrameOriginFailsCreation() {
...@@ -590,6 +598,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -590,6 +598,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
queryPaymentApps(); queryPaymentApps();
Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) Mockito.verify(mBrowserPaymentRequest, Mockito.times(1))
.onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean()); .onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean());
verifyJourneyLoggerRecordedTransactionAmount();
} }
@Test @Test
...@@ -605,6 +615,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -605,6 +615,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
updateWith(service); updateWith(service);
Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) Mockito.verify(mBrowserPaymentRequest, Mockito.times(1))
.onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean()); .onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean());
verifyJourneyLoggerRecordedTransactionAmount();
} }
@Test @Test
...@@ -620,6 +632,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient { ...@@ -620,6 +632,8 @@ public class PaymentRequestServiceTest implements PaymentRequestClient {
queryPaymentApps(); queryPaymentApps();
Mockito.verify(mBrowserPaymentRequest, Mockito.times(1)) Mockito.verify(mBrowserPaymentRequest, Mockito.times(1))
.onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean()); .onShowCalledAndAppsQueriedAndDetailsFinalized(Mockito.anyBoolean());
verifyJourneyLoggerRecordedTransactionAmount();
} }
@Test @Test
......
...@@ -128,11 +128,6 @@ public class WebLayerPaymentRequestService implements BrowserPaymentRequest { ...@@ -128,11 +128,6 @@ public class WebLayerPaymentRequestService implements BrowserPaymentRequest {
PaymentApp selectedPaymentApp = mAvailableApps.get(0); PaymentApp selectedPaymentApp = mAvailableApps.get(0);
if (mShouldSkipAppSelector) { if (mShouldSkipAppSelector) {
mJourneyLogger.setEventOccurred(Event.SKIPPED_SHOW); mJourneyLogger.setEventOccurred(Event.SKIPPED_SHOW);
assert mSpec.getRawTotal() != null;
// The total amount in details should be finalized at this point. So it is safe to
// record the triggered transaction amount.
mJourneyLogger.recordTransactionAmount(mSpec.getRawTotal().amount.currency,
mSpec.getRawTotal().amount.value, false /*completed*/);
PaymentResponseHelperInterface paymentResponseHelper = new PaymentResponseHelper( PaymentResponseHelperInterface paymentResponseHelper = new PaymentResponseHelper(
selectedPaymentApp.handlesShippingAddress(), mSpec.getPaymentOptions()); selectedPaymentApp.handlesShippingAddress(), mSpec.getPaymentOptions());
mPaymentRequestService.invokePaymentApp(selectedPaymentApp, paymentResponseHelper); mPaymentRequestService.invokePaymentApp(selectedPaymentApp, paymentResponseHelper);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment