// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.omnibox;
import android.annotation.SuppressLint;
import android.view.KeyEvent;
import android.widget.ImageView;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.MediumTest;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.params.SkipCommandLineParameterization;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.EnormousTest;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteController.OnSuggestionsReceivedListener;
import org.chromium.chrome.browser.profiles.ProfileManager;
import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
import org.chromium.chrome.browser.theme.ThemeColorProvider.ThemeColorObserver;
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.net.test.EmbeddedTestServer;
import org.chromium.net.test.ServerCertificate;
import java.util.List;
/**
* Tests of the Omnibox.
*
* <p>TODO(yolandyan): Replace the ParameterizedCommandLineFlags with new JUnit4 parameterized
* framework once it supports Test Rule Parameterization.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
@SuppressLint("SetTextI18n")
@Batch(Batch.PER_CLASS)
public class OmniboxTest {
@Rule
public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
private void clearUrlBar() {
final UrlBar urlBar = (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
Assert.assertNotNull(urlBar);
ThreadUtils.runOnUiThreadBlocking(
() -> {
urlBar.setText("");
});
}
private static final OnSuggestionsReceivedListener sEmptySuggestionListener =
(result, isFinal) -> {};
/**
* Sanity check of Omnibox. The problem in http://b/5021723 would cause this to fail (hang or
* crash).
*/
@Test
@EnormousTest
@Feature({"Omnibox"})
public void testSimpleUse() throws InterruptedException {
mActivityTestRule.startMainActivityOnBlankPage();
OmniboxTestUtils omnibox = new OmniboxTestUtils(mActivityTestRule.getActivity());
omnibox.requestFocus();
omnibox.typeText("aaaaaaa", false);
omnibox.checkSuggestionsShown();
ChromeTabUtils.waitForTabPageLoadStart(
mActivityTestRule.getActivity().getActivityTab(),
null,
() -> omnibox.sendKey(KeyEvent.KEYCODE_ENTER),
20L);
}
// Sanity check that no text is displayed in the omnibox when on the NTP page and that the hint
// text is correct.
@Test
@MediumTest
@Feature({"Omnibox"})
public void testDefaultText() {
mActivityTestRule.startMainActivityWithURL(UrlConstants.NTP_URL);
final UrlBar urlBar = (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
// Omnibox on NTP shows the hint text.
Assert.assertNotNull(urlBar);
Assert.assertEquals("Location bar has text.", "", urlBar.getText().toString());
Assert.assertEquals(
"Location bar has incorrect hint.",
mActivityTestRule
.getActivity()
.getResources()
.getString(R.string.omnibox_empty_hint),
urlBar.getHint().toString());
// Type something in the omnibox.
// Note that the TextView does not provide a way to test if the hint is showing, the API
// documentation simply says it shows when the text is empty.
ThreadUtils.runOnUiThreadBlocking(
() -> {
urlBar.requestFocus();
urlBar.setText("G");
});
Assert.assertEquals("Location bar should have text.", "G", urlBar.getText().toString());
}
@Test
@MediumTest
@Feature({"Omnibox"})
public void testAltEnterOpensSearchResultInNewTab() {
mActivityTestRule.startMainActivityOnBlankPage();
int tabCount = ChromeTabUtils.getNumOpenTabs(mActivityTestRule.getActivity());
Tab currentTab = mActivityTestRule.getActivity().getActivityTab();
OmniboxTestUtils omnibox = new OmniboxTestUtils(mActivityTestRule.getActivity());
omnibox.requestFocus();
omnibox.typeText("hello", false);
omnibox.checkSuggestionsShown();
// Dispatch ALT + ENTER key event.
omnibox.sendKey(KeyEvent.KEYCODE_ENTER, KeyEvent.META_ALT_ON);
Tab resultTab = mActivityTestRule.getActivity().getActivityTab();
Assert.assertNotEquals(
"The result should be loaded in a new tab that is brought to the foreground.",
currentTab,
resultTab);
Assert.assertEquals(
"Tab count should reflect new tab.",
tabCount + 1,
ChromeTabUtils.getNumOpenTabs(mActivityTestRule.getActivity()));
}
/**
* The following test is a basic way to assess how much instant slows down typing in the
* omnibox. It is meant to be run manually for investigation purposes. When instant was enabled
* for all suggestions (including searched), I would get a 40% increase in the average time on
* this test. With instant off, it was almost identical. Marking the test disabled so it is not
* picked up by our test runner, as it is supposed to be run manually.
*/
public void manualTestTypingPerformance() throws InterruptedException {
final String text = "searching for pizza";
// Type 10 times something on the omnibox and get the average time with and without instant.
long instantAverage = 0;
long noInstantAverage = 0;
for (int i = 0; i < 2; ++i) {
boolean instantOn = (i == 1);
mActivityTestRule.setNetworkPredictionEnabled(instantOn);
for (int j = 0; j < 10; ++j) {
long before = System.currentTimeMillis();
mActivityTestRule.typeInOmnibox(text, true);
if (instantOn) {
instantAverage += System.currentTimeMillis() - before;
} else {
noInstantAverage += System.currentTimeMillis() - before;
}
clearUrlBar();
InstrumentationRegistry.getInstrumentation().waitForIdleSync();
}
}
instantAverage /= 10;
noInstantAverage /= 10;
System.err.println("******************************************************************");
System.err.println("**** Instant average=" + instantAverage);
System.err.println("**** No instant average=" + noInstantAverage);
System.err.println("******************************************************************");
}
/** Test to verify that the security icon is present when visiting http:// URLs. */
@Test
@MediumTest
@SkipCommandLineParameterization
public void testSecurityIconOnHTTP() {
mActivityTestRule.startMainActivityOnBlankPage();
EmbeddedTestServer testServer =
EmbeddedTestServer.createAndStartServer(
ApplicationProvider.getApplicationContext());
final String testUrl = testServer.getURL("/chrome/test/data/android/omnibox/one.html");
mActivityTestRule.loadUrl(testUrl);
final LocationBarLayout locationBar =
(LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
StatusCoordinator statusCoordinator = locationBar.getStatusCoordinatorForTesting();
boolean securityIcon = statusCoordinator.isSecurityViewShown();
Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
Assert.assertEquals(
R.drawable.omnibox_info, statusCoordinator.getSecurityIconResourceIdForTesting());
}
/** Test to verify that the security icon is present when visiting https:// URLs. */
@Test
@MediumTest
@SkipCommandLineParameterization
public void testSecurityIconOnHTTPS() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage();
EmbeddedTestServer httpsTestServer =
EmbeddedTestServer.createAndStartHTTPSServer(
ApplicationProvider.getApplicationContext(), ServerCertificate.CERT_OK);
CallbackHelper onSSLStateUpdatedCallbackHelper = new CallbackHelper();
TabObserver observer =
new EmptyTabObserver() {
@Override
public void onSSLStateUpdated(Tab tab) {
onSSLStateUpdatedCallbackHelper.notifyCalled();
}
};
ThreadUtils.runOnUiThreadBlocking(
() -> mActivityTestRule.getActivity().getActivityTab().addObserver(observer));
final String testHttpsUrl =
httpsTestServer.getURL("/chrome/test/data/android/omnibox/one.html");
ImageView securityView =
(ImageView)
mActivityTestRule.getActivity().findViewById(R.id.location_bar_status_icon);
mActivityTestRule.loadUrl(testHttpsUrl);
onSSLStateUpdatedCallbackHelper.waitForCallback(0);
final LocationBarLayout locationBar =
(LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
StatusCoordinator statusCoordinator = locationBar.getStatusCoordinatorForTesting();
boolean securityIcon = statusCoordinator.isSecurityViewShown();
Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
Assert.assertEquals(
"location_bar_status_icon with wrong resource-id",
R.id.location_bar_status_icon,
securityView.getId());
Assert.assertTrue(securityView.isShown());
Assert.assertEquals(
ChromeFeatureList.isEnabled(
ChromeFeatureList.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS)
? R.drawable.omnibox_https_valid_refresh
: R.drawable.omnibox_https_valid,
statusCoordinator.getSecurityIconResourceIdForTesting());
}
/**
* Test to verify that the security icon is present after
*
* <ol>
* <li>visiting a https:// URL
* <li>focusing the url bar
* <li>pressing back
* </ol>
*
* All while the search engine is not the default one. See https://crbug.com/1173447
*/
@Test
@MediumTest
@SkipCommandLineParameterization
public void testSecurityIconOnHTTPSFocusAndBack() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage();
setNonDefaultSearchEngine();
EmbeddedTestServer httpsTestServer =
EmbeddedTestServer.createAndStartHTTPSServer(
ApplicationProvider.getApplicationContext(), ServerCertificate.CERT_OK);
CallbackHelper onSSLStateUpdatedCallbackHelper = new CallbackHelper();
TabObserver observer =
new EmptyTabObserver() {
@Override
public void onSSLStateUpdated(Tab tab) {
onSSLStateUpdatedCallbackHelper.notifyCalled();
}
};
ThreadUtils.runOnUiThreadBlocking(
() -> mActivityTestRule.getActivity().getActivityTab().addObserver(observer));
try {
final String testHttpsUrl =
httpsTestServer.getURL("/chrome/test/data/android/omnibox/one.html");
ImageView securityView =
(ImageView)
mActivityTestRule
.getActivity()
.findViewById(R.id.location_bar_status_icon);
mActivityTestRule.loadUrl(testHttpsUrl);
onSSLStateUpdatedCallbackHelper.waitForCallback(0);
final LocationBarLayout locationBar =
(LocationBarLayout)
mActivityTestRule.getActivity().findViewById(R.id.location_bar);
final StatusCoordinator statusCoordinator =
locationBar.getStatusCoordinatorForTesting();
final int firstIcon = statusCoordinator.getSecurityIconResourceIdForTesting();
UrlBar urlBar = (UrlBar) mActivityTestRule.getActivity().findViewById(R.id.url_bar);
ThreadUtils.runOnUiThreadBlocking(() -> urlBar.requestFocus());
CriteriaHelper.pollUiThread(
() -> statusCoordinator.getSecurityIconResourceIdForTesting() != firstIcon);
final int secondIcon = statusCoordinator.getSecurityIconResourceIdForTesting();
ThreadUtils.runOnUiThreadBlocking(() -> urlBar.clearFocus());
CriteriaHelper.pollUiThread(
() -> statusCoordinator.getSecurityIconResourceIdForTesting() != secondIcon);
boolean securityIcon = statusCoordinator.isSecurityViewShown();
Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
Assert.assertEquals(
"location_bar_status_icon with wrong resource-id",
R.id.location_bar_status_icon,
securityView.getId());
Assert.assertTrue(securityView.isShown());
Assert.assertEquals(
ChromeFeatureList.isEnabled(
ChromeFeatureList
.OMNIBOX_UPDATED_CONNECTION_SECURITY_INDICATORS)
? R.drawable.omnibox_https_valid_refresh
: R.drawable.omnibox_https_valid,
statusCoordinator.getSecurityIconResourceIdForTesting());
} finally {
restoreDefaultSearchEngine();
}
}
private void setNonDefaultSearchEngine() {
TemplateUrlService templateUrlService =
ThreadUtils.runOnUiThreadBlocking(
() ->
TemplateUrlServiceFactory.getForProfile(
ProfileManager.getLastUsedRegularProfile()));
ThreadUtils.runOnUiThreadBlocking(() -> templateUrlService.load());
CriteriaHelper.pollUiThread(() -> templateUrlService.isLoaded());
ThreadUtils.runOnUiThreadBlocking(
() -> {
List<TemplateUrl> searchEngines = templateUrlService.getTemplateUrls();
TemplateUrl defaultEngine =
templateUrlService.getDefaultSearchEngineTemplateUrl();
TemplateUrl notDefault = null;
for (TemplateUrl searchEngine : searchEngines) {
if (!searchEngine.equals(defaultEngine)) {
notDefault = searchEngine;
break;
}
}
Assert.assertNotNull(notDefault);
templateUrlService.setSearchEngine(notDefault.getKeyword());
});
}
private void restoreDefaultSearchEngine() {
ThreadUtils.runOnUiThreadBlocking(
() -> {
TemplateUrlService service =
TemplateUrlServiceFactory.getForProfile(
ProfileManager.getLastUsedRegularProfile());
TemplateUrl defaultEngine = service.getDefaultSearchEngineTemplateUrl();
service.setSearchEngine(defaultEngine.getKeyword());
});
}
/** Test whether the color of the Location bar is correct for HTTPS scheme. */
@Test
@SmallTest
@SkipCommandLineParameterization
public void testHttpsLocationBarColor() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage();
EmbeddedTestServer testServer =
EmbeddedTestServer.createAndStartHTTPSServer(
InstrumentationRegistry.getInstrumentation().getContext(),
ServerCertificate.CERT_OK);
CallbackHelper didThemeColorChangedCallbackHelper = new CallbackHelper();
CallbackHelper onSSLStateUpdatedCallbackHelper = new CallbackHelper();
ThreadUtils.runOnUiThreadBlocking(
() -> {
new TabModelSelectorTabObserver(
mActivityTestRule.getActivity().getTabModelSelector()) {
@Override
public void onSSLStateUpdated(Tab tab) {
onSSLStateUpdatedCallbackHelper.notifyCalled();
}
};
mActivityTestRule
.getActivity()
.getRootUiCoordinatorForTesting()
.getTopUiThemeColorProvider()
.addThemeColorObserver(
new ThemeColorObserver() {
@Override
public void onThemeColorChanged(
int color, boolean shouldAnimate) {
didThemeColorChangedCallbackHelper.notifyCalled();
}
});
});
final String testHttpsUrl =
testServer.getURL("/chrome/test/data/android/theme_color_test.html");
mActivityTestRule.loadUrl(testHttpsUrl);
// Tablets don't have website theme colors.
if (!mActivityTestRule.getActivity().isTablet()) {
didThemeColorChangedCallbackHelper.waitForCallback(0);
}
onSSLStateUpdatedCallbackHelper.waitForCallback(0);
LocationBarLayout locationBarLayout =
(LocationBarLayout) mActivityTestRule.getActivity().findViewById(R.id.location_bar);
ImageView securityView =
(ImageView)
mActivityTestRule.getActivity().findViewById(R.id.location_bar_status_icon);
boolean securityIcon =
locationBarLayout.getStatusCoordinatorForTesting().isSecurityViewShown();
Assert.assertTrue("Omnibox should have a Security icon", securityIcon);
Assert.assertEquals(
"location_bar_status_icon with wrong resource-id",
R.id.location_bar_status_icon,
securityView.getId());
if (mActivityTestRule.getActivity().isTablet()) {
Assert.assertTrue(
mActivityTestRule
.getActivity()
.getToolbarManager()
.getLocationBarModelForTesting()
.shouldEmphasizeHttpsScheme());
} else {
Assert.assertFalse(
mActivityTestRule
.getActivity()
.getToolbarManager()
.getLocationBarModelForTesting()
.shouldEmphasizeHttpsScheme());
}
}
}