0

[GURL] Migrate PseudoTab.

This includes a one-time migration for clients that have string URLs persisted as we convert them to serialized GURLs. Bots shouldn't see this (no persistence) but should cause a temporary blip (and then slow long-tail) reports of early GURL loads.

Bug: 783819

Change-Id: I4bade009cff4d698ac3441d1c416fe4b7d251349
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2945815
Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: Wei-Yin Chen (陳威尹) <wychen@chromium.org>
Commit-Queue: Yaron Friedman <yfriedman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#893008}
This commit is contained in:
Yaron Friedman
2021-06-16 14:45:29 +00:00
committed by Chromium LUCI CQ
parent 83e92d5c4f
commit b106742d25
23 changed files with 151 additions and 102 deletions

@ -1460,6 +1460,7 @@ android_library("chrome_test_java") {
"//ui/base/mojom:mojom_java",
"//url:gurl_java",
"//url:gurl_javatests",
"//url:gurl_junit_test_support",
"//url:origin_java",
"//url/mojom:url_mojom_gurl_java",
]

@ -1092,7 +1092,8 @@ public class InstantStartTest {
}
private void startAndWaitNativeInitialization() {
Assert.assertFalse(LibraryLoader.getInstance().isInitialized());
Assert.assertFalse(
NativeLibraryLoadedStatus.getProviderForTesting().areMainDexNativeMethodsReady());
CommandLine.getInstance().removeSwitch(ChromeSwitches.DISABLE_NATIVE_INITIALIZATION);
TestThreadUtils.runOnUiThreadBlocking(

@ -62,6 +62,7 @@ import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVis
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.content_public.browser.test.util.TestTouchUtils;
import org.chromium.url.GURL;
import org.chromium.url.JUnitTestGURLs;
import java.io.File;
import java.io.FileOutputStream;
@ -360,14 +361,18 @@ public class StartSurfaceTestUtils {
*/
public static List<SiteSuggestion> createFakeSiteSuggestions() {
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
siteSuggestions.add(new SiteSuggestion("0 EXPLORE_SITES", new GURL("https://www.bar.com"),
"", TileTitleSource.UNKNOWN, TileSource.EXPLORE, TileSectionType.PERSONALIZED,
new Date()));
siteSuggestions.add(new SiteSuggestion("0 EXPLORE_SITES",
// Use pre-serialized GURL to avoid loading native.
JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL), "", TileTitleSource.UNKNOWN,
TileSource.EXPLORE, TileSectionType.PERSONALIZED, new Date()));
String urlTemplate = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1_NUMERAL).serialize();
for (int i = 0; i < 7; i++) {
siteSuggestions.add(new SiteSuggestion(String.valueOf(i),
new GURL("https://www." + i + ".com"), "", TileTitleSource.TITLE_TAG,
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
// Use pre-serialized GURL to avoid loading native.
GURL.deserialize(urlTemplate.replace("www.1.com", "www." + i + ".com")), "",
TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
new Date()));
}
return siteSuggestions;

@ -133,8 +133,7 @@ public class SingleTabSwitcherMediator implements TabSwitcher.Controller {
private void updateFavicon(Tab tab) {
assert mTabListFaviconProvider.isInitialized();
// TODO(crbug/783819): convert TabListFaviconProvider to GURL
mTabListFaviconProvider.getFaviconForUrlAsync(tab.getUrl().getSpec(), false,
mTabListFaviconProvider.getFaviconForUrlAsync(tab.getUrl(), false,
(Drawable favicon) -> { mPropertyModel.set(FAVICON, favicon); });
}
@ -253,7 +252,7 @@ public class SingleTabSwitcherMediator implements TabSwitcher.Controller {
private void updateSelectedTab(Tab tab) {
mPropertyModel.set(TITLE, tab.getTitle());
mTabListFaviconProvider.getFaviconForUrlAsync(tab.getUrl().getSpec(), false,
mTabListFaviconProvider.getFaviconForUrlAsync(tab.getUrl(), false,
(Drawable favicon) -> { mPropertyModel.set(FAVICON, favicon); });
}

@ -26,6 +26,7 @@ import org.chromium.chrome.browser.tabmodel.TabbedModeTabPersistencePolicy;
import org.chromium.chrome.browser.tabpersistence.TabStateDirectory;
import org.chromium.chrome.browser.tasks.tab_management.TabUiFeatureUtilities;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.url.GURL;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
@ -179,10 +180,9 @@ public class PseudoTab {
* Get the URL of the {@link PseudoTab}.
* @return The URL
*/
public String getUrl() {
// TODO(crbug/783819): Return the GURL directly.
public GURL getUrl() {
if (mTab != null && mTab.get() != null && mTab.get().isInitialized()) {
return mTab.get().getUrl() != null ? mTab.get().getUrl().getSpec() : null;
return mTab.get().getUrl();
}
assert mTabId != null;
return TabAttributeCache.getUrl(mTabId);

@ -65,8 +65,7 @@ public class TabAttributeCache {
@Override
public void onUrlUpdated(Tab tab) {
if (tab.isIncognito()) return;
String url = tab.getUrl().getSpec();
cacheUrl(tab.getId(), url);
cacheUrl(tab.getId(), tab.getUrl());
}
@Override
@ -107,6 +106,7 @@ public class TabAttributeCache {
int id = tab.getId();
getSharedPreferences()
.edit()
.remove(getDeprecatedUrlKey(id))
.remove(getUrlKey(id))
.remove(getTitleKey(id))
.remove(getRootIdKey(id))
@ -126,7 +126,7 @@ public class TabAttributeCache {
mTabModelSelector.getTabModelFilterProvider().getTabModelFilter(false);
for (int i = 0; i < filter.getCount(); i++) {
Tab tab = filter.getTabAt(i);
cacheUrl(tab.getId(), tab.getUrl().getSpec());
cacheUrl(tab.getId(), tab.getUrl());
cacheTitle(tab.getId(), tab.getTitle());
cacheRootId(tab.getId(), CriticalPersistedTabData.from(tab).getRootId());
cacheTimestampMillis(
@ -168,6 +168,11 @@ public class TabAttributeCache {
}
private static String getUrlKey(int id) {
return id + "_gurl";
}
// Legacy from when URL was serialized as raw string.
private static String getDeprecatedUrlKey(int id) {
return id + "_url";
}
@ -176,13 +181,16 @@ public class TabAttributeCache {
* @param id The ID of the {@link PseudoTab}.
* @return The URL
*/
public static String getUrl(int id) {
return getSharedPreferences().getString(getUrlKey(id), "");
public static GURL getUrl(int id) {
String url = getSharedPreferences().getString(getUrlKey(id), "");
if (!url.isEmpty()) {
return GURL.deserialize(url);
}
return new GURL(getSharedPreferences().getString(getDeprecatedUrlKey(id), ""));
}
private static void cacheUrl(int id, String url) {
// TODO(crbug/783819): Use GURL directly.
getSharedPreferences().edit().putString(getUrlKey(id), url).apply();
private static void cacheUrl(int id, GURL url) {
getSharedPreferences().edit().putString(getUrlKey(id), url.serialize()).apply();
}
/**
@ -190,7 +198,7 @@ public class TabAttributeCache {
* @param id The ID of the {@link PseudoTab}.
* @param url The URL
*/
static void setUrlForTesting(int id, String url) {
static void setUrlForTesting(int id, GURL url) {
cacheUrl(id, url);
}

@ -28,6 +28,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tasks.pseudotab.PseudoTab;
import org.chromium.chrome.tab_ui.R;
import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.List;
@ -115,7 +116,7 @@ public class MultiThumbnailCardProvider implements TabListMediator.ThumbnailProv
for (int i = 0; i < 4; i++) {
if (mTabs.get(i) != null) {
final int index = i;
final String url = mTabs.get(i).getUrl();
final GURL url = mTabs.get(i).getUrl();
final boolean isIncognito = mTabs.get(i).isIncognito();
// getTabThumbnailWithCallback() might call the callback up to twice,
// so use |lastFavicon| to avoid fetching the favicon the second time.

@ -23,6 +23,7 @@ import org.chromium.chrome.browser.ui.native_page.NativePage;
import org.chromium.chrome.tab_ui.R;
import org.chromium.components.embedder_support.util.UrlUtilities;
import org.chromium.ui.base.ViewUtils;
import org.chromium.url.GURL;
import java.util.List;
@ -153,7 +154,7 @@ public class TabListFaviconProvider {
* @param faviconCallback The callback that requests for favicon.
*/
public void getFaviconForUrlAsync(
String url, boolean isIncognito, Callback<Drawable> faviconCallback) {
GURL url, boolean isIncognito, Callback<Drawable> faviconCallback) {
if (mFaviconHelper == null || UrlUtilities.isNTPUrl(url)) {
faviconCallback.onResult(getRoundedChromeDrawable(isIncognito));
} else {
@ -175,7 +176,7 @@ public class TabListFaviconProvider {
* @param icon The favicon that was received.
* @return The processed favicon.
*/
public Drawable getFaviconForUrlSync(String url, boolean isIncognito, Bitmap icon) {
public Drawable getFaviconForUrlSync(GURL url, boolean isIncognito, Bitmap icon) {
if (icon == null) {
boolean isNativeUrl = NativePage.isNativePageUrl(url, isIncognito);
return isNativeUrl ? getRoundedChromeDrawable(isIncognito)
@ -192,7 +193,7 @@ public class TabListFaviconProvider {
* @param faviconCallback The callback that requests for the composed favicon.
*/
public void getComposedFaviconImageAsync(
List<String> urls, boolean isIncognito, Callback<Drawable> faviconCallback) {
List<GURL> urls, boolean isIncognito, Callback<Drawable> faviconCallback) {
assert urls != null && urls.size() > 1 && urls.size() <= 4;
mFaviconHelper.getComposedFaviconImage(mProfile, urls, mFaviconSize, (image, iconUrl) -> {

@ -1614,11 +1614,11 @@ class TabListMediator {
}
// The order of the url list matches the multi-thumbnail.
List<String> urls = new ArrayList<>();
List<GURL> urls = new ArrayList<>();
urls.add(pseudoTab.getUrl());
for (int i = 0; urls.size() < 4 && i < relatedTabList.size(); i++) {
if (pseudoTab.getId() == relatedTabList.get(i).getId()) continue;
urls.add(relatedTabList.get(i).getUrl().getSpec());
urls.add(relatedTabList.get(i).getUrl());
}
// For tab group card in grid tab switcher, the favicon is the composed favicon.

@ -44,6 +44,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
import org.chromium.chrome.browser.tasks.tab_management.TabListFaviconProvider;
import org.chromium.chrome.browser.tasks.tab_management.TabSwitcher;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL;
import org.chromium.url.JUnitTestGURLs;
/** Tests for {@link SingleTabSwitcherMediator}. */
@ -52,10 +53,10 @@ import org.chromium.url.JUnitTestGURLs;
public class SingleTabSwitcherMediatorUnitTest {
private final int mTabId = 1;
private final String mTitle = "test";
private final String mUrlString = JUnitTestGURLs.URL_1;
private final GURL mUrl = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1);
private final int mTabId2 = 2;
private final String mTitle2 = "test2";
private final String mUrlString2 = JUnitTestGURLs.URL_2;
private final GURL mUrl2 = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
private SingleTabSwitcherMediator mMediator;
private PropertyModel mPropertyModel;
@ -99,10 +100,10 @@ public class SingleTabSwitcherMediatorUnitTest {
doReturn(0).when(mNormalTabModel).index();
doReturn(1).when(mNormalTabModel).getCount();
doReturn(false).when(mNormalTabModel).isIncognito();
doReturn(JUnitTestGURLs.getGURL(mUrlString)).when(mTab).getUrl();
doReturn(mUrl).when(mTab).getUrl();
doReturn(mTabId).when(mTab).getId();
doReturn(mTitle).when(mTab).getTitle();
doReturn(JUnitTestGURLs.getGURL(mUrlString2)).when(mTab2).getUrl();
doReturn(mUrl2).when(mTab2).getUrl();
doReturn(mTabId2).when(mTab2).getId();
doReturn(mTitle2).when(mTab2).getTitle();
doReturn(true).when(mIncognitoTabModel).isIncognito();
@ -130,7 +131,7 @@ public class SingleTabSwitcherMediatorUnitTest {
.addTabModelFilterObserver(mTabModelObserverCaptor.capture());
verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture());
verify(mTabListFaviconProvider)
.getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture());
.getFaviconForUrlAsync(eq(mUrl), eq(false), mFaviconCallbackCaptor.capture());
assertTrue(mMediator.overviewVisible());
verify(mOverviewModeObserver).startedShowing();
verify(mOverviewModeObserver).finishedShowing();
@ -160,7 +161,7 @@ public class SingleTabSwitcherMediatorUnitTest {
.addTabModelFilterObserver(mTabModelObserverCaptor.capture());
verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture());
verify(mTabListFaviconProvider)
.getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture());
.getFaviconForUrlAsync(eq(mUrl), eq(false), mFaviconCallbackCaptor.capture());
assertTrue(mMediator.overviewVisible());
verify(mOverviewModeObserver).startedShowing();
verify(mOverviewModeObserver).finishedShowing();
@ -199,7 +200,7 @@ public class SingleTabSwitcherMediatorUnitTest {
.addTabModelFilterObserver(mTabModelObserverCaptor.capture());
verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture());
verify(mTabListFaviconProvider)
.getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture());
.getFaviconForUrlAsync(eq(mUrl), eq(false), mFaviconCallbackCaptor.capture());
assertTrue(mMediator.overviewVisible());
verify(mOverviewModeObserver).startedShowing();
verify(mOverviewModeObserver).finishedShowing();
@ -228,7 +229,7 @@ public class SingleTabSwitcherMediatorUnitTest {
.addTabModelFilterObserver(mTabModelObserverCaptor.capture());
verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture());
verify(mTabListFaviconProvider)
.getFaviconForUrlAsync(eq(mUrlString), eq(false), mFaviconCallbackCaptor.capture());
.getFaviconForUrlAsync(eq(mUrl), eq(false), mFaviconCallbackCaptor.capture());
assertEquals(mPropertyModel.get(TITLE), mTitle);
mTabModelSelectorObserverCaptor.getValue().onTabModelSelected(

@ -32,6 +32,7 @@ import org.chromium.chrome.browser.tasks.tab_management.TabUiUnitTestUtils;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.chrome.test.util.browser.Features.DisableFeatures;
import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
import org.chromium.url.GURL;
import org.chromium.url.JUnitTestGURLs;
import java.util.ArrayList;
@ -250,11 +251,11 @@ public class PseudoTabUnitTest {
@Test
public void getUrl_real() {
String url = JUnitTestGURLs.EXAMPLE_URL;
doReturn(JUnitTestGURLs.getGURL(url)).when(mTab1).getUrl();
GURL url = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
doReturn(url).when(mTab1).getUrl();
PseudoTab tab = PseudoTab.fromTabId(TAB1_ID);
Assert.assertEquals("", tab.getUrl());
Assert.assertEquals(GURL.emptyGURL(), tab.getUrl());
PseudoTab realTab = PseudoTab.fromTab(mTab1);
Assert.assertNotEquals(tab, realTab);
@ -263,11 +264,11 @@ public class PseudoTabUnitTest {
@Test
public void getUrl_cache() {
String url = "url 1";
TabAttributeCache.setUrlForTesting(TAB1_ID, url);
String url = JUnitTestGURLs.URL_1;
TabAttributeCache.setUrlForTesting(TAB1_ID, JUnitTestGURLs.getGURL(url));
PseudoTab tab = PseudoTab.fromTabId(TAB1_ID);
Assert.assertEquals(url, tab.getUrl());
Assert.assertEquals(url, tab.getUrl().getSpec());
PseudoTab realTab = PseudoTab.fromTab(mTab1);
Assert.assertNotEquals(tab, realTab);
@ -466,7 +467,7 @@ public class PseudoTabUnitTest {
// Url was not set. Without the isInitialized() check,
// pseudoTab.getUrl() would crash here with
// UnsupportedOperationException
Assert.assertEquals("", pseudoTab.getUrl());
Assert.assertEquals("", pseudoTab.getUrl().getSpec());
}
@Test

@ -130,8 +130,8 @@ public class TabAttributeCacheUnitTest {
@Test
public void updateUrl() {
String url = JUnitTestGURLs.EXAMPLE_URL;
doReturn(JUnitTestGURLs.getGURL(url)).when(mTab1).getUrl();
GURL url = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
doReturn(url).when(mTab1).getUrl();
Assert.assertNotEquals(url, TabAttributeCache.getUrl(TAB1_ID));
@ -359,8 +359,8 @@ public class TabAttributeCacheUnitTest {
@Test
public void onTabStateInitialized() {
String url1 = JUnitTestGURLs.EXAMPLE_URL;
doReturn(JUnitTestGURLs.getGURL(url1)).when(mTab1).getUrl();
GURL url1 = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
doReturn(url1).when(mTab1).getUrl();
String title1 = "title 1";
doReturn(title1).when(mTab1).getTitle();
int rootId1 = 1337;
@ -368,8 +368,8 @@ public class TabAttributeCacheUnitTest {
long timestamp1 = 123456;
doReturn(timestamp1).when(mCriticalPersistedTabData1).getTimestampMillis();
String url2 = JUnitTestGURLs.URL_2;
doReturn(JUnitTestGURLs.getGURL(url2)).when(mTab2).getUrl();
GURL url2 = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
doReturn(url2).when(mTab2).getUrl();
String title2 = "title 2";
doReturn(title2).when(mTab2).getTitle();
int rootId2 = 42;

@ -36,6 +36,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tasks.tab_management.TabUiUnitTestUtils;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import org.chromium.url.GURL;
import java.util.ArrayList;
import java.util.Arrays;
@ -90,9 +91,9 @@ public class TabGroupUtilsUnitTest {
MockitoAnnotations.initMocks(this);
mTab1 = TabUiUnitTestUtils.prepareTab(TAB1_ID, TAB1_TITLE, "");
mTab2 = TabUiUnitTestUtils.prepareTab(TAB2_ID, TAB2_TITLE, "");
mTab3 = TabUiUnitTestUtils.prepareTab(TAB3_ID, TAB3_TITLE, "");
mTab1 = TabUiUnitTestUtils.prepareTab(TAB1_ID, TAB1_TITLE, GURL.emptyGURL());
mTab2 = TabUiUnitTestUtils.prepareTab(TAB2_ID, TAB2_TITLE, GURL.emptyGURL());
mTab3 = TabUiUnitTestUtils.prepareTab(TAB3_ID, TAB3_TITLE, GURL.emptyGURL());
doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider();
doReturn(mTabGroupModelFilter).when(mTabModelFilterProvider).getCurrentTabModelFilter();

@ -64,6 +64,7 @@ import org.chromium.chrome.test.util.browser.Features;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.ui.KeyboardVisibilityDelegate;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.url.GURL;
import org.chromium.url.JUnitTestGURLs;
import java.util.ArrayList;
@ -1072,7 +1073,7 @@ public class TabGridDialogMediatorUnitTest {
}
private TabImpl prepareTab(int id, String title) {
TabImpl tab = TabUiUnitTestUtils.prepareTab(id, title, "");
TabImpl tab = TabUiUnitTestUtils.prepareTab(id, title, GURL.emptyGURL());
doReturn(true).when(tab).isIncognito();
return tab;
}

@ -19,6 +19,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyObject;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
@ -177,9 +178,9 @@ public class TabListMediatorUnitTest {
private static final String NEW_TITLE = "New title";
private static final String CUSTOMIZED_DIALOG_TITLE1 = "Cool Tabs";
private static final String TAB_GROUP_TITLES_FILE_NAME = "tab_group_titles";
private static final String TAB1_URL = JUnitTestGURLs.URL_1;
private static final String TAB2_URL = JUnitTestGURLs.URL_2;
private static final String TAB3_URL = JUnitTestGURLs.URL_3;
private static final GURL TAB1_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_1);
private static final GURL TAB2_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_2);
private static final GURL TAB3_URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.URL_3);
private static final String NEW_URL = JUnitTestGURLs.EXAMPLE_URL;
private static final int TAB1_ID = 456;
private static final int TAB2_ID = 789;
@ -315,9 +316,9 @@ public class TabListMediatorUnitTest {
// Ensure native pointer is initialized
doReturn(1L).when(mOptimizationGuideBridgeJniMock).init();
mTab1Domain = JUnitTestGURLs.getGURL(TAB1_URL).getHost().replace("www.", "");
mTab2Domain = JUnitTestGURLs.getGURL(TAB2_URL).getHost().replace("www.", "");
mTab3Domain = JUnitTestGURLs.getGURL(TAB3_URL).getHost().replace("www.", "");
mTab1Domain = TAB1_URL.getHost().replace("www.", "");
mTab2Domain = TAB2_URL.getHost().replace("www.", "");
mTab3Domain = TAB3_URL.getHost().replace("www.", "");
mNewDomain = JUnitTestGURLs.getGURL(NEW_URL).getHost().replace("www.", "");
CachedFeatureFlags.setForTesting(ChromeFeatureList.START_SURFACE_ANDROID, false);
@ -356,10 +357,10 @@ public class TabListMediatorUnitTest {
doReturn(2).when(mTabModel).getCount();
doNothing()
.when(mTabListFaviconProvider)
.getFaviconForUrlAsync(anyString(), anyBoolean(), mCallbackCaptor.capture());
.getFaviconForUrlAsync(anyObject(), anyBoolean(), mCallbackCaptor.capture());
doReturn(mFaviconDrawable)
.when(mTabListFaviconProvider)
.getFaviconForUrlSync(anyString(), anyBoolean(), any(Bitmap.class));
.getFaviconForUrlSync(anyObject(), anyBoolean(), any(Bitmap.class));
doReturn(mTab1).when(mTabModelSelector).getTabById(TAB1_ID);
doReturn(mTab2).when(mTabModelSelector).getTabById(TAB2_ID);
doReturn(tabs1).when(mTabGroupModelFilter).getRelatedTabList(TAB1_ID);
@ -379,13 +380,13 @@ public class TabListMediatorUnitTest {
doReturn(mSpanSizeLookup).when(mGridLayoutManager).getSpanSizeLookup();
doReturn(mTab1Domain)
.when(mUrlUtilitiesJniMock)
.getDomainAndRegistry(eq(TAB1_URL), anyBoolean());
.getDomainAndRegistry(eq(TAB1_URL.getSpec()), anyBoolean());
doReturn(mTab2Domain)
.when(mUrlUtilitiesJniMock)
.getDomainAndRegistry(eq(TAB2_URL), anyBoolean());
.getDomainAndRegistry(eq(TAB2_URL.getSpec()), anyBoolean());
doReturn(mTab3Domain)
.when(mUrlUtilitiesJniMock)
.getDomainAndRegistry(eq(TAB3_URL), anyBoolean());
.getDomainAndRegistry(eq(TAB3_URL.getSpec()), anyBoolean());
doNothing().when(mTemplateUrlService).addObserver(mTemplateUrlServiceObserver.capture());
doReturn(true).when(mTabListFaviconProvider).isInitialized();
@ -1919,10 +1920,8 @@ public class TabListMediatorUnitTest {
PriceTrackingUtilities.TRACK_PRICES_ON_TABS, priceTrackingEnabled);
Profile.setLastUsedProfileForTesting(mProfile);
Map<GURL, Any> responses = new HashMap<>();
GURL gurl1 = JUnitTestGURLs.getGURL(TAB1_URL);
GURL gurl2 = JUnitTestGURLs.getGURL(TAB2_URL);
responses.put(gurl1, ANY_BUYABLE_PRODUCT_INITIAL);
responses.put(gurl2, ANY_EMPTY);
responses.put(TAB1_URL, ANY_BUYABLE_PRODUCT_INITIAL);
responses.put(TAB2_URL, ANY_EMPTY);
mockOptimizationGuideResponse(OptimizationGuideDecision.TRUE, responses);
PersistedTabDataConfiguration.setUseTestConfig(true);
initAndAssertAllProperties(mMediatorSpy);
@ -2436,7 +2435,7 @@ public class TabListMediatorUnitTest {
List<Tab> tabs = new ArrayList<>(Arrays.asList(mTab1, mTab2, tab3));
createTabGroup(tabs, TAB1_ID);
mTabObserverCaptor.getValue().onFaviconUpdated(mTab1, mFaviconBitmap);
List<String> urls = new ArrayList<>(Arrays.asList(TAB1_URL, TAB2_URL, TAB3_URL));
List<GURL> urls = new ArrayList<>(Arrays.asList(TAB1_URL, TAB2_URL, TAB3_URL));
verify(mTabListFaviconProvider).getComposedFaviconImageAsync(eq(urls), anyBoolean(), any());
mCallbackCaptor.getValue().onResult(mFaviconDrawable);
assertThat(mModel.get(0).model.get(TabProperties.FAVICON), equalTo(mFaviconDrawable));
@ -2444,11 +2443,12 @@ public class TabListMediatorUnitTest {
// Test a group of five.
mModel.get(1).model.set(TabProperties.FAVICON, null);
TabImpl tab4 = prepareTab(0, "tab 4", TAB2_URL);
TabImpl tab5 = prepareTab(1, "tab 5", "www.tab5.com");
TabImpl tab5 = prepareTab(1, "tab 5", JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL));
tabs.addAll(Arrays.asList(tab4, tab5));
createTabGroup(tabs, TAB2_ID);
mTabObserverCaptor.getValue().onFaviconUpdated(mTab2, mFaviconBitmap);
urls = new ArrayList<>(Arrays.asList(TAB2_URL, TAB1_URL, TAB3_URL, TAB2_URL));
verify(mTabListFaviconProvider).getComposedFaviconImageAsync(eq(urls), anyBoolean(), any());
mCallbackCaptor.getValue().onResult(mFaviconDrawable);
assertThat(mModel.get(1).model.get(TabProperties.FAVICON), equalTo(mFaviconDrawable));
@ -2704,7 +2704,7 @@ public class TabListMediatorUnitTest {
instanceOf(TabListMediator.TabActionListener.class));
}
private TabImpl prepareTab(int id, String title, String url) {
private TabImpl prepareTab(int id, String title, GURL url) {
TabImpl tab = TabUiUnitTestUtils.prepareTab(id, title, url);
when(tab.getView()).thenReturn(mock(View.class));
doReturn(true).when(tab).isIncognito();

@ -53,17 +53,13 @@ public class TabUiUnitTestUtils {
doReturn(userDataHost).when(tab).getUserDataHost();
}
public static TabImpl prepareTab(int id, String title, String urlString) {
public static TabImpl prepareTab(int id, String title, GURL url) {
CriticalPersistedTabData criticalPersistedTabData = mock(CriticalPersistedTabData.class);
TabImpl tab = prepareTab(id, criticalPersistedTabData);
doReturn(id).when(criticalPersistedTabData).getRootId();
doReturn(title).when(tab).getTitle();
// TODO(crbug/783819): don't mock GURL here.
GURL gurl = mock(GURL.class);
doReturn(urlString).when(gurl).getSpec();
doReturn(gurl).when(tab).getOriginalUrl();
doReturn(gurl).when(tab).getUrl();
doReturn(url).when(tab).getOriginalUrl();
doReturn(url).when(tab).getUrl();
return tab;
}

@ -58,7 +58,7 @@ class FaviconHelper::Job {
public:
Job(FaviconHelper* favicon_helper,
favicon::FaviconService* favicon_service,
std::vector<std::string> urls,
std::vector<GURL> urls,
int desire_size_in_pixel,
JobFinishedCallback job_finished_callback,
favicon_base::FaviconResultsCallback result_callback);
@ -73,7 +73,7 @@ class FaviconHelper::Job {
const favicon_base::FaviconRawBitmapResult& result);
FaviconHelper* favicon_helper_;
favicon::FaviconService* favicon_service_;
std::vector<std::string> urls_;
std::vector<GURL> urls_;
int desire_size_in_pixel_;
JobFinishedCallback job_finished_callback_;
favicon_base::FaviconResultsCallback result_callback_;
@ -86,7 +86,7 @@ class FaviconHelper::Job {
FaviconHelper::Job::Job(FaviconHelper* favicon_helper,
favicon::FaviconService* favicon_service,
std::vector<std::string> urls,
std::vector<GURL> urls,
int desire_size_in_pixel,
JobFinishedCallback job_finished_callback,
favicon_base::FaviconResultsCallback result_callback)
@ -113,7 +113,7 @@ void FaviconHelper::Job::Start() {
weak_ptr_factory_.GetWeakPtr(), i);
favicon_helper_->GetLocalFaviconImageForURLInternal(
favicon_service_, GURL(urls_.at(i)), desire_size_in_pixel_,
favicon_service_, urls_.at(i), desire_size_in_pixel_,
std::move(callback));
}
}
@ -180,8 +180,8 @@ jboolean FaviconHelper::GetComposedFaviconImage(
ScopedJavaGlobalRef<jobject>(j_favicon_image_callback),
desired_size_in_pixel);
std::vector<std::string> urls;
base::android::AppendJavaStringArrayToStringVector(env, j_urls, &urls);
std::vector<GURL> urls;
url::GURLAndroid::JavaGURLArrayToGURLVector(env, j_urls, &urls);
GetComposedFaviconImageInternal(favicon_service, urls,
static_cast<int>(j_desired_size_in_pixel),
@ -192,7 +192,7 @@ jboolean FaviconHelper::GetComposedFaviconImage(
void FaviconHelper::GetComposedFaviconImageInternal(
favicon::FaviconService* favicon_service,
std::vector<std::string> urls,
std::vector<GURL> urls,
int desired_size_in_pixel,
favicon_base::FaviconResultsCallback callback_runner) {
DCHECK(favicon_service);

@ -48,7 +48,7 @@ class FaviconHelper {
favicon_base::FaviconRawBitmapCallback callback_runner);
void GetComposedFaviconImageInternal(
favicon::FaviconService* favicon_service,
std::vector<std::string> urls,
std::vector<GURL> urls,
int desired_size_in_pixel,
favicon_base::FaviconResultsCallback callback_runner);
void OnJobFinished(int job_id);

@ -89,10 +89,9 @@ TEST_F(FaviconHelperTest, GetLargestSizeIndex) {
TEST_F(FaviconHelperTest, GetComposedFaviconImage) {
raw_bitmap_results_.clear();
std::vector<std::string> urls = {"http://www.tab1.com",
"http://www.tab2.com"};
GURL url1 = GURL(urls[0]);
GURL url2 = GURL(urls[1]);
GURL url1 = GURL("http://www.tab1.com");
GURL url2 = GURL("http://www.tab2.com");
std::vector<GURL> urls = {url1, url2};
EXPECT_CALL(mock_favicon_service_,
GetRawFaviconForPageURL(url1, _, _, 16, _, _))
@ -112,11 +111,10 @@ TEST_F(FaviconHelperTest, GetComposedFaviconImage) {
TEST_F(FaviconHelperTest, GetComposedFaviconImageWithOneFaviconFailed) {
raw_bitmap_results_.clear();
std::vector<std::string> urls = {"http://www.tab1.com", "http://www.tab2.com",
"http://www.tab3.com"};
GURL url1 = GURL(urls[0]);
GURL url2 = GURL(urls[1]);
GURL url3 = GURL(urls[2]);
GURL url1 = GURL("http://www.tab1.com");
GURL url2 = GURL("http://www.tab2.com");
GURL url3 = GURL("http://www.tab3.com");
std::vector<GURL> urls = {url1, url2, url3};
EXPECT_CALL(mock_favicon_service_,
GetRawFaviconForPageURL(url1, _, _, 16, _, _))
@ -144,11 +142,10 @@ TEST_F(FaviconHelperTest, GetComposedFaviconImageWithOneFaviconFailed) {
TEST_F(FaviconHelperTest, GetComposedFaviconImageOrderMatchesInput) {
raw_bitmap_results_.clear();
std::vector<std::string> urls = {"http://www.tab1.com", "http://www.tab2.com",
"http://www.tab3.com"};
GURL url1 = GURL(urls[0]);
GURL url2 = GURL(urls[1]);
GURL url3 = GURL(urls[2]);
GURL url1 = GURL("http://www.tab1.com");
GURL url2 = GURL("http://www.tab2.com");
GURL url3 = GURL("http://www.tab3.com");
std::vector<GURL> urls = {url1, url2, url3};
EXPECT_CALL(mock_favicon_service_,
GetRawFaviconForPageURL(url1, _, _, 16, _, _))

@ -191,7 +191,7 @@ public class FaviconHelper {
* that this callback is not called if this method returns false.
* @return True if GetLocalFaviconImageForURL is successfully called.
*/
public boolean getComposedFaviconImage(Profile profile, @NonNull List<String> urls,
public boolean getComposedFaviconImage(Profile profile, @NonNull List<GURL> urls,
int desiredSizeInPixel, FaviconImageCallback faviconImageCallback) {
assert mNativeFaviconHelper != 0;
@ -201,14 +201,14 @@ public class FaviconHelper {
}
return FaviconHelperJni.get().getComposedFaviconImage(mNativeFaviconHelper, profile,
urls.toArray(new String[0]), desiredSizeInPixel, faviconImageCallback);
urls.toArray(new GURL[0]), desiredSizeInPixel, faviconImageCallback);
}
@NativeMethods
interface Natives {
long init();
void destroy(long nativeFaviconHelper);
boolean getComposedFaviconImage(long nativeFaviconHelper, Profile profile, String[] urls,
boolean getComposedFaviconImage(long nativeFaviconHelper, Profile profile, GURL[] urls,
int desiredSizeInDip, FaviconImageCallback faviconImageCallback);
boolean getLocalFaviconImageForURL(long nativeFaviconHelper, Profile profile,
String pageUrl, int desiredSizeInDip, FaviconImageCallback faviconImageCallback);

@ -57,6 +57,17 @@ static void InitFromGURL(JNIEnv* env,
gurl.parsed_for_possibly_invalid_spec()));
}
// As |GetArrayLength| makes no guarantees about the returned value (e.g., it
// may be -1 if |array| is not a valid Java array), provide a safe wrapper
// that always returns a valid, non-negative size.
template <typename JavaArrayType>
size_t SafeGetArrayLength(JNIEnv* env, const JavaRef<JavaArrayType>& jarray) {
DCHECK(jarray);
jsize length = env->GetArrayLength(jarray.obj());
DCHECK_GE(length, 0) << "Invalid array length: " << length;
return static_cast<size_t>(std::max(0, length));
}
} // namespace
// static
@ -67,6 +78,23 @@ std::unique_ptr<GURL> GURLAndroid::ToNativeGURL(
reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
}
void GURLAndroid::JavaGURLArrayToGURLVector(
JNIEnv* env,
const base::android::JavaRef<jobjectArray>& array,
std::vector<GURL>* out) {
DCHECK(out);
DCHECK(out->empty());
if (!array)
return;
size_t len = SafeGetArrayLength(env, array);
for (size_t i = 0; i < len; ++i) {
ScopedJavaLocalRef<jobject> j_gurl(
env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
out->emplace_back(
*reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
}
}
// static
ScopedJavaLocalRef<jobject> GURLAndroid::FromNativeGURL(JNIEnv* env,
const GURL& gurl) {

@ -25,6 +25,10 @@ class GURLAndroid {
static base::android::ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfGURLs(
JNIEnv* env,
base::span<base::android::ScopedJavaLocalRef<jobject>> v);
static void JavaGURLArrayToGURLVector(
JNIEnv* env,
const base::android::JavaRef<jobjectArray>& gurl_array,
std::vector<GURL>* out);
};
} // namespace url

@ -25,6 +25,7 @@ public class JUnitTestGURLs {
// in the map.
public static final String EXAMPLE_URL = "https://www.example.com/";
public static final String URL_1 = "https://www.one.com/";
public static final String URL_1_NUMERAL = "https://www.1.com/";
public static final String URL_1_WITH_PATH = "https://www.one.com/some_path.html";
public static final String URL_2 = "https://www.two.com/";
public static final String URL_3 = "https://www.three.com/";
@ -56,6 +57,9 @@ public class JUnitTestGURLs {
map.put(URL_1,
"78,1,true,0,5,0,-1,0,-1,8,11,0,-1,19,1,0,-1,0,-1,"
+ "false,false,https://www.one.com/");
map.put(URL_1_NUMERAL,
"75,1,true,0,5,0,-1,0,-1,8,9,0,-1,17,1,0,-1,0,-1,"
+ "false,false,https://www.1.com/");
map.put(URL_1_WITH_PATH,
"93,1,true,0,5,0,-1,0,-1,8,11,0,-1,19,15,0,-1,0,-1,"
+ "false,false,https://www.one.com/some_path.html");