chromium/chrome/browser/ui/android/autofill/internal/java/src/org/chromium/chrome/browser/ui/autofill/AutofillErrorDialogBridge.java

// Copyright 2021 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.ui.autofill;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.DrawableRes;
import androidx.core.content.res.ResourcesCompat;

import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;

import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.ui.autofill.internal.R;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;

/**
 * Controller that allows the native autofill code to show an error dialog.
 * For example: When unmasking a virtual card returns an error, we show an error dialog with more
 * information about the error.
 *
 * Note: The error dialog only shows a positive button which dismisses the dialog.
 */
@JNINamespace("autofill")
public class AutofillErrorDialogBridge {
    private final long mNativeAutofillErrorDialogView;
    private final ModalDialogManager mModalDialogManager;
    private final Context mContext;
    private PropertyModel mDialogModel;

    private final ModalDialogProperties.Controller mModalDialogController =
            new ModalDialogProperties.Controller() {
                @Override
                public void onClick(PropertyModel model, int buttonType) {
                    mModalDialogManager.dismissDialog(
                            mDialogModel, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
                }

                @Override
                public void onDismiss(PropertyModel model, int dismissalCause) {
                    AutofillErrorDialogBridgeJni.get().onDismissed(mNativeAutofillErrorDialogView);
                }
            };

    public AutofillErrorDialogBridge(
            long nativeAutofillErrorDialogView,
            ModalDialogManager modalDialogManager,
            Context context) {
        this.mNativeAutofillErrorDialogView = nativeAutofillErrorDialogView;
        this.mModalDialogManager = modalDialogManager;
        this.mContext = context;
    }

    @CalledByNative
    public static AutofillErrorDialogBridge create(
            long nativeAutofillErrorDialogView, WindowAndroid windowAndroid) {
        return new AutofillErrorDialogBridge(
                nativeAutofillErrorDialogView,
                windowAndroid.getModalDialogManager(),
                windowAndroid.getActivity().get());
    }

    /**
     * Shows an error dialog.
     *
     * @param title Title for the error dialog.
     * @param description Description for the error dialog which shows below the title.
     * @param buttonLabel Label for the positive button which acts as a cancel button.
     * @param titleIconId The resource id for the icon to be displayed to the left of the title. If
     * flag 'AUTOFILL_ENABLE_MOVING_GPAY_LOGO_TO_THE_RIGHT_ON_CLANK' is enabled titleIconId is
     * overridden.
     */
    @CalledByNative
    public void show(String title, String description, String buttonLabel, int titleIconId) {
        View errorDialogContentView =
                LayoutInflater.from(mContext).inflate(R.layout.autofill_error_dialog, null);
        ((TextView) errorDialogContentView.findViewById(R.id.error_message)).setText(description);

        boolean useCustomTitleView =
                ChromeFeatureList.isEnabled(
                        ChromeFeatureList.AUTOFILL_ENABLE_MOVING_GPAY_LOGO_TO_THE_RIGHT_ON_CLANK);
        if (useCustomTitleView) {
            ViewStub stub = errorDialogContentView.findViewById(R.id.title_with_icon_stub);
            stub.setLayoutResource(R.layout.icon_after_title_view);
            stub.inflate();
            titleIconId = R.drawable.google_pay;
        }
        PropertyModel.Builder builder =
                new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
                        .with(ModalDialogProperties.CONTROLLER, mModalDialogController)
                        .with(ModalDialogProperties.CUSTOM_VIEW, errorDialogContentView)
                        .with(ModalDialogProperties.NEGATIVE_BUTTON_DISABLED, true)
                        .with(ModalDialogProperties.POSITIVE_BUTTON_TEXT, buttonLabel);
        updateTitleView(useCustomTitleView, title, titleIconId, builder, errorDialogContentView);
        mDialogModel = builder.build();
        mModalDialogManager.showDialog(mDialogModel, ModalDialogManager.ModalDialogType.TAB);
    }

    /**
     * Updates the title and icon view. If AUTOFILL_ENABLE_MOVING_GPAY_LOGO_TO_THE_RIGHT_ON_CLANK
     * feature is enabled, sets title and icon in the customView otherwise uses
     * PropertyModel.Builder for title and icon.
     *
     * @param useCustomTitleView Indicates true/false to use custom title view.
     * @param title Title of the prompt dialog.
     * @param titleIcon Icon near the title.
     * @param builder The PropertyModel.Builder instance.
     * @param errorDialogContentView The CUSTOM_VIEW used in the PropertyModel that also has the
     * view stub for custom title view.
     */
    private void updateTitleView(
            boolean useCustomTitleView,
            String title,
            @DrawableRes int titleIcon,
            PropertyModel.Builder builder,
            View errorDialogContentView) {
        if (useCustomTitleView) {
            TextView titleView = (TextView) errorDialogContentView.findViewById(R.id.title);
            titleView.setText(title);
            ImageView iconView = (ImageView) errorDialogContentView.findViewById(R.id.title_icon);
            iconView.setImageResource(titleIcon);
        } else {
            builder.with(ModalDialogProperties.TITLE, title);
            if (titleIcon != 0) {
                builder.with(
                        ModalDialogProperties.TITLE_ICON,
                        ResourcesCompat.getDrawable(
                                mContext.getResources(), titleIcon, mContext.getTheme()));
            }
        }
    }

    /** Dismisses the currently showing dialog. */
    @CalledByNative
    public void dismiss() {
        mModalDialogManager.dismissDialog(mDialogModel, DialogDismissalCause.DISMISSED_BY_NATIVE);
    }

    @NativeMethods
    interface Natives {
        void onDismissed(long nativeAutofillErrorDialogViewAndroid);
    }
}