chromium/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/toolbar/PaymentHandlerToolbarCoordinator.java

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.payments.handler.toolbar;

import android.app.Activity;
import android.view.View;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
import org.chromium.chrome.browser.page_info.ChromePageInfoControllerDelegate;
import org.chromium.chrome.browser.page_info.ChromePageInfoHighlight;
import org.chromium.chrome.browser.payments.handler.toolbar.PaymentHandlerToolbarMediator.PaymentHandlerToolbarMediatorDelegate;
import org.chromium.components.omnibox.SecurityStatusIcon;
import org.chromium.components.page_info.PageInfoController;
import org.chromium.components.security_state.ConnectionSecurityLevel;
import org.chromium.components.security_state.SecurityStateModel;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.DeviceFormFactor;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.chromium.url.GURL;

/**
 * PaymentHandlerToolbar coordinator, which owns the component overall, i.e., creates other objects
 * in the component and connects them. It decouples the implementation of this component from other
 * components and acts as the point of contact between them. Any code in this component that needs
 * to interact with another component does that through this coordinator.
 */
public class PaymentHandlerToolbarCoordinator implements PaymentHandlerToolbarMediatorDelegate {
    private final WebContents mWebContents;
    private final Activity mActivity;
    private final boolean mIsSmallDevice;
    private final PropertyModel mModel;
    private final PaymentHandlerToolbarView mToolbarView;
    private final PaymentHandlerToolbarMediator mMediator;
    private final Supplier<ModalDialogManager> mModalDialogManagerSupplier;

    /** Observer for the error of the payment handler toolbar. */
    public interface PaymentHandlerToolbarObserver {
        /** Called when the close button is clicked. */
        void onToolbarCloseButtonClicked();
    }

    /**
     * Constructs the payment-handler toolbar component coordinator.
     * @param activity The main activity.
     * @param webContents The {@link WebContents} of the payment handler app.
     * @param url The url of the payment handler app, i.e., that of
     *         "PaymentRequestEvent.openWindow(url)".
     * @param modalDialogManagerSupplier Supplies the {@link ModalDialogManager}.
     */
    public PaymentHandlerToolbarCoordinator(
            @NonNull Activity activity,
            @NonNull WebContents webContents,
            @NonNull GURL url,
            @NonNull Supplier<ModalDialogManager> modalDialogManagerSupplier) {
        assert activity != null;
        assert webContents != null;
        assert url != null;
        mWebContents = webContents;
        mActivity = activity;
        mModalDialogManagerSupplier = modalDialogManagerSupplier;
        int defaultSecurityLevel = ConnectionSecurityLevel.NONE;
        mModel =
                new PropertyModel.Builder(PaymentHandlerToolbarProperties.ALL_KEYS)
                        .with(PaymentHandlerToolbarProperties.PROGRESS_VISIBLE, true)
                        .with(
                                PaymentHandlerToolbarProperties.LOAD_PROGRESS,
                                PaymentHandlerToolbarMediator.MINIMUM_LOAD_PROGRESS)
                        .with(
                                PaymentHandlerToolbarProperties.SECURITY_ICON,
                                getSecurityIconResource(defaultSecurityLevel))
                        .with(
                                PaymentHandlerToolbarProperties.SECURITY_ICON_CONTENT_DESCRIPTION,
                                getSecurityIconContentDescription(defaultSecurityLevel))
                        .with(PaymentHandlerToolbarProperties.URL, url)
                        .with(
                                PaymentHandlerToolbarProperties.SECURITY_ICON_ON_CLICK_CALLBACK,
                                this::showPageInfoDialog)
                        .build();
        mIsSmallDevice = !DeviceFormFactor.isNonMultiDisplayContextOnTablet(mActivity);
        mMediator = new PaymentHandlerToolbarMediator(mModel, webContents, /* delegate= */ this);
        mToolbarView = new PaymentHandlerToolbarView(mActivity);
        webContents.addObserver(mMediator);
        PropertyModelChangeProcessor.create(
                mModel, mToolbarView, PaymentHandlerToolbarViewBinder::bind);
    }

    /** Set a callback for the close button's onclick event. */
    public void setCloseButtonOnClickCallback(Runnable callback) {
        mModel.set(PaymentHandlerToolbarProperties.CLOSE_BUTTON_ON_CLICK_CALLBACK, callback);
    }

    /** @return The height of the toolbar in px. */
    public int getToolbarHeightPx() {
        return mToolbarView.getToolbarHeightPx();
    }

    /** @return The height of the toolbar shadow height in px. */
    public int getShadowHeightPx() {
        return mToolbarView.getShadowHeightPx();
    }

    /** @return The toolbar of the PaymentHandler. */
    public View getView() {
        return mToolbarView.getView();
    }

    /** Simulates a click on the security icon of the payment handler toolbar. */
    public void clickSecurityIconForTest() {
        mToolbarView.mSecurityIconView.performClick();
    }

    /** Simulates a click on the close button of the payment handler toolbar. */
    public void clickCloseButtonForTest() {
        mToolbarView.mCloseButton.performClick();
    }

    // Implement PaymentHandlerToolbarMediatorDelegate.
    @Override
    public @ConnectionSecurityLevel int getSecurityLevel() {
        return SecurityStateModel.getSecurityLevelForWebContents(mWebContents);
    }

    // Implement PaymentHandlerToolbarMediatorDelegate.
    @Override
    public @DrawableRes int getSecurityIconResource(@ConnectionSecurityLevel int securityLevel) {
        return SecurityStatusIcon.getSecurityIconResource(
                securityLevel,
                mIsSmallDevice,
                /* skipIconForNeutralState= */ false,
                /* useUpdatedConnectionSecurityIndicators= */ false);
    }

    // Implement PaymentHandlerToolbarMediatorDelegate.
    @Override
    public String getSecurityIconContentDescription(@ConnectionSecurityLevel int securityLevel) {
        int contentDescriptionRes =
                SecurityStatusIcon.getSecurityIconContentDescriptionResourceId(securityLevel);
        return mActivity.getResources().getString(contentDescriptionRes);
    }

    private void showPageInfoDialog() {
        // When creating the {@link ChromePageInfoControllerDelegate} here, we don't need
        // storeInfoActionHandlerSupplier or ephemeralTabCoordinatorSupplier and don't show
        // "store info" row because this UI is already in a bottom sheet and clicking "store info"
        // row would trigger another bottom sheet.
        PageInfoController.show(
                mActivity,
                mWebContents,
                null,
                PageInfoController.OpenedFromSource.TOOLBAR,
                new ChromePageInfoControllerDelegate(
                        mActivity,
                        mWebContents,
                        mModalDialogManagerSupplier,
                        /* offlinePageLoadUrlDelegate= */ new OfflinePageUtils
                                .WebContentsOfflinePageLoadUrlDelegate(mWebContents),
                        /* storeInfoActionHandlerSupplier= */ null,
                        /* ephemeralTabCoordinatorSupplier= */ null,
                        ChromePageInfoHighlight.noHighlight(),
                        null),
                ChromePageInfoHighlight.noHighlight());
    }
}