chromium/chrome/android/junit/src/org/chromium/chrome/browser/tab/RequestDesktopUtilsUnitTest.java

// Copyright 2021 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.tab;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import static org.chromium.components.content_settings.PrefNames.DESKTOP_SITE_WINDOW_SETTING_ENABLED;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;

import androidx.test.core.app.ApplicationProvider;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.shadows.ShadowPackageManager;

import org.chromium.base.ContextUtils;
import org.chromium.base.FeatureList;
import org.chromium.base.FeatureList.TestValues;
import org.chromium.base.ResettersForTesting;
import org.chromium.base.SysUtils;
import org.chromium.base.shared_preferences.SharedPreferencesManager;
import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker;
import org.chromium.build.BuildConfig;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowDisplayAndroid;
import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowDisplayAndroidManager;
import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowDisplayUtil;
import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowSysUtils;
import org.chromium.chrome.browser.tab.RequestDesktopUtilsUnitTest.ShadowTabUtils;
import org.chromium.components.browser_ui.site_settings.SingleCategorySettingsConstants;
import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridge;
import org.chromium.components.browser_ui.site_settings.WebsitePreferenceBridgeJni;
import org.chromium.components.browser_ui.util.ConversionUtils;
import org.chromium.components.content_settings.ContentSettingValues;
import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.feature_engagement.FeatureConstants;
import org.chromium.components.feature_engagement.Tracker;
import org.chromium.components.messages.MessageBannerProperties;
import org.chromium.components.messages.MessageDispatcher;
import org.chromium.components.messages.MessageIdentifier;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.components.user_prefs.UserPrefsJni;
import org.chromium.ui.display.DisplayAndroid;
import org.chromium.ui.display.DisplayAndroidManager;
import org.chromium.ui.display.DisplayUtil;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL;
import org.chromium.url.JUnitTestGURLs;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

/** Unit tests for {@link RequestDesktopUtils}. */
@RunWith(BaseRobolectricTestRunner.class)
@Config(
        manifest = Config.NONE,
        shadows = {
            ShadowSysUtils.class,
            ShadowDisplayAndroid.class,
            ShadowDisplayAndroidManager.class,
            ShadowTabUtils.class,
            ShadowDisplayUtil.class
        })
public class RequestDesktopUtilsUnitTest {
    @Rule public JniMocker mJniMocker = new JniMocker();

    /** Shadows {@link SysUtils} class for testing. */
    @Implements(SysUtils.class)
    public static class ShadowSysUtils {
        private static int sMemoryInMB;

        public static void setMemoryInMB(int memoryInMB) {
            sMemoryInMB = memoryInMB;
        }

        @Implementation
        public static int amountOfPhysicalMemoryKB() {
            return sMemoryInMB * ConversionUtils.KILOBYTES_PER_MEGABYTE;
        }
    }

    @Implements(DisplayAndroid.class)
    static class ShadowDisplayAndroid {
        private static DisplayAndroid sDisplayAndroid;

        public static void setDisplayAndroid(DisplayAndroid displayAndroid) {
            sDisplayAndroid = displayAndroid;
        }

        @Implementation
        public static DisplayAndroid getNonMultiDisplay(Context context) {
            return sDisplayAndroid;
        }
    }

    @Implements(DisplayAndroidManager.class)
    static class ShadowDisplayAndroidManager {
        private static Display sDisplay;

        public static void setDisplay(Display display) {
            sDisplay = display;
        }

        @Implementation
        public static Display getDefaultDisplayForContext(Context context) {
            return sDisplay;
        }
    }

    @Implements(TabUtils.class)
    static class ShadowTabUtils {
        private static boolean sIsGlobalSetting;

        public static void setIsGlobalSetting(Boolean isGlobalSetting) {
            sIsGlobalSetting = isGlobalSetting;
        }

        @Implementation
        public static boolean isRequestDesktopSiteContentSettingsGlobal(Profile profile, GURL url) {
            return sIsGlobalSetting;
        }
    }

    @Implements(DisplayUtil.class)
    static class ShadowDisplayUtil {
        private static int sSmallestScreenWidthDp;

        public static void setCurrentSmallestScreenWidth(int smallestScreenWidthDp) {
            sSmallestScreenWidthDp = smallestScreenWidthDp;
        }

        @Implementation
        public static int getCurrentSmallestScreenWidth(Context context) {
            return sSmallestScreenWidthDp;
        }
    }

    @Mock private WebsitePreferenceBridge.Natives mWebsitePreferenceBridgeJniMock;
    @Mock private MessageDispatcher mMessageDispatcher;
    @Mock private Activity mActivity;
    @Mock private Window mWindow;
    @Mock private WindowManager.LayoutParams mLayoutParams;
    @Mock private DisplayMetrics mDisplayMetrics;
    @Mock private Profile mProfile;
    @Mock private Tracker mTracker;
    @Mock private ObservableSupplier<Tab> mCurrentTabSupplier;
    @Mock private DisplayAndroid mDisplayAndroid;
    @Mock private Display mDisplay;
    @Mock private UserPrefs.Natives mUserPrefsJni;
    @Mock private PrefService mPrefService;

    private Tab mTab;
    private @ContentSettingValues int mRdsDefaultValue;
    private boolean mWindowSetting;
    private SharedPreferencesManager mSharedPreferencesManager;

    private final Map<String, Integer> mContentSettingMap = new HashMap<>();
    private final GURL mGoogleUrl = JUnitTestGURLs.GOOGLE_URL;
    private final GURL mMapsUrl = JUnitTestGURLs.MAPS_URL;

    private Resources mResources;

    private final TestValues mTestValues = new TestValues();

    private static final String ANY_SUBDOMAIN_PATTERN = "[*.]";
    private static final String GOOGLE_COM = "[*.]google.com/";
    private ShadowPackageManager mShadowPackageManager;
    private boolean mIsDefaultValuePreference;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        mJniMocker.mock(WebsitePreferenceBridgeJni.TEST_HOOKS, mWebsitePreferenceBridgeJniMock);
        mJniMocker.mock(UserPrefsJni.TEST_HOOKS, mUserPrefsJni);

        mTab = createTab();

        doAnswer(invocation -> mRdsDefaultValue)
                .when(mWebsitePreferenceBridgeJniMock)
                .getDefaultContentSetting(any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE));

        doAnswer(
                        invocation -> {
                            mRdsDefaultValue =
                                    invocation.getArgument(2)
                                            ? ContentSettingValues.ALLOW
                                            : ContentSettingValues.BLOCK;
                            return null;
                        })
                .when(mWebsitePreferenceBridgeJniMock)
                .setContentSettingEnabled(
                        any(), eq(ContentSettingsType.REQUEST_DESKTOP_SITE), anyBoolean());

        doAnswer(
                        invocation -> {
                            mContentSettingMap.put(
                                    invocation.getArgument(2), invocation.getArgument(4));
                            return null;
                        })
                .when(mWebsitePreferenceBridgeJniMock)
                .setContentSettingCustomScope(
                        any(),
                        eq(ContentSettingsType.REQUEST_DESKTOP_SITE),
                        anyString(),
                        anyString(),
                        anyInt());
        doAnswer(invocation -> toDomainWildcardPattern(invocation.getArgument(0)))
                .when(mWebsitePreferenceBridgeJniMock)
                .toDomainWildcardPattern(anyString());

        mSharedPreferencesManager = ChromeSharedPreferences.getInstance();

        mResources = ApplicationProvider.getApplicationContext().getResources();
        mResources.getConfiguration().smallestScreenWidthDp = 600;
        when(mActivity.getResources()).thenReturn(mResources);

        TrackerFactory.setTrackerForTests(mTracker);
        disableGlobalDefaultsExperimentFeatures();

        ShadowSysUtils.setMemoryInMB(7000);
        ShadowDisplayAndroid.setDisplayAndroid(mDisplayAndroid);
        when(mDisplayAndroid.getDisplayWidth()).thenReturn(1600);
        when(mDisplayAndroid.getDisplayHeight()).thenReturn(2560);
        when(mDisplayAndroid.getXdpi()).thenReturn(275.5f);
        when(mDisplayAndroid.getYdpi()).thenReturn(276.5f);
        ShadowDisplayAndroidManager.setDisplay(mDisplay);
        when(mDisplay.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY);
        ShadowDisplayUtil.setCurrentSmallestScreenWidth(800);
        when(mUserPrefsJni.get(mProfile)).thenReturn(mPrefService);
        doAnswer(invocation -> mWindowSetting)
                .when(mPrefService)
                .getBoolean(eq(DESKTOP_SITE_WINDOW_SETTING_ENABLED));
        doAnswer(invocation -> mIsDefaultValuePreference)
                .when(mPrefService)
                .isDefaultValuePreference(eq(DESKTOP_SITE_WINDOW_SETTING_ENABLED));
        doAnswer(
                        invocation -> {
                            mWindowSetting = invocation.getArgument(1);
                            return true;
                        })
                .when(mPrefService)
                .setBoolean(eq(DESKTOP_SITE_WINDOW_SETTING_ENABLED), anyBoolean());
        ShadowTabUtils.setIsGlobalSetting(true);
        when(mActivity.getWindow()).thenReturn(mWindow);
        when(mWindow.getAttributes()).thenReturn(mLayoutParams);
        mLayoutParams.width = -1;
        mDisplayMetrics.density = 1.0f;
        mDisplayMetrics.widthPixels = 800;
        mShadowPackageManager =
                Shadows.shadowOf(ContextUtils.getApplicationContext().getPackageManager());
        mShadowPackageManager.setSystemFeature(
                PackageManager.FEATURE_AUTOMOTIVE, /* supported= */ false);
        RequestDesktopUtils.setTestDisplayMetrics(mDisplayMetrics);
        BuildConfig.IS_DESKTOP_ANDROID = false;
        ResettersForTesting.register(() -> BuildConfig.IS_DESKTOP_ANDROID = false);
    }

    @After
    public void tearDown() {
        FeatureList.setTestValues(null);
        ShadowDisplayAndroid.setDisplayAndroid(null);
        if (mSharedPreferencesManager != null) {
            mSharedPreferencesManager.removeKey(
                    ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING);
            mSharedPreferencesManager.removeKey(
                    SingleCategorySettingsConstants
                            .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY);
        }
    }

    @Test
    public void testSetRequestDesktopSiteContentSettingsForUrl_DefaultBlock_Incognito() {
        // Incognito profile type.
        when(mProfile.isOffTheRecord()).thenReturn(true);
        when(mProfile.isPrimaryOTRProfile()).thenReturn(true);
        mRdsDefaultValue = ContentSettingValues.BLOCK;

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void testSetRequestDesktopSiteContentSettingsForUrl_DefaultAllow_Incognito() {
        // Incognito profile type.
        when(mProfile.isOffTheRecord()).thenReturn(true);
        when(mProfile.isPrimaryOTRProfile()).thenReturn(true);
        mRdsDefaultValue = ContentSettingValues.ALLOW;

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultBlock_SiteBlock_WindowSettingOn() {
        mWindowSetting = true;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.BLOCK;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.BLOCK);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should not be removed "
                        + "when window setting is ON.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultBlock_SiteBlock_WindowSettingOff() {
        mWindowSetting = false;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.BLOCK;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.BLOCK);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should be removed "
                        + "when window setting is OFF.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultBlock_SiteAllow_WindowSettingOn() {
        mWindowSetting = true;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.BLOCK;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.ALLOW);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should not be removed "
                        + "when window setting is ON.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultBlock_SiteAllow_WindowSettingOff() {
        mWindowSetting = false;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.BLOCK;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.ALLOW);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should be removed "
                        + "when window setting is OFF.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultAllow_SiteAllow_WindowSettingOn() {
        mWindowSetting = true;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.ALLOW;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.ALLOW);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should not be removed "
                        + "when window setting is ON.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultAllow_SiteAllow_WindowSettingOff() {
        mWindowSetting = false;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.ALLOW;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.ALLOW);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should be removed "
                        + "when window setting is OFF.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultAllow_SiteBlock_WindowSettingOn() {
        mWindowSetting = true;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.ALLOW;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.BLOCK);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should not be removed "
                        + "when window setting is ON.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    @Test
    public void
            testSetRequestDesktopSiteContentSettingsForUrl_DefaultAllow_SiteBlock_WindowSettingOff() {
        mWindowSetting = false;
        // Regular profile type.
        when(mProfile.isOffTheRecord()).thenReturn(false);
        mRdsDefaultValue = ContentSettingValues.ALLOW;
        // Pre-existing subdomain setting.
        mContentSettingMap.put(mGoogleUrl.getHost(), ContentSettingValues.BLOCK);
        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mGoogleUrl, true);
        Assert.assertEquals(
                "Request Desktop Site domain level setting should be removed "
                        + "when window setting is OFF.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        Assert.assertEquals(
                "Request Desktop Site subdomain level setting should be removed.",
                ContentSettingValues.DEFAULT,
                mContentSettingMap.get(mGoogleUrl.getHost()).intValue());

        RequestDesktopUtils.setRequestDesktopSiteContentSettingsForUrl(mProfile, mMapsUrl, false);
        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.BLOCK,
                mContentSettingMap.get(GOOGLE_COM).intValue());
    }

    /**
     * Helper to get domain wildcard pattern from URL. The real implementation calls
     * {@link WebsitePreferenceBridge}.
     * @param origin A URL.
     * @return The domain wildcard pattern from the given URL.
     */
    private String toDomainWildcardPattern(String origin) {
        return ANY_SUBDOMAIN_PATTERN + origin.replaceAll(".*\\.(.+\\.[^.]+$)", "$1");
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_IsAndroidDesktop() {
        BuildConfig.IS_DESKTOP_ANDROID = true;
        ShadowSysUtils.setMemoryInMB(4000);
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(11, mActivity);
        Assert.assertTrue(
                "Desktop site global setting should be default-enabled on desktop "
                        + "Android, even for low memory",
                shouldDefaultEnable);
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_MemoryThreshold() {
        ShadowSysUtils.setMemoryInMB(6000);
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mActivity);
        Assert.assertFalse(
                "Desktop site global setting should not be default-enabled on devices below the "
                        + "memory threshold.",
                shouldDefaultEnable);
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_CustomScreenSizeThreshold() {
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(11.0, mActivity);
        Assert.assertTrue(
                "Desktop site global setting should be default-enabled on 10\"+ " + "devices.",
                shouldDefaultEnable);
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_WithSmallDisplay() {
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(7, mActivity);
        Assert.assertFalse(
                "Desktop site global setting should not be default-enabled", shouldDefaultEnable);
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_ExternalDisplay() {
        when(mDisplay.getDisplayId()).thenReturn(/*non built-in display*/ 2);
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mActivity);
        Assert.assertFalse(
                "Desktop site global setting should not be default-enabled on external display",
                shouldDefaultEnable);

        when(mDisplay.getDisplayId()).thenReturn(Display.DEFAULT_DISPLAY);
        shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mActivity);
        Assert.assertTrue(
                "Desktop site global setting should be default-enabled on built-in display",
                shouldDefaultEnable);
    }

    @Test
    public void testShouldDefaultEnableGlobalSetting_UserPreviouslyUpdatedSetting() {
        // This SharedPreference key will ideally be updated when the user explicitly requests for
        // an update to the desktop site global setting.
        mSharedPreferencesManager.writeBoolean(
                SingleCategorySettingsConstants
                        .USER_ENABLED_DESKTOP_SITE_GLOBAL_SETTING_PREFERENCE_KEY,
                true);
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mActivity);
        Assert.assertFalse(
                "Desktop site global setting should not be default-enabled if it has been "
                        + "previously updated by the user.",
                shouldDefaultEnable);
    }

    @Test
    public void testMaybeDefaultEnableGlobalSetting() {
        boolean didDefaultEnable =
                RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mProfile,
                        mActivity);
        Assert.assertTrue(
                "Desktop site global setting should be default-enabled on big screen devices.",
                didDefaultEnable);
        Assert.assertEquals(
                "Desktop site content setting should be set correctly.",
                ContentSettingValues.ALLOW,
                mRdsDefaultValue);
        Assert.assertTrue(
                "SharedPreference DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING should be true.",
                mSharedPreferencesManager.contains(
                                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING)
                        && mSharedPreferencesManager.readBoolean(
                                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING,
                                false));

        // Verify that the desktop site global setting will be default-enabled at most once.
        boolean shouldDefaultEnable =
                RequestDesktopUtils.shouldDefaultEnableGlobalSetting(
                        RequestDesktopUtils
                                .DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                        mActivity);
        Assert.assertFalse(
                "Desktop site global setting should not be default-enabled more than once.",
                shouldDefaultEnable);
    }

    @Test
    public void testMaybeShowDefaultEnableGlobalSettingMessage() {
        when(mTracker.shouldTriggerHelpUI(FeatureConstants.REQUEST_DESKTOP_SITE_DEFAULT_ON_FEATURE))
                .thenReturn(true);

        // Default-enable the global setting before the message is shown.
        RequestDesktopUtils.maybeDefaultEnableGlobalSetting(
                RequestDesktopUtils.DEFAULT_GLOBAL_SETTING_DEFAULT_ON_DISPLAY_SIZE_THRESHOLD_INCHES,
                mProfile,
                mActivity);

        when(mWebsitePreferenceBridgeJniMock.isContentSettingEnabled(
                        mProfile, ContentSettingsType.REQUEST_DESKTOP_SITE))
                .thenReturn(true);
        RequestDesktopUtils.maybeShowDefaultEnableGlobalSettingMessage(
                mProfile, mMessageDispatcher, mActivity);

        ArgumentCaptor<PropertyModel> message = ArgumentCaptor.forClass(PropertyModel.class);
        verify(mMessageDispatcher).enqueueWindowScopedMessage(message.capture(), eq(false));
        Assert.assertEquals(
                "Message identifier should match.",
                MessageIdentifier.DESKTOP_SITE_GLOBAL_DEFAULT_OPT_OUT,
                message.getValue().get(MessageBannerProperties.MESSAGE_IDENTIFIER));
        Assert.assertEquals(
                "Message title should match.",
                mResources.getString(R.string.rds_global_default_on_message_title),
                message.getValue().get(MessageBannerProperties.TITLE));
        Assert.assertEquals(
                "Message primary button text should match.",
                mResources.getString(R.string.rds_global_default_on_message_button),
                message.getValue().get(MessageBannerProperties.PRIMARY_BUTTON_TEXT));
        Assert.assertEquals(
                "Message icon resource ID should match.",
                R.drawable.ic_desktop_windows,
                message.getValue().get(MessageBannerProperties.ICON_RESOURCE_ID));
    }

    @Test
    public void testMaybeShowDefaultEnableGlobalSettingMessage_DoNotShowIfSettingIsDisabled() {
        when(mTracker.shouldTriggerHelpUI(FeatureConstants.REQUEST_DESKTOP_SITE_DEFAULT_ON_FEATURE))
                .thenReturn(true);

        // Preference is set when the setting is default-enabled.
        mSharedPreferencesManager.writeBoolean(
                ChromePreferenceKeys.DEFAULT_ENABLED_DESKTOP_SITE_GLOBAL_SETTING, true);

        // Simulate disabling of the setting by the user before the message is shown.
        when(mWebsitePreferenceBridgeJniMock.isContentSettingEnabled(
                        mProfile, ContentSettingsType.REQUEST_DESKTOP_SITE))
                .thenReturn(false);

        boolean shown =
                RequestDesktopUtils.maybeShowDefaultEnableGlobalSettingMessage(
                        mProfile, mMessageDispatcher, mActivity);
        Assert.assertFalse(
                "Message should not be shown if the content setting is disabled.", shown);
    }

    @Test
    public void testMaybeShowDefaultEnableGlobalSettingMessage_DoNotShowIfDesktopAndroid() {
        BuildConfig.IS_DESKTOP_ANDROID = true;

        boolean shown =
                RequestDesktopUtils.maybeShowDefaultEnableGlobalSettingMessage(
                        mProfile, mMessageDispatcher, mActivity);
        Assert.assertFalse("Message should not be shown for desktop Android.", shown);
    }

    @Test
    public void testUpgradeTabLevelDesktopSiteSetting() {
        mRdsDefaultValue = ContentSettingValues.BLOCK;
        @TabUserAgent int tabUserAgent = TabUserAgent.DESKTOP;

        RequestDesktopUtils.maybeUpgradeTabLevelDesktopSiteSetting(
                mTab, mProfile, tabUserAgent, mGoogleUrl);

        Assert.assertEquals(
                "Request Desktop Site domain level setting is not set correctly.",
                ContentSettingValues.ALLOW,
                mContentSettingMap.get(GOOGLE_COM).intValue());
        verify(mTab).setUserAgent(TabUserAgent.DEFAULT);
    }

    @Test
    public void testShouldApplyWindowSetting_IsAutomotive() {
        mShadowPackageManager.setSystemFeature(
                PackageManager.FEATURE_AUTOMOTIVE, /* supported= */ true);
        mWindowSetting = true;
        boolean shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertFalse(
                "Desktop site window setting should not be applied on automotive",
                shouldApplyWindowSetting);
    }

    @Test
    public void testShouldApplyWindowSetting_SettingOff() {
        mWindowSetting = false;
        boolean shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertFalse(
                "Desktop site window setting should not be applied when window setting is off",
                shouldApplyWindowSetting);
    }

    @Test
    public void testShouldApplyWindowSetting_isNotGlobalSetting() {
        mWindowSetting = true;
        ShadowTabUtils.setIsGlobalSetting(false);
        boolean shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertFalse(
                "Desktop site window setting should not be applied when the current RDS setting "
                        + "is domain setting",
                shouldApplyWindowSetting);
    }

    @Test
    public void testShouldApplyWindowSetting_windowAttributesWidthValid() {
        mWindowSetting = true;
        ShadowTabUtils.setIsGlobalSetting(true);
        mLayoutParams.width = 800;
        boolean shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertFalse(
                "Desktop site window setting should not be applied when window width in dp is "
                        + "larger than 600",
                shouldApplyWindowSetting);

        mLayoutParams.width = 400;
        shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertTrue(
                "Desktop site window setting should be applied when window width in dp is "
                        + "smaller than 600",
                shouldApplyWindowSetting);
    }

    @Test
    public void testShouldApplyWindowSetting_windowAttributesWidthInvalid() {
        mWindowSetting = true;
        ShadowTabUtils.setIsGlobalSetting(true);
        mDisplayMetrics.density = 2.0f;
        mDisplayMetrics.widthPixels = 1600;
        boolean shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertFalse(
                "Desktop site window setting should not be applied when window width in dp is "
                        + "larger than 600",
                shouldApplyWindowSetting);

        mDisplayMetrics.widthPixels = 1000;
        shouldApplyWindowSetting =
                RequestDesktopUtils.shouldApplyWindowSetting(mProfile, mGoogleUrl, mActivity);
        Assert.assertTrue(
                "Desktop site window setting should be applied when window width in dp is "
                        + "smaller than 600",
                shouldApplyWindowSetting);
    }

    @Test
    public void testMaybeDefaultEnableWindowSetting_PhoneSizedScreen() {
        mWindowSetting = false;
        mIsDefaultValuePreference = true;
        ShadowDisplayUtil.setCurrentSmallestScreenWidth(400);
        RequestDesktopUtils.maybeDefaultEnableWindowSetting(mActivity, mProfile);
        Assert.assertFalse(
                "Desktop site window setting should not be default enabled when the smallest "
                        + "screen width is less than 600dp",
                mWindowSetting);
    }

    @Test
    public void testMaybeDefaultEnableWindowSetting_DesktopAndroid() {
        mWindowSetting = false;
        mIsDefaultValuePreference = true;
        BuildConfig.IS_DESKTOP_ANDROID = true;
        RequestDesktopUtils.maybeDefaultEnableWindowSetting(mActivity, mProfile);
        Assert.assertFalse(
                "Desktop site window setting should not be default enabled for desktop "
                        + "Android",
                mWindowSetting);
    }

    @Test
    public void testMaybeDefaultEnableWindowSetting_ExternalDisplay() {
        mWindowSetting = false;
        mIsDefaultValuePreference = true;
        when(mDisplay.getDisplayId()).thenReturn(/*non built-in display*/ 2);
        RequestDesktopUtils.maybeDefaultEnableWindowSetting(mActivity, mProfile);
        Assert.assertFalse(
                "Desktop site window setting should not be default enabled when Chrome is opened "
                        + "on external display",
                mWindowSetting);
    }

    @Test
    public void testMaybeDefaultEnableWindowSetting_NotDefaultValuePreference() {
        mWindowSetting = false;
        mIsDefaultValuePreference = false;
        RequestDesktopUtils.maybeDefaultEnableWindowSetting(mActivity, mProfile);
        Assert.assertFalse(
                "Desktop site window setting should not be default enabled when the preference "
                        + "has been previously changed",
                mWindowSetting);
    }

    @Test
    public void testMaybeDefaultEnableWindowSetting_ShouldDefaultEnable() {
        mWindowSetting = false;
        mIsDefaultValuePreference = true;
        RequestDesktopUtils.maybeDefaultEnableWindowSetting(mActivity, mProfile);
        Assert.assertTrue("Desktop site window setting should be default enabled", mWindowSetting);
    }

    private Tab createTab() {
        return mock(Tab.class);
    }

    private void enableFeature(String featureName, boolean enable) {
        enableFeatureWithParams(featureName, null, enable);
    }

    private void enableFeatureWithParams(
            String featureName, Map<String, String> params, boolean enable) {
        mTestValues.addFeatureFlagOverride(featureName, enable);
        if (params != null) {
            for (Entry<String, String> param : params.entrySet()) {
                mTestValues.addFieldTrialParamOverride(
                        featureName, param.getKey(), param.getValue());
            }
        }
        FeatureList.setTestValues(mTestValues);
    }

    private void disableGlobalDefaultsExperimentFeatures() {
        enableFeatureWithParams("RequestDesktopSiteDefaults", null, false);
        enableFeatureWithParams("RequestDesktopSiteDefaultsControl", null, false);
        enableFeatureWithParams("RequestDesktopSiteDefaultsControlCohort1", null, false);
        enableFeatureWithParams("RequestDesktopSiteDefaultsEnabledCohort1", null, false);
        enableFeatureWithParams("RequestDesktopSiteDefaultsControlCohort2", null, false);
        enableFeatureWithParams("RequestDesktopSiteDefaultsEnabledCohort2", null, false);
    }
}