chromium/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/LocationBarTest.java

// Copyright 2020 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.omnibox;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;

import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;

import android.content.Intent;
import android.content.res.Configuration;
import android.view.View;
import android.widget.LinearLayout;

import androidx.lifecycle.Lifecycle;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;

import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import org.chromium.base.CommandLine;
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.DisabledTest;
import org.chromium.base.test.util.DoNotBatch;
import org.chromium.base.test.util.Features.DisableFeatures;
import org.chromium.base.test.util.Features.EnableFeatures;
import org.chromium.base.test.util.Restriction;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.app.ChromeActivity;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.lens.LensController;
import org.chromium.chrome.browser.lifecycle.InflationObserver;
import org.chromium.chrome.browser.locale.LocaleManager;
import org.chromium.chrome.browser.locale.LocaleManagerDelegate;
import org.chromium.chrome.browser.omnibox.status.StatusProperties.StatusIconResource;
import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.R;
import org.chromium.chrome.test.util.ChromeTabUtils;
import org.chromium.chrome.test.util.OmniboxTestUtils;
import org.chromium.components.embedder_support.util.UrlConstants;
import org.chromium.components.search_engines.TemplateUrl;
import org.chromium.components.search_engines.TemplateUrlService;
import org.chromium.content_public.common.ContentSwitches;
import org.chromium.ui.KeyboardUtils;
import org.chromium.ui.base.ActivityKeyboardVisibilityDelegate;
import org.chromium.ui.test.util.UiRestriction;
import org.chromium.ui.test.util.ViewUtils;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/** Instrumentation tests for the LocationBar component. */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({
    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
    ContentSwitches.HOST_RESOLVER_RULES + "=MAP * 127.0.0.1",
    "ignore-certificate-errors"
})
@DoNotBatch(reason = "Test start up behaviors.")
public class LocationBarTest {
    private static final String TEST_QUERY = "testing query";
    private static final List<String> TEST_PARAMS = Arrays.asList("foo=bar");
    private static final String HOSTNAME = "suchwowveryyes.edu";
    private static final String GOOGLE_URL = "https://www.google.com";
    private static final String NON_GOOGLE_URL = "https://www.notgoogle.com";

    @Rule
    public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();

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

    @Mock TemplateUrlService mTemplateUrlService;
    @Mock private TemplateUrl mGoogleSearchEngine;
    @Mock private TemplateUrl mNonGoogleSearchEngine;
    @Mock private LensController mLensController;
    @Mock private LocaleManagerDelegate mLocaleManagerDelegate;
    @Mock private VoiceRecognitionHandler mVoiceRecognitionHandler;
    @Mock private SearchEngineUtils mSearchEngineUtils;

    private ChromeTabbedActivity mActivity;
    private UrlBar mUrlBar;
    private LocationBarCoordinator mLocationBarCoordinator;
    private LocationBarMediator mLocationBarMediator;
    private String mSearchUrl;
    private ActivityKeyboardVisibilityDelegate mKeyboardDelegate;
    private OmniboxTestUtils mOmnibox;

    @Before
    public void setUp() throws InterruptedException {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);
                    LocaleManager.getInstance().setDelegateForTest(mLocaleManagerDelegate);
                    doReturn(new StatusIconResource(null))
                            .when(mSearchEngineUtils)
                            .getSearchEngineLogo(anyInt());
                });
    }

    private void startActivityNormally() {
        mActivityTestRule.startMainActivityOnBlankPage();
        mActivity = mActivityTestRule.getActivity();
        doPostActivitySetup(mActivity);
    }

    private void startActivityWithDeferredNativeInitialization() {
        CommandLine.getInstance().appendSwitch(ChromeSwitches.DISABLE_NATIVE_INITIALIZATION);
        Intent intent = new Intent("about:blank");
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        mActivityTestRule.prepareUrlIntent(intent, "about:blank");
        mActivityTestRule.launchActivity(intent);
        mActivity = mActivityTestRule.getActivity();
        if (!mActivity.isInitialLayoutInflationComplete()) {
            AtomicBoolean isInflated = new AtomicBoolean();
            mActivity
                    .getLifecycleDispatcher()
                    .register(
                            new InflationObserver() {
                                @Override
                                public void onPreInflationStartup() {}

                                @Override
                                public void onPostInflationStartup() {
                                    isInflated.set(true);
                                }
                            });
            CriteriaHelper.pollUiThread(isInflated::get);
        }
        doPostActivitySetup(mActivity);
    }

    private void triggerAndWaitForDeferredNativeInitialization() {
        CommandLine.getInstance().removeSwitch(ChromeSwitches.DISABLE_NATIVE_INITIALIZATION);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mActivityTestRule.getActivity().startDelayedNativeInitializationForTests();
                });
        mActivityTestRule.waitForActivityNativeInitializationComplete();
    }

    private void doPostActivitySetup(ChromeActivity activity) {
        mOmnibox = new OmniboxTestUtils(activity);
        mUrlBar = activity.findViewById(R.id.url_bar);
        mLocationBarCoordinator =
                ((LocationBarCoordinator)
                        activity.getToolbarManager().getToolbarLayoutForTesting().getLocationBar());
        mLocationBarMediator = mLocationBarCoordinator.getMediatorForTesting();
        mSearchUrl = mActivityTestRule.getEmbeddedTestServerRule().getServer().getURL("/search");
        mLocationBarCoordinator.setVoiceRecognitionHandlerForTesting(mVoiceRecognitionHandler);
        mLocationBarCoordinator.setLensControllerForTesting(mLensController);
        mKeyboardDelegate = mActivity.getWindowAndroid().getKeyboardDelegate();
    }

    private void setupSearchEngineLogo(String url) {
        boolean isGoogle = url.equals(GOOGLE_URL);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    // Do not show a logo image on NTP, unless the default engine is Google, to
                    // avoid occasional timeout in loading it.
                    doReturn(isGoogle).when(mTemplateUrlService).doesDefaultSearchEngineHaveLogo();
                    doReturn(isGoogle).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
                    doReturn(isGoogle ? mGoogleSearchEngine : mNonGoogleSearchEngine)
                            .when(mTemplateUrlService)
                            .getDefaultSearchEngineTemplateUrl();

                    StatusIconResource logo =
                            new StatusIconResource(
                                    isGoogle
                                            ? R.drawable.ic_logo_googleg_20dp
                                            : R.drawable.ic_search,
                                    0);

                    doReturn(logo).when(mSearchEngineUtils).getSearchEngineLogo(anyInt());
                });
    }

    private void assertTheLastVisibleButtonInSearchBoxById(int id) {
        LinearLayout urlActionContainer =
                mActivityTestRule.getActivity().findViewById(R.id.url_action_container);

        for (int i = urlActionContainer.getChildCount() - 1; i >= 0; i--) {
            if (urlActionContainer.getChildAt(i).getVisibility() != View.VISIBLE) {
                continue;
            }
            Assert.assertEquals(urlActionContainer.getChildAt(i).getId(), id);
            break;
        }
    }

    private void updateLocationBar() {
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    LocationBarMediator mediator = mLocationBarCoordinator.getMediatorForTesting();
                    mediator.onIncognitoStateChanged();
                    mediator.onPrimaryColorChanged();
                    mediator.onSecurityStateChanged();
                    mediator.onTemplateURLServiceChanged();
                    mediator.onUrlChanged();
                });
    }

    @Test
    @MediumTest
    public void testSetSearchQueryFocusesUrlBar() {
        startActivityNormally();
        final String query = "testing query";

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarMediator.setSearchQuery(query);
                    Assert.assertEquals(query, mUrlBar.getTextWithoutAutocomplete());
                    Assert.assertTrue(mLocationBarMediator.isUrlBarFocused());
                });

        CriteriaHelper.pollUiThread(
                () -> mKeyboardDelegate.isKeyboardShowing(mUrlBar.getContext(), mUrlBar));
    }

    @Test
    @MediumTest
    @DisabledTest(message = "crbug.com/1470145")
    public void testSetSearchQueryFocusesUrlBar_preNative() {
        startActivityWithDeferredNativeInitialization();
        final String query = "testing query";

        ThreadUtils.runOnUiThreadBlocking(() -> mLocationBarMediator.setSearchQuery(query));

        triggerAndWaitForDeferredNativeInitialization();
        CriteriaHelper.pollUiThread(
                () -> {
                    Criteria.checkThat(mUrlBar.getTextWithoutAutocomplete(), Matchers.is(query));
                    Criteria.checkThat(mLocationBarMediator.isUrlBarFocused(), Matchers.is(true));
                });
    }

    @Test
    @MediumTest
    public void testPerformSearchQuery() {
        startActivityNormally();
        doReturn(mSearchUrl)
                .when(mTemplateUrlService)
                .getUrlForSearchQuery(TEST_QUERY, TEST_PARAMS);

        ThreadUtils.runOnUiThreadBlocking(
                () -> mLocationBarMediator.performSearchQuery(TEST_QUERY, TEST_PARAMS));

        ChromeTabUtils.waitForTabPageLoaded(
                mActivityTestRule.getActivity().getActivityTab(), mSearchUrl);
    }

    @Test
    @MediumTest
    public void testPerformSearchQuery_emptyUrl() {
        startActivityNormally();
        doReturn("").when(mTemplateUrlService).getUrlForSearchQuery(TEST_QUERY, TEST_PARAMS);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarMediator.performSearchQuery(TEST_QUERY, TEST_PARAMS);
                    Assert.assertEquals(TEST_QUERY, mUrlBar.getTextWithoutAutocomplete());
                });
    }

    @Test
    @MediumTest
    public void testOnConfigurationChanged() {
        startActivityNormally();
        // We expect the UrlBar to be focused iff a Hardware keyboard handler does not automatically
        // call up Software keyboard (IME).
        boolean wantUrlBarFocus = !KeyboardUtils.shouldShowImeWithHardwareKeyboard(mActivity);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarMediator.showUrlBarCursorWithoutFocusAnimations();
                    // If IME is configured to show up with hardware keys, url bar should not
                    // receive focus.
                    Assert.assertEquals(wantUrlBarFocus, mLocationBarMediator.isUrlBarFocused());
                });

        Configuration configuration = mActivity.getSavedConfigurationForTesting();
        configuration.keyboard = Configuration.KEYBOARD_12KEY;

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarMediator.onConfigurationChanged(configuration);
                    Assert.assertFalse(mLocationBarMediator.isUrlBarFocused());
                });
    }

    @Test
    @MediumTest
    public void testPostDestroyFocusLogic() {
        startActivityNormally();
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mActivity.finish();
                });

        CriteriaHelper.pollUiThread(
                () -> mActivity.getLifecycle().getCurrentState().equals(Lifecycle.State.DESTROYED));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarMediator.setUrlFocusChangeInProgress(false);
                    mLocationBarMediator.finishUrlFocusChange(true, true);
                });
    }

    @Test
    @MediumTest
    public void testEditingText() {
        startActivityNormally();
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        mActivityTestRule.loadUrl(url);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    Assert.assertTrue(mUrlBar.getText().toString().startsWith(HOSTNAME));
                    mUrlBar.requestFocus();
                    Assert.assertEquals("", mUrlBar.getText().toString());
                    mLocationBarCoordinator.setOmniboxEditingText(url);
                    Assert.assertEquals(url, mUrlBar.getText().toString());
                    Assert.assertEquals(url.length(), mUrlBar.getSelectionStart());
                    Assert.assertEquals(url.length(), mUrlBar.getSelectionEnd());
                });
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_buttonVisibilityPhone() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        mActivityTestRule.loadUrl(url);

        onView(withId(R.id.url_action_container))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });

        ViewUtils.waitForVisibleView(allOf(withId(R.id.url_action_container)));
        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarCoordinator.setOmniboxEditingText(url);
                });

        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                });

        ViewUtils.waitForViewCheckingState(withId(R.id.url_action_container), ViewUtils.VIEW_GONE);
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_cameraAssistedSearchLenButtonVisibilityPhone_lensDisabled() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        doReturn(false).when(mLensController).isLensEnabled(any());
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        mActivityTestRule.loadUrl(url);

        onView(withId(R.id.url_action_container)).check(matches(not(isDisplayed())));
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        onView(withId(R.id.delete_button)).check(matches(not(isDisplayed())));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });

        ViewUtils.waitForVisibleView(withId(R.id.url_action_container));
        onView(withId(R.id.lens_camera_button)).check((matches(not(isDisplayed()))));
        onView(withId(R.id.delete_button)).check(matches(not(isDisplayed())));
        assertTheLastVisibleButtonInSearchBoxById(R.id.mic_button);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarCoordinator.setOmniboxEditingText(url);
                });

        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        onView(withId(R.id.delete_button)).check(matches(isDisplayed()));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                });

        ViewUtils.waitForViewCheckingState(withId(R.id.url_action_container), ViewUtils.VIEW_GONE);
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_cameraAssistedSearchLenButtonVisibilityPhone_lensEnabled() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        doReturn(true).when(mLensController).isLensEnabled(any());
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        mActivityTestRule.loadUrl(url);

        onView(withId(R.id.url_action_container)).check(matches(not(isDisplayed())));
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        onView(withId(R.id.delete_button)).check(matches(not(isDisplayed())));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });

        ViewUtils.waitForVisibleView(withId(R.id.url_action_container));
        onView(withId(R.id.lens_camera_button)).check((matches(isDisplayed())));
        onView(withId(R.id.delete_button)).check(matches(not(isDisplayed())));
        assertTheLastVisibleButtonInSearchBoxById(R.id.lens_camera_button);

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarCoordinator.setOmniboxEditingText(url);
                });

        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        onView(withId(R.id.delete_button)).check(matches(isDisplayed()));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                });

        ViewUtils.waitForViewCheckingState(withId(R.id.url_action_container), ViewUtils.VIEW_GONE);
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_lenButtonVisibilityOnNtpPhone_updatedOnceWhenNtpScrolled() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();

        mActivityTestRule.loadUrl(UrlConstants.NTP_URL);

        ViewUtils.waitForVisibleView(withId(R.id.voice_search_button));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    Mockito.reset(mVoiceRecognitionHandler);
                    doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();

                    // Updating the fraction once should query voice search visibility.
                    mLocationBarMediator.setUrlFocusChangeFraction(.5f, .5f);
                    Mockito.verify(mVoiceRecognitionHandler).isVoiceSearchEnabled();

                    // Further updates to the fraction shouldn't trigger a button visibility update.
                    mLocationBarMediator.setUrlFocusChangeFraction(.6f, .6f);
                    Mockito.verify(mVoiceRecognitionHandler, Mockito.times(1))
                            .isVoiceSearchEnabled();
                });
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_lenButtonVisibilityOnLocationBarOnIncognitoStateChange() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        doReturn(false).when(mLensController).isLensEnabled(any());
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        // Test when incognito is true.
        mActivityTestRule.loadUrlInNewTab(
                url,
                /** incognito = */
                true);
        updateLocationBar();
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });
        ViewUtils.waitForViewCheckingState(withId(R.id.lens_camera_button), ViewUtils.VIEW_GONE);
        ViewUtils.waitForVisibleView(withId(R.id.mic_button));
        assertTheLastVisibleButtonInSearchBoxById(R.id.mic_button);

        // Test when incognito is false.
        doReturn(true).when(mLensController).isLensEnabled(any());
        mActivityTestRule.loadUrlInNewTab(
                url,
                /** incognito = */
                false);
        updateLocationBar();
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });
        ViewUtils.waitForVisibleView(withId(R.id.lens_camera_button));
        assertTheLastVisibleButtonInSearchBoxById(R.id.lens_camera_button);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                });
    }

    @Test
    @MediumTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_lenButtonVisibilityOnLocationBarOnDefaultSearchEngineChange() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        doReturn(false).when(mLensController).isLensEnabled(any());
        doReturn(false).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        // Test when search engine is not Google.
        mActivityTestRule.loadUrlInNewTab(
                url,
                /** incognito = */
                false);
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });
        ViewUtils.waitForViewCheckingState(withId(R.id.lens_camera_button), ViewUtils.VIEW_GONE);
        ViewUtils.waitForVisibleView(withId(R.id.mic_button));
        assertTheLastVisibleButtonInSearchBoxById(R.id.mic_button);

        // Test when search engine is Google.
        doReturn(true).when(mLensController).isLensEnabled(any());
        doReturn(true).when(mTemplateUrlService).isDefaultSearchEngineGoogle();
        mActivityTestRule.loadUrlInNewTab(
                url,
                /** incognito = */
                false);
        updateLocationBar();
        onView(withId(R.id.lens_camera_button)).check(matches(not(isDisplayed())));
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });
        ViewUtils.waitForVisibleView(withId(R.id.lens_camera_button));
        assertTheLastVisibleButtonInSearchBoxById(R.id.lens_camera_button);
        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                });
    }

    @Test
    @MediumTest
    @CommandLineFlags.Add({
        "disable-features="
                + ChromeFeatureList.ADAPTIVE_BUTTON_IN_TOP_TOOLBAR_CUSTOMIZATION_V2
    })
    @Restriction(UiRestriction.RESTRICTION_TYPE_TABLET)
    public void testFocusLogic_buttonVisibilityTablet() {
        startActivityNormally();
        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
        String url =
                mActivityTestRule
                        .getEmbeddedTestServerRule()
                        .getServer()
                        .getURLWithHostName(HOSTNAME, "/");
        mActivityTestRule.loadUrl(url);

        onView(withId(R.id.url_action_container))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.bookmark_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
        onView(withId(R.id.save_offline_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.requestFocus();
                });

        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mLocationBarCoordinator.setOmniboxEditingText(url);
                });

        onView(withId(R.id.mic_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.delete_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)));

        ThreadUtils.runOnUiThreadBlocking(
                () -> {
                    mUrlBar.clearFocus();
                    mLocationBarCoordinator.setShouldShowButtonsWhenUnfocusedForTablet(false);
                });

        onView(withId(R.id.bookmark_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
        onView(withId(R.id.save_offline_button))
                .check(matches(withEffectiveVisibility(ViewMatchers.Visibility.GONE)));
    }

    @Test
    @MediumTest
    public void testFocusLogic_keyboardVisibility() {
        startActivityNormally();
        assertFalse(mKeyboardDelegate.isKeyboardShowing(mUrlBar.getContext(), mUrlBar));

        mOmnibox.requestFocus();
        mOmnibox.checkFocus(true);
        mOmnibox.clearFocus();
        mOmnibox.checkFocus(false);
    }

    /** Test that back press should make the omnibox unfocused. */
    @Test
    @MediumTest
    @DisableFeatures(ChromeFeatureList.BACK_GESTURE_REFACTOR)
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_backPress() {
        startActivityNormally();

        mOmnibox.requestFocus();
        mOmnibox.checkFocus(true);
        ThreadUtils.runOnUiThreadBlocking(() -> mLocationBarMediator.backKeyPressed());
        mOmnibox.checkFocus(false);
    }

    /** Same with {@link #testFocusLogic_backPress()}, but with predictive back gesture enabled. */
    @Test
    @MediumTest
    @EnableFeatures(ChromeFeatureList.BACK_GESTURE_REFACTOR)
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testFocusLogic_backPress_Refactored() {
        startActivityNormally();

        mOmnibox.requestFocus();
        mOmnibox.checkFocus(true);
        Assert.assertTrue(mLocationBarMediator.getHandleBackPressChangedSupplier().get());
        ThreadUtils.runOnUiThreadBlocking(
                () -> mActivity.getOnBackPressedDispatcher().onBackPressed());
        Assert.assertFalse(mLocationBarMediator.getHandleBackPressChangedSupplier().get());
        mOmnibox.checkFocus(false);
    }

    @Test
    @SmallTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testOmniboxSearchEngineLogo_unfocusedOnSRP() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(not(isDisplayed())));
    }

    @Test
    @SmallTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testOmniboxSearchEngineLogo_unfocusedOnSRP_nonGoogleSearchEngine() {
        setupSearchEngineLogo(NON_GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(not(isDisplayed())));
    }

    @Test
    @SmallTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testOmniboxSearchEngineLogo_unfocusedOnSRP_incognito() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrlInNewTab(UrlConstants.NTP_URL, /* incognito= */ true);
        onView(withId(R.id.location_bar_status_icon)).check(matches(not(isDisplayed())));
    }

    @Test
    @SmallTest
    public void testOmniboxSearchEngineLogo_focusedOnSRP() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
        mOmnibox.requestFocus();
        onView(withId(R.id.location_bar_status_icon)).check(matches(isDisplayed()));
    }

    @Test
    @SmallTest
    @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
    public void testOmniboxSearchEngineLogo_ntpToSite() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrl(UrlConstants.NTP_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(not(isDisplayed())));

        mActivityTestRule.loadUrl(UrlConstants.ABOUT_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(isDisplayed()));
    }

    @Test
    @SmallTest
    public void testOmniboxSearchEngineLogo_siteToSite() {
        setupSearchEngineLogo(GOOGLE_URL);
        startActivityNormally();

        mActivityTestRule.loadUrl(UrlConstants.GPU_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(isDisplayed()));

        mActivityTestRule.loadUrl(UrlConstants.VERSION_URL);
        onView(withId(R.id.location_bar_status_icon)).check(matches(isDisplayed()));
    }
}