Commit 1983372d authored by Liquan (Max) Gu's avatar Liquan (Max) Gu Committed by Chromium LUCI CQ

[Modular] Breaks PaymentUiService's dependency on ChromeActivity

PaymentUiService used to depend on ChromeActivity. This is undesirable
because the Clank modularization efforts requires that "ChromeActivity
should fully build/initialize the app without feature code having to
reference ChromeActivity for dependencies". This CL breaks this
dependency.

This also unblocks CL https://crrev.com/c/2602382 because
PaymentRequestParamsBuilder no longer has to depend on ChromeActivity
after this change.

Bug: 1155788
Change-Id: Ib539f37ca5056565d3c385b56f0ada0f1a430533
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2615480Reviewed-by: default avatarLiquan (Max) Gu <maxlg@chromium.org>
Reviewed-by: default avatarNick Burris <nburris@chromium.org>
Commit-Queue: Liquan (Max) Gu <maxlg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841625}
parent 586bd5ee
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.payments;
import android.app.Activity;
import android.content.Context;
import android.text.TextUtils;
......@@ -11,9 +12,14 @@ import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.payments.ui.PaymentUiService;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.components.autofill.EditableOption;
import org.chromium.components.payments.AbortReason;
import org.chromium.components.payments.AndroidPaymentApp;
......@@ -123,15 +129,15 @@ public class ChromePaymentRequestService
}
/**
* Looks up the Chrome activity of the given web contents. This can be null. Should never be
* cached, because web contents can change activities, e.g., when user selects "Open in
* Looks up the Android Activity of the given web contents. This can be null. Should never
* be cached, because web contents can change activities, e.g., when user selects "Open in
* Chrome" menu item.
*
* @param webContents The web contents for which to lookup the Chrome activity.
* @return Possibly null Chrome activity that should never be cached.
* @param webContents The web contents for which to lookup the Android activity.
* @return Possibly null Android activity that should never be cached.
*/
@Nullable
default ChromeActivity getChromeActivity(WebContents webContents) {
default Activity getActivity(WebContents webContents) {
return ChromeActivity.fromWebContents(webContents);
}
......@@ -189,6 +195,50 @@ public class ChromePaymentRequestService
WebContents webContents, PaymentRequestUpdateEventListener listener) {
return new PaymentHandlerHost(webContents, listener);
}
/**
* @param webContents Any WebContents.
* @return The TabModelSelector of the given WebContents.
*/
@Nullable
default TabModelSelector getTabModelSelector(WebContents webContents) {
ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
return activity == null ? null : activity.getTabModelSelector();
}
/**
* @param webContents Any WebContents.
* @return The TabModel of the given WebContents.
*/
@Nullable
default TabModel getTabModel(WebContents webContents) {
ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
return activity == null ? null : activity.getCurrentTabModel();
}
/**
* @param webContents Any WebContents.
* @return The OverviewModeBehavior of the given WebContents.
*/
@Nullable
default OverviewModeBehavior getOverviewModeBehavior(WebContents webContents) {
ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
if (activity == null) return null;
if (!(activity instanceof ChromeTabbedActivity)) return null;
return ((ChromeTabbedActivity) activity).getOverviewModeBehaviorSupplier().get();
}
/**
* @param webContents Any WebContents.
* @return The ActivityLifecycleDispatcher of the ChromeActivity that contains the given
* WebContents.
*/
@Nullable
default ActivityLifecycleDispatcher getActivityLifecycleDispatcher(
WebContents webContents) {
ChromeActivity activity = ChromeActivity.fromWebContents(webContents);
return activity == null ? null : activity.getLifecycleDispatcher();
}
}
/**
......@@ -317,10 +367,15 @@ public class ChromePaymentRequestService
@Override
public String showOrSkipAppSelector(boolean isShowWaitingForUpdatedDetails, PaymentItem total,
boolean shouldSkipAppSelector) {
ChromeActivity chromeActivity = mDelegate.getChromeActivity(mWebContents);
if (chromeActivity == null) return ErrorStrings.ACTIVITY_NOT_FOUND;
String error = mPaymentUiService.buildPaymentRequestUI(chromeActivity,
/*isWebContentsActive=*/mDelegate.isWebContentsActive(mRenderFrameHost));
Activity activity = mDelegate.getActivity(mWebContents);
if (activity == null) return ErrorStrings.ACTIVITY_NOT_FOUND;
TabModelSelector tabModelSelector = mDelegate.getTabModelSelector(mWebContents);
if (tabModelSelector == null) return ErrorStrings.TAB_NOT_FOUND;
TabModel tabModel = mDelegate.getTabModel(mWebContents);
if (tabModel == null) return ErrorStrings.TAB_NOT_FOUND;
String error = mPaymentUiService.buildPaymentRequestUI(
/*isWebContentsActive=*/mDelegate.isWebContentsActive(mRenderFrameHost), activity,
tabModelSelector, tabModel, mDelegate.getOverviewModeBehavior(mWebContents));
if (error != null) return error;
// Calculate skip ui and build ui only after all payment apps are ready and
// request.show() is called.
......@@ -770,4 +825,11 @@ public class ChromePaymentRequestService
public Context getContext() {
return mDelegate.getContext(mRenderFrameHost);
}
// Implement PaymentUiService.Delegate:
@Override
@Nullable
public ActivityLifecycleDispatcher getActivityLifecycleDispatcher() {
return mDelegate.getActivityLifecycleDispatcher(mWebContents);
}
}
......@@ -4,6 +4,7 @@
package org.chromium.chrome.browser.payments.ui;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.text.TextUtils;
......@@ -14,8 +15,6 @@ import androidx.annotation.VisibleForTesting;
import org.chromium.base.Callback;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.AutofillProfile;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
......@@ -23,6 +22,7 @@ import org.chromium.chrome.browser.autofill.PersonalDataManager.NormalizedAddres
import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.payments.AddressEditor;
import org.chromium.chrome.browser.payments.AutofillAddress;
import org.chromium.chrome.browser.payments.AutofillContact;
......@@ -221,6 +221,10 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
*/
@Nullable
Context getContext();
/** @return The ActivityLifecycleDispatcher of the current ChromeActivity. */
@Nullable
ActivityLifecycleDispatcher getActivityLifecycleDispatcher();
}
/**
......@@ -1196,12 +1200,17 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
/**
* Build the PaymentRequest UI.
* @param activity The ChromeActivity for the payment request, cannot be null.
* @param isWebContentsActive Whether the merchant's WebContents is active.
* @param activity The activity of the current tab.
* @param tabModelSelector The tab model selector of the current tab.
* @param tabModel The tab model of the current tab.
* @param overviewModeBehavior The overview model behaviour of the current tab, can be null.
* @return The error message if built unsuccessfully; null otherwise.
*/
@Nullable
public String buildPaymentRequestUI(ChromeActivity activity, boolean isWebContentsActive) {
public String buildPaymentRequestUI(boolean isWebContentsActive, Activity activity,
TabModelSelector tabModelSelector, TabModel tabModel,
@Nullable OverviewModeBehavior overviewModeBehavior) {
// Payment methods section must be ready before building the rest of the UI. This is because
// shipping and contact sections (when requested by merchant) are populated depending on
// whether or not the selected payment app (if such exists) can provide the required
......@@ -1209,6 +1218,9 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
assert mPaymentMethodsSection != null;
assert activity != null;
assert tabModelSelector != null;
assert tabModel != null;
assert overviewModeBehavior != null;
// Only the currently selected tab is allowed to show the payment UI.
if (!isWebContentsActive) return ErrorStrings.CANNOT_SHOW_IN_BACKGROUND_TAB;
......@@ -1220,21 +1232,20 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
if (mObservedTabModelSelector != null) {
mObservedTabModelSelector.removeObserver(mSelectorObserver);
}
mObservedTabModelSelector = activity.getTabModelSelector();
mObservedTabModelSelector = tabModelSelector;
mObservedTabModelSelector.addObserver(mSelectorObserver);
if (mObservedTabModel != null) {
mObservedTabModel.removeObserver(mTabModelObserver);
}
mObservedTabModel = activity.getCurrentTabModel();
mObservedTabModel = tabModel;
mObservedTabModel.addObserver(mTabModelObserver);
// Catch any time the user enters the overview mode and dismiss the payment UI.
if (activity instanceof ChromeTabbedActivity) {
if (overviewModeBehavior != null) {
if (mOverviewModeBehavior != null) {
mOverviewModeBehavior.removeOverviewModeObserver(mOverviewModeObserver);
}
mOverviewModeBehavior =
((ChromeTabbedActivity) activity).getOverviewModeBehaviorSupplier().get();
mOverviewModeBehavior = overviewModeBehavior;
assert mOverviewModeBehavior != null;
if (mOverviewModeBehavior.overviewVisible()) return ErrorStrings.TAB_OVERVIEW_MODE;
......@@ -1252,8 +1263,10 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
SecurityStateModel.getSecurityLevelForWebContents(mWebContents),
new ShippingStrings(mParams.getPaymentOptions().shippingType),
mPaymentUisShowStateReconciler, Profile.fromWebContents(mWebContents));
activity.getLifecycleDispatcher().register(
mPaymentRequestUI); // registered as a PauseResumeWithNativeObserver
ActivityLifecycleDispatcher dispatcher = mDelegate.getActivityLifecycleDispatcher();
if (dispatcher != null) {
dispatcher.register(mPaymentRequestUI); // registered as a PauseResumeWithNativeObserver
}
final FaviconHelper faviconHelper = new FaviconHelper();
faviconHelper.getLocalFaviconImageForURL(Profile.fromWebContents(mWebContents),
......@@ -1685,9 +1698,9 @@ public class PaymentUiService implements SettingsAutofillAndPaymentsObserver.Obs
if (mPaymentRequestUI != null) {
mPaymentRequestUI.close();
ChromeActivity activity = ChromeActivity.fromWebContents(mWebContents);
if (activity != null) {
activity.getLifecycleDispatcher().unregister(mPaymentRequestUI);
ActivityLifecycleDispatcher dispatcher = mDelegate.getActivityLifecycleDispatcher();
if (dispatcher != null) {
dispatcher.unregister(mPaymentRequestUI);
}
mPaymentRequestUI = null;
mPaymentUisShowStateReconciler.onPaymentRequestUiClosed();
......
......@@ -24,7 +24,8 @@ public class MockPaymentUiServiceBuilder {
mPaymentUiService = Mockito.mock(PaymentUiService.class);
Mockito.doReturn(null)
.when(mPaymentUiService)
.buildPaymentRequestUI(Mockito.any(), Mockito.anyBoolean());
.buildPaymentRequestUI(Mockito.anyBoolean(), Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any());
Mockito.doReturn(true).when(mPaymentUiService).hasAvailableApps();
List<PaymentApp> apps = new ArrayList<>();
apps.add(app);
......@@ -35,7 +36,8 @@ public class MockPaymentUiServiceBuilder {
/* package */ MockPaymentUiServiceBuilder setBuildPaymentRequestUIResult(String result) {
Mockito.doReturn(result)
.when(mPaymentUiService)
.buildPaymentRequestUI(Mockito.any(), Mockito.anyBoolean());
.buildPaymentRequestUI(Mockito.anyBoolean(), Mockito.any(), Mockito.any(),
Mockito.any(), Mockito.any());
return this;
}
......
......@@ -4,14 +4,19 @@
package org.chromium.chrome.browser.payments;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import androidx.annotation.Nullable;
import org.mockito.Mockito;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.payments.ui.PaymentUiService;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.components.payments.BrowserPaymentRequest;
import org.chromium.components.payments.JourneyLogger;
import org.chromium.components.payments.MojoPaymentRequestGateKeeper;
......@@ -48,7 +53,6 @@ public class PaymentRequestParamsBuilder implements ChromePaymentRequestService.
private final WebContents mWebContents;
private final JourneyLogger mJourneyLogger;
private final PaymentRequestSpec mSpec;
private final ChromeActivity mActivity;
private final PaymentUiService mPaymentUiService;
private final boolean mGoogleBridgeEligible;
private final PaymentOptions mOptions;
......@@ -63,7 +67,6 @@ public class PaymentRequestParamsBuilder implements ChromePaymentRequestService.
mClient = client;
mDelegate = this;
mPaymentUiService = paymentUiService;
mActivity = Mockito.mock(ChromeActivity.class);
mJourneyLogger = Mockito.mock(JourneyLogger.class);
mWebContents = Mockito.mock(WebContents.class);
Mockito.doReturn("https://top.level.origin").when(mWebContents).getLastCommittedUrl();
......@@ -184,8 +187,35 @@ public class PaymentRequestParamsBuilder implements ChromePaymentRequestService.
}
@Override
public ChromeActivity getChromeActivity(WebContents webContents) {
return mActivity;
public Activity getActivity(WebContents webContents) {
Activity activity = Mockito.mock(Activity.class);
Resources resources = Mockito.mock(Resources.class);
Mockito.doReturn(resources).when(activity).getResources();
return activity;
}
@Nullable
@Override
public TabModelSelector getTabModelSelector(WebContents webContents) {
return Mockito.mock(TabModelSelector.class);
}
@Nullable
@Override
public TabModel getTabModel(WebContents webContents) {
return Mockito.mock(TabModel.class);
}
@Nullable
@Override
public OverviewModeBehavior getOverviewModeBehavior(WebContents webContents) {
return Mockito.mock(OverviewModeBehavior.class);
}
@Nullable
@Override
public ActivityLifecycleDispatcher getActivityLifecycleDispatcher(WebContents webContents) {
return Mockito.mock(ActivityLifecycleDispatcher.class);
}
@Override
......
......@@ -30,6 +30,8 @@ public abstract class ErrorStrings {{
public static final String CONTEXT_NOT_FOUND = "Unable to find Chrome context.";
public static final String TAB_NOT_FOUND = "Unable to find Chrome tab.";
public static final String WINDOW_NOT_FOUND = "Unable to find Chrome window.";
public static final String PAYMENT_APP_INVALID_RESPONSE = "Payment app response is not valid.";
......
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