chromium/chrome/android/java/src/org/chromium/chrome/browser/autofill/vcn/AutofillVcnEnrollBottomSheetMediator.java

// Copyright 2023 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.autofill.vcn;

import androidx.annotation.IntDef;
import androidx.annotation.VisibleForTesting;

import org.chromium.base.metrics.RecordHistogram;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetControllerProvider;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;

/** The mediator controller for the virtual card number (VCN) enrollment bottom sheet. */
/*package*/ class AutofillVcnEnrollBottomSheetMediator {
    @VisibleForTesting
    static final String LOADING_SHOWN_HISTOGRAM = "Autofill.VirtualCardEnrollBubble.LoadingShown";

    @VisibleForTesting
    static final String LOADING_RESULT_HISTOGRAM = "Autofill.VirtualCardEnrollBubble.LoadingResult";

    private final AutofillVcnEnrollBottomSheetContent mContent;
    private final AutofillVcnEnrollBottomSheetLifecycle mLifecycle;
    private BottomSheetController mBottomSheetController;
    private final PropertyModel mModel;
    private @VirtualCardEnrollmentBubbleResult int mLoadingResult;

    // These values are persisted to logs. Entries should not be renumbered and
    // numeric values should never be reused.
    // Needs to stay in sync with AutofillVirtualCardEnrollBubbleResult in enums.xml.
    @IntDef({
        VirtualCardEnrollmentBubbleResult.UNKNOWN,
        VirtualCardEnrollmentBubbleResult.ACCEPTED,
        VirtualCardEnrollmentBubbleResult.CLOSED,
        VirtualCardEnrollmentBubbleResult.NOT_INTERACTED,
        VirtualCardEnrollmentBubbleResult.LOST_FOCUS,
        VirtualCardEnrollmentBubbleResult.CANCELLED,
        VirtualCardEnrollmentBubbleResult.COUNT
    })
    @VisibleForTesting
    @interface VirtualCardEnrollmentBubbleResult {
        int UNKNOWN = 0;
        int ACCEPTED = 1;
        int CLOSED = 2;
        int NOT_INTERACTED = 3;
        int LOST_FOCUS = 4;
        int CANCELLED = 5;
        int COUNT = 6;
    }

    /**
     * Constructs the mediator controller for the virtual card enrollment bottom sheet.
     *
     * @param content The bottom sheet content.
     * @param lifecycle A custom lifecycle that ignores page navigations.
     */
    AutofillVcnEnrollBottomSheetMediator(
            AutofillVcnEnrollBottomSheetContent content,
            AutofillVcnEnrollBottomSheetLifecycle lifecycle,
            PropertyModel model) {
        mContent = content;
        mLifecycle = lifecycle;
        mModel = model;
    }

    /**
     * Requests to show the bottom sheet.
     *
     * @param window The window where the bottom sheet should be shown.
     * @return True if shown.
     */
    boolean requestShowContent(WindowAndroid window) {
        if (!mLifecycle.canBegin()) return false;

        mBottomSheetController = BottomSheetControllerProvider.from(window);
        if (mBottomSheetController == null) return false;

        boolean didShow = mBottomSheetController.requestShowContent(mContent, /* animate= */ true);

        if (didShow) mLifecycle.begin(/* onEndOfLifecycle= */ this::hide);

        return didShow;
    }

    /** Callback for when the user hits the [accept] button. */
    void onAccept() {
        if (ChromeFeatureList.isEnabled(
                ChromeFeatureList.AUTOFILL_ENABLE_VCN_ENROLL_LOADING_AND_CONFIRMATION)) {
            mModel.set(AutofillVcnEnrollBottomSheetProperties.SHOW_LOADING_STATE, true);
            mLoadingResult = VirtualCardEnrollmentBubbleResult.ACCEPTED;
            RecordHistogram.recordBooleanHistogram(LOADING_SHOWN_HISTOGRAM, true);
        } else {
            hide();
        }
    }

    /** Callback for when the user hits the [cancel] button. */
    void onCancel() {
        if (mModel.get(AutofillVcnEnrollBottomSheetProperties.SHOW_LOADING_STATE)) {
            mLoadingResult = VirtualCardEnrollmentBubbleResult.CLOSED;
        }
        hide();
    }

    /** Hides the bottom sheet, if present. */
    void hide() {
        if (mLifecycle.hasBegun()) mLifecycle.end();
        if (mBottomSheetController != null) {
            mBottomSheetController.hideContent(
                    mContent,
                    /* animate= */ true,
                    BottomSheetController.StateChangeReason.INTERACTION_COMPLETE);
        }
        if (mModel.get(AutofillVcnEnrollBottomSheetProperties.SHOW_LOADING_STATE)) {
            // Reset loading state to false to prevent a race condition from recording the metric
            // twice.
            mModel.set(AutofillVcnEnrollBottomSheetProperties.SHOW_LOADING_STATE, false);
            RecordHistogram.recordEnumeratedHistogram(
                    LOADING_RESULT_HISTOGRAM,
                    mLoadingResult,
                    VirtualCardEnrollmentBubbleResult.COUNT);
        }
    }
}