chromium/chrome/browser/ui/android/google_bottom_bar/java/src/org/chromium/chrome/browser/ui/google_bottom_bar/BottomBarConfigCreatorTest.java

// Copyright 2024 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.ui.google_bottom_bar;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.ADD_NOTES;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.CUSTOM;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.PIH_BASIC;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.REFRESH;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.SAVE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.ButtonId.SHARE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.GoogleBottomBarVariantLayoutType.DOUBLE_DECKER;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.GoogleBottomBarVariantLayoutType.NO_VARIANT;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.GoogleBottomBarVariantLayoutType.SINGLE_DECKER;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.GoogleBottomBarVariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfigCreator.CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfigCreator.GOOGLE_BOTTOM_BAR_NO_VARIANT_HEIGHT_DP_PARAM_VALUE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfigCreator.GOOGLE_BOTTOM_BAR_SINGLE_DECKER_HEIGHT_DP_PARAM_VALUE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfigCreator.GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE;
import static org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfigCreator.IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED;

import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;

import androidx.test.ext.junit.rules.ActivityScenarioRule;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.annotation.Config;

import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.chrome.browser.browserservices.intents.CustomButtonParams;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.ChromeSharedPreferences;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.ui.google_bottom_bar.BottomBarConfig.GoogleBottomBarVariantLayoutType;
import org.chromium.chrome.browser.ui.google_bottom_bar.proto.IntentParams.GoogleBottomBarIntentParams;
import org.chromium.chrome.browser.ui.google_bottom_bar.proto.IntentParams.GoogleBottomBarIntentParams.VariantLayoutType;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.ui.UiUtils;
import org.chromium.ui.base.TestActivity;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/** Unit tests for {@link BottomBarConfig}. */
@RunWith(BaseRobolectricTestRunner.class)
@Batch(Batch.UNIT_TESTS)
@Config(manifest = Config.NONE)
public class BottomBarConfigCreatorTest {

    @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();

    @Rule
    public ActivityScenarioRule<TestActivity> mActivityScenarioRule =
            new ActivityScenarioRule<>(TestActivity.class);

    @Mock private CustomButtonParams mCustomButtonParams;
    @Mock private TemplateUrlService mTemplateUrlService;
    @Mock private Profile mProfile;

    private BottomBarConfigCreator mConfigCreator;
    private Context mContext;

    @Before
    public void setup() {
        mActivityScenarioRule.getScenario().onActivity(activity -> mContext = activity);
        mConfigCreator = new BottomBarConfigCreator(mContext);
        TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);
    }

    @After
    public void tearDown() {
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
    }

    @Test
    public void emptyList_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params = GoogleBottomBarIntentParams.getDefaultInstance();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), NO_VARIANT);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void doubleDecker_emptyList_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .build();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), DOUBLE_DECKER);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void singleDecker_emptyList_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), SINGLE_DECKER);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void singleDeckerWithRightButtons_emptyList_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .build();

        assertDefaultConfig(
                mConfigCreator.create(params, List.of()), SINGLE_DECKER_WITH_RIGHT_BUTTONS);
    }

    @Test
    public void onlyOneItem_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder().addEncodedButton(1).build();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), NO_VARIANT);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void singleDeckerWithRightButtons_moreThanTwoButtons_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .addAllEncodedButton(List.of(1, 1, 2, 3))
                        .build();

        assertDefaultConfig(
                mConfigCreator.create(params, List.of()), SINGLE_DECKER_WITH_RIGHT_BUTTONS);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            singleDeckerWithRightButtons_withSpotlightButtonInList_returnsConfigWithoutSpotlight() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .addAllEncodedButton(List.of(1, 1, 2))
                        .build();

        BottomBarConfig config = mConfigCreator.create(params, List.of());

        assertNull(config.getSpotlightId());
    }

    @Test
    public void invalidButtonIdInList_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 15, 1))
                        .build();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), NO_VARIANT);
    }

    @Test
    public void invalidSpotlightButton_returnsDefaultConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(15, 1, 2, 3))
                        .build();

        assertDefaultConfig(mConfigCreator.create(params, List.of()), NO_VARIANT);
    }

    @Test
    public void noSpotlightParamList_nullSpotlight_correctButtonList() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of());

        assertNull(buttonConfig.getSpotlightId());
        assertEquals(3, buttonConfig.getButtonList().size());
        assertEquals(PIH_BASIC, buttonConfig.getButtonList().get(0).getId());
    }

    @Test
    public void withSpotlightParamList_correctSpotlightSet_correctButtonList() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(1, 1, 2, 3))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of());
        Integer spotlight = buttonConfig.getSpotlightId();

        assertNotNull(spotlight);
        assertEquals(spotlight.intValue(), PIH_BASIC);
        assertEquals(3, buttonConfig.getButtonList().size());
    }

    @Test
    public void createButtonConfigList_emptyCustomButtonParamsList() {
        List<Integer> buttonIdList = List.of(PIH_BASIC, PIH_BASIC, SHARE, SAVE, ADD_NOTES, REFRESH);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder().addAllEncodedButton(buttonIdList).build();

        // empty customButtonParamsList - SAVE and ADD_NOTES are not included in the final list
        BottomBarConfig buttonConfig = mConfigCreator.create(params, new ArrayList<>());
        assertEquals(3, buttonConfig.getButtonList().size());
    }

    @Test
    public void createButtonConfigList_withCustomButtonParamsList() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(100); // SAVE
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        List<Integer> buttonIdList =
                List.of(
                        PIH_BASIC, PIH_BASIC, SHARE, SAVE, ADD_NOTES,
                        REFRESH); // PIH_BASIC, SHARE, SAVE, ADD_NOTES, REFRESH
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder().addAllEncodedButton(buttonIdList).build();

        // ADD_NOTES and REFRESH are not included in the final list as they are not supported
        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));
        assertEquals(3, buttonConfig.getButtonList().size());
    }

    @Test
    public void createButtonConfigList_buttonIdListWithoutCustomParamId() {
        List<Integer> buttonIdList = List.of(PIH_BASIC, PIH_BASIC, SHARE); // PIH_BASIC, SHARE
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder().addAllEncodedButton(buttonIdList).build();

        when(mCustomButtonParams.getId()).thenReturn(100); // SAVE

        // SAVE is not included in the final list
        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));
        assertEquals(2, buttonConfig.getButtonList().size());
    }

    @Test
    public void withCorrectCustomParams_hasCorrectButtonConfig() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(100); // SAVE
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        var pendingIntent = mock(PendingIntent.class);
        when(mCustomButtonParams.getPendingIntent()).thenReturn(pendingIntent);
        // PIH_BASIC, SHARE, SAVE, REFRESH
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(1, 1, 2, 3, 5))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));

        // the button has the expected custom button params set
        assertEquals(pendingIntent, buttonConfig.getButtonList().get(2).getPendingIntent());
    }

    @Test
    public void hasPageInsightsCustomParams_usesChromePageInsightsIconInButtonConfig() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(103); // PAGE INSIGHTS
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        var pendingIntent = mock(PendingIntent.class);
        when(mCustomButtonParams.getPendingIntent()).thenReturn(pendingIntent);
        // PIH_BASIC, SHARE, SAVE
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));

        Bitmap expectedBitmap =
                drawableToBitmap(
                        UiUtils.getTintedDrawable(
                                mContext,
                                R.drawable.bottom_bar_page_insights_icon,
                                R.color.default_icon_color_baseline));
        Bitmap actualBitmap = drawableToBitmap(buttonConfig.getButtonList().get(0).getIcon());
        // the button has the expected custom button params set
        assertTrue(expectedBitmap.sameAs(actualBitmap));
    }

    @Test
    public void hasSearchCustomParams_usesChromeSearchIconInButtonConfig() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(106); // SEARCH
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        var pendingIntent = mock(PendingIntent.class);
        when(mCustomButtonParams.getPendingIntent()).thenReturn(pendingIntent);
        // SEARCH, SHARE, SAVE
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 9, 2, 3))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));

        Bitmap expectedBitmap =
                drawableToBitmap(
                        UiUtils.getTintedDrawable(
                                mContext,
                                R.drawable.ic_search,
                                R.color.default_icon_color_baseline));
        Bitmap actualBitmap = drawableToBitmap(buttonConfig.getButtonList().get(0).getIcon());
        // the button has the expected custom button params set
        assertTrue(expectedBitmap.sameAs(actualBitmap));
    }

    @Test
    public void hasHomeCustomParams_usesChromeHomeIconInButtonConfig() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(107); // HOME
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        var pendingIntent = mock(PendingIntent.class);
        when(mCustomButtonParams.getPendingIntent()).thenReturn(pendingIntent);
        // HOME, SHARE, SAVE
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 10, 2, 3))
                        .build();

        BottomBarConfig buttonConfig = mConfigCreator.create(params, List.of(mCustomButtonParams));

        Bitmap expectedBitmap =
                drawableToBitmap(
                        UiUtils.getTintedDrawable(
                                mContext,
                                R.drawable.bottom_bar_home_icon,
                                R.color.default_icon_color_baseline));
        Bitmap actualBitmap = drawableToBitmap(buttonConfig.getButtonList().get(0).getIcon());
        // the button has the expected custom button params set
        assertTrue(expectedBitmap.sameAs(actualBitmap));
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void singleDeckerWithRightButtons_returnsCorrectConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .addAllEncodedButton(List.of(0, SHARE))
                        .build();

        BottomBarConfig config = mConfigCreator.create(params, List.of());

        assertNull(config.getSpotlightId());
        assertEquals(1, config.getButtonList().size());
        assertEquals(SHARE, config.getButtonList().get(0).getId());
    }

    @Test
    @DisableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsDisabled_intentParamDoubleDecker_showsOnlyButtons() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(NO_VARIANT, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamNotSet_finchParamNotSet_showsOnlyButtons() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(NO_VARIANT, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_defaultSearchEngineCheckDisabledAndNotEqualToGoogle_doubleDeckerLayoutSet_showsDoubleDeckerLayout() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(false);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(DOUBLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_defaultSearchEngineCheckEnabledAndNotEqualToGoogle_doubleDeckerLayoutSet_showsNoVariantLayout() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(true);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(NO_VARIANT, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamChromeControlled_finchParamNotSet_returnsDoubleDecker() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.CHROME_CONTROLLED)
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(DOUBLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamChromeControlled_finchParamDoubleDecker_returnsDoubleDecker() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.CHROME_CONTROLLED)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(DOUBLE_DECKER);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(DOUBLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamChromeControlled_finchParamSingleDecker_returnsSingleDecker() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.CHROME_CONTROLLED)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(SINGLE_DECKER);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(SINGLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamChromeControlled_finchParamSingleDeckerWithRightButtons_returnsSingleDeckerWithRightButtons() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.CHROME_CONTROLLED)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(SINGLE_DECKER_WITH_RIGHT_BUTTONS);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(SINGLE_DECKER_WITH_RIGHT_BUTTONS, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamDoubleDecker_showsDoubleDecker() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(NO_VARIANT);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(DOUBLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamSingleDecker_showsSingleDecker() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(NO_VARIANT);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(SINGLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getVariantLayoutType_variantLayoutsEnabled_intentParamSingleDeckerWithRightButtons_showsSingleDeckerWithRightButtons() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1, 2, 3))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();
        GOOGLE_BOTTOM_BAR_VARIANT_LAYOUT_VALUE.setForTesting(NO_VARIANT);

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(SINGLE_DECKER, bottomBarConfig.getVariantLayoutType());
    }

    @Test
    public void create_noVariant_heightNotSpecified_hasDefaultHeight() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(
                BottomBarConfigCreator.DEFAULT_NO_VARIANT_HEIGHT_DP, bottomBarConfig.getHeightDp());
    }

    @Test
    public void create_noVariant_heightSpecifiedByFinch_hasFinchHeight() {
        GOOGLE_BOTTOM_BAR_NO_VARIANT_HEIGHT_DP_PARAM_VALUE.setForTesting(123);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(123, bottomBarConfig.getHeightDp());
    }

    @Test
    public void create_noVariant_heightSpecifiedByIntent_hasIntentHeight() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .setNoVariantHeightDp(123)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(123, bottomBarConfig.getHeightDp());
    }

    @Test
    public void create_noVariant_heightSpecifiedByFinchAndIntent_hasIntentHeight() {
        GOOGLE_BOTTOM_BAR_NO_VARIANT_HEIGHT_DP_PARAM_VALUE.setForTesting(123);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .setNoVariantHeightDp(456)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(456, bottomBarConfig.getHeightDp());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_singleDecker_withEmptyList_hasCorrectBottomBarConfig() {
        Drawable drawable = mock(Drawable.class);
        when(mCustomButtonParams.getId()).thenReturn(105); // CUSTOM
        when(mCustomButtonParams.getIcon(mContext)).thenReturn(drawable);
        var pendingIntent = mock(PendingIntent.class);
        when(mCustomButtonParams.getPendingIntent()).thenReturn(pendingIntent);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        BottomBarConfig bottomBarConfig =
                mConfigCreator.create(params, List.of(mCustomButtonParams));

        assertEquals(SINGLE_DECKER, bottomBarConfig.getVariantLayoutType());
        assertEquals(0, bottomBarConfig.getButtonList().size());
        assertNull(bottomBarConfig.getSpotlightId());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_singleDecker_heightNotSpecified_hasDefaultHeight() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(
                BottomBarConfigCreator.DEFAULT_SINGLE_DECKER_HEIGHT_DP,
                bottomBarConfig.getHeightDp());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_singleDecker_heightSpecifiedByFinch_hasFinchHeight() {
        GOOGLE_BOTTOM_BAR_SINGLE_DECKER_HEIGHT_DP_PARAM_VALUE.setForTesting(123);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(123, bottomBarConfig.getHeightDp());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_singleDecker_heightSpecifiedByIntent_hasIntentHeight() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .setSingleDeckerHeightDp(123)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(123, bottomBarConfig.getHeightDp());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_singleDecker_heightSpecifiedByFinchAndIntent_hasIntentHeight() {
        GOOGLE_BOTTOM_BAR_SINGLE_DECKER_HEIGHT_DP_PARAM_VALUE.setForTesting(123);
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .setSingleDeckerHeightDp(456)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(456, bottomBarConfig.getHeightDp());
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void create_withEmptyList_singleDeckerWithRightButtons_hasCorrectBottomBarConfig() {
        GoogleBottomBarIntentParams params =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, 1))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        BottomBarConfig bottomBarConfig = mConfigCreator.create(params, List.of());

        assertEquals(SINGLE_DECKER, bottomBarConfig.getVariantLayoutType());
        assertEquals(0, bottomBarConfig.getButtonList().size());
        assertNull(bottomBarConfig.getSpotlightId());
    }

    @Test
    @DisableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void initDefaultSearchEngine_variantLayoutsDisabled_doesNotCheckDefaultSearchEngine() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(false);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(true);

        BottomBarConfigCreator.initDefaultSearchEngine(mProfile);

        verifyNoInteractions(mTemplateUrlService);
        // Verify that true value is not written to Shared preferences
        // Use true as default value as we expect to get false
        assertFalse(
                ChromeSharedPreferences.getInstance()
                        .readBoolean(
                                IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, /* defaultValue= */ true));
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            initDefaultSearchEngine_variantLayoutsEnabled_defaultSearchEngineCheckEnabled_doesNotCheckDefaultSearchEngine() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(false);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(true);

        BottomBarConfigCreator.initDefaultSearchEngine(mProfile);

        verifyNoInteractions(mTemplateUrlService);
        // Verify that true value is not written to Shared preferences
        // Use true as default value as we expect to get false
        assertFalse(
                ChromeSharedPreferences.getInstance()
                        .readBoolean(
                                IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, /* defaultValue= */ true));
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            initDefaultSearchEngine_variantLayoutsEnabled_defaultSearchEngineCheckEnabledAndNotEqualToGoogle_writesFalse() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(true);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, true);
        when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(false);

        BottomBarConfigCreator.initDefaultSearchEngine(mProfile);

        // Use true as default value as we expect to get false
        assertFalse(
                ChromeSharedPreferences.getInstance()
                        .readBoolean(
                                IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, /* defaultValue= */ true));
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            initDefaultSearchEngine_variantLayoutsEnabled_defaultSearchEngineCheckEnabledAndEqualsToGoogle_writesTrue() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(true);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        when(mTemplateUrlService.isDefaultSearchEngineGoogle()).thenReturn(true);

        BottomBarConfigCreator.initDefaultSearchEngine(mProfile);

        // Use false as default value as we expect to get true
        assertTrue(
                ChromeSharedPreferences.getInstance()
                        .readBoolean(
                                IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, /* defaultValue= */ false));
    }

    @Test
    @DisableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsDisabled_returnsSetWithAllSupportedCustomParams() {
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(
                CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP.keySet(), supportedGoogleBottomBarButtons);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabled_noVariantLayout_returnsSetWithAllSupportedCustomParams() {
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.NO_VARIANT)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(
                CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP.keySet(), supportedGoogleBottomBarButtons);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabled_doubleDecker_returnsSetWithAllSupportedCustomParams() {
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.DOUBLE_DECKER)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(
                CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP.keySet(), supportedGoogleBottomBarButtons);
    }

    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabled_singleDecker_returnsEmptySet() {
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(Set.of(), supportedGoogleBottomBarButtons);
    }

    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabledButNotSupported_singleDecker_returnsSetWithAllSupportedCustomParams() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(true);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, SHARE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(
                CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP.keySet(), supportedGoogleBottomBarButtons);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabled_singleDeckerWithButtonsOnRight_returnsSetWithEncodedButtons() {
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(Set.of(100, 105), supportedGoogleBottomBarButtons);
    }

    @Test
    @EnableFeatures(ChromeFeatureList.CCT_GOOGLE_BOTTOM_BAR_VARIANT_LAYOUTS)
    public void
            getSupportedCustomButtonParamIds_variantLayoutsEnabledButNotSupported_singleDeckerWithButtonsOnRight_returnsSetWithAllSupportedCustomParams() {
        IS_GOOGLE_DEFAULT_SEARCH_ENGINE_CHECK_ENABLED.setForTesting(true);
        ChromeSharedPreferences.getInstance()
                .writeBoolean(IS_CHROME_DEFAULT_SEARCH_ENGINE_GOOGLE, false);
        GoogleBottomBarIntentParams intentParams =
                GoogleBottomBarIntentParams.newBuilder()
                        .addAllEncodedButton(List.of(0, SAVE, CUSTOM))
                        .setVariantLayoutType(VariantLayoutType.SINGLE_DECKER_WITH_RIGHT_BUTTONS)
                        .build();

        Set<Integer> supportedGoogleBottomBarButtons =
                BottomBarConfigCreator.getSupportedCustomButtonParamIds(intentParams);

        assertEquals(
                CUSTOM_BUTTON_PARAM_ID_TO_BUTTON_ID_MAP.keySet(), supportedGoogleBottomBarButtons);
    }

    private static Bitmap drawableToBitmap(Drawable drawable) {
        Bitmap bitmap =
                Bitmap.createBitmap(
                        drawable.getIntrinsicWidth(),
                        drawable.getIntrinsicHeight(),
                        Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return bitmap;
    }

    private static void assertDefaultConfig(
            BottomBarConfig config, @GoogleBottomBarVariantLayoutType int layoutType) {
        assertNull(config.getSpotlightId());

        if (layoutType == NO_VARIANT) {
            assertEquals(2, config.getButtonList().size());
            assertEquals(SAVE, config.getButtonList().get(0).getId());
            assertEquals(SHARE, config.getButtonList().get(1).getId());
            assertEquals(BottomBarConfigCreator.DEFAULT_NO_VARIANT_HEIGHT_DP, config.getHeightDp());
        } else if (layoutType == DOUBLE_DECKER) {
            assertEquals(2, config.getButtonList().size());
            assertEquals(SAVE, config.getButtonList().get(0).getId());
            assertEquals(SHARE, config.getButtonList().get(1).getId());
            assertEquals(BottomBarConfigCreator.DOUBLE_DECKER_HEIGHT_DP, config.getHeightDp());
        } else if (layoutType == SINGLE_DECKER_WITH_RIGHT_BUTTONS) {
            assertEquals(1, config.getButtonList().size());
            assertEquals(SHARE, config.getButtonList().get(0).getId());
            assertEquals(
                    BottomBarConfigCreator.SINGLE_DECKER_WITH_RIGHT_BUTTONS_HEIGHT_DP,
                    config.getHeightDp());
        } else if (layoutType == SINGLE_DECKER) {
            assertEquals(0, config.getButtonList().size());
            assertEquals(
                    BottomBarConfigCreator.DEFAULT_SINGLE_DECKER_HEIGHT_DP, config.getHeightDp());
        } else {
            throw new IllegalArgumentException(
                    String.format("Layout type with id %s is not tested.", layoutType));
        }
        assertEquals(config.getVariantLayoutType(), layoutType);
    }
}