chromium/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java

// Copyright 2015 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.partnercustomizations;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.PopupMenu;

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

import org.hamcrest.Matchers;
import org.junit.Assert;
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.Feature;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.incognito.IncognitoUtils;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.chrome.test.partnercustomizations.TestPartnerBrowserCustomizationsProvider;
import org.chromium.net.test.EmbeddedTestServer;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/** Integration tests for the partner disabling incognito mode feature. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class PartnerDisableIncognitoModeIntegrationTest {
    @Rule
    public BasePartnerBrowserCustomizationIntegrationTestRule mActivityTestRule =
            new BasePartnerBrowserCustomizationIntegrationTestRule();

    private void setParentalControlsEnabled(boolean enabled) {
        Uri uri =
                CustomizationProviderDelegateUpstreamImpl.buildQueryUri(
                        PartnerBrowserCustomizations.PARTNER_DISABLE_INCOGNITO_MODE_PATH);
        Bundle bundle = new Bundle();
        bundle.putBoolean(
                TestPartnerBrowserCustomizationsProvider.INCOGNITO_MODE_DISABLED_KEY, enabled);
        Context context = ApplicationProvider.getApplicationContext();
        context.getContentResolver().call(uri, "setIncognitoModeDisabled", null, bundle);
    }

    private void assertIncognitoMenuItemEnabled(boolean enabled) throws ExecutionException {
        Menu menu =
                ThreadUtils.runOnUiThreadBlocking(
                        new Callable<Menu>() {
                            @Override
                            public Menu call() {
                                // PopupMenu is a convenient way of building a temp menu.
                                PopupMenu tempMenu =
                                        new PopupMenu(
                                                mActivityTestRule.getActivity(),
                                                mActivityTestRule
                                                        .getActivity()
                                                        .findViewById(R.id.menu_anchor_stub));
                                tempMenu.inflate(R.menu.main_menu);
                                Menu menu = tempMenu.getMenu();

                                return menu;
                            }
                        });
        for (int i = 0; i < menu.size(); ++i) {
            MenuItem item = menu.getItem(i);
            if (item.getItemId() == R.id.new_incognito_tab_menu_id && item.isVisible()) {
                Assert.assertEquals(
                        "Menu item enabled state is not correct.", enabled, item.isEnabled());
            }
        }
    }

    private void waitForParentalControlsEnabledState(final boolean parentalControlsEnabled) {
        CriteriaHelper.pollUiThread(
                () -> {
                    // areParentalControlsEnabled is updated on a background thread, so we
                    // also wait on the isIncognitoModeEnabled to ensure the updates on the
                    // UI thread have also triggered.
                    Criteria.checkThat(
                            PartnerBrowserCustomizations.isIncognitoDisabled(),
                            Matchers.is(parentalControlsEnabled));
                    Criteria.checkThat(
                            IncognitoUtils.isIncognitoModeEnabled(
                                    ProfileManager.getLastUsedRegularProfile()),
                            Matchers.not(parentalControlsEnabled));
                });
    }

    private void toggleActivityForegroundState() {
        ThreadUtils.runOnUiThreadBlocking(() -> mActivityTestRule.getActivity().onPause());
        ThreadUtils.runOnUiThreadBlocking(() -> mActivityTestRule.getActivity().onStop());
        ThreadUtils.runOnUiThreadBlocking(() -> mActivityTestRule.getActivity().onStart());
        ThreadUtils.runOnUiThreadBlocking(() -> mActivityTestRule.getActivity().onResume());
    }

    @Test
    @MediumTest
    @Feature({"DisableIncognitoMode"})
    public void testIncognitoEnabledIfNoParentalControls() throws InterruptedException {
        setParentalControlsEnabled(false);
        mActivityTestRule.startMainActivityOnBlankPage();
        waitForParentalControlsEnabledState(false);
        mActivityTestRule.newIncognitoTabFromMenu();
    }

    @Test
    @MediumTest
    @Feature({"DisableIncognitoMode"})
    public void testIncognitoMenuItemEnabledBasedOnParentalControls()
            throws InterruptedException, ExecutionException {
        setParentalControlsEnabled(true);
        mActivityTestRule.startMainActivityOnBlankPage();
        waitForParentalControlsEnabledState(true);
        assertIncognitoMenuItemEnabled(false);

        setParentalControlsEnabled(false);
        toggleActivityForegroundState();
        waitForParentalControlsEnabledState(false);
        assertIncognitoMenuItemEnabled(true);
    }

    @Test
    @MediumTest
    @Feature({"DisableIncognitoMode"})
    public void testEnabledParentalControlsClosesIncognitoTabs() throws InterruptedException {
        EmbeddedTestServer testServer =
                EmbeddedTestServer.createAndStartServer(
                        ApplicationProvider.getApplicationContext());

        String[] testUrls = {
            testServer.getURL("/chrome/test/data/android/about.html"),
            testServer.getURL("/chrome/test/data/android/ok.txt"),
            testServer.getURL("/chrome/test/data/android/test.html")
        };
        setParentalControlsEnabled(false);
        mActivityTestRule.startMainActivityOnBlankPage();
        waitForParentalControlsEnabledState(false);
        mActivityTestRule.loadUrlInNewTab(testUrls[0], true);
        mActivityTestRule.loadUrlInNewTab(testUrls[1], true);
        mActivityTestRule.loadUrlInNewTab(testUrls[2], true);
        mActivityTestRule.loadUrlInNewTab(testUrls[0], false);
        setParentalControlsEnabled(true);
        toggleActivityForegroundState();
        waitForParentalControlsEnabledState(true);
        CriteriaHelper.pollInstrumentationThread(
                () -> {
                    Criteria.checkThat(
                            mActivityTestRule.tabsCount(/* incognito= */ true), Matchers.is(0));
                });
    }
}