Commit f8ec9c39 authored by Yue Zhang's avatar Yue Zhang Committed by Commit Bot

Show correct favicons on Tab strip

Changes to make sure the favicons on Tab strip show correctly. Show
corresponding favicons for pages with icons and default globe icon
(R.drawable.ic_globe_24dp) for unknown or loading pages. Show chrome
icon (R.drawable.chromelogo16) for native pages.

Bug: 937941, 941293
Change-Id: Iff0da86cc9eb33781aeacca4c22085ac5b060cd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1524912
Commit-Queue: Yue Zhang <yuezhanggg@google.com>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Reviewed-by: default avatarWei-Yin Chen (陳威尹) <wychen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#642690}
parent 87f3769a
...@@ -34,6 +34,7 @@ android_library("java") { ...@@ -34,6 +34,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripToolbarViewProperties.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripToolbarViewProperties.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewBinder.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewBinder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewHolder.java", "java/src/org/chromium/chrome/browser/tasks/tab_management/TabStripViewHolder.java",
"java/src/org/chromium/chrome/browser/tasks/tab_management/TabListFaviconProvider.java",
] ]
classpath_deps = [ classpath_deps = [
......
...@@ -25,7 +25,8 @@ import org.chromium.chrome.R; ...@@ -25,7 +25,8 @@ import org.chromium.chrome.R;
R.string.bottom_tab_grid_new_tab, R.plurals.bottom_tab_grid_title_placeholder, R.string.bottom_tab_grid_new_tab, R.plurals.bottom_tab_grid_title_placeholder,
R.string.iph_tab_groups_tap_to_see_another_tab_accessibility_text, R.string.iph_tab_groups_tap_to_see_another_tab_accessibility_text,
R.string.accessibility_bottom_tab_strip_expand_tab_sheet, R.string.accessibility_bottom_tab_strip_expand_tab_sheet,
R.layout.bottom_tab_strip_toolbar, R.drawable.tabstrip_selected}; R.layout.bottom_tab_strip_toolbar, R.drawable.tabstrip_selected,
R.drawable.tabstrip_favicon_background};
private SilenceLintErrors() {} private SilenceLintErrors() {}
} }
...@@ -58,7 +58,7 @@ class TabGridViewBinder { ...@@ -58,7 +58,7 @@ class TabGridViewBinder {
item.get(TabProperties.TAB_CLOSED_LISTENER).run(holder.getTabId()); item.get(TabProperties.TAB_CLOSED_LISTENER).run(holder.getTabId());
}); });
} else if (TabProperties.FAVICON == propertyKey) { } else if (TabProperties.FAVICON == propertyKey) {
holder.favicon.setImageBitmap(item.get(TabProperties.FAVICON)); holder.favicon.setImageDrawable(item.get(TabProperties.FAVICON));
} else if (TabProperties.THUMBNAIL_FETCHER == propertyKey) { } else if (TabProperties.THUMBNAIL_FETCHER == propertyKey) {
TabListMediator.ThumbnailFetcher fetcher = item.get(TabProperties.THUMBNAIL_FETCHER); TabListMediator.ThumbnailFetcher fetcher = item.get(TabProperties.THUMBNAIL_FETCHER);
if (fetcher == null) return; if (fetcher == null) return;
......
...@@ -80,7 +80,9 @@ public class TabGroupUiMediator implements Destroyable { ...@@ -80,7 +80,9 @@ public class TabGroupUiMediator implements Destroyable {
mTabModelObserver = new EmptyTabModelObserver() { mTabModelObserver = new EmptyTabModelObserver() {
@Override @Override
public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) { public void didSelectTab(Tab tab, @TabSelectionType int type, int lastId) {
if (getRelatedTabsForId(lastId).contains(tab)) return; if (type == TabSelectionType.FROM_CLOSE
|| getRelatedTabsForId(lastId).contains(tab))
return;
resetTabStripWithRelatedTabsForId(tab.getId()); resetTabStripWithRelatedTabsForId(tab.getId());
} }
......
...@@ -15,7 +15,6 @@ import android.view.ViewGroup; ...@@ -15,7 +15,6 @@ import android.view.ViewGroup;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.favicon.FaviconHelper;
import org.chromium.chrome.browser.lifecycle.Destroyable; import org.chromium.chrome.browser.lifecycle.Destroyable;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
...@@ -107,8 +106,11 @@ public class TabListCoordinator implements Destroyable { ...@@ -107,8 +106,11 @@ public class TabListCoordinator implements Destroyable {
mRecyclerView.setHasFixedSize(true); mRecyclerView.setHasFixedSize(true);
mMediator = new TabListMediator(Profile.getLastUsedProfile(), tabListModel, context, TabListFaviconProvider mTabListFaviconProvider =
tabModelSelector, tabContentManager, new FaviconHelper(), componentName); new TabListFaviconProvider(context, Profile.getLastUsedProfile());
mMediator = new TabListMediator(tabListModel, tabModelSelector, tabContentManager,
mTabListFaviconProvider, componentName);
} }
/** /**
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.tasks.tab_management;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.content.res.AppCompatResources;
import org.chromium.base.Callback;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.favicon.FaviconHelper;
import org.chromium.chrome.browser.native_page.NativePageFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.util.ViewUtils;
/**
* Provider for processed favicons in Tab list.
*/
public class TabListFaviconProvider {
private static Drawable sGlobeDrawable;
private static Drawable sChromeDrawable;
private final int mFaviconSize;
private final Profile mProfile;
private final FaviconHelper mFaviconHelper;
/**
* Construct the provider that provides favicons for tab list.
* @param context The context to use for accessing {@link android.content.res.Resources}
* @param profile The profile to use for getting favicons.
*/
public TabListFaviconProvider(Context context, Profile profile) {
mFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.default_favicon_size);
mProfile = profile;
mFaviconHelper = new FaviconHelper();
if (sGlobeDrawable == null) {
Drawable globeDrawable =
AppCompatResources.getDrawable(context, R.drawable.ic_globe_24dp);
Bitmap globeBitmap =
Bitmap.createBitmap(mFaviconSize, mFaviconSize, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(globeBitmap);
globeDrawable.setBounds(0, 0, mFaviconSize, mFaviconSize);
globeDrawable.draw(canvas);
sGlobeDrawable = processBitmap(globeBitmap);
}
if (sChromeDrawable == null) {
Bitmap chromeBitmap =
BitmapFactory.decodeResource(context.getResources(), R.drawable.chromelogo16);
sChromeDrawable = processBitmap(chromeBitmap);
}
}
private Drawable processBitmap(Bitmap bitmap) {
return ViewUtils.createRoundedBitmapDrawable(
Bitmap.createScaledBitmap(bitmap, mFaviconSize, mFaviconSize, true),
ViewUtils.DEFAULT_FAVICON_CORNER_RADIUS);
}
/**
* @return The scaled rounded Globe Drawable as default favicon.
*/
public Drawable getDefaultFaviconDrawable() {
return sGlobeDrawable;
}
/**
* Asynchronously get the processed favicon Drawable.
* @param url The URL whose favicon is requested.
* @param isIncognito Whether the tab is incognito or not.
* @param faviconCallback The callback that requests for favicon.
*/
public void getFaviconForUrlAsync(
String url, boolean isIncognito, Callback<Drawable> faviconCallback) {
if (NativePageFactory.isNativePageUrl(url, isIncognito)) {
faviconCallback.onResult(sChromeDrawable);
} else {
mFaviconHelper.getLocalFaviconImageForURL(
mProfile, url, mFaviconSize, (image, iconUrl) -> {
if (image == null) return;
Drawable drawable = processBitmap(image);
faviconCallback.onResult(drawable);
});
}
}
/**
* Synchronously get the processed favicon Drawable.
* @param url The URL whose favicon is requested.
* @param isIncognito Whether the tab is in cognito or not.
* @param icon The favicon that was received.
* @return The processed favicon.
*/
public Drawable getFaviconForUrlSync(String url, boolean isIncognito, Bitmap icon) {
if (icon == null) {
boolean isNativeUrl = NativePageFactory.isNativePageUrl(url, isIncognito);
return isNativeUrl ? sChromeDrawable : sGlobeDrawable;
} else {
return processBitmap(icon);
}
}
}
...@@ -4,20 +4,17 @@ ...@@ -4,20 +4,17 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.chromium.base.Callback; import org.chromium.base.Callback;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.native_page.NativePageFactory;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.EmptyTabObserver; import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabFavicon;
import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModel;
...@@ -25,6 +22,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelObserver; ...@@ -25,6 +22,7 @@ import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.browser.tabmodel.TabModelUtils;
import org.chromium.chrome.browser.tabmodel.TabSelectionType; import org.chromium.chrome.browser.tabmodel.TabSelectionType;
import org.chromium.content_public.browser.NavigationHandle;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -61,12 +59,10 @@ class TabListMediator { ...@@ -61,12 +59,10 @@ class TabListMediator {
mThumbnailProvider.getTabThumbnailWithCallback(mTab, callback); mThumbnailProvider.getTabThumbnailWithCallback(mTab, callback);
} }
} }
private final int mFaviconSize; private final TabListFaviconProvider mTabListFaviconProvider;
private final FaviconHelper mFaviconHelper;
private final TabListModel mModel; private final TabListModel mModel;
private final TabModelSelector mTabModelSelector; private final TabModelSelector mTabModelSelector;
private final TabContentManager mTabContentManager; private final TabContentManager mTabContentManager;
private final Profile mProfile;
private final String mComponentName; private final String mComponentName;
private final TabActionListener mTabSelectedListener = new TabActionListener() { private final TabActionListener mTabSelectedListener = new TabActionListener() {
...@@ -120,6 +116,16 @@ class TabListMediator { ...@@ -120,6 +116,16 @@ class TabListMediator {
}; };
private final TabObserver mTabObserver = new EmptyTabObserver() { private final TabObserver mTabObserver = new EmptyTabObserver() {
@Override
public void onDidStartNavigation(Tab tab, NavigationHandle navigationHandle) {
if (NativePageFactory.isNativePageUrl(tab.getUrl(), tab.isIncognito())) return;
if (navigationHandle.isSameDocument() || !navigationHandle.isInMainFrame()) return;
if (mModel.indexFromId(tab.getId()) == TabModel.INVALID_TAB_INDEX) return;
mModel.get(mModel.indexFromId(tab.getId()))
.set(TabProperties.FAVICON,
mTabListFaviconProvider.getDefaultFaviconDrawable());
}
@Override @Override
public void onTitleUpdated(Tab updatedTab) { public void onTitleUpdated(Tab updatedTab) {
int index = mModel.indexFromId(updatedTab.getId()); int index = mModel.indexFromId(updatedTab.getId());
...@@ -131,7 +137,9 @@ class TabListMediator { ...@@ -131,7 +137,9 @@ class TabListMediator {
public void onFaviconUpdated(Tab updatedTab, Bitmap icon) { public void onFaviconUpdated(Tab updatedTab, Bitmap icon) {
int index = mModel.indexFromId(updatedTab.getId()); int index = mModel.indexFromId(updatedTab.getId());
if (index == TabModel.INVALID_TAB_INDEX) return; if (index == TabModel.INVALID_TAB_INDEX) return;
mModel.get(index).set(TabProperties.FAVICON, icon); Drawable drawable = mTabListFaviconProvider.getFaviconForUrlSync(
updatedTab.getUrl(), updatedTab.isIncognito(), icon);
mModel.get(index).set(TabProperties.FAVICON, drawable);
} }
}; };
...@@ -146,22 +154,19 @@ class TabListMediator { ...@@ -146,22 +154,19 @@ class TabListMediator {
* Construct the Mediator with the given Models and observing hooks from the given * Construct the Mediator with the given Models and observing hooks from the given
* ChromeActivity. * ChromeActivity.
* @param model The Model to keep state about a list of {@link Tab}s. * @param model The Model to keep state about a list of {@link Tab}s.
* @param context The context to use for accessing {@link android.content.res.Resources}
* @param tabModelSelector {@link TabModelSelector} that will provide and receive signals about * @param tabModelSelector {@link TabModelSelector} that will provide and receive signals about
* the tabs concerned. * the tabs concerned.
* @param tabContentManager {@link TabContentManager} to provide screenshot related details. * @param tabContentManager {@link TabContentManager} to provide screenshot related details.
* @param componentName This is a unique string to identify different components. * @param componentName This is a unique string to identify different components.
*/ */
public TabListMediator(Profile profile, TabListModel model, Context context,
TabModelSelector tabModelSelector, TabContentManager tabContentManager,
FaviconHelper faviconHelper, String componentName) {
mFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.tab_grid_favicon_size);
public TabListMediator(TabListModel model, TabModelSelector tabModelSelector,
TabContentManager tabContentManager, TabListFaviconProvider tabListFaviconProvider,
String componentName) {
mTabModelSelector = tabModelSelector; mTabModelSelector = tabModelSelector;
mTabContentManager = tabContentManager; mTabContentManager = tabContentManager;
mModel = model; mModel = model;
mFaviconHelper = faviconHelper; mTabListFaviconProvider = tabListFaviconProvider;
mProfile = profile;
mComponentName = componentName; mComponentName = componentName;
mTabModelObserver = new EmptyTabModelObserver() { mTabModelObserver = new EmptyTabModelObserver() {
...@@ -243,7 +248,8 @@ class TabListMediator { ...@@ -243,7 +248,8 @@ class TabListMediator {
new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID) new PropertyModel.Builder(TabProperties.ALL_KEYS_TAB_GRID)
.with(TabProperties.TAB_ID, tab.getId()) .with(TabProperties.TAB_ID, tab.getId())
.with(TabProperties.TITLE, tab.getTitle()) .with(TabProperties.TITLE, tab.getTitle())
.with(TabProperties.FAVICON, TabFavicon.getBitmap(tab)) .with(TabProperties.FAVICON,
mTabListFaviconProvider.getDefaultFaviconDrawable())
.with(TabProperties.IS_SELECTED, isSelected) .with(TabProperties.IS_SELECTED, isSelected)
.with(TabProperties.TAB_SELECTED_LISTENER, mTabSelectedListener) .with(TabProperties.TAB_SELECTED_LISTENER, mTabSelectedListener)
.with(TabProperties.TAB_CLOSED_LISTENER, mTabClosedListener) .with(TabProperties.TAB_CLOSED_LISTENER, mTabClosedListener)
...@@ -253,11 +259,16 @@ class TabListMediator { ...@@ -253,11 +259,16 @@ class TabListMediator {
} else { } else {
mModel.add(index, tabInfo); mModel.add(index, tabInfo);
} }
mFaviconHelper.getLocalFaviconImageForURL(
mProfile, tab.getUrl(), mFaviconSize, (image, iconUrl) -> { Callback<Drawable> faviconCallback = drawable -> {
if (mModel.indexFromId(tab.getId()) == Tab.INVALID_TAB_ID) return; int modelIndex = mModel.indexFromId(tab.getId());
mModel.get(mModel.indexFromId(tab.getId())).set(TabProperties.FAVICON, image); if (modelIndex != Tab.INVALID_TAB_ID && drawable != null) {
}); mModel.get(modelIndex).set(TabProperties.FAVICON, drawable);
}
};
mTabListFaviconProvider.getFaviconForUrlAsync(
tab.getUrl(), tab.isIncognito(), faviconCallback);
ThumbnailFetcher callback = ThumbnailFetcher callback =
new ThumbnailFetcher(mTabContentManager::getTabThumbnailWithCallback, tab); new ThumbnailFetcher(mTabContentManager::getTabThumbnailWithCallback, tab);
tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback); tabInfo.set(TabProperties.THUMBNAIL_FETCHER, callback);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.graphics.Bitmap; import android.graphics.drawable.Drawable;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -24,7 +24,7 @@ public class TabProperties { ...@@ -24,7 +24,7 @@ public class TabProperties {
public static final WritableObjectPropertyKey<TabListMediator.TabActionListener> public static final WritableObjectPropertyKey<TabListMediator.TabActionListener>
TAB_CLOSED_LISTENER = new WritableObjectPropertyKey<>(); TAB_CLOSED_LISTENER = new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<Bitmap> FAVICON = public static final WritableObjectPropertyKey<Drawable> FAVICON =
new WritableObjectPropertyKey<>(); new WritableObjectPropertyKey<>();
public static final WritableObjectPropertyKey<TabListMediator.ThumbnailFetcher> public static final WritableObjectPropertyKey<TabListMediator.ThumbnailFetcher>
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
package org.chromium.chrome.browser.tasks.tab_management; package org.chromium.chrome.browser.tasks.tab_management;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
...@@ -12,7 +11,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder; ...@@ -12,7 +11,6 @@ import android.support.v7.widget.RecyclerView.ViewHolder;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.util.ViewUtils;
import org.chromium.ui.modelutil.PropertyKey; import org.chromium.ui.modelutil.PropertyKey;
import org.chromium.ui.modelutil.PropertyModel; import org.chromium.ui.modelutil.PropertyModel;
...@@ -56,14 +54,11 @@ class TabStripViewBinder { ...@@ -56,14 +54,11 @@ class TabStripViewBinder {
R.string.accessibility_tabstrip_tab, title)); R.string.accessibility_tabstrip_tab, title));
} }
} else if (TabProperties.FAVICON == propertyKey) { } else if (TabProperties.FAVICON == propertyKey) {
Bitmap favicon = item.get(TabProperties.FAVICON); Drawable faviconDrawable = item.get(TabProperties.FAVICON);
if (favicon == null) return; holder.button.setBackgroundResource(R.drawable.tabstrip_favicon_background);
int faviconSize = holder.itemView.getContext().getResources().getDimensionPixelSize( if (faviconDrawable != null) {
R.dimen.default_favicon_size); holder.button.setImageDrawable(faviconDrawable);
Drawable drawable = ViewUtils.createRoundedBitmapDrawable( }
Bitmap.createScaledBitmap(favicon, faviconSize, faviconSize, true),
ViewUtils.DEFAULT_FAVICON_CORNER_RADIUS);
holder.button.setImageDrawable(drawable);
} else if (TabProperties.TAB_ID == propertyKey) { } else if (TabProperties.TAB_ID == propertyKey) {
holder.setTabId(item.get(TabProperties.TAB_ID)); holder.setTabId(item.get(TabProperties.TAB_ID));
} }
......
...@@ -10,7 +10,9 @@ import static org.junit.Assert.assertNotNull; ...@@ -10,7 +10,9 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
...@@ -18,9 +20,9 @@ import static org.mockito.Mockito.mock; ...@@ -18,9 +20,9 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.graphics.Color;
import android.content.res.Resources; import android.graphics.drawable.ColorDrawable;
import android.graphics.Bitmap; import android.graphics.drawable.Drawable;
import android.view.View; import android.view.View;
import org.junit.After; import org.junit.After;
...@@ -33,12 +35,12 @@ import org.mockito.Mock; ...@@ -33,12 +35,12 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import org.chromium.base.Callback;
import org.chromium.base.UserDataHost; import org.chromium.base.UserDataHost;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction; import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager; import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
import org.chromium.chrome.browser.favicon.FaviconHelper; import org.chromium.chrome.browser.favicon.FaviconHelper;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabObserver; import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tabmodel.TabLaunchType; import org.chromium.chrome.browser.tabmodel.TabLaunchType;
...@@ -57,7 +59,6 @@ import java.util.List; ...@@ -57,7 +59,6 @@ import java.util.List;
@RunWith(LocalRobolectricTestRunner.class) @RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
public class TabListMediatorUnitTest { public class TabListMediatorUnitTest {
private static final int MOCK_FAVICON_SIZE = 10;
private static final String TAB1_TITLE = "Tab1"; private static final String TAB1_TITLE = "Tab1";
private static final String TAB2_TITLE = "Tab2"; private static final String TAB2_TITLE = "Tab2";
private static final String TAB3_TITLE = "Tab3"; private static final String TAB3_TITLE = "Tab3";
...@@ -75,19 +76,15 @@ public class TabListMediatorUnitTest { ...@@ -75,19 +76,15 @@ public class TabListMediatorUnitTest {
@Mock @Mock
TabModel mTabModel; TabModel mTabModel;
@Mock @Mock
Context mContext; TabListFaviconProvider mTabListFaviconProvider;
@Mock
Resources mResources;
@Mock
FaviconHelper mFaviconHelper;
@Mock
Profile mProfile;
@Captor @Captor
ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor; ArgumentCaptor<TabModelObserver> mTabModelObserverCaptor;
@Captor @Captor
ArgumentCaptor<FaviconHelper.FaviconImageCallback> mFaviconCallbackCaptor; ArgumentCaptor<FaviconHelper.FaviconImageCallback> mFaviconCallbackCaptor;
@Captor @Captor
ArgumentCaptor<TabObserver> mTabObserverCaptor; ArgumentCaptor<TabObserver> mTabObserverCaptor;
@Captor
ArgumentCaptor<Callback<Drawable>> mCallbackCaptor;
private Tab mTab1; private Tab mTab1;
private Tab mTab2; private Tab mTab2;
...@@ -108,12 +105,6 @@ public class TabListMediatorUnitTest { ...@@ -108,12 +105,6 @@ public class TabListMediatorUnitTest {
tabModelList.add(mTabModel); tabModelList.add(mTabModel);
doNothing().when(mTabContentManager).getTabThumbnailWithCallback(any(), any()); doNothing().when(mTabContentManager).getTabThumbnailWithCallback(any(), any());
doReturn(mResources).when(mContext).getResources();
doReturn(MOCK_FAVICON_SIZE).when(mResources).getDimensionPixelSize(anyInt());
doReturn(true)
.when(mFaviconHelper)
.getLocalFaviconImageForURL(
any(), any(), anyInt(), mFaviconCallbackCaptor.capture());
doReturn(mTabModel).when(mTabModelSelector).getCurrentModel(); doReturn(mTabModel).when(mTabModelSelector).getCurrentModel();
doReturn(tabModelList).when(mTabModelSelector).getModels(); doReturn(tabModelList).when(mTabModelSelector).getModels();
doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider(); doReturn(mTabModelFilterProvider).when(mTabModelSelector).getTabModelFilterProvider();
...@@ -126,10 +117,13 @@ public class TabListMediatorUnitTest { ...@@ -126,10 +117,13 @@ public class TabListMediatorUnitTest {
doNothing().when(mTab1).addObserver(mTabObserverCaptor.capture()); doNothing().when(mTab1).addObserver(mTabObserverCaptor.capture());
doReturn(0).when(mTabModel).index(); doReturn(0).when(mTabModel).index();
doReturn(2).when(mTabModel).getCount(); doReturn(2).when(mTabModel).getCount();
doNothing()
.when(mTabListFaviconProvider)
.getFaviconForUrlAsync(anyString(), anyBoolean(), mCallbackCaptor.capture());
mModel = new TabListModel(); mModel = new TabListModel();
mMediator = new TabListMediator(mProfile, mModel, mContext, mTabModelSelector, mMediator = new TabListMediator(mModel, mTabModelSelector, mTabContentManager,
mTabContentManager, mFaviconHelper, getClass().getSimpleName()); mTabListFaviconProvider, getClass().getSimpleName());
} }
@After @After
...@@ -257,8 +251,8 @@ public class TabListMediatorUnitTest { ...@@ -257,8 +251,8 @@ public class TabListMediatorUnitTest {
tabs.add(mTabModel.getTabAt(i)); tabs.add(mTabModel.getTabAt(i));
} }
mMediator.resetWithListOfTabs(tabs); mMediator.resetWithListOfTabs(tabs);
for (FaviconHelper.FaviconImageCallback callback : mFaviconCallbackCaptor.getAllValues()) { for (Callback<Drawable> callback : mCallbackCaptor.getAllValues()) {
callback.onFaviconAvailable(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888), null); callback.onResult(new ColorDrawable(Color.RED));
} }
assertThat(mModel.size(), equalTo(2)); assertThat(mModel.size(), equalTo(2));
...@@ -269,8 +263,8 @@ public class TabListMediatorUnitTest { ...@@ -269,8 +263,8 @@ public class TabListMediatorUnitTest {
assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB1_TITLE)); assertThat(mModel.get(0).get(TabProperties.TITLE), equalTo(TAB1_TITLE));
assertThat(mModel.get(1).get(TabProperties.TITLE), equalTo(TAB2_TITLE)); assertThat(mModel.get(1).get(TabProperties.TITLE), equalTo(TAB2_TITLE));
assertThat(mModel.get(0).get(TabProperties.FAVICON), instanceOf(Bitmap.class)); assertThat(mModel.get(0).get(TabProperties.FAVICON), instanceOf(Drawable.class));
assertThat(mModel.get(1).get(TabProperties.FAVICON), instanceOf(Bitmap.class)); assertThat(mModel.get(1).get(TabProperties.FAVICON), instanceOf(Drawable.class));
assertThat(mModel.get(0).get(TabProperties.IS_SELECTED), equalTo(true)); assertThat(mModel.get(0).get(TabProperties.IS_SELECTED), equalTo(true));
assertThat(mModel.get(1).get(TabProperties.IS_SELECTED), equalTo(false)); assertThat(mModel.get(1).get(TabProperties.IS_SELECTED), equalTo(false));
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2019 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file. -->
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:left="8dp"
android:top="8dp"
android:right="8dp"
android:bottom="8dp">
<shape
android:shape="oval">
<solid android:color="@color/modern_grey_100" />
</shape>
</item>
</layer-list>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment