chromium/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordManagerDialogMediator.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.password_manager;

import static org.chromium.chrome.browser.password_manager.PasswordManagerDialogProperties.ILLUSTRATION_VISIBLE;

import android.content.res.Resources;
import android.view.View;

import org.chromium.base.Callback;
import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
import org.chromium.chrome.browser.modaldialog.ChromeTabModalPresenter;
import org.chromium.ui.modaldialog.DialogDismissalCause;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modaldialog.ModalDialogProperties;
import org.chromium.ui.modelutil.PropertyModel;

/** Mediator class responsible for the logic of showing the password manager dialog. */
class PasswordManagerDialogMediator implements View.OnLayoutChangeListener {
    private final ModalDialogManager mDialogManager;
    private final View mAndroidContentView;
    private final BrowserControlsStateProvider mBrowserControlsStateProvider;

    private PropertyModel.Builder mHostDialogModelBuilder;
    private PropertyModel mHostDialogModel;
    private PropertyModel mModel;
    private Resources mResources;
    private @ModalDialogManager.ModalDialogType int mDialogType;

    private static class DialogClickHandler implements ModalDialogProperties.Controller {
        private Callback<Integer> mCallback;

        DialogClickHandler(Callback<Integer> onClick) {
            mCallback = onClick;
        }

        @Override
        public void onClick(PropertyModel model, int buttonType) {
            switch (buttonType) {
                case ModalDialogProperties.ButtonType.POSITIVE:
                    mCallback.onResult(DialogDismissalCause.POSITIVE_BUTTON_CLICKED);
                    break;
                case ModalDialogProperties.ButtonType.NEGATIVE:
                    mCallback.onResult(DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
                    break;
                default:
                    assert false : "Unexpected button pressed in dialog: " + buttonType;
            }
        }

        @Override
        public void onDismiss(PropertyModel model, @DialogDismissalCause int dismissalCause) {
            mCallback.onResult(dismissalCause);
        }
    }

    PasswordManagerDialogMediator(
            PropertyModel.Builder hostDialogModelBuilder,
            ModalDialogManager manager,
            View androidContentView,
            BrowserControlsStateProvider controlsStateProvider) {
        mDialogManager = manager;
        mHostDialogModelBuilder = hostDialogModelBuilder;
        mAndroidContentView = androidContentView;
        mBrowserControlsStateProvider = controlsStateProvider;
        mAndroidContentView.addOnLayoutChangeListener(this);
    }

    void initialize(PropertyModel model, View view, PasswordManagerDialogContents contents) {
        mResources = view.getResources();
        mModel = model;
        mHostDialogModel =
                mHostDialogModelBuilder
                        .with(ModalDialogProperties.CUSTOM_VIEW, view)
                        .with(
                                ModalDialogProperties.CONTROLLER,
                                new DialogClickHandler(contents.getButtonClickCallback()))
                        .with(ModalDialogProperties.CONTENT_DESCRIPTION, contents.getTitle())
                        .with(
                                ModalDialogProperties.POSITIVE_BUTTON_TEXT,
                                contents.getPrimaryButtonText())
                        .with(
                                ModalDialogProperties.NEGATIVE_BUTTON_TEXT,
                                contents.getSecondaryButtonText())
                        .with(
                                ModalDialogProperties.BUTTON_STYLES,
                                contents.isPrimaryButtonFilled()
                                        ? ModalDialogProperties.ButtonStyles
                                                .PRIMARY_FILLED_NEGATIVE_OUTLINE
                                        : ModalDialogProperties.ButtonStyles
                                                .PRIMARY_OUTLINE_NEGATIVE_OUTLINE)
                        .build();
        mDialogType = contents.getDialogType();
    }

    private boolean hasSufficientSpaceForIllustration(int heightPx) {
        // If |mResources| is null, it means that the dialog was not initialized yet.
        if (mResources == null) return false;
        heightPx -=
                ChromeTabModalPresenter.getContainerTopMargin(
                        mResources, mBrowserControlsStateProvider);
        heightPx -= ChromeTabModalPresenter.getContainerBottomMargin(mBrowserControlsStateProvider);
        return heightPx
                >= mResources.getDimensionPixelSize(
                        R.dimen.password_manager_dialog_min_vertical_space_to_show_illustration);
    }

    @Override
    public void onLayoutChange(
            View view,
            int left,
            int top,
            int right,
            int bottom,
            int oldLeft,
            int oldTop,
            int oldRight,
            int oldBottom) {
        // Return if the dialog wasn't initialized
        if (mModel == null) return;
        int oldHeight = oldBottom - oldTop;
        int newHeight = bottom - top;
        if (newHeight == oldHeight) return;
        PostTask.postTask(
                TaskTraits.UI_DEFAULT,
                () -> {
                    mModel.set(ILLUSTRATION_VISIBLE, hasSufficientSpaceForIllustration(newHeight));
                });
    }

    void showDialog() {
        mModel.set(
                ILLUSTRATION_VISIBLE,
                hasSufficientSpaceForIllustration(mAndroidContentView.getHeight()));
        mHostDialogModel = mHostDialogModelBuilder.build();
        mDialogManager.showDialog(mHostDialogModel, mDialogType);
    }

    void dismissDialog(int dismissalCause) {
        mDialogManager.dismissDialog(mHostDialogModel, dismissalCause);
        mAndroidContentView.removeOnLayoutChangeListener(this);
    }

    public PropertyModel getModelForTesting() {
        return mModel;
    }
}