chromium/components/webapps/browser/android/java/src/org/chromium/components/webapps/AddToHomescreenCoordinator.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.components.webapps;

import android.content.Context;

import androidx.annotation.VisibleForTesting;

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

import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;

/**
 * This class is responsible for setting up and coordinating everything related to the
 * add-to-homescreen UI component.
 *
 * <p>The {@link #showForAppMenu} method is used to show the add-to-homescreen UI when the user
 * chooses the "Add to Home screen" option from the app menu.
 */
@JNINamespace("webapps")
public class AddToHomescreenCoordinator {
    private Context mActivityContext;
    private ModalDialogManager mModalDialogManager;
    private PropertyModel mModel;
    private WindowAndroid mWindowAndroid;
    // May be null during tests.
    private WebContents mWebContents;

    @VisibleForTesting
    public AddToHomescreenCoordinator(
            WebContents webContents,
            Context activityContext,
            WindowAndroid windowAndroid,
            ModalDialogManager modalDialogManager) {
        mActivityContext = activityContext;
        mWindowAndroid = windowAndroid;
        mModalDialogManager = modalDialogManager;
        mWebContents = webContents;
    }

    /**
     * Starts and shows the add-to-homescreen UI component for the given {@link WebContents}.
     *
     * @return whether add-to-homescreen UI was started successfully.
     */
    public static void showForAppMenu(
            Context activityContext,
            WindowAndroid windowAndroid,
            ModalDialogManager modalDialogManager,
            WebContents webContents,
            int menuItemType) {
        new AddToHomescreenCoordinator(
                        webContents, activityContext, windowAndroid, modalDialogManager)
                .showForAppMenu(menuItemType);
    }

    @VisibleForTesting
    public boolean showForAppMenu(int type) {
        // Don't start if there is no visible URL to add.
        if (mWebContents == null || mWebContents.getVisibleUrl().isEmpty()) {
            return false;
        }

        buildMediatorAndShowDialog().startForAppMenu(mWebContents, type);
        return true;
    }

    /**
     * Constructs all MVC components on request from the C++ side.
     *
     * @param webContents The {@link WebContents} that initiated the add to homescreen request. Used
     *     for accessing activity {@link Context} and {@link ModalDialogManager}.
     * @return A C++ pointer to the associated add_to_homescreen_mediator.cc object. This will be
     *     used by add_to_homescreen_coordinator.cc to complete the initialization of the mediator.
     */
    @CalledByNative
    private static long initMvcAndReturnMediator(WebContents webContents) {
        WindowAndroid windowAndroid = webContents.getTopLevelNativeWindow();
        if (windowAndroid == null) return 0;

        ModalDialogManager modalDialogManager = windowAndroid.getModalDialogManager();

        if (modalDialogManager == null) return 0;

        AddToHomescreenCoordinator coordinator =
                new AddToHomescreenCoordinator(
                        webContents,
                        windowAndroid.getContext().get(),
                        windowAndroid,
                        modalDialogManager);
        return coordinator.buildMediatorAndShowDialog().getNativeMediator();
    }

    /**
     * Constructs all MVC components. {@link AddToHomescreenDialogView} is shown as soon as it's
     * constructed.
     *
     * @return The instance of {@link AddToHomescreenMediator} that was constructed.
     */
    private AddToHomescreenMediator buildMediatorAndShowDialog() {
        mModel = new PropertyModel.Builder(AddToHomescreenProperties.ALL_KEYS).build();
        AddToHomescreenMediator addToHomescreenMediator =
                new AddToHomescreenMediator(mModel, mWindowAndroid);
        PropertyModelChangeProcessor.create(
                mModel, initView(addToHomescreenMediator), AddToHomescreenViewBinder::bind);
        return addToHomescreenMediator;
    }

    /**
     * Creates and returns a {@link AddToHomescreenDialogView}. Extracted into a separate method for
     * easier testing.
     */
    @VisibleForTesting
    protected AddToHomescreenDialogView initView(AddToHomescreenViewDelegate delegate) {
        return new AddToHomescreenDialogView(mActivityContext, mModalDialogManager, delegate);
    }

    protected ModalDialogManager getModalDialogManagerForTests() {
        return mModalDialogManager;
    }

    protected Context getContextForTests() {
        return mActivityContext;
    }

    public PropertyModel getPropertyModelForTesting() {
        return mModel;
    }
}