chromium/chrome/android/javatests/src/org/chromium/chrome/browser/multiwindow/MultiWindowIntegrationTest.java

// Copyright 2016 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.multiwindow;

import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.moveActivityToFront;
import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForSecondChromeTabbedActivity;
import static org.chromium.chrome.browser.multiwindow.MultiWindowTestHelper.waitForTabs;

import android.os.Build.VERSION_CODES;

import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.MediumTest;
import androidx.test.platform.app.InstrumentationRegistry;

import org.hamcrest.Matchers;
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.CommandLineFlags;
import org.chromium.base.test.util.Criteria;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.ChromeTabbedActivity2;
import org.chromium.chrome.browser.app.tabmodel.TabWindowManagerSingleton;
import org.chromium.chrome.browser.firstrun.FirstRunStatus;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.layouts.LayoutTestUtils;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.R;
import org.chromium.chrome.test.util.MenuUtils;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.test.util.UiDisableIf;
import org.chromium.ui.test.util.UiRestriction;

/** Integration testing for Android's N+ MultiWindow. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class MultiWindowIntegrationTest {
    @Rule
    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();

    private EmbeddedTestServer mTestServer;

    @Before
    public void setUp() throws InterruptedException {
        mTestServer =
                EmbeddedTestServer.createAndStartServer(
                        ApplicationProvider.getApplicationContext());
        mActivityTestRule.startMainActivityOnBlankPage();
    }

    @Test
    @MediumTest
    @Feature("MultiWindow")
    @DisabledTest(message = "Flaky on test-n-phone https://crbug/1197125")
    @CommandLineFlags.Add(ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING)
    public void testIncognitoNtpHandledCorrectly() {
        try {
            ThreadUtils.runOnUiThreadBlocking(() -> FirstRunStatus.setFirstRunFlowComplete(true));

            mActivityTestRule.newIncognitoTabFromMenu();
            Assert.assertTrue(mActivityTestRule.getActivity().getActivityTab().isIncognito());
            final int incognitoTabId = mActivityTestRule.getActivity().getActivityTab().getId();

            MenuUtils.invokeCustomMenuActionSync(
                    InstrumentationRegistry.getInstrumentation(),
                    mActivityTestRule.getActivity(),
                    R.id.move_to_other_window_menu_id);

            final ChromeTabbedActivity2 cta2 = waitForSecondChromeTabbedActivity();

            CriteriaHelper.pollUiThread(
                    () -> {
                        Criteria.checkThat(
                                cta2.getTabModelSelector().getModel(true).getCount(),
                                Matchers.is(1));
                    });

            ThreadUtils.runOnUiThreadBlocking(
                    () -> {
                        Assert.assertEquals(
                                1, TabWindowManagerSingleton.getInstance().getIncognitoTabCount());

                        // Ensure the same tab exists in the new activity.
                        Assert.assertEquals(incognitoTabId, cta2.getActivityTab().getId());
                    });
        } finally {
            ThreadUtils.runOnUiThreadBlocking(() -> FirstRunStatus.setFirstRunFlowComplete(false));
        }
    }

    @Test
    @MediumTest
    @DisableIf.Device(type = {UiDisableIf.TABLET}) // https://crbug.com/338976206
    @DisableIf.Build(sdk_is_greater_than = VERSION_CODES.S_V2) // https://crbug.com/1297370
    @Feature("MultiWindow")
    @CommandLineFlags.Add({
        ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING,
        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE
    })
    public void testMoveTabTwice() {
        // Load 'google' in separate tab.
        int googleTabId =
                mActivityTestRule
                        .loadUrlInNewTab(
                                mTestServer.getURL("/chrome/test/data/android/google.html"))
                        .getId();

        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();

        // Move 'google' tab to cta2.
        MenuUtils.invokeCustomMenuActionSync(
                InstrumentationRegistry.getInstrumentation(),
                cta,
                R.id.move_to_other_window_menu_id);

        final ChromeTabbedActivity2 cta2 = waitForSecondChromeTabbedActivity();

        // At this point cta should have NTP tab, and cta2 should have 'google' tab.
        waitForTabs("CTA", cta, 1, Tab.INVALID_TAB_ID);
        waitForTabs("CTA2", cta2, 1, googleTabId);

        // Move 'google' tab back to cta.
        moveActivityToFront(cta2);
        MenuUtils.invokeCustomMenuActionSync(
                InstrumentationRegistry.getInstrumentation(),
                cta2,
                R.id.move_to_other_window_menu_id);

        // At this point cta2 should have zero tabs, and cta should have 2 tabs (NTP, 'google').
        waitForTabs("CTA2", cta2, 0, Tab.INVALID_TAB_ID);
        waitForTabs("CTA", cta, 2, googleTabId);
    }

    @Test
    @MediumTest
    @Feature("MultiWindow")
    @DisabledTest(message = "Flaky on test-n-phone https://crbug/1197125")
    @CommandLineFlags.Add({
        ChromeSwitches.DISABLE_TAB_MERGING_FOR_TESTING,
        ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE
    })
    // TODO(crbug.com/40822813): Enable this test for tablet once the tab switcher is supported.
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testMovingLastTabKeepsActivityAlive() {
        final ChromeTabbedActivity cta = mActivityTestRule.getActivity();
        int blankTab = cta.getActivityTabProvider().get().getId();

        // Move the blank tab to cta2.
        MenuUtils.invokeCustomMenuActionSync(
                InstrumentationRegistry.getInstrumentation(),
                cta,
                R.id.move_to_other_window_menu_id);

        final ChromeTabbedActivity2 cta2 = waitForSecondChromeTabbedActivity();

        // At this point cta2 should have zero tabs, and cta should have 1 tab.
        waitForTabs("CTA", cta, 0, Tab.INVALID_TAB_ID);
        waitForTabs("CTA2", cta2, 1, blankTab);

        // Once all the tabs from one activity have been removed, the tab switcher should be shown.
        LayoutTestUtils.waitForLayout(cta.getLayoutManager(), LayoutType.TAB_SWITCHER);

        // The activity should also remain alive.
        Assert.assertFalse("The original activity should not be finishing!", cta.isFinishing());
        Assert.assertFalse("The original activity should still be alive!", cta.isDestroyed());
    }
}