chromium/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/AddToHomescreenInstallTest.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.webapps;

import android.content.Context;
import android.os.Handler;
import android.text.TextUtils;

import androidx.test.filters.SmallTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.HistogramWatcher;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.banners.AppMenuVerbiage;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.util.browser.TabLoadObserver;
import org.chromium.components.webapps.AddToHomescreenCoordinator;
import org.chromium.components.webapps.AddToHomescreenDialogView;
import org.chromium.components.webapps.AddToHomescreenProperties;
import org.chromium.components.webapps.AddToHomescreenViewDelegate;
import org.chromium.components.webapps.AppType;
import org.chromium.content_public.browser.WebContents;
import org.chromium.net.test.EmbeddedTestServerRule;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.test.util.DeviceRestriction;

/**
 * Tests org.chromium.chrome.browser.webapps.addtohomescreen.AddToHomescreenManager and its C++
 * counterpart.
 */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.PER_CLASS)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@Restriction(DeviceRestriction.RESTRICTION_TYPE_NON_AUTO)
public class AddToHomescreenInstallTest {
    @Rule
    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();

    @Rule public EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();

    private static final String MANIFEST_TEST_PAGE_PATH =
            "/chrome/test/data/banners/manifest_test_page.html";
    private static final String MANIFEST_TEST_PAGE_TITLE = "Web app banner test page";

    private static final String INSTALL_PATH_HISTOGRAM_NAME = "WebApk.Install.PathToInstall";

    /**
     * Test TestAddToHomescreenCoordinator subclass which mocks showing the add-to-homescreen view
     * and adds the shortcut to the home screen once it is ready.
     */
    private static class TestAddToHomescreenCoordinator extends AddToHomescreenCoordinator {
        private String mTitle;

        // The type of of dialog expected to show (at the time of submission).
        private @AppType int mExpectedDialogType;

        TestAddToHomescreenCoordinator(
                WebContents webContents,
                Context context,
                WindowAndroid windowAndroid,
                ModalDialogManager modalDialogManager,
                String title,
                @AppType int expectedDialogType) {
            super(webContents, context, windowAndroid, modalDialogManager);
            mTitle = title;
            mExpectedDialogType = expectedDialogType;
        }

        @Override
        protected AddToHomescreenDialogView initView(AddToHomescreenViewDelegate delegate) {
            return new AddToHomescreenDialogView(
                    getContextForTests(), getModalDialogManagerForTests(), delegate) {
                @Override
                protected void setTitle(String title) {
                    if (TextUtils.isEmpty(mTitle)) {
                        mTitle = title;
                    }
                }

                @Override
                protected void setCanSubmit(boolean canSubmit) {
                    Assert.assertEquals(
                            mExpectedDialogType,
                            getPropertyModelForTesting().get(AddToHomescreenProperties.TYPE));

                    // Submit the dialog.
                    new Handler().post(() -> mDelegate.onAddToHomescreen(mTitle, AppType.WEBAPK));
                }
            };
        }
    }

    private ChromeActivity mActivity;
    private Tab mTab;
    private HistogramWatcher mInstallHistogramsWatcher;

    @Before
    public void setUp() throws Exception {
        mActivityTestRule.startMainActivityOnBlankPage();
        mActivity = mActivityTestRule.getActivity();
        mTab = mActivity.getActivityTab();
        mInstallHistogramsWatcher =
                HistogramWatcher.newSingleRecordWatcher("Webapp.Install.InstallEvent", 0);
    }

    private void loadUrl(String url, String expectedPageTitle) throws Exception {
        new TabLoadObserver(mTab, expectedPageTitle, null).fullyLoadUrl(url);
    }

    private void installApp(
            Tab tab, String title, boolean expectAdded, @AppType int expectedDialogType) {
        // Install the webapp.
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    boolean started =
                            new TestAddToHomescreenCoordinator(
                                            tab.getWebContents(),
                                            mActivity,
                                            mActivity.getWindowAndroid(),
                                            mActivity.getModalDialogManager(),
                                            title,
                                            expectedDialogType)
                                    .showForAppMenu(AppMenuVerbiage.APP_MENU_OPTION_INSTALL);
                    Assert.assertEquals(expectAdded, started);
                });

        // Make sure that the webapp was installed.
        if (expectAdded) {
            mInstallHistogramsWatcher.pollInstrumentationThreadUntilSatisfied();
        }
    }

    @Test
    @SmallTest
    @Feature("{Webapp}")
    public void testInstallWebApk() throws Exception {
        HistogramWatcher histogram =
                HistogramWatcher.newSingleRecordWatcher(INSTALL_PATH_HISTOGRAM_NAME, 2);

        // Test the baseline of no adaptive icon.
        loadUrl(
                mTestServerRule.getServer().getURL(MANIFEST_TEST_PAGE_PATH),
                MANIFEST_TEST_PAGE_TITLE);
        installApp(mTab, "", /* expectAdded= */ true, /* expectedDialogType= */ AppType.WEBAPK);

        histogram.assertExpected();
    }
}