Migrate Suggestions UI code to GURL
Mostly straightforward changes, migrated a few junit tests to batched instrumentation tests without issue. Also, added a version to the MostVisitedSitesMetadataUtils so that further updates to the cache structure can be made without invalidating the existing cache. The cache is currently unused, so my breaking change shouldn't cause any problems. Bug: 783819 Change-Id: I25f2fb281c495d15e8a05b9f64fcfc79cc5733fb Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2426731 Reviewed-by: Xi Han <hanxi@chromium.org> Reviewed-by: Yaron Friedman <yfriedman@chromium.org> Commit-Queue: Michael Thiessen <mthiesse@chromium.org> Cr-Commit-Position: refs/heads/master@{#810767}
This commit is contained in:

committed by
Commit Bot

parent
06d5b65582
commit
6f303a8518
chrome
android
chrome_junit_test_java_sources.gnichrome_test_java_sources.gni
features
tab_ui
java
src
org
chromium
chrome
javatests
src
org
chromium
junit
src
org
chromium
chrome
browser
suggestions
browser
android
offline_pages
test
android
javatests
src
org
chromium
chrome
test
util
NewTabPageTestUtils.java
browser
url/android
@ -139,7 +139,6 @@ chrome_junit_test_java_sources = [
|
||||
"junit/src/org/chromium/chrome/browser/notifications/NotificationTriggerBackgroundTaskTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/notifications/NotificationTriggerSchedulerTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/notifications/channels/ChromeChannelDefinitionsTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/ntp/TitleUtilTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/ntp/cards/InnerNodeTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/ntp/cards/promo/HomepagePromoUnitTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/ntp/cards/promo/HomepagePromoVariationManagerTest.java",
|
||||
@ -215,7 +214,6 @@ chrome_junit_test_java_sources = [
|
||||
"junit/src/org/chromium/chrome/browser/signin/account_picker/AccountPickerMediatorTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/status_indicator/StatusIndicatorMediatorTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/suggestions/SuggestionsImageFetcherTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/survey/ChromeSurveyControllerTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/tab/HistoricalTabSaverUnitTest.java",
|
||||
"junit/src/org/chromium/chrome/browser/tab/TabAttributesTest.java",
|
||||
|
@ -299,6 +299,7 @@ chrome_test_java_sources = [
|
||||
"javatests/src/org/chromium/chrome/browser/ntp/NewTabPageNavigationTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/ntp/RecentTabsPageTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/ntp/TitleUtilTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/ntp/cards/promo/HomepagePromoTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/offlinepages/MHTMLPageTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageArchivePublisherBridgeTest.java",
|
||||
@ -526,6 +527,7 @@ chrome_test_java_sources = [
|
||||
"javatests/src/org/chromium/chrome/browser/suggestions/mostvisited/MostVisitedSitesMetadataUtilsTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGroupUnitTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/sync/AndroidSyncSettingsTest.java",
|
||||
"javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java",
|
||||
|
@ -217,6 +217,7 @@ android_library("java") {
|
||||
"//third_party/android_deps:androidx_recyclerview_recyclerview_java",
|
||||
"//third_party/android_deps:material_design_java",
|
||||
"//ui/android:ui_java",
|
||||
"//url:gurl_java",
|
||||
]
|
||||
resources_package = "org.chromium.chrome.tab_ui"
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ class MostVisitedListCoordinator implements TileGroup.Observer, TileGroup.TileSe
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ReturnToChromeExperimentsUtil.willHandleLoadUrlFromStartSurface(
|
||||
mTile.getUrl(), PageTransition.AUTO_BOOKMARK);
|
||||
mTile.getUrl().getSpec(), PageTransition.AUTO_BOOKMARK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -562,12 +562,12 @@ public class RecentTabsRowAdapter extends BaseExpandableListAdapter {
|
||||
String title = TitleUtil.getTitleForDisplay(tab.title, tab.url);
|
||||
viewHolder.textView.setText(title);
|
||||
|
||||
String domain = UrlUtilities.getDomainAndRegistry(tab.url, false);
|
||||
String domain = UrlUtilities.getDomainAndRegistry(tab.url.getSpec(), false);
|
||||
if (!TextUtils.isEmpty(domain)) {
|
||||
viewHolder.domainView.setText(domain);
|
||||
viewHolder.domainView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
loadFavicon(viewHolder, tab.url, FaviconLocality.LOCAL);
|
||||
loadFavicon(viewHolder, tab.url.getSpec(), FaviconLocality.LOCAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -10,6 +10,7 @@ import org.chromium.base.annotations.CalledByNative;
|
||||
import org.chromium.base.annotations.NativeMethods;
|
||||
import org.chromium.chrome.browser.profiles.Profile;
|
||||
import org.chromium.chrome.browser.tab.Tab;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -24,8 +25,7 @@ public class RecentlyClosedBridge implements RecentlyClosedTabManager {
|
||||
private Runnable mTabsUpdatedRunnable;
|
||||
|
||||
@CalledByNative
|
||||
private static void pushTab(
|
||||
List<RecentlyClosedTab> tabs, int id, String title, String url) {
|
||||
private static void pushTab(List<RecentlyClosedTab> tabs, int id, String title, GURL url) {
|
||||
RecentlyClosedTab tab = new RecentlyClosedTab(id, title, url);
|
||||
tabs.add(tab);
|
||||
}
|
||||
|
@ -4,15 +4,17 @@
|
||||
|
||||
package org.chromium.chrome.browser.ntp;
|
||||
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Represents a recently closed tab.
|
||||
*/
|
||||
public class RecentlyClosedTab {
|
||||
public final int id;
|
||||
public final String title;
|
||||
public final String url;
|
||||
public final GURL url;
|
||||
|
||||
public RecentlyClosedTab(int id, String title, String url) {
|
||||
public RecentlyClosedTab(int id, String title, GURL url) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
|
@ -4,11 +4,12 @@
|
||||
|
||||
package org.chromium.chrome.browser.ntp;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Provides functions for working with link titles.
|
||||
*/
|
||||
@ -19,15 +20,14 @@ public final class TitleUtil {
|
||||
* Returns a title suitable for display for a link. If |title| is non-empty, this simply returns
|
||||
* it. Otherwise, returns a shortened form of the URL.
|
||||
*/
|
||||
public static String getTitleForDisplay(@Nullable String title, @Nullable String url) {
|
||||
if (!TextUtils.isEmpty(title) || TextUtils.isEmpty(url)) {
|
||||
public static String getTitleForDisplay(@Nullable String title, @Nullable GURL url) {
|
||||
if (!TextUtils.isEmpty(title) || GURL.isEmptyOrInvalid(url)) {
|
||||
return title;
|
||||
}
|
||||
|
||||
Uri uri = Uri.parse(url);
|
||||
String host = uri.getHost();
|
||||
String host = url.getHost();
|
||||
if (host == null) host = "";
|
||||
String path = uri.getPath();
|
||||
String path = url.getPath();
|
||||
if (path == null || path.equals("/")) path = "";
|
||||
title = host + path;
|
||||
return title;
|
||||
|
@ -24,6 +24,7 @@ import org.chromium.components.offline_items_collection.LaunchLocation;
|
||||
import org.chromium.components.offlinepages.DeletePageResult;
|
||||
import org.chromium.content_public.browser.LoadUrlParams;
|
||||
import org.chromium.content_public.browser.WebContents;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -240,8 +241,8 @@ public class OfflinePageBridge {
|
||||
* @param callback callback to pass back the matching {@link OfflinePageItem} if found. Will
|
||||
* pass back null if not.
|
||||
*/
|
||||
public void selectPageForOnlineUrl(String onlineUrl, int tabId,
|
||||
Callback<OfflinePageItem> callback) {
|
||||
public void selectPageForOnlineUrl(
|
||||
GURL onlineUrl, int tabId, Callback<OfflinePageItem> callback) {
|
||||
OfflinePageBridgeJni.get().selectPageForOnlineUrl(
|
||||
mNativeOfflinePageBridge, OfflinePageBridge.this, onlineUrl, tabId, callback);
|
||||
}
|
||||
@ -689,7 +690,7 @@ public class OfflinePageBridge {
|
||||
void publishInternalPageByGuid(long nativeOfflinePageBridge, OfflinePageBridge caller,
|
||||
String guid, Callback<String> publishedCallback);
|
||||
void selectPageForOnlineUrl(long nativeOfflinePageBridge, OfflinePageBridge caller,
|
||||
String onlineUrl, int tabId, Callback<OfflinePageItem> callback);
|
||||
GURL onlineUrl, int tabId, Callback<OfflinePageItem> callback);
|
||||
void savePage(long nativeOfflinePageBridge, OfflinePageBridge caller,
|
||||
SavePageCallback callback, WebContents webContents, String clientNamespace,
|
||||
String clientId, String origin);
|
||||
|
@ -8,6 +8,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import org.chromium.chrome.browser.profiles.Profile;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Class responsible for fetching images for the views in the NewTabPage and Chrome Home.
|
||||
@ -41,10 +42,10 @@ public class ImageFetcher {
|
||||
* @param callback The callback to be notified when the icon is available.
|
||||
*/
|
||||
public void makeLargeIconRequest(
|
||||
String url, int size, LargeIconBridge.LargeIconCallback callback) {
|
||||
GURL url, int size, LargeIconBridge.LargeIconCallback callback) {
|
||||
assert !mIsDestroyed;
|
||||
|
||||
getLargeIconBridge().getLargeIconForStringUrl(url, size, callback);
|
||||
getLargeIconBridge().getLargeIconForUrl(url, size, callback);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
|
@ -6,12 +6,14 @@ package org.chromium.chrome.browser.suggestions;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Exposes the data of a suggestion that can be saved offline.
|
||||
*/
|
||||
public interface OfflinableSuggestion {
|
||||
/** @return The URL of this suggestion. */
|
||||
String getUrl();
|
||||
GURL getUrl();
|
||||
|
||||
/** Assigns an offline page id to the suggestion. Set to {@code null} to clear. */
|
||||
void setOfflinePageOfflineId(@Nullable Long offlineId);
|
||||
|
@ -7,6 +7,7 @@ package org.chromium.chrome.browser.suggestions;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileSectionType;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileSource;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileTitleSource;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -20,7 +21,7 @@ public class SiteSuggestion {
|
||||
public final String title;
|
||||
|
||||
/** URL of the suggested site. */
|
||||
public final String url;
|
||||
public final GURL url;
|
||||
|
||||
/** Id of the favicon. It is optional and used when caching the favion on device. */
|
||||
public int faviconId;
|
||||
@ -47,7 +48,7 @@ public class SiteSuggestion {
|
||||
(produced by a ranking algorithm). */
|
||||
public final Date dataGenerationTime;
|
||||
|
||||
public SiteSuggestion(String title, String url, String whitelistIconPath, int titleSource,
|
||||
public SiteSuggestion(String title, GURL url, String whitelistIconPath, int titleSource,
|
||||
int source, int sectionType, Date dataGenerationTime) {
|
||||
this.title = title;
|
||||
this.url = url;
|
||||
|
@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
|
||||
import org.chromium.base.annotations.CalledByNative;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.chrome.browser.suggestions.tile.Tile;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -29,7 +30,7 @@ public interface MostVisitedSites {
|
||||
*
|
||||
* @param siteUrl URL of site with newly-cached icon.
|
||||
*/
|
||||
void onIconMadeAvailable(String siteUrl);
|
||||
void onIconMadeAvailable(GURL siteUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,12 +67,12 @@ public interface MostVisitedSites {
|
||||
/**
|
||||
* Blocklists a URL from the most visited URLs list.
|
||||
*/
|
||||
void addBlocklistedUrl(String url);
|
||||
void addBlocklistedUrl(GURL url);
|
||||
|
||||
/**
|
||||
* Removes a URL from the most visited URLs blocklist.
|
||||
*/
|
||||
void removeBlocklistedUrl(String url);
|
||||
void removeBlocklistedUrl(GURL url);
|
||||
|
||||
/**
|
||||
* Records metrics about an impression of the surface with tiles.
|
||||
|
@ -10,6 +10,7 @@ import org.chromium.base.annotations.NativeMethods;
|
||||
import org.chromium.chrome.browser.profiles.Profile;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.chrome.browser.suggestions.tile.Tile;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -62,14 +63,14 @@ public class MostVisitedSitesBridge implements MostVisitedSites {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBlocklistedUrl(String url) {
|
||||
public void addBlocklistedUrl(GURL url) {
|
||||
if (mNativeMostVisitedSitesBridge == 0) return;
|
||||
MostVisitedSitesBridgeJni.get().addOrRemoveBlockedUrl(
|
||||
mNativeMostVisitedSitesBridge, MostVisitedSitesBridge.this, url, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBlocklistedUrl(String url) {
|
||||
public void removeBlocklistedUrl(GURL url) {
|
||||
if (mNativeMostVisitedSitesBridge == 0) return;
|
||||
MostVisitedSitesBridgeJni.get().addOrRemoveBlockedUrl(
|
||||
mNativeMostVisitedSitesBridge, MostVisitedSitesBridge.this, url, false);
|
||||
@ -103,7 +104,7 @@ public class MostVisitedSitesBridge implements MostVisitedSites {
|
||||
* Utility function to convert JNI friendly site suggestion data to a Java friendly list of
|
||||
* {@link SiteSuggestion}s.
|
||||
*/
|
||||
public static List<SiteSuggestion> buildSiteSuggestions(String[] titles, String[] urls,
|
||||
public static List<SiteSuggestion> buildSiteSuggestions(String[] titles, GURL[] urls,
|
||||
int[] sections, String[] allowlistIconPaths, int[] titleSources, int[] sources,
|
||||
long[] dataGenerationTimesMs) {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>(titles.length);
|
||||
@ -127,7 +128,7 @@ public class MostVisitedSitesBridge implements MostVisitedSites {
|
||||
* @param sources For each tile, the {@code TileSource} that generated the tile.
|
||||
*/
|
||||
@CalledByNative
|
||||
private void onURLsAvailable(String[] titles, String[] urls, int[] sections,
|
||||
private void onURLsAvailable(String[] titles, GURL[] urls, int[] sections,
|
||||
String[] allowlistIconPaths, int[] titleSources, int[] sources,
|
||||
long[] dataGenerationTimesMs) {
|
||||
// Don't notify observer if we've already been destroyed.
|
||||
@ -148,7 +149,7 @@ public class MostVisitedSitesBridge implements MostVisitedSites {
|
||||
* @param siteUrl URL of site with newly-cached icon.
|
||||
*/
|
||||
@CalledByNative
|
||||
private void onIconMadeAvailable(String siteUrl) {
|
||||
private void onIconMadeAvailable(GURL siteUrl) {
|
||||
// Don't notify observer if we've already been destroyed.
|
||||
if (mNativeMostVisitedSitesBridge != 0) {
|
||||
mWrappedObserver.onIconMadeAvailable(siteUrl);
|
||||
@ -166,12 +167,12 @@ public class MostVisitedSitesBridge implements MostVisitedSites {
|
||||
void setObserver(long nativeMostVisitedSitesBridge, MostVisitedSitesBridge caller,
|
||||
MostVisitedSitesBridge observer, int numSites);
|
||||
void addOrRemoveBlockedUrl(long nativeMostVisitedSitesBridge, MostVisitedSitesBridge caller,
|
||||
String url, boolean addUrl);
|
||||
GURL url, boolean addUrl);
|
||||
void recordPageImpression(
|
||||
long nativeMostVisitedSitesBridge, MostVisitedSitesBridge caller, int tilesCount);
|
||||
void recordTileImpression(long nativeMostVisitedSitesBridge, MostVisitedSitesBridge caller,
|
||||
int index, int type, int iconType, int titleSource, int source,
|
||||
long dataGenerationTimeMs, String url);
|
||||
long dataGenerationTimeMs, GURL url);
|
||||
void recordOpenedMostVisitedItem(long nativeMostVisitedSitesBridge,
|
||||
MostVisitedSitesBridge caller, int index, int tileType, int titleSource, int source,
|
||||
long dataGenerationTimeMs);
|
||||
|
@ -62,9 +62,9 @@ public class MostVisitedSitesFaviconHelper {
|
||||
* @param callback The callback function after skipping the existing favicon or saving favicon.
|
||||
*/
|
||||
public void saveFaviconsToFile(
|
||||
List<SiteSuggestion> topSitesInfo, Set<String> urlsToUpdate, Runnable callback) {
|
||||
List<SiteSuggestion> topSitesInfo, Set<GURL> urlsToUpdate, Runnable callback) {
|
||||
for (SiteSuggestion siteData : topSitesInfo) {
|
||||
String url = siteData.url;
|
||||
GURL url = siteData.url;
|
||||
if (!urlsToUpdate.contains(url)) {
|
||||
if (callback != null) {
|
||||
callback.run();
|
||||
@ -91,7 +91,7 @@ public class MostVisitedSitesFaviconHelper {
|
||||
private void fetchIcon(
|
||||
final SiteSuggestion siteData, final LargeIconBridge.LargeIconCallback iconCallback) {
|
||||
if (siteData.whitelistIconPath.isEmpty()) {
|
||||
mLargeIconBridge.getLargeIconForUrl(new GURL(siteData.url), mMinIconSize, iconCallback);
|
||||
mLargeIconBridge.getLargeIconForUrl(siteData.url, mMinIconSize, iconCallback);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -108,8 +108,7 @@ public class MostVisitedSitesFaviconHelper {
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap icon) {
|
||||
if (icon == null) {
|
||||
mLargeIconBridge.getLargeIconForUrl(
|
||||
new GURL(siteData.url), mMinIconSize, iconCallback);
|
||||
mLargeIconBridge.getLargeIconForUrl(siteData.url, mMinIconSize, iconCallback);
|
||||
} else {
|
||||
iconCallback.onLargeIconAvailable(icon, Color.BLACK, false, IconType.INVALID);
|
||||
}
|
||||
@ -127,7 +126,7 @@ public class MostVisitedSitesFaviconHelper {
|
||||
* @param icon The favicon fetched from native.
|
||||
* @param callback The callback function after saving each favicon.
|
||||
*/
|
||||
private void saveFaviconToFile(String fileName, File directory, String url, int fallbackColor,
|
||||
private void saveFaviconToFile(String fileName, File directory, GURL url, int fallbackColor,
|
||||
Bitmap icon, Runnable callback) {
|
||||
new AsyncTask<Void>() {
|
||||
@Override
|
||||
@ -135,9 +134,11 @@ public class MostVisitedSitesFaviconHelper {
|
||||
Bitmap newIcon = icon;
|
||||
// If icon is null, we need to generate a favicon.
|
||||
if (newIcon == null) {
|
||||
Log.i(TAG, "Favicon is null for " + url + ". Generating an icon for it.");
|
||||
Log.i(TAG,
|
||||
"Favicon is null for " + url.getSpec()
|
||||
+ ". Generating an icon for it.");
|
||||
mIconGenerator.setBackgroundColor(fallbackColor);
|
||||
newIcon = mIconGenerator.generateIconForUrl(url);
|
||||
newIcon = mIconGenerator.generateIconForUrl(url.getSpec());
|
||||
}
|
||||
// Save icon to file.
|
||||
File metadataFile = new File(directory, fileName);
|
||||
|
@ -14,6 +14,7 @@ import org.chromium.chrome.browser.profiles.Profile;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -38,15 +39,15 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
|
||||
// The map mapping URL to faviconId. This map will be updated once there are new suggestions
|
||||
// available.
|
||||
private final Map<String, Integer> mUrlToIdMap = new HashMap<>();
|
||||
private final Map<GURL, Integer> mUrlToIdMap = new HashMap<>();
|
||||
|
||||
// The map mapping faviconId to URL. This map will be reconstructed based on the mUrlToIdMap
|
||||
// once there are new suggestions available.
|
||||
private final Map<Integer, String> mIdToUrlMap = new HashMap<>();
|
||||
private final Map<Integer, GURL> mIdToUrlMap = new HashMap<>();
|
||||
|
||||
// The set of URLs needed to fetch favicon. This set will be reconstructed once there are new
|
||||
// suggestions available.
|
||||
private final Set<String> mUrlsToUpdateFavicon = new HashSet<>();
|
||||
private final Set<GURL> mUrlsToUpdateFavicon = new HashSet<>();
|
||||
|
||||
private static boolean sSkipRestoreFromDiskForTests;
|
||||
/** The singleton helper class for this class. */
|
||||
@ -127,7 +128,7 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIconMadeAvailable(String siteUrl) {}
|
||||
public void onIconMadeAvailable(GURL siteUrl) {}
|
||||
|
||||
/**
|
||||
* Start the observer.
|
||||
@ -222,7 +223,7 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
List<SiteSuggestion> newSuggestions, Set<String> existingIconFiles) {
|
||||
// Add topsites URLs which need to fetch icon to the mUrlsToUpdateFavicon Set.
|
||||
for (SiteSuggestion topSiteData : newSuggestions) {
|
||||
String url = topSiteData.url;
|
||||
GURL url = topSiteData.url;
|
||||
// If the old map doesn't contain the URL or there is no favicon file for this URL, then
|
||||
// add this URL to mUrlsToUpdateFavicon.
|
||||
if (!mUrlToIdMap.containsKey(url)
|
||||
@ -239,14 +240,14 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
*/
|
||||
private void updateMapForNewSites(List<SiteSuggestion> newSuggestions, Runnable callback) {
|
||||
// Get the set of new top sites' URLs.
|
||||
Set<String> newUrls = new HashSet<>();
|
||||
Set<GURL> newUrls = new HashSet<>();
|
||||
for (SiteSuggestion topSiteData : newSuggestions) {
|
||||
newUrls.add(topSiteData.url);
|
||||
}
|
||||
|
||||
// Add new URLs and ids to the mUrlToIDMap.
|
||||
int id = 0;
|
||||
for (String url : mUrlsToUpdateFavicon) {
|
||||
for (GURL url : mUrlsToUpdateFavicon) {
|
||||
if (mUrlToIdMap.containsKey(url)) {
|
||||
continue;
|
||||
}
|
||||
@ -275,7 +276,7 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected int getNextAvailableId(int start, Set<String> newTopSiteUrls) {
|
||||
protected int getNextAvailableId(int start, Set<GURL> newTopSiteUrls) {
|
||||
int id = start;
|
||||
// The available ids should be in range [0, newTopSiteUrls.size()), since we only need
|
||||
// |newTopSiteUrls.size()| ids.
|
||||
@ -293,7 +294,7 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
@VisibleForTesting
|
||||
protected void buildIdToUrlMap() {
|
||||
mIdToUrlMap.clear();
|
||||
for (Map.Entry<String, Integer> entry : mUrlToIdMap.entrySet()) {
|
||||
for (Map.Entry<GURL, Integer> entry : mUrlToIdMap.entrySet()) {
|
||||
mIdToUrlMap.put(entry.getValue(), entry.getKey());
|
||||
}
|
||||
}
|
||||
@ -303,12 +304,12 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
* @param newUrls The URLs in new SiteSuggestions.
|
||||
* @return The list of faviconIds needed to remove.
|
||||
*/
|
||||
private List<Integer> removeStaleData(Set<String> newUrls) {
|
||||
private List<Integer> removeStaleData(Set<GURL> newUrls) {
|
||||
List<Integer> idsToDeleteFile = new ArrayList<>();
|
||||
for (Iterator<Map.Entry<String, Integer>> it = mUrlToIdMap.entrySet().iterator();
|
||||
for (Iterator<Map.Entry<GURL, Integer>> it = mUrlToIdMap.entrySet().iterator();
|
||||
it.hasNext();) {
|
||||
Map.Entry<String, Integer> entry = it.next();
|
||||
String url = entry.getKey();
|
||||
Map.Entry<GURL, Integer> entry = it.next();
|
||||
GURL url = entry.getKey();
|
||||
int faviconId = entry.getValue();
|
||||
if (!newUrls.contains(url)) {
|
||||
it.remove();
|
||||
@ -362,17 +363,17 @@ public class MostVisitedSitesHost implements MostVisitedSites.Observer {
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected Map<String, Integer> getUrlToIDMapForTesting() {
|
||||
protected Map<GURL, Integer> getUrlToIDMapForTesting() {
|
||||
return mUrlToIdMap;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected Set<String> getUrlsToUpdateFaviconForTesting() {
|
||||
protected Set<GURL> getUrlsToUpdateFaviconForTesting() {
|
||||
return mUrlsToUpdateFavicon;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected Map<Integer, String> getIdToUrlMapForTesting() {
|
||||
protected Map<Integer, GURL> getIdToUrlMapForTesting() {
|
||||
return mIdToUrlMap;
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import org.chromium.base.StreamUtil;
|
||||
import org.chromium.base.StrictModeContext;
|
||||
import org.chromium.base.task.AsyncTask;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
@ -38,6 +39,9 @@ public class MostVisitedSitesMetadataUtils {
|
||||
/** Prevents two MostVisitedSitesUtils from saving the same file simultaneously. */
|
||||
private static final Object SAVE_LIST_LOCK = new Object();
|
||||
|
||||
/** Current version of the cache, to be updated when the cache structure or meaning changes. */
|
||||
private static final int CACHE_VERSION = 1;
|
||||
|
||||
private static File sStateDirectory;
|
||||
private static String sStateDirName = "top_sites";
|
||||
private static String sStateFileName = "top_sites";
|
||||
@ -118,9 +122,10 @@ public class MostVisitedSitesMetadataUtils {
|
||||
|
||||
// Save top sites.
|
||||
for (int i = 0; i < topSitesCount; i++) {
|
||||
stream.writeInt(CACHE_VERSION);
|
||||
stream.writeInt(topSitesInfo.get(i).faviconId);
|
||||
stream.writeUTF(topSitesInfo.get(i).title);
|
||||
stream.writeUTF(topSitesInfo.get(i).url);
|
||||
stream.writeUTF(topSitesInfo.get(i).url.serialize());
|
||||
stream.writeUTF(topSitesInfo.get(i).whitelistIconPath);
|
||||
stream.writeInt(topSitesInfo.get(i).titleSource);
|
||||
stream.writeInt(topSitesInfo.get(i).source);
|
||||
@ -150,9 +155,15 @@ public class MostVisitedSitesMetadataUtils {
|
||||
// Restore top sites.
|
||||
List<SiteSuggestion> suggestions = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int version = stream.readInt();
|
||||
if (version > CACHE_VERSION) {
|
||||
throw new IOException("Cache version not supported.");
|
||||
}
|
||||
int faviconId = stream.readInt();
|
||||
String title = stream.readUTF();
|
||||
String url = stream.readUTF();
|
||||
GURL url = GURL.deserialize(stream.readUTF());
|
||||
if (url.isEmpty()) throw new IOException("GURL deserialization failed.");
|
||||
|
||||
String whitelistIconPath = stream.readUTF();
|
||||
int titleSource = stream.readInt();
|
||||
int source = stream.readInt();
|
||||
|
@ -11,6 +11,7 @@ import android.util.AttributeSet;
|
||||
import org.chromium.chrome.R;
|
||||
import org.chromium.chrome.browser.ntp.TitleUtil;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* The view for a site suggestion tile. Displays the title of the site beneath a large icon. If a
|
||||
@ -46,7 +47,7 @@ public class SuggestionsTileView extends TileView {
|
||||
}
|
||||
|
||||
/** Retrieves url associated with this view. */
|
||||
public String getUrl() {
|
||||
public GURL getUrl() {
|
||||
return mData.url;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import androidx.annotation.Nullable;
|
||||
import org.chromium.chrome.browser.suggestions.OfflinableSuggestion;
|
||||
import org.chromium.chrome.browser.suggestions.SiteSuggestion;
|
||||
import org.chromium.chrome.browser.ui.favicon.IconType;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Holds the details to populate a site suggestion tile.
|
||||
@ -46,7 +47,7 @@ public class Tile implements OfflinableSuggestion {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
public GURL getUrl() {
|
||||
return mSiteData.url;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSites;
|
||||
import org.chromium.chrome.browser.ui.favicon.IconType;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge;
|
||||
import org.chromium.ui.mojom.WindowOpenDisposition;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -53,7 +54,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
* @param removalUndoneCallback The callback to invoke if the removal is reverted. The
|
||||
* callback's argument is the URL being restored.
|
||||
*/
|
||||
void removeMostVisitedItem(Tile tile, Callback<String> removalUndoneCallback);
|
||||
void removeMostVisitedItem(Tile tile, Callback<GURL> removalUndoneCallback);
|
||||
|
||||
void openMostVisitedItem(int windowDisposition, Tile tile);
|
||||
|
||||
@ -199,7 +200,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
* the tile backend.
|
||||
*/
|
||||
@Nullable
|
||||
private String mPendingRemovalUrl;
|
||||
private GURL mPendingRemovalUrl;
|
||||
|
||||
/**
|
||||
* URL of the most recently added tile. Used to identify when a given tile's insertion is
|
||||
@ -207,7 +208,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
* then the user undoes the action and wants that tile back.
|
||||
*/
|
||||
@Nullable
|
||||
private String mPendingInsertionUrl;
|
||||
private GURL mPendingInsertionUrl;
|
||||
|
||||
private boolean mHasReceivedData;
|
||||
private boolean mExploreSitesLoaded;
|
||||
@ -287,7 +288,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIconMadeAvailable(String siteUrl) {
|
||||
public void onIconMadeAvailable(GURL siteUrl) {
|
||||
for (Tile tile : findTilesForUrl(siteUrl)) {
|
||||
mTileRenderer.updateIcon(tile.getData(),
|
||||
new LargeIconCallbackImpl(tile.getData(), /* trackLoadTask = */ false));
|
||||
@ -412,7 +413,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
* @param tiles The section to search in, represented by the contained list of tiles.
|
||||
* @return A tile matching the provided URL and section, or {@code null} if none is found.
|
||||
*/
|
||||
private Tile findTile(String url, @Nullable List<Tile> tiles) {
|
||||
private Tile findTile(GURL url, @Nullable List<Tile> tiles) {
|
||||
if (tiles == null) return null;
|
||||
for (Tile tile : tiles) {
|
||||
if (tile.getUrl().equals(url)) return tile;
|
||||
@ -421,7 +422,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
}
|
||||
|
||||
/** @return All tiles matching the provided URL, or an empty list if none is found. */
|
||||
private List<Tile> findTilesForUrl(String url) {
|
||||
private List<Tile> findTilesForUrl(GURL url) {
|
||||
List<Tile> tiles = new ArrayList<>();
|
||||
for (int i = 0; i < mTileSections.size(); ++i) {
|
||||
for (Tile tile : mTileSections.valueAt(i)) {
|
||||
@ -563,7 +564,7 @@ public class TileGroup implements MostVisitedSites.Observer {
|
||||
|
||||
@Override
|
||||
public String getUrl() {
|
||||
return mSuggestion.url;
|
||||
return mSuggestion.url.getSpec();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@ import org.chromium.chrome.browser.ui.messages.snackbar.Snackbar;
|
||||
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
|
||||
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager.SnackbarController;
|
||||
import org.chromium.ui.mojom.WindowOpenDisposition;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@ -45,7 +46,7 @@ public class TileGroupDelegateImpl implements TileGroup.Delegate {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMostVisitedItem(Tile item, Callback<String> removalUndoneCallback) {
|
||||
public void removeMostVisitedItem(Tile item, Callback<GURL> removalUndoneCallback) {
|
||||
assert !mIsDestroyed;
|
||||
|
||||
mMostVisitedSites.addBlocklistedUrl(item.getUrl());
|
||||
@ -56,7 +57,7 @@ public class TileGroupDelegateImpl implements TileGroup.Delegate {
|
||||
public void openMostVisitedItem(int windowDisposition, Tile item) {
|
||||
assert !mIsDestroyed;
|
||||
|
||||
String url = item.getUrl();
|
||||
String url = item.getUrl().getSpec();
|
||||
|
||||
// TODO(treib): Should we call recordOpenedMostVisitedItem here?
|
||||
if (windowDisposition != WindowOpenDisposition.NEW_WINDOW) {
|
||||
@ -103,7 +104,7 @@ public class TileGroupDelegateImpl implements TileGroup.Delegate {
|
||||
mMostVisitedSites.destroy();
|
||||
}
|
||||
|
||||
private void showTileRemovedSnackbar(String url, final Callback<String> removalUndoneCallback) {
|
||||
private void showTileRemovedSnackbar(GURL url, final Callback<GURL> removalUndoneCallback) {
|
||||
if (mTileRemovedSnackbarController == null) {
|
||||
mTileRemovedSnackbarController = new SnackbarController() {
|
||||
@Override
|
||||
@ -113,7 +114,7 @@ public class TileGroupDelegateImpl implements TileGroup.Delegate {
|
||||
@Override
|
||||
public void onAction(Object actionData) {
|
||||
if (mIsDestroyed) return;
|
||||
String url = (String) actionData;
|
||||
GURL url = (GURL) actionData;
|
||||
removalUndoneCallback.onResult(url);
|
||||
mMostVisitedSites.removeBlocklistedUrl(url);
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ public class TileRenderer {
|
||||
return;
|
||||
}
|
||||
mIconGenerator.setBackgroundColor(fallbackColor);
|
||||
Bitmap icon = mIconGenerator.generateIconForUrl(tile.getUrl());
|
||||
Bitmap icon = mIconGenerator.generateIconForUrl(tile.getUrl().getSpec());
|
||||
tile.setIcon(new BitmapDrawable(mResources, icon));
|
||||
tile.setType(
|
||||
isFallbackColorDefault ? TileVisualType.ICON_DEFAULT : TileVisualType.ICON_COLOR);
|
||||
|
@ -34,6 +34,7 @@ import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependencies
|
||||
import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
|
||||
import org.chromium.components.embedder_support.util.UrlConstants;
|
||||
import org.chromium.net.test.EmbeddedTestServer;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Tests for events around the loading of a New Tab Page.
|
||||
@ -94,8 +95,8 @@ public class NewTabPageLoadTest {
|
||||
|
||||
private static class AsyncMockLargeIconBridge extends LargeIconBridge {
|
||||
@Override
|
||||
public boolean getLargeIconForStringUrl(String pageUrl, int desiredSizePx,
|
||||
final LargeIconBridge.LargeIconCallback callback) {
|
||||
public boolean getLargeIconForUrl(
|
||||
GURL pageUrl, int desiredSizePx, final LargeIconBridge.LargeIconCallback callback) {
|
||||
new Handler().postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -251,15 +251,15 @@ public class NewTabPageTest {
|
||||
@SmallTest
|
||||
@Feature({"NewTabPage", "FeedNewTabPage"})
|
||||
public void testClickMostVisitedItem() {
|
||||
ChromeTabUtils.waitForTabPageLoaded(mTab, mSiteSuggestions.get(0).url, new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
View mostVisitedItem = mTileGridLayout.getChildAt(0);
|
||||
TouchCommon.singleClickView(mostVisitedItem);
|
||||
}
|
||||
});
|
||||
Assert.assertEquals(
|
||||
mSiteSuggestions.get(0).url, ChromeTabUtils.getUrlStringOnUiThread(mTab));
|
||||
ChromeTabUtils.waitForTabPageLoaded(
|
||||
mTab, mSiteSuggestions.get(0).url.getSpec(), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
View mostVisitedItem = mTileGridLayout.getChildAt(0);
|
||||
TouchCommon.singleClickView(mostVisitedItem);
|
||||
}
|
||||
});
|
||||
Assert.assertEquals(mSiteSuggestions.get(0).url, ChromeTabUtils.getUrlOnUiThread(mTab));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -272,7 +272,7 @@ public class NewTabPageTest {
|
||||
public void testOpenMostVisitedItemInNewTab() throws ExecutionException {
|
||||
ChromeTabUtils.invokeContextMenuAndOpenInANewTab(mActivityTestRule,
|
||||
mTileGridLayout.getChildAt(0), ContextMenuManager.ContextMenuItemId.OPEN_IN_NEW_TAB,
|
||||
false, mSiteSuggestions.get(0).url);
|
||||
false, mSiteSuggestions.get(0).url.getSpec());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,7 +285,7 @@ public class NewTabPageTest {
|
||||
ChromeTabUtils.invokeContextMenuAndOpenInANewTab(mActivityTestRule,
|
||||
mTileGridLayout.getChildAt(0),
|
||||
ContextMenuManager.ContextMenuItemId.OPEN_IN_INCOGNITO_TAB, true,
|
||||
mSiteSuggestions.get(0).url);
|
||||
mSiteSuggestions.get(0).url.getSpec());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -40,6 +40,7 @@ import org.chromium.content_public.browser.test.util.CriteriaHelper;
|
||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||
import org.chromium.content_public.browser.test.util.TestTouchUtils;
|
||||
import org.chromium.content_public.common.ContentUrlConstants;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -133,7 +134,8 @@ public class RecentTabsPageTest {
|
||||
final List<RecentlyClosedTab> tabs = new ArrayList<>();
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
tabs.add(new RecentlyClosedTab(i, "RecentlyClosedTab title " + i, "url " + i));
|
||||
tabs.add(new RecentlyClosedTab(i, "RecentlyClosedTab title " + i,
|
||||
new GURL("https://www.example.com/url" + i)));
|
||||
}
|
||||
mManager.setRecentlyClosedTabs(tabs);
|
||||
});
|
||||
|
@ -7,28 +7,33 @@ package org.chromium.chrome.browser.ntp;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import org.chromium.base.test.BaseRobolectricTestRunner;
|
||||
import org.chromium.base.test.BaseJUnit4ClassRunner;
|
||||
import org.chromium.base.test.util.Batch;
|
||||
import org.chromium.base.test.util.Feature;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
/**
|
||||
* Unit tests for TitleUtil.
|
||||
*/
|
||||
@RunWith(BaseRobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(BaseJUnit4ClassRunner.class)
|
||||
@Batch(Batch.UNIT_TESTS)
|
||||
public class TitleUtilTest {
|
||||
/**
|
||||
* Tests for the getTitleForDisplay method.
|
||||
*/
|
||||
@Test
|
||||
@SmallTest
|
||||
@Feature({"Ntp"})
|
||||
public void testGetTitleForDisplay() {
|
||||
// If the title is not null or empty it is simply returned.
|
||||
assertEquals("title", TitleUtil.getTitleForDisplay("title", "https://example.com/path"));
|
||||
assertEquals("title", TitleUtil.getTitleForDisplay("title", ""));
|
||||
assertEquals("title",
|
||||
TitleUtil.getTitleForDisplay("title", new GURL("https://example.com/path")));
|
||||
assertEquals("title", TitleUtil.getTitleForDisplay("title", GURL.emptyGURL()));
|
||||
assertEquals("title", TitleUtil.getTitleForDisplay("title", null));
|
||||
|
||||
// If the url is null or empty the title is simply returned.
|
||||
@ -37,9 +42,11 @@ public class TitleUtilTest {
|
||||
|
||||
// If the title is null or empty but not the url, a shortened form of the url is returned.
|
||||
assertEquals("example.com/foo/bar",
|
||||
TitleUtil.getTitleForDisplay(null, "https://example.com/foo/bar"));
|
||||
assertEquals("example.com", TitleUtil.getTitleForDisplay(null, "https://example.com/"));
|
||||
assertEquals("foo/bar", TitleUtil.getTitleForDisplay(null, "foo/bar"));
|
||||
assertEquals("", TitleUtil.getTitleForDisplay(null, "/"));
|
||||
TitleUtil.getTitleForDisplay(null, new GURL("https://example.com/foo/bar")));
|
||||
assertEquals("example.com",
|
||||
TitleUtil.getTitleForDisplay(null, new GURL("https://example.com/")));
|
||||
assertEquals("foo/bar", TitleUtil.getTitleForDisplay(null, new GURL("file://foo/bar")));
|
||||
assertEquals(null, TitleUtil.getTitleForDisplay(null, new GURL("/")));
|
||||
assertEquals("", TitleUtil.getTitleForDisplay("", new GURL("/")));
|
||||
}
|
||||
}
|
@ -29,6 +29,7 @@ import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||
import org.chromium.content_public.browser.test.util.Criteria;
|
||||
import org.chromium.content_public.browser.test.util.CriteriaHelper;
|
||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -69,7 +70,7 @@ public class MostVisitedSitesFaviconHelperTest {
|
||||
@MediumTest
|
||||
public void testSaveFaviconsToFile() {
|
||||
// Add sites' URLs into the urlsToUpdate, except the last one.
|
||||
Set<String> urlsToUpdate = new HashSet<>();
|
||||
Set<GURL> urlsToUpdate = new HashSet<>();
|
||||
for (int i = 0; i < mExpectedSiteSuggestions.size() - 1; i++) {
|
||||
urlsToUpdate.add(mExpectedSiteSuggestions.get(i).url);
|
||||
}
|
||||
@ -106,16 +107,16 @@ public class MostVisitedSitesFaviconHelperTest {
|
||||
private static List<SiteSuggestion> createFakeSiteSuggestions() {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
|
||||
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", "https://www.foo.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", new GURL("https://www.foo.com"), "",
|
||||
TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", "https://www.bar.com",
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", new GURL("https://www.bar.com"),
|
||||
"/not_exist.png", TileTitleSource.UNKNOWN, TileSource.WHITELIST,
|
||||
TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES", "https://www.baz.com",
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES", new GURL("https://www.baz.com"),
|
||||
createBitmapAndWriteToFile(), TileTitleSource.UNKNOWN, TileSource.WHITELIST,
|
||||
TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("3 TOP_SITES", "https://www.qux.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("3 TOP_SITES", new GURL("https://www.qux.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.WHITELIST, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.get(0).faviconId = 0;
|
||||
|
@ -29,6 +29,7 @@ import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
||||
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||
import org.chromium.content_public.browser.test.util.CriteriaHelper;
|
||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@ -62,32 +63,36 @@ public class MostVisitedSitesHostTest {
|
||||
@Test
|
||||
@SmallTest
|
||||
public void testNextAvailableId() {
|
||||
Set<String> newTopSiteUrls = new HashSet<>();
|
||||
Set<GURL> newTopSiteUrls = new HashSet<>();
|
||||
GURL url0 = new GURL("https://www.0.com");
|
||||
GURL url1 = new GURL("https://www.1.com");
|
||||
GURL url2 = new GURL("https://www.2.com");
|
||||
GURL url3 = new GURL("https://www.3.com");
|
||||
|
||||
// Update map and set.
|
||||
newTopSiteUrls.add("https://www.0.com");
|
||||
newTopSiteUrls.add("https://www.1.com");
|
||||
newTopSiteUrls.add(url0);
|
||||
newTopSiteUrls.add(url1);
|
||||
mMostVisitedSitesHost.getUrlsToUpdateFaviconForTesting().addAll(newTopSiteUrls);
|
||||
|
||||
// The next available ID should be 0.
|
||||
assertEquals(0, mMostVisitedSitesHost.getNextAvailableId(0, newTopSiteUrls));
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put("https://www.0.com", 0);
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put(url0, 0);
|
||||
mMostVisitedSitesHost.buildIdToUrlMap();
|
||||
|
||||
// The next available ID should be 1.
|
||||
assertEquals(1, mMostVisitedSitesHost.getNextAvailableId(1, newTopSiteUrls));
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put("https://www.1.com", 1);
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put(url1, 1);
|
||||
mMostVisitedSitesHost.buildIdToUrlMap();
|
||||
|
||||
// Create a new batch of SiteSuggestions.
|
||||
newTopSiteUrls.clear();
|
||||
newTopSiteUrls.add("https://www.0.com");
|
||||
newTopSiteUrls.add("https://www.2.com");
|
||||
newTopSiteUrls.add("https://www.3.com");
|
||||
newTopSiteUrls.add(url0);
|
||||
newTopSiteUrls.add(url2);
|
||||
newTopSiteUrls.add(url3);
|
||||
|
||||
// The next available ID should be ID for "https://www.1.com".
|
||||
assertEquals(1, mMostVisitedSitesHost.getNextAvailableId(0, newTopSiteUrls));
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put("https://www.2.com", 1);
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().put(url2, 1);
|
||||
|
||||
// After setting 1 to "https://www.2.com", the next available ID should be 2.
|
||||
assertEquals(2, mMostVisitedSitesHost.getNextAvailableId(2, newTopSiteUrls));
|
||||
@ -96,11 +101,13 @@ public class MostVisitedSitesHostTest {
|
||||
@Test
|
||||
@SmallTest
|
||||
public void testUpdateMapAndSet() {
|
||||
GURL url0 = new GURL("https://www.0.com");
|
||||
GURL url2 = new GURL("https://www.2.com");
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().clear();
|
||||
mMostVisitedSitesHost.getUrlsToUpdateFaviconForTesting().clear();
|
||||
mMostVisitedSitesHost.getIdToUrlMapForTesting().clear();
|
||||
|
||||
Set<String> newUrls;
|
||||
Set<GURL> newUrls;
|
||||
Set<Integer> expectedIdsInMap = new HashSet<>();
|
||||
AtomicBoolean isUpdated = new AtomicBoolean(false);
|
||||
|
||||
@ -117,10 +124,12 @@ public class MostVisitedSitesHostTest {
|
||||
checkMapAndSet(newUrls, newUrls, expectedIdsInMap, newTopSites);
|
||||
|
||||
// Record ID of "https://www.0.com" for checking later.
|
||||
int expectedId0 = mMostVisitedSitesHost.getUrlToIDMapForTesting().get("https://www.0.com");
|
||||
int expectedId0 =
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().get(new GURL("https://www.0.com"));
|
||||
|
||||
// Emulate saving favicons for the first batch of sites except "https://www.2.com".
|
||||
int expectedId2 = mMostVisitedSitesHost.getUrlToIDMapForTesting().get("https://www.2.com");
|
||||
int expectedId2 =
|
||||
mMostVisitedSitesHost.getUrlToIDMapForTesting().get(new GURL("https://www.2.com"));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (i == expectedId2) {
|
||||
continue;
|
||||
@ -136,14 +145,12 @@ public class MostVisitedSitesHostTest {
|
||||
CriteriaHelper.pollInstrumentationThread(isUpdated::get);
|
||||
|
||||
// Check the map and set.
|
||||
Set<String> expectedUrlsToFetchIcon = new HashSet<>(newUrls);
|
||||
expectedUrlsToFetchIcon.remove("https://www.0.com");
|
||||
Set<GURL> expectedUrlsToFetchIcon = new HashSet<>(newUrls);
|
||||
expectedUrlsToFetchIcon.remove(url0);
|
||||
expectedIdsInMap.add(3);
|
||||
checkMapAndSet(expectedUrlsToFetchIcon, newUrls, expectedIdsInMap, newTopSites);
|
||||
assertEquals(expectedId0,
|
||||
(int) mMostVisitedSitesHost.getUrlToIDMapForTesting().get("https://www.0.com"));
|
||||
assertEquals(expectedId2,
|
||||
(int) mMostVisitedSitesHost.getUrlToIDMapForTesting().get("https://www.2.com"));
|
||||
assertEquals(expectedId0, (int) mMostVisitedSitesHost.getUrlToIDMapForTesting().get(url0));
|
||||
assertEquals(expectedId2, (int) mMostVisitedSitesHost.getUrlToIDMapForTesting().get(url2));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -217,7 +224,7 @@ public class MostVisitedSitesHostTest {
|
||||
CriteriaHelper.pollInstrumentationThread(isPendingRun::get);
|
||||
}
|
||||
|
||||
private void checkMapAndSet(Set<String> expectedUrlsToFetchIcon, Set<String> expectedUrlsInMap,
|
||||
private void checkMapAndSet(Set<GURL> expectedUrlsToFetchIcon, Set<GURL> expectedUrlsInMap,
|
||||
Set<Integer> expectedIdsInMap, List<SiteSuggestion> newSiteSuggestions) {
|
||||
// Check whether mExpectedSiteSuggestions' faviconIDs have been updated.
|
||||
for (SiteSuggestion siteData : newSiteSuggestions) {
|
||||
@ -225,8 +232,8 @@ public class MostVisitedSitesHostTest {
|
||||
siteData.faviconId);
|
||||
}
|
||||
|
||||
Set<String> urlsToUpdateFavicon = mMostVisitedSitesHost.getUrlsToUpdateFaviconForTesting();
|
||||
Map<String, Integer> urlToIDMap = mMostVisitedSitesHost.getUrlToIDMapForTesting();
|
||||
Set<GURL> urlsToUpdateFavicon = mMostVisitedSitesHost.getUrlsToUpdateFaviconForTesting();
|
||||
Map<GURL, Integer> urlToIDMap = mMostVisitedSitesHost.getUrlToIDMapForTesting();
|
||||
|
||||
assertEquals(expectedUrlsToFetchIcon, urlsToUpdateFavicon);
|
||||
assertThat(expectedUrlsInMap, containsInAnyOrder(urlToIDMap.keySet().toArray()));
|
||||
@ -235,37 +242,37 @@ public class MostVisitedSitesHostTest {
|
||||
|
||||
private static List<SiteSuggestion> createFakeSiteSuggestions1() {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", "https://www.0.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", new GURL("https://www.0.com"), "",
|
||||
TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(
|
||||
new SiteSuggestion("1 WHITELIST", "https://www.1.com", "", TileTitleSource.UNKNOWN,
|
||||
TileSource.WHITELIST, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(
|
||||
new SiteSuggestion("2 TOP_SITES", "https://www.2.com", "", TileTitleSource.UNKNOWN,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", new GURL("https://www.1.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.WHITELIST, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES", new GURL("https://www.2.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
return siteSuggestions;
|
||||
}
|
||||
|
||||
private static List<SiteSuggestion> createFakeSiteSuggestions2() {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", "https://www.0.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", new GURL("https://www.0.com"), "",
|
||||
TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(
|
||||
new SiteSuggestion("2 TOP_SITES", "https://www.2.com", "", TileTitleSource.UNKNOWN,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(
|
||||
new SiteSuggestion("3 TOP_SITES", "https://www.3.com", "", TileTitleSource.UNKNOWN,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(
|
||||
new SiteSuggestion("4 TOP_SITES", "https://www.4.com", "", TileTitleSource.UNKNOWN,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES", new GURL("https://www.2.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("3 TOP_SITES", new GURL("https://www.3.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("4 TOP_SITES", new GURL("https://www.4.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
return siteSuggestions;
|
||||
}
|
||||
|
||||
private Set<String> getUrls(List<SiteSuggestion> newSuggestions) {
|
||||
Set<String> newTopSiteUrls = new HashSet<>();
|
||||
private Set<GURL> getUrls(List<SiteSuggestion> newSuggestions) {
|
||||
Set<GURL> newTopSiteUrls = new HashSet<>();
|
||||
for (SiteSuggestion topSiteData : newSuggestions) {
|
||||
newTopSiteUrls.add(topSiteData.url);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import org.chromium.chrome.browser.suggestions.tile.TileSource;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileTitleSource;
|
||||
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
|
||||
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -84,10 +85,10 @@ public class MostVisitedSitesMetadataUtilsTest {
|
||||
|
||||
private static List<SiteSuggestion> createFakeSiteSuggestions() {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", "https://www.foo.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", new GURL("https://www.foo.com"), "",
|
||||
TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", "https://www.bar.com", "",
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", new GURL("https://www.bar.com"), "",
|
||||
TileTitleSource.UNKNOWN, TileSource.WHITELIST, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.get(1).faviconId = 1;
|
||||
|
13
chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java
13
chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/tile/TileGridLayoutTest.java
@ -66,6 +66,7 @@ import org.chromium.net.test.EmbeddedTestServerRule;
|
||||
import org.chromium.ui.base.ViewUtils;
|
||||
import org.chromium.ui.modelutil.ListObservable;
|
||||
import org.chromium.ui.test.util.NightModeTestUtils;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@ -191,7 +192,7 @@ public class TileGridLayoutTest {
|
||||
public void testTileAppearanceModern(boolean nightModeEnabled)
|
||||
throws IOException, InterruptedException, TimeoutException {
|
||||
List<SiteSuggestion> suggestions = makeSuggestions(2);
|
||||
List<String> offlineAvailableUrls = Collections.singletonList(suggestions.get(0).url);
|
||||
List<GURL> offlineAvailableUrls = Collections.singletonList(suggestions.get(0).url);
|
||||
ViewGroup tiles = renderTiles(suggestions, offlineAvailableUrls);
|
||||
|
||||
mLoadCompleteHelper.waitForCallback(0);
|
||||
@ -277,8 +278,8 @@ public class TileGridLayoutTest {
|
||||
* Starts and sets up an activity to render the provided site suggestions in the activity.
|
||||
* @return the layout in which the suggestions are rendered.
|
||||
*/
|
||||
private TileGridLayout renderTiles(List<SiteSuggestion> siteSuggestions,
|
||||
List<String> offlineUrls) throws InterruptedException {
|
||||
private TileGridLayout renderTiles(List<SiteSuggestion> siteSuggestions, List<GURL> offlineUrls)
|
||||
throws InterruptedException {
|
||||
// Launching the activity, that should now use the right UI.
|
||||
mActivityTestRule.startMainActivityOnBlankPage();
|
||||
ChromeActivity activity = mActivityTestRule.getActivity();
|
||||
@ -316,7 +317,7 @@ public class TileGridLayoutTest {
|
||||
}
|
||||
|
||||
private SiteSection createSiteSection(
|
||||
final SiteSectionViewHolder viewHolder, UiConfig uiConfig, List<String> offlineUrls) {
|
||||
final SiteSectionViewHolder viewHolder, UiConfig uiConfig, List<GURL> offlineUrls) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
ChromeActivity activity = mActivityTestRule.getActivity();
|
||||
@ -329,8 +330,8 @@ public class TileGridLayoutTest {
|
||||
FakeOfflinePageBridge offlinePageBridge = new FakeOfflinePageBridge();
|
||||
List<OfflinePageItem> offlinePageItems = new ArrayList<>();
|
||||
for (int i = 0; i < offlineUrls.size(); i++) {
|
||||
offlinePageItems.add(
|
||||
FakeOfflinePageBridge.createOfflinePageItem(offlineUrls.get(i), i + 1L));
|
||||
offlinePageItems.add(FakeOfflinePageBridge.createOfflinePageItem(
|
||||
offlineUrls.get(i).getSpec(), i + 1L));
|
||||
}
|
||||
offlinePageBridge.setItems(offlinePageItems);
|
||||
offlinePageBridge.setIsOfflinePageModelLoaded(true);
|
||||
|
@ -45,6 +45,7 @@ import org.chromium.content_public.browser.test.util.CriteriaHelper;
|
||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||
import org.chromium.content_public.browser.test.util.TestTouchUtils;
|
||||
import org.chromium.net.test.EmbeddedTestServer;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -113,7 +114,7 @@ public class TileGroupTest {
|
||||
|
||||
// Dismiss the tile using the context menu.
|
||||
invokeContextMenu(tileView, ContextMenuManager.ContextMenuItemId.REMOVE);
|
||||
Assert.assertTrue(mMostVisitedSites.isUrlBlocklisted(mSiteSuggestionUrls[0]));
|
||||
Assert.assertTrue(mMostVisitedSites.isUrlBlocklisted(new GURL(mSiteSuggestionUrls[0])));
|
||||
|
||||
// Ensure that the removal is reflected in the ui.
|
||||
Assert.assertEquals(3, getTileGridLayout().getChildCount());
|
||||
@ -146,6 +147,9 @@ public class TileGroupTest {
|
||||
@MediumTest
|
||||
@Feature({"NewTabPage"})
|
||||
public void testDismissTileUndo() throws Exception {
|
||||
GURL url0 = new GURL(mSiteSuggestionUrls[0]);
|
||||
GURL url1 = new GURL(mSiteSuggestionUrls[1]);
|
||||
GURL url2 = new GURL(mSiteSuggestionUrls[2]);
|
||||
SiteSuggestion siteToDismiss = mMostVisitedSites.getCurrentSites().get(0);
|
||||
final ViewGroup tileContainer = getTileGridLayout();
|
||||
final View tileView = getTileViewFor(siteToDismiss);
|
||||
@ -162,10 +166,10 @@ public class TileGroupTest {
|
||||
Assert.assertEquals(2, tileContainer.getChildCount());
|
||||
final View snackbarButton = waitForSnackbar(mActivityTestRule.getActivity());
|
||||
|
||||
Assert.assertTrue(mMostVisitedSites.isUrlBlocklisted(mSiteSuggestionUrls[0]));
|
||||
Assert.assertTrue(mMostVisitedSites.isUrlBlocklisted(url0));
|
||||
TestThreadUtils.runOnUiThreadBlocking(() -> { snackbarButton.callOnClick(); });
|
||||
|
||||
Assert.assertFalse(mMostVisitedSites.isUrlBlocklisted(mSiteSuggestionUrls[0]));
|
||||
Assert.assertFalse(mMostVisitedSites.isUrlBlocklisted(url0));
|
||||
|
||||
// Ensure that the removal of the update goes through.
|
||||
TestThreadUtils.runOnUiThreadBlocking(
|
||||
@ -259,8 +263,8 @@ public class TileGroupTest {
|
||||
new ArrayList<>(mMostVisitedSites.getCurrentSites());
|
||||
|
||||
SiteSuggestion exploreTile = new SiteSuggestion("chrome-native://explore",
|
||||
"chrome-native://explore", "", TileTitleSource.UNKNOWN, TileSource.EXPLORE,
|
||||
TileSectionType.PERSONALIZED, new Date());
|
||||
new GURL("chrome-native://explore"), "", TileTitleSource.UNKNOWN,
|
||||
TileSource.EXPLORE, TileSectionType.PERSONALIZED, new Date());
|
||||
currentSuggestions.add(exploreTile);
|
||||
TestThreadUtils.runOnUiThreadBlocking(
|
||||
() -> mMostVisitedSites.setTileSuggestions(currentSuggestions));
|
||||
|
@ -13,7 +13,6 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.times;
|
||||
@ -24,10 +23,13 @@ import static org.mockito.Mockito.when;
|
||||
import static org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites.createSiteSuggestion;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.graphics.Color;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@ -37,10 +39,11 @@ import org.junit.rules.TestRule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.robolectric.RuntimeEnvironment;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import org.chromium.base.test.BaseRobolectricTestRunner;
|
||||
import org.chromium.base.ContextUtils;
|
||||
import org.chromium.base.test.BaseJUnit4ClassRunner;
|
||||
import org.chromium.base.test.UiThreadTest;
|
||||
import org.chromium.base.test.util.Batch;
|
||||
import org.chromium.chrome.browser.native_page.ContextMenuManager;
|
||||
import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters;
|
||||
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
|
||||
@ -53,6 +56,7 @@ import org.chromium.chrome.browser.ui.favicon.IconType;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge.LargeIconCallback;
|
||||
import org.chromium.chrome.test.util.browser.Features;
|
||||
import org.chromium.chrome.test.util.browser.suggestions.mostvisited.FakeMostVisitedSites;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -61,12 +65,12 @@ import java.util.List;
|
||||
/**
|
||||
* Unit tests for {@link TileGroup}.
|
||||
*/
|
||||
@RunWith(BaseRobolectricTestRunner.class)
|
||||
@Config(manifest = Config.NONE)
|
||||
@RunWith(BaseJUnit4ClassRunner.class)
|
||||
@Batch(Batch.UNIT_TESTS)
|
||||
public class TileGroupUnitTest {
|
||||
private static final int MAX_TILES_TO_FETCH = 4;
|
||||
private static final int TILE_TITLE_LINES = 1;
|
||||
private static final String[] URLS = {"https://www.google.com", "https://tellmedadjokes.com"};
|
||||
private static final String[] URLS = {"https://www.google.com/", "https://tellmedadjokes.com/"};
|
||||
|
||||
@Rule
|
||||
public TestRule mFeaturesProcessor = new Features.JUnitProcessor();
|
||||
@ -75,6 +79,18 @@ public class TileGroupUnitTest {
|
||||
private TileGroup.Observer mTileGroupObserver;
|
||||
@Mock
|
||||
private TileGroup.Delegate mTileGroupDelegate;
|
||||
@Mock
|
||||
private SuggestionsUiDelegate mSuggestionsUiDelegate;
|
||||
@Mock
|
||||
private ContextMenuManager mContextMenuManager;
|
||||
@Mock
|
||||
private OfflinePageBridge mOfflinePageBridge;
|
||||
@Mock
|
||||
private ImageFetcher mMockImageFetcher;
|
||||
@Mock
|
||||
private SuggestionsTileView mSuggestionsTileView1;
|
||||
@Mock
|
||||
private SuggestionsTileView mSuggestionsTileView2;
|
||||
|
||||
private FakeMostVisitedSites mMostVisitedSites;
|
||||
private FakeImageFetcher mImageFetcher;
|
||||
@ -86,8 +102,8 @@ public class TileGroupUnitTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mImageFetcher = new FakeImageFetcher();
|
||||
mTileRenderer = new TileRenderer(
|
||||
RuntimeEnvironment.application, TileStyle.MODERN, TILE_TITLE_LINES, mImageFetcher);
|
||||
mTileRenderer = new TileRenderer(ContextUtils.getApplicationContext(), TileStyle.MODERN,
|
||||
TILE_TITLE_LINES, mImageFetcher);
|
||||
mMostVisitedSites = new FakeMostVisitedSites();
|
||||
|
||||
doAnswer(invocation -> {
|
||||
@ -105,12 +121,13 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testInitialiseWithTileList() {
|
||||
mMostVisitedSites.setTileSuggestions(URLS);
|
||||
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mock(SuggestionsUiDelegate.class),
|
||||
mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
|
||||
mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mSuggestionsUiDelegate,
|
||||
mContextMenuManager, mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
verify(mTileGroupObserver).onTileCountChanged();
|
||||
@ -126,10 +143,11 @@ public class TileGroupUnitTest {
|
||||
* event though the data did not change (still empty just like before initialisation).
|
||||
*/
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testInitialiseWithEmptyTileList() {
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mock(SuggestionsUiDelegate.class),
|
||||
mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
|
||||
mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mSuggestionsUiDelegate,
|
||||
mContextMenuManager, mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
verify(mTileGroupObserver).onTileCountChanged();
|
||||
@ -141,6 +159,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testReceiveNewTilesWithoutChanges() {
|
||||
TileGroup tileGroup = initialiseTileGroup(URLS);
|
||||
|
||||
@ -153,6 +173,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testReceiveNewTilesWithoutChanges_TrackLoad() {
|
||||
TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
|
||||
|
||||
@ -166,12 +188,14 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testReceiveNewTilesWithDataChanges() {
|
||||
TileGroup tileGroup = initialiseTileGroup(URLS);
|
||||
|
||||
// Notify the about different URLs, but the same number. #onTileCountChanged() should not be
|
||||
// called.
|
||||
mMostVisitedSites.setTileSuggestions("foo", "bar");
|
||||
mMostVisitedSites.setTileSuggestions("http://foo.com", "http://bar.com");
|
||||
|
||||
verify(mTileGroupObserver, never()).onTileCountChanged(); // Tile count is still 2.
|
||||
verify(mTileGroupObserver).onTileDataChanged(); // Data DID change.
|
||||
@ -182,12 +206,14 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testReceiveNewTilesWithDataChanges_TrackLoad() {
|
||||
TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true, URLS);
|
||||
|
||||
// Notify the about different URLs, but the same number. #onTileCountChanged() should not be
|
||||
// called.
|
||||
mMostVisitedSites.setTileSuggestions("foo", "bar");
|
||||
mMostVisitedSites.setTileSuggestions("http://foo.com", "http://bar.com");
|
||||
tileGroup.onSwitchToForeground(/* trackLoadTask: */ true);
|
||||
|
||||
verify(mTileGroupObserver).onTileDataChanged(); // Now data DID change.
|
||||
@ -199,6 +225,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testReceiveNewTilesWithCountChanges() {
|
||||
TileGroup tileGroup = initialiseTileGroup(URLS);
|
||||
|
||||
@ -212,12 +240,13 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testTileLoadingWhenVisibleNotBlockedForInit() {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
|
||||
when(uiDelegate.isVisible()).thenReturn(true);
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, uiDelegate, mContextMenuManager,
|
||||
mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
mMostVisitedSites.setTileSuggestions(URLS);
|
||||
@ -227,12 +256,13 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testTileLoadingWhenVisibleBlocked() {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
|
||||
when(uiDelegate.isVisible()).thenReturn(true);
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, uiDelegate, mContextMenuManager,
|
||||
mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
mMostVisitedSites.setTileSuggestions(URLS);
|
||||
@ -251,6 +281,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testTileLoadingWhenVisibleBlocked_2() {
|
||||
TileGroup tileGroup = initialiseTileGroup(true, URLS);
|
||||
|
||||
@ -267,12 +299,13 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testRenderTileView() {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, uiDelegate, mContextMenuManager,
|
||||
mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
TileGridViewHolder tileGrid = setupView(tileGroup);
|
||||
@ -284,18 +317,19 @@ public class TileGroupUnitTest {
|
||||
// Render them to the layout.
|
||||
tileGrid.refreshData();
|
||||
assertThat(layout.getChildCount(), is(2));
|
||||
assertThat(((SuggestionsTileView) layout.getChildAt(0)).getUrl(), is(URLS[0]));
|
||||
assertThat(((SuggestionsTileView) layout.getChildAt(1)).getUrl(), is(URLS[1]));
|
||||
assertThat(((SuggestionsTileView) layout.getChildAt(0)).getUrl().getSpec(), is(URLS[0]));
|
||||
assertThat(((SuggestionsTileView) layout.getChildAt(1)).getUrl().getSpec(), is(URLS[1]));
|
||||
}
|
||||
|
||||
/** Check for https://crbug.com/703628: don't crash on duplicated URLs. */
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testRenderTileViewWithDuplicatedUrl() {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mMockImageFetcher);
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, uiDelegate, mContextMenuManager,
|
||||
mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
TileGridViewHolder tileGrid = setupView(tileGroup);
|
||||
|
||||
@ -307,22 +341,23 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testRenderTileViewReplacing() {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mock(ImageFetcher.class));
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
SuggestionsUiDelegate uiDelegate = mSuggestionsUiDelegate;
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mMockImageFetcher);
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, uiDelegate, mContextMenuManager,
|
||||
mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
mMostVisitedSites.setTileSuggestions(URLS);
|
||||
|
||||
// Initialise the layout with views whose URLs don't match the ones of the new tiles.
|
||||
TileGridViewHolder tileGrid = setupView(tileGroup);
|
||||
TileGridLayout layout = (TileGridLayout) tileGrid.itemView;
|
||||
SuggestionsTileView view1 = mock(SuggestionsTileView.class);
|
||||
SuggestionsTileView view1 = mSuggestionsTileView1;
|
||||
layout.addView(view1);
|
||||
|
||||
SuggestionsTileView view2 = mock(SuggestionsTileView.class);
|
||||
SuggestionsTileView view2 = mSuggestionsTileView2;
|
||||
layout.addView(view2);
|
||||
|
||||
// The tiles should be updated, the old ones removed.
|
||||
@ -333,21 +368,22 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testRenderTileViewRecycling() {
|
||||
mMostVisitedSites.setTileSuggestions(URLS);
|
||||
List<SiteSuggestion> sites = mMostVisitedSites.getCurrentSites();
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mock(SuggestionsUiDelegate.class),
|
||||
mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
|
||||
mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mSuggestionsUiDelegate,
|
||||
mContextMenuManager, mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
|
||||
// Initialise the layout with views whose URLs match the ones of the new tiles.
|
||||
TileGridLayout layout = new TileGridLayout(RuntimeEnvironment.application, null);
|
||||
SuggestionsTileView view1 = mock(SuggestionsTileView.class);
|
||||
TileGridLayout layout = new TileGridLayout(ContextUtils.getApplicationContext(), null);
|
||||
SuggestionsTileView view1 = mSuggestionsTileView1;
|
||||
when(view1.getData()).thenReturn(sites.get(0));
|
||||
layout.addView(view1);
|
||||
|
||||
SuggestionsTileView view2 = mock(SuggestionsTileView.class);
|
||||
SuggestionsTileView view2 = mSuggestionsTileView2;
|
||||
when(view2.getData()).thenReturn(sites.get(1));
|
||||
layout.addView(view2);
|
||||
|
||||
@ -359,6 +395,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testIconLoadingForInit() {
|
||||
TileGroup tileGroup = initialiseTileGroup(URLS);
|
||||
Tile tile = tileGroup.getTileSections().get(TileSectionType.PERSONALIZED).get(0);
|
||||
@ -375,11 +413,13 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testIconLoadingWhenTileNotRegistered() {
|
||||
TileGroup tileGroup = initialiseTileGroup();
|
||||
Tile tile = new Tile(createSiteSuggestion("title", URLS[0]), 0);
|
||||
|
||||
ViewGroup layout = new FrameLayout(RuntimeEnvironment.application, null);
|
||||
ViewGroup layout = new FrameLayout(ContextUtils.getApplicationContext(), null);
|
||||
mTileRenderer.buildTileView(tile, layout, tileGroup.getTileSetupDelegate());
|
||||
|
||||
// Ensure we run the callback for the new tile.
|
||||
@ -390,13 +430,15 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
private TileGridViewHolder setupView(TileGroup tileGroup) {
|
||||
TileGridLayout layout = new TileGridLayout(RuntimeEnvironment.application, null);
|
||||
TileGridLayout layout = new TileGridLayout(ContextUtils.getApplicationContext(), null);
|
||||
TileGridViewHolder tileGrid = new TileGridViewHolder(layout, 4, 2);
|
||||
tileGrid.bindDataSource(tileGroup, mTileRenderer);
|
||||
return tileGrid;
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testIconLoading_Sync() {
|
||||
TileGroup tileGroup = initialiseTileGroup();
|
||||
mImageFetcher.fulfillLargeIconRequests();
|
||||
@ -414,6 +456,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testIconLoading_AsyncNoTrack() {
|
||||
TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
|
||||
mImageFetcher.fulfillLargeIconRequests();
|
||||
@ -432,6 +476,8 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@UiThreadTest
|
||||
@SmallTest
|
||||
public void testIconLoading_AsyncTrack() {
|
||||
TileGroup tileGroup = initialiseTileGroup(/* deferLoad: */ true);
|
||||
mImageFetcher.fulfillLargeIconRequests();
|
||||
@ -461,15 +507,13 @@ public class TileGroupUnitTest {
|
||||
* @param urls URLs used to initialise the tile group.
|
||||
*/
|
||||
private TileGroup initialiseTileGroup(boolean deferLoad, String... urls) {
|
||||
SuggestionsUiDelegate uiDelegate = mock(SuggestionsUiDelegate.class);
|
||||
when(uiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
|
||||
when(uiDelegate.isVisible()).thenReturn(deferLoad);
|
||||
when(mSuggestionsUiDelegate.getImageFetcher()).thenReturn(mImageFetcher);
|
||||
when(mSuggestionsUiDelegate.isVisible()).thenReturn(deferLoad);
|
||||
|
||||
mMostVisitedSites.setTileSuggestions(urls);
|
||||
|
||||
TileGroup tileGroup =
|
||||
new TileGroup(mTileRenderer, uiDelegate, mock(ContextMenuManager.class),
|
||||
mTileGroupDelegate, mTileGroupObserver, mock(OfflinePageBridge.class));
|
||||
TileGroup tileGroup = new TileGroup(mTileRenderer, mSuggestionsUiDelegate,
|
||||
mContextMenuManager, mTileGroupDelegate, mTileGroupObserver, mOfflinePageBridge);
|
||||
tileGroup.startObserving(MAX_TILES_TO_FETCH);
|
||||
setupView(tileGroup).refreshData();
|
||||
|
||||
@ -486,7 +530,7 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void makeLargeIconRequest(String url, int size, LargeIconCallback callback) {
|
||||
public void makeLargeIconRequest(GURL url, int size, LargeIconCallback callback) {
|
||||
mCallbackList.add(callback);
|
||||
}
|
||||
|
||||
@ -502,7 +546,7 @@ public class TileGroupUnitTest {
|
||||
}
|
||||
|
||||
public void fulfillLargeIconRequests() {
|
||||
fulfillLargeIconRequests(mock(Bitmap.class), Color.BLACK, false);
|
||||
fulfillLargeIconRequests(Bitmap.createBitmap(1, 1, Config.ALPHA_8), Color.BLACK, false);
|
||||
}
|
||||
}
|
||||
}
|
@ -24,6 +24,8 @@ import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge;
|
||||
import org.chromium.chrome.browser.ui.favicon.LargeIconBridge.LargeIconCallback;
|
||||
import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
|
||||
import org.chromium.url.GURL;
|
||||
import org.chromium.url.JUnitTestGURLs;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@ -34,7 +36,7 @@ import java.util.HashMap;
|
||||
@Config(manifest = Config.NONE)
|
||||
public class SuggestionsImageFetcherTest {
|
||||
public static final int IMAGE_SIZE_PX = 100;
|
||||
public static final String URL_STRING = "http://www.test.com";
|
||||
public static final GURL URL = JUnitTestGURLs.getGURL(JUnitTestGURLs.EXAMPLE_URL);
|
||||
|
||||
@Rule
|
||||
public SuggestionsDependenciesRule mSuggestionsDeps = new SuggestionsDependenciesRule();
|
||||
@ -57,10 +59,9 @@ public class SuggestionsImageFetcherTest {
|
||||
public void testLargeIconFetch() {
|
||||
ImageFetcher imageFetcher = new ImageFetcher(mock(Profile.class));
|
||||
|
||||
imageFetcher.makeLargeIconRequest(URL_STRING, IMAGE_SIZE_PX, mock(LargeIconCallback.class));
|
||||
imageFetcher.makeLargeIconRequest(URL, IMAGE_SIZE_PX, mock(LargeIconCallback.class));
|
||||
|
||||
verify(mLargeIconBridge)
|
||||
.getLargeIconForStringUrl(
|
||||
eq(URL_STRING), eq(IMAGE_SIZE_PX), any(LargeIconCallback.class));
|
||||
.getLargeIconForUrl(eq(URL), eq(IMAGE_SIZE_PX), any(LargeIconCallback.class));
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "components/ntp_tiles/most_visited_sites.h"
|
||||
#include "components/ntp_tiles/section_type.h"
|
||||
#include "ui/gfx/android/java_bitmap.h"
|
||||
#include "url/android/gurl_android.h"
|
||||
|
||||
using base::android::AttachCurrentThread;
|
||||
using base::android::ConvertJavaStringToUTF8;
|
||||
@ -151,7 +152,7 @@ void MostVisitedSitesBridge::JavaObserver::OnURLsAvailable(
|
||||
const std::map<SectionType, NTPTilesVector>& sections) {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
std::vector<base::string16> titles;
|
||||
std::vector<std::string> urls;
|
||||
std::vector<base::android::ScopedJavaLocalRef<jobject>> urls;
|
||||
std::vector<std::string> whitelist_icons;
|
||||
std::vector<int> title_sources;
|
||||
std::vector<int> sources;
|
||||
@ -163,7 +164,7 @@ void MostVisitedSitesBridge::JavaObserver::OnURLsAvailable(
|
||||
static_cast<int>(section.first));
|
||||
for (const auto& tile : tiles) {
|
||||
titles.emplace_back(tile.title);
|
||||
urls.emplace_back(tile.url.spec());
|
||||
urls.emplace_back(url::GURLAndroid::FromNativeGURL(env, tile.url));
|
||||
whitelist_icons.emplace_back(tile.whitelist_icon_path.value());
|
||||
title_sources.emplace_back(static_cast<int>(tile.title_source));
|
||||
sources.emplace_back(static_cast<int>(tile.source));
|
||||
@ -173,7 +174,8 @@ void MostVisitedSitesBridge::JavaObserver::OnURLsAvailable(
|
||||
}
|
||||
Java_MostVisitedSitesBridge_onURLsAvailable(
|
||||
env, observer_, ToJavaArrayOfStrings(env, titles),
|
||||
ToJavaArrayOfStrings(env, urls), ToJavaIntArray(env, section_types),
|
||||
url::GURLAndroid::ToJavaArrayOfGURLs(env, urls),
|
||||
ToJavaIntArray(env, section_types),
|
||||
ToJavaArrayOfStrings(env, whitelist_icons),
|
||||
ToJavaIntArray(env, title_sources), ToJavaIntArray(env, sources),
|
||||
ToJavaLongArray(env, data_generation_times));
|
||||
@ -183,7 +185,7 @@ void MostVisitedSitesBridge::JavaObserver::OnIconMadeAvailable(
|
||||
const GURL& site_url) {
|
||||
JNIEnv* env = AttachCurrentThread();
|
||||
Java_MostVisitedSitesBridge_onIconMadeAvailable(
|
||||
env, observer_, ConvertUTF8ToJavaString(env, site_url.spec()));
|
||||
env, observer_, url::GURLAndroid::FromNativeGURL(env, site_url));
|
||||
}
|
||||
|
||||
MostVisitedSitesBridge::MostVisitedSitesBridge(Profile* profile)
|
||||
@ -225,10 +227,10 @@ void MostVisitedSitesBridge::SetObserver(
|
||||
void MostVisitedSitesBridge::AddOrRemoveBlockedUrl(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& obj,
|
||||
const JavaParamRef<jstring>& j_url,
|
||||
const JavaParamRef<jobject>& j_url,
|
||||
jboolean add_url) {
|
||||
GURL url(ConvertJavaStringToUTF8(env, j_url));
|
||||
most_visited_->AddOrRemoveBlockedUrl(url, add_url);
|
||||
std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, j_url);
|
||||
most_visited_->AddOrRemoveBlockedUrl(*url, add_url);
|
||||
}
|
||||
|
||||
void MostVisitedSitesBridge::RecordPageImpression(
|
||||
@ -247,8 +249,8 @@ void MostVisitedSitesBridge::RecordTileImpression(
|
||||
jint jtitle_source,
|
||||
jint jsource,
|
||||
jlong jdata_generation_time_ms,
|
||||
const JavaParamRef<jstring>& jurl) {
|
||||
GURL url(ConvertJavaStringToUTF8(env, jurl));
|
||||
const JavaParamRef<jobject>& jurl) {
|
||||
std::unique_ptr<GURL> url = url::GURLAndroid::ToNativeGURL(env, jurl);
|
||||
TileTitleSource title_source = static_cast<TileTitleSource>(jtitle_source);
|
||||
TileSource source = static_cast<TileSource>(jsource);
|
||||
TileVisualType visual_type = static_cast<TileVisualType>(jvisual_type);
|
||||
@ -257,7 +259,7 @@ void MostVisitedSitesBridge::RecordTileImpression(
|
||||
|
||||
ntp_tiles::metrics::RecordTileImpression(ntp_tiles::NTPTileImpression(
|
||||
jindex, source, title_source, visual_type, icon_type,
|
||||
base::Time::FromJavaTime(jdata_generation_time_ms), url));
|
||||
base::Time::FromJavaTime(jdata_generation_time_ms), *url));
|
||||
}
|
||||
|
||||
void MostVisitedSitesBridge::RecordOpenedMostVisitedItem(
|
||||
|
@ -39,7 +39,7 @@ class MostVisitedSitesBridge {
|
||||
|
||||
void AddOrRemoveBlockedUrl(JNIEnv* env,
|
||||
const base::android::JavaParamRef<jobject>& obj,
|
||||
const base::android::JavaParamRef<jstring>& j_url,
|
||||
const base::android::JavaParamRef<jobject>& j_url,
|
||||
jboolean add_url);
|
||||
void RecordPageImpression(JNIEnv* env,
|
||||
const base::android::JavaParamRef<jobject>& obj,
|
||||
@ -52,7 +52,7 @@ class MostVisitedSitesBridge {
|
||||
jint jtitle_source,
|
||||
jint jsource,
|
||||
jlong jdata_generation_time_ms,
|
||||
const base::android::JavaParamRef<jstring>& jurl);
|
||||
const base::android::JavaParamRef<jobject>& jurl);
|
||||
void RecordOpenedMostVisitedItem(
|
||||
JNIEnv* env,
|
||||
const base::android::JavaParamRef<jobject>& obj,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "components/sessions/core/live_tab.h"
|
||||
#include "components/sessions/core/tab_restore_service.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "url/android/gurl_android.h"
|
||||
|
||||
using base::android::AttachCurrentThread;
|
||||
using base::android::ConvertUTF16ToJavaString;
|
||||
@ -34,7 +35,7 @@ void JNI_RecentlyClosedBridge_AddTabToList(
|
||||
Java_RecentlyClosedBridge_pushTab(
|
||||
env, jtabs_list, tab.id.id(),
|
||||
ConvertUTF16ToJavaString(env, current_navigation.title()),
|
||||
ConvertUTF8ToJavaString(env, current_navigation.virtual_url().spec()));
|
||||
url::GURLAndroid::FromNativeGURL(env, current_navigation.virtual_url()));
|
||||
}
|
||||
|
||||
void JNI_RecentlyClosedBridge_AddTabsToList(
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "components/offline_pages/core/request_header/offline_page_header.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "net/base/filename_util.h"
|
||||
#include "url/android/gurl_android.h"
|
||||
|
||||
using base::android::ConvertJavaStringToUTF8;
|
||||
using base::android::ConvertUTF16ToJavaString;
|
||||
@ -486,13 +487,13 @@ void OfflinePageBridge::GetPagesByNamespace(
|
||||
void OfflinePageBridge::SelectPageForOnlineUrl(
|
||||
JNIEnv* env,
|
||||
const JavaParamRef<jobject>& obj,
|
||||
const JavaParamRef<jstring>& j_online_url,
|
||||
const JavaParamRef<jobject>& j_online_url,
|
||||
int tab_id,
|
||||
const JavaParamRef<jobject>& j_callback_obj) {
|
||||
DCHECK(j_callback_obj);
|
||||
|
||||
OfflinePageUtils::SelectPagesForURL(
|
||||
key_, GURL(ConvertJavaStringToUTF8(env, j_online_url)), tab_id,
|
||||
key_, *url::GURLAndroid::ToNativeGURL(env, j_online_url), tab_id,
|
||||
base::BindOnce(&SelectPageCallback,
|
||||
ScopedJavaGlobalRef<jobject>(j_callback_obj)));
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ class OfflinePageBridge : public OfflinePageModel::Observer,
|
||||
void SelectPageForOnlineUrl(
|
||||
JNIEnv* env,
|
||||
const base::android::JavaParamRef<jobject>& obj,
|
||||
const base::android::JavaParamRef<jstring>& j_online_url,
|
||||
const base::android::JavaParamRef<jobject>& j_online_url,
|
||||
int tab_id,
|
||||
const base::android::JavaParamRef<jobject>& j_callback_obj);
|
||||
|
||||
|
@ -16,6 +16,7 @@ import org.chromium.chrome.browser.tab.Tab;
|
||||
import org.chromium.content_public.browser.test.util.Criteria;
|
||||
import org.chromium.content_public.browser.test.util.CriteriaHelper;
|
||||
import org.chromium.net.test.EmbeddedTestServer;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@ -49,30 +50,30 @@ public class NewTabPageTestUtils {
|
||||
|
||||
public static List<SiteSuggestion> createFakeSiteSuggestions(EmbeddedTestServer testServer) {
|
||||
List<SiteSuggestion> siteSuggestions = new ArrayList<>();
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES", testServer.getURL(TEST_PAGE) + "#0",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST", testServer.getURL(TEST_PAGE) + "#1",
|
||||
"/test.png", TileTitleSource.UNKNOWN, TileSource.WHITELIST,
|
||||
TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES", testServer.getURL(TEST_PAGE) + "#2",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("3 TOP_SITES", testServer.getURL(TEST_PAGE) + "#3",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("4 TOP_SITES", testServer.getURL(TEST_PAGE) + "#4",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("5 TOP_SITES", testServer.getURL(TEST_PAGE) + "#5",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("6 TOP_SITES", testServer.getURL(TEST_PAGE) + "#6",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("7 TOP_SITES", testServer.getURL(TEST_PAGE) + "#7",
|
||||
"", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES, TileSectionType.PERSONALIZED,
|
||||
new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("0 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#0"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("1 WHITELIST",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#1"), "/test.png", TileTitleSource.UNKNOWN,
|
||||
TileSource.WHITELIST, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("2 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#2"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("3 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#3"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("4 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#4"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("5 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#5"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("6 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#6"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
siteSuggestions.add(new SiteSuggestion("7 TOP_SITES",
|
||||
new GURL(testServer.getURL(TEST_PAGE) + "#7"), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date()));
|
||||
return siteSuggestions;
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ package org.chromium.chrome.test.util.browser.offlinepages;
|
||||
import org.chromium.base.Callback;
|
||||
import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
|
||||
import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -48,7 +49,7 @@ public class FakeOfflinePageBridge extends OfflinePageBridge {
|
||||
|
||||
@Override
|
||||
public void selectPageForOnlineUrl(
|
||||
String onlineUrl, int tabId, Callback<OfflinePageItem> callback) {
|
||||
GURL onlineUrl, int tabId, Callback<OfflinePageItem> callback) {
|
||||
assert tabId == 0;
|
||||
if (mAnswersRequestsImmediately) {
|
||||
answerRequest(onlineUrl, callback);
|
||||
@ -58,10 +59,10 @@ public class FakeOfflinePageBridge extends OfflinePageBridge {
|
||||
mRequests.add(new SelectPageRequest(onlineUrl, callback));
|
||||
}
|
||||
|
||||
private void answerRequest(String onlineUrl, Callback<OfflinePageItem> callback) {
|
||||
private void answerRequest(GURL onlineUrl, Callback<OfflinePageItem> callback) {
|
||||
OfflinePageItem result = null;
|
||||
for (OfflinePageItem item : mItems) {
|
||||
if (!item.getUrl().equals(onlineUrl)) continue;
|
||||
if (!item.getUrl().equals(onlineUrl.getSpec())) continue;
|
||||
if (result == null || item.getCreationTimeMs() > result.getCreationTimeMs()) {
|
||||
result = item;
|
||||
}
|
||||
@ -81,10 +82,10 @@ public class FakeOfflinePageBridge extends OfflinePageBridge {
|
||||
}
|
||||
|
||||
private static class SelectPageRequest {
|
||||
public final String onlineUrl;
|
||||
public final GURL onlineUrl;
|
||||
public final Callback<OfflinePageItem> callback;
|
||||
|
||||
public SelectPageRequest(String onlineUrl, Callback<OfflinePageItem> callback) {
|
||||
public SelectPageRequest(GURL onlineUrl, Callback<OfflinePageItem> callback) {
|
||||
this.onlineUrl = onlineUrl;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import org.chromium.chrome.browser.suggestions.tile.Tile;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileSectionType;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileSource;
|
||||
import org.chromium.chrome.browser.suggestions.tile.TileTitleSource;
|
||||
import org.chromium.url.GURL;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -25,7 +26,7 @@ import java.util.List;
|
||||
* be made on the UI thread, as they can result in UI manipulations.
|
||||
*/
|
||||
public class FakeMostVisitedSites implements MostVisitedSites {
|
||||
private final List<String> mBlocklistedUrls = new ArrayList<>();
|
||||
private final List<GURL> mBlocklistedUrls = new ArrayList<>();
|
||||
|
||||
private List<SiteSuggestion> mSites = new ArrayList<>();
|
||||
private Observer mObserver;
|
||||
@ -40,12 +41,12 @@ public class FakeMostVisitedSites implements MostVisitedSites {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBlocklistedUrl(String url) {
|
||||
public void addBlocklistedUrl(GURL url) {
|
||||
mBlocklistedUrls.add(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBlocklistedUrl(String url) {
|
||||
public void removeBlocklistedUrl(GURL url) {
|
||||
mBlocklistedUrls.remove(url);
|
||||
}
|
||||
|
||||
@ -65,7 +66,7 @@ public class FakeMostVisitedSites implements MostVisitedSites {
|
||||
}
|
||||
|
||||
/** @return Whether {@link #addBlocklistedUrl} has been called on the given URL. */
|
||||
public boolean isUrlBlocklisted(String url) {
|
||||
public boolean isUrlBlocklisted(GURL url) {
|
||||
return mBlocklistedUrls.contains(url);
|
||||
}
|
||||
|
||||
@ -116,8 +117,8 @@ public class FakeMostVisitedSites implements MostVisitedSites {
|
||||
}
|
||||
|
||||
public static SiteSuggestion createSiteSuggestion(String title, String url) {
|
||||
return new SiteSuggestion(title, url, "", TileTitleSource.TITLE_TAG, TileSource.TOP_SITES,
|
||||
TileSectionType.PERSONALIZED, new Date());
|
||||
return new SiteSuggestion(title, new GURL(url), "", TileTitleSource.TITLE_TAG,
|
||||
TileSource.TOP_SITES, TileSectionType.PERSONALIZED, new Date());
|
||||
}
|
||||
|
||||
private void notifyTileSuggestionsAvailable() {
|
||||
|
@ -80,6 +80,21 @@ ScopedJavaLocalRef<jobject> GURLAndroid::EmptyGURL(JNIEnv* env) {
|
||||
return Java_GURL_emptyGURL(env);
|
||||
}
|
||||
|
||||
// static
|
||||
ScopedJavaLocalRef<jobjectArray> GURLAndroid::ToJavaArrayOfGURLs(
|
||||
JNIEnv* env,
|
||||
base::span<ScopedJavaLocalRef<jobject>> v) {
|
||||
jclass clazz = org_chromium_url_GURL_clazz(env);
|
||||
DCHECK(clazz);
|
||||
jobjectArray joa = env->NewObjectArray(v.size(), clazz, nullptr);
|
||||
base::android::CheckException(env);
|
||||
|
||||
for (size_t i = 0; i < v.size(); ++i) {
|
||||
env->SetObjectArrayElement(joa, i, v[i].obj());
|
||||
}
|
||||
return ScopedJavaLocalRef<jobjectArray>(env, joa);
|
||||
}
|
||||
|
||||
static void JNI_GURL_GetOrigin(JNIEnv* env,
|
||||
const JavaParamRef<jstring>& j_spec,
|
||||
jboolean is_valid,
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "base/android/scoped_java_ref.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "url/gurl.h"
|
||||
|
||||
namespace url {
|
||||
@ -21,6 +22,9 @@ class GURLAndroid {
|
||||
JNIEnv* env,
|
||||
const GURL& gurl);
|
||||
static base::android::ScopedJavaLocalRef<jobject> EmptyGURL(JNIEnv* env);
|
||||
static base::android::ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfGURLs(
|
||||
JNIEnv* env,
|
||||
base::span<base::android::ScopedJavaLocalRef<jobject>> v);
|
||||
};
|
||||
|
||||
} // namespace url
|
||||
|
@ -115,6 +115,11 @@ public class GURL {
|
||||
}
|
||||
}
|
||||
|
||||
/** @return true if the GURL is null, empty, or invalid. */
|
||||
public static boolean isEmptyOrInvalid(@Nullable GURL gurl) {
|
||||
return gurl == null || gurl.isEmpty() || !gurl.isValid();
|
||||
}
|
||||
|
||||
@CalledByNative
|
||||
private void init(String spec, boolean isValid, Parsed parsed) {
|
||||
mSpec = spec;
|
||||
|
Reference in New Issue
Block a user