chromium/components/javascript_dialogs/android/java/src/org/chromium/components/javascript_dialogs/JavascriptModalDialog.java

// Copyright 2018 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.components.javascript_dialogs;

import android.content.Context;
import android.content.res.Resources;

import androidx.annotation.StringRes;

import org.chromium.base.Log;
import org.chromium.ui.LayoutInflaterUtils;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;

/** A base class for creating, showing and dismissing a modal dialog for a JavaScript popup. */
public abstract class JavascriptModalDialog implements ModalDialogProperties.Controller {
    private static final String TAG = "JSModalDialog";

    private final String mTitle;
    private final String mMessage;
    private final int mPositiveButtonTextId;
    private final int mNegativeButtonTextId;
    private final String mDefaultPromptText;
    private final boolean mShouldShowSuppressCheckBox;

    private ModalDialogManager mModalDialogManager;
    private PropertyModel mDialogModel;
    protected JavascriptDialogCustomView mDialogCustomView;

    protected JavascriptModalDialog(
            String title,
            String message,
            String promptText,
            boolean shouldShowSuppressCheckBox,
            @StringRes int positiveButtonTextId,
            @StringRes int negativeButtonTextId) {
        mTitle = title;
        mMessage = message;
        mPositiveButtonTextId = positiveButtonTextId;
        mNegativeButtonTextId = negativeButtonTextId;
        mDefaultPromptText = promptText;
        mShouldShowSuppressCheckBox = shouldShowSuppressCheckBox;
    }

    /**
     * Showing a modal dialog for a JavaScript popup with the specified dialog type.
     * @param context The {@link Context} that this dialog is shown upon.
     * @param dialogType The {@link ModalDialogManager.ModalDialogType} of the dialog.
     */
    protected void show(
            Context context,
            ModalDialogManager manager,
            @ModalDialogManager.ModalDialogType int dialogType) {
        assert manager != null;
        mDialogCustomView =
                (JavascriptDialogCustomView)
                        LayoutInflaterUtils.inflate(context, R.layout.js_modal_dialog, null);
        mDialogCustomView.setPromptText(mDefaultPromptText);
        mDialogCustomView.setSuppressCheckBoxVisibility(mShouldShowSuppressCheckBox);

        Resources resources = context.getResources();

        mDialogModel =
                new PropertyModel.Builder(ModalDialogProperties.ALL_KEYS)
                        .with(ModalDialogProperties.CONTROLLER, this)
                        .with(ModalDialogProperties.TITLE, mTitle)
                        .with(ModalDialogProperties.MESSAGE_PARAGRAPH_1, mMessage)
                        .with(ModalDialogProperties.CUSTOM_VIEW, mDialogCustomView)
                        .with(
                                ModalDialogProperties.POSITIVE_BUTTON_TEXT,
                                resources,
                                mPositiveButtonTextId)
                        .with(
                                ModalDialogProperties.NEGATIVE_BUTTON_TEXT,
                                resources,
                                mNegativeButtonTextId)
                        .with(ModalDialogProperties.TITLE_SCROLLABLE, true)
                        .build();

        mModalDialogManager = manager;
        mModalDialogManager.showDialog(mDialogModel, dialogType);
    }

    /**
     * Dismissing the dialog with the specified reason.
     * @param dismissalCause The specified reason that the dialog is dismissed.
     */
    protected void dismiss(@DialogDismissalCause int dismissalCause) {
        if (mModalDialogManager == null) return;
        mModalDialogManager.dismissDialog(mDialogModel, dismissalCause);
    }

    @Override
    public void onClick(PropertyModel model, int buttonType) {
        if (mModalDialogManager == null) return;
        switch (buttonType) {
            case ModalDialogProperties.ButtonType.POSITIVE:
                mModalDialogManager.dismissDialog(
                        model, DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
                break;
            case ModalDialogProperties.ButtonType.NEGATIVE:
                mModalDialogManager.dismissDialog(
                        model, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
                break;
            default:
                Log.e(TAG, "Unexpected button pressed in dialog: " + buttonType);
        }
    }

    @Override
    public void onDismiss(PropertyModel model, int dismissalCause) {
        if (mDialogCustomView == null) return;
        switch (dismissalCause) {
            case DialogDismissalCause.POSITIVE_BUTTON_CLICKED:
                accept(
                        mDialogCustomView.getPromptText(),
                        mDialogCustomView.isSuppressCheckBoxChecked());
                break;
            case DialogDismissalCause.NEGATIVE_BUTTON_CLICKED:
                cancel(true, mDialogCustomView.isSuppressCheckBoxChecked());
                break;
            case DialogDismissalCause.DISMISSED_BY_NATIVE:
                // We don't need to call native back in this case.
                break;
            default:
                cancel(false, mDialogCustomView.isSuppressCheckBoxChecked());
        }
        mDialogModel = null;
        mDialogCustomView = null;
        mModalDialogManager = null;
    }

    /**
     * Sends notification to native that the user accepts the dialog.
     * @param promptResult The text edited by user.
     * @param suppressDialogs Whether the upcoming JavaScript popups should be suppressed.
     */
    protected abstract void accept(String promptResult, boolean suppressDialogs);

    /**
     * Sends notification to native that the user accepts the dialog.
     * @param buttonClicked Whether the dialog is cancelled by user clicking the cancel button.
     * @param suppressDialogs Whether the upcoming JavaScript popups should be suppressed.
     */
    protected abstract void cancel(boolean buttonClicked, boolean suppressDialogs);
}