| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..882d7ee15067a1b9027a693e54b2cee0a9050bda
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
|
| @@ -0,0 +1,835 @@
|
| +// Copyright 2015 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.ntp;
|
| +
|
| +import android.app.Activity;
|
| +import android.content.res.Resources;
|
| +import android.graphics.Bitmap;
|
| +import android.graphics.drawable.BitmapDrawable;
|
| +import android.graphics.drawable.Drawable;
|
| +import android.text.TextUtils;
|
| +import android.util.LruCache;
|
| +import android.view.ContextMenu;
|
| +import android.view.LayoutInflater;
|
| +import android.view.MenuItem;
|
| +import android.view.MenuItem.OnMenuItemClickListener;
|
| +import android.view.View;
|
| +import android.view.ViewGroup;
|
| +import android.widget.BaseExpandableListAdapter;
|
| +import android.widget.TextView;
|
| +
|
| +import com.google.android.apps.chrome.R;
|
| +
|
| +import org.chromium.base.ApiCompatibilityUtils;
|
| +import org.chromium.chrome.browser.ForeignSessionHelper.ForeignSession;
|
| +import org.chromium.chrome.browser.ForeignSessionHelper.ForeignSessionTab;
|
| +import org.chromium.chrome.browser.ForeignSessionHelper.ForeignSessionWindow;
|
| +import org.chromium.chrome.browser.RecentlyClosedBridge.RecentlyClosedTab;
|
| +import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
|
| +import org.chromium.ui.WindowOpenDisposition;
|
| +import org.chromium.ui.base.DeviceFormFactor;
|
| +
|
| +import java.util.ArrayList;
|
| +import java.util.List;
|
| +import java.util.concurrent.TimeUnit;
|
| +
|
| +/**
|
| + * Row adapter for presenting recently closed tabs, synced tabs from other devices, the sync or
|
| + * sign in promo, and currently open tabs (only in document mode) in a grouped list view.
|
| + */
|
| +public class RecentTabsRowAdapter extends BaseExpandableListAdapter {
|
| + private static final int MAX_NUM_FAVICONS_TO_CACHE = 256;
|
| +
|
| + private enum ChildType {
|
| + NONE, DEFAULT_CONTENT, SYNC_PROMO
|
| + }
|
| +
|
| + private enum GroupType {
|
| + CONTENT, VISIBLE_SEPARATOR, INVISIBLE_SEPARATOR
|
| + }
|
| +
|
| + private final Activity mActivity;
|
| + private final ArrayList<Group> mGroups;
|
| + private final Drawable mDefaultFavicon;
|
| + private final RecentTabsManager mRecentTabsManager;
|
| + private final RecentlyClosedTabsGroup mRecentlyClosedTabsGroup = new RecentlyClosedTabsGroup();
|
| + private final SeparatorGroup mVisibleSeparatorGroup = new SeparatorGroup(true);
|
| + private final SeparatorGroup mInvisibleSeparatorGroup = new SeparatorGroup(false);
|
| + private final long mInitializationTimestamp; // Seconds since Unix epoch.
|
| + private final FaviconCache mFaviconCache;
|
| + private final int mFaviconSize;
|
| +
|
| + /**
|
| + * A generic group of objects to be shown in the RecentTabsRowAdapter, such as the list of
|
| + * recently closed tabs.
|
| + */
|
| + abstract class Group {
|
| + /**
|
| + * @return The type of group: GroupType.CONTENT or GroupType.SEPARATOR.
|
| + */
|
| + abstract GroupType getGroupType();
|
| +
|
| + /**
|
| + * @return The number of children in this group.
|
| + */
|
| + abstract int getChildrenCount();
|
| +
|
| + /**
|
| + * @return The child type.
|
| + */
|
| + abstract ChildType getChildType();
|
| +
|
| +
|
| + /**
|
| + * @return The child at the position childPosition.
|
| + */
|
| + abstract Object getChild(int childPosition);
|
| +
|
| + /**
|
| + * Returns the view corresponding to the child view at a given position.
|
| + *
|
| + * @param childPosition The position of the child.
|
| + * @param isLastChild Whether this child is the last one.
|
| + * @param convertView The re-usable child view (may be null).
|
| + * @param parent The parent view group.
|
| + *
|
| + * @return The view corresponding to the child.
|
| + */
|
| + View getChildView(int childPosition, boolean isLastChild,
|
| + View convertView, ViewGroup parent) {
|
| + View childView = convertView;
|
| + if (childView == null) {
|
| + LayoutInflater inflater = LayoutInflater.from(mActivity);
|
| + childView = inflater.inflate(R.layout.recent_tabs_list_item, parent, false);
|
| +
|
| + ViewHolder viewHolder = new ViewHolder();
|
| + viewHolder.textView = (TextView) childView;
|
| + childView.setTag(viewHolder);
|
| + }
|
| +
|
| + ViewHolder viewHolder = (ViewHolder) childView.getTag();
|
| + configureChildView(childPosition, viewHolder);
|
| +
|
| + return childView;
|
| + }
|
| +
|
| + /**
|
| + * Configures a view inflated from recent_tabs_list_item.xml to display information about
|
| + * a child in this group.
|
| + *
|
| + * @param childPosition The position of the child within this group.
|
| + * @param viewHolder The ViewHolder with references to pieces of the view.
|
| + */
|
| + abstract void configureChildView(int childPosition, ViewHolder viewHolder);
|
| +
|
| + /**
|
| + * Returns the view corresponding to this group.
|
| + *
|
| + * @param isExpanded Whether the group is expanded.
|
| + * @param convertView The re-usable group view (may be null).
|
| + * @param parent The parent view group.
|
| + *
|
| + * @return The view corresponding to the group.
|
| + */
|
| + public View getGroupView(boolean isExpanded, View convertView, ViewGroup parent) {
|
| + assert convertView == null || convertView instanceof RecentTabsGroupView;
|
| + RecentTabsGroupView groupView = (RecentTabsGroupView) convertView;
|
| + if (groupView == null) {
|
| + groupView = (RecentTabsGroupView) LayoutInflater.from(mActivity).inflate(
|
| + R.layout.recent_tabs_group_item, parent, false);
|
| + groupView.initialize(mInitializationTimestamp);
|
| + }
|
| + configureGroupView(groupView, isExpanded);
|
| + return groupView;
|
| + }
|
| +
|
| + /**
|
| + * Configures an RecentTabsGroupView to display the header of this group.
|
| + * @param groupView The RecentTabsGroupView to configure.
|
| + * @param isExpanded Whether the view is currently expanded.
|
| + */
|
| + abstract void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded);
|
| +
|
| + /**
|
| + * Sets whether this group is collapsed (i.e. whether only the header is visible).
|
| + */
|
| + abstract void setCollapsed(boolean isCollapsed);
|
| +
|
| + /**
|
| + * @return Whether this group is collapsed.
|
| + */
|
| + abstract boolean isCollapsed();
|
| +
|
| + /**
|
| + * Called when a child item is clicked.
|
| + * @param childPosition The position of the child in the group.
|
| + * @return Whether the click was handled.
|
| + */
|
| + abstract boolean onChildClick(int childPosition);
|
| +
|
| + /**
|
| + * Called when the context menu for the group view is being built.
|
| + * @param menu The context menu being built.
|
| + * @param activity The current activity.
|
| + */
|
| + void onCreateContextMenuForGroup(ContextMenu menu, Activity activity) {
|
| + }
|
| +
|
| + /**
|
| + * Called when a context menu for one of the child views is being built.
|
| + * @param childPosition The position of the child in the group.
|
| + * @param menu The context menu being built.
|
| + * @param activity The current activity.
|
| + */
|
| + void onCreateContextMenuForChild(int childPosition, ContextMenu menu,
|
| + Activity activity) {
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * A group containing all the tabs currently open on this device.
|
| + */
|
| + class CurrentlyOpenTabsGroup extends Group {
|
| + private static final int NUM_DEFAULT_VISIBLE_TABS = 6;
|
| +
|
| + private final List<CurrentlyOpenTab> mCurrentlyOpenTabs;
|
| + private final boolean mShowingAll;
|
| +
|
| + public CurrentlyOpenTabsGroup(List<CurrentlyOpenTab> tabsList) {
|
| + mCurrentlyOpenTabs = tabsList;
|
| + mShowingAll = mRecentTabsManager.isCurrentlyOpenTabsShowingAll();
|
| + }
|
| +
|
| + private boolean isMoreButton(int childPosition) {
|
| + return !mShowingAll && childPosition
|
| + == Math.min(NUM_DEFAULT_VISIBLE_TABS, mCurrentlyOpenTabs.size());
|
| + }
|
| +
|
| + @Override
|
| + GroupType getGroupType() {
|
| + return GroupType.CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + int getChildrenCount() {
|
| + if (mShowingAll) return mCurrentlyOpenTabs.size();
|
| + return Math.min(NUM_DEFAULT_VISIBLE_TABS, mCurrentlyOpenTabs.size() - 1) + 1;
|
| + }
|
| +
|
| + @Override
|
| + ChildType getChildType() {
|
| + return ChildType.DEFAULT_CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + CurrentlyOpenTab getChild(int childPosition) {
|
| + if (isMoreButton(childPosition)) return null;
|
| +
|
| + return mCurrentlyOpenTabs.get(childPosition);
|
| + }
|
| +
|
| + @Override
|
| + void configureChildView(int childPosition, ViewHolder viewHolder) {
|
| + if (isMoreButton(childPosition)) {
|
| + Resources resources = mActivity.getResources();
|
| + String text = resources.getString(R.string.recent_tabs_show_more);
|
| + viewHolder.textView.setText(text);
|
| + Drawable drawable = ApiCompatibilityUtils.getDrawable(
|
| + resources, R.drawable.more_horiz);
|
| + ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
| + viewHolder.textView, drawable, null, null, null);
|
| + } else {
|
| + CurrentlyOpenTab openTab = getChild(childPosition);
|
| + viewHolder.textView.setText(TextUtils.isEmpty(openTab.getTitle()) ? openTab.getUrl()
|
| + : openTab.getTitle());
|
| + loadLocalFavicon(viewHolder, openTab.getUrl());
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded) {
|
| + groupView.configureForCurrentlyOpenTabs(isExpanded);
|
| + }
|
| +
|
| + @Override
|
| + void setCollapsed(boolean isCollapsed) {
|
| + mRecentTabsManager.setCurrentlyOpenTabsCollapsed(isCollapsed);
|
| + }
|
| +
|
| + @Override
|
| + boolean isCollapsed() {
|
| + return mRecentTabsManager.isCurrentlyOpenTabsCollapsed();
|
| + }
|
| +
|
| + @Override
|
| + boolean onChildClick(int childPosition) {
|
| + if (isMoreButton(childPosition)) {
|
| + mRecentTabsManager.setCurrentlyOpenTabsShowAll(true);
|
| + } else {
|
| + getChild(childPosition).getRunnable().run();
|
| + }
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * A group containing all the tabs associated with a foreign session from a synced device.
|
| + */
|
| + class ForeignSessionGroup extends Group {
|
| + private final ForeignSession mForeignSession;
|
| +
|
| + ForeignSessionGroup(ForeignSession foreignSession) {
|
| + mForeignSession = foreignSession;
|
| + }
|
| +
|
| + @Override
|
| + public GroupType getGroupType() {
|
| + return GroupType.CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + public int getChildrenCount() {
|
| + int count = 0;
|
| + for (ForeignSessionWindow window : mForeignSession.windows) {
|
| + count += window.tabs.size();
|
| + }
|
| + return count;
|
| + }
|
| +
|
| + @Override
|
| + public ChildType getChildType() {
|
| + return ChildType.DEFAULT_CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + public ForeignSessionTab getChild(int childPosition) {
|
| + for (ForeignSessionWindow window : mForeignSession.windows) {
|
| + if (childPosition < window.tabs.size()) {
|
| + return window.tabs.get(childPosition);
|
| + }
|
| + childPosition -= window.tabs.size();
|
| + }
|
| + assert false;
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public void configureChildView(int childPosition, ViewHolder viewHolder) {
|
| + ForeignSessionTab sessionTab = getChild(childPosition);
|
| + viewHolder.textView.setText(TextUtils.isEmpty(sessionTab.title) ? sessionTab.url
|
| + : sessionTab.title);
|
| + loadSyncedFavicon(viewHolder, sessionTab.url);
|
| + }
|
| +
|
| + @Override
|
| + public void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded) {
|
| + groupView.configureForForeignSession(mForeignSession, isExpanded);
|
| + }
|
| +
|
| + @Override
|
| + public void setCollapsed(boolean isCollapsed) {
|
| + mRecentTabsManager.setForeignSessionCollapsed(mForeignSession, isCollapsed);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isCollapsed() {
|
| + return mRecentTabsManager.getForeignSessionCollapsed(mForeignSession);
|
| + }
|
| +
|
| + @Override
|
| + public boolean onChildClick(int childPosition) {
|
| + ForeignSessionTab foreignSessionTab = getChild(childPosition);
|
| + mRecentTabsManager.openForeignSessionTab(mForeignSession, foreignSessionTab,
|
| + WindowOpenDisposition.CURRENT_TAB);
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public void onCreateContextMenuForGroup(ContextMenu menu, Activity activity) {
|
| + OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
| + @Override
|
| + public boolean onMenuItemClick(MenuItem item) {
|
| + mRecentTabsManager.deleteForeignSession(mForeignSession);
|
| + return true;
|
| + }
|
| + };
|
| + menu.add(R.string.ntp_recent_tabs_remove_menu_option)
|
| + .setOnMenuItemClickListener(listener);
|
| + }
|
| +
|
| + @Override
|
| + public void onCreateContextMenuForChild(int childPosition, ContextMenu menu,
|
| + Activity activity) {
|
| + final ForeignSessionTab foreignSessionTab = getChild(childPosition);
|
| + OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
| + @Override
|
| + public boolean onMenuItemClick(MenuItem item) {
|
| + mRecentTabsManager.openForeignSessionTab(mForeignSession, foreignSessionTab,
|
| + WindowOpenDisposition.NEW_BACKGROUND_TAB);
|
| + return true;
|
| + }
|
| + };
|
| + menu.add(R.string.contextmenu_open_in_new_tab).setOnMenuItemClickListener(listener);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * A group containing tabs that were recently closed on this device and a link to the history
|
| + * page.
|
| + */
|
| + class RecentlyClosedTabsGroup extends Group {
|
| + private static final int ID_OPEN_IN_NEW_TAB = 1;
|
| + private static final int ID_REMOVE_ALL = 2;
|
| +
|
| + @Override
|
| + public GroupType getGroupType() {
|
| + return GroupType.CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + public int getChildrenCount() {
|
| + // The number of children is the number of recently closed tabs, plus one for the "Show
|
| + // full history" item.
|
| + return 1 + mRecentTabsManager.getRecentlyClosedTabs().size();
|
| + }
|
| +
|
| + @Override
|
| + public ChildType getChildType() {
|
| + return ChildType.DEFAULT_CONTENT;
|
| + }
|
| +
|
| + /**
|
| + * @param childPosition The index of an item in the recently closed list.
|
| + * @return Whether the item at childPosition is the link to the history page.
|
| + */
|
| + private boolean isHistoryLink(int childPosition) {
|
| + return childPosition == mRecentTabsManager.getRecentlyClosedTabs().size();
|
| + }
|
| +
|
| + @Override
|
| + public RecentlyClosedTab getChild(int childPosition) {
|
| + if (isHistoryLink(childPosition)) {
|
| + return null;
|
| + }
|
| + return mRecentTabsManager.getRecentlyClosedTabs().get(childPosition);
|
| + }
|
| +
|
| + @Override
|
| + public void configureChildView(int childPosition, ViewHolder viewHolder) {
|
| + if (isHistoryLink(childPosition)) {
|
| + viewHolder.textView.setText(R.string.show_full_history);
|
| + ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
| + viewHolder.textView, R.drawable.history_favicon, 0, 0, 0);
|
| + } else {
|
| + RecentlyClosedTab tab = getChild(childPosition);
|
| + String title = NewTabPageView.getTitleForDisplay(tab.title, tab.url);
|
| + viewHolder.textView.setText(title);
|
| + loadLocalFavicon(viewHolder, tab.url);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded) {
|
| + groupView.configureForRecentlyClosedTabs(isExpanded);
|
| + }
|
| +
|
| + @Override
|
| + public void setCollapsed(boolean isCollapsed) {
|
| + mRecentTabsManager.setRecentlyClosedTabsCollapsed(isCollapsed);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isCollapsed() {
|
| + return mRecentTabsManager.isRecentlyClosedTabsCollapsed();
|
| + }
|
| +
|
| + @Override
|
| + public boolean onChildClick(int childPosition) {
|
| + if (isHistoryLink(childPosition)) {
|
| + mRecentTabsManager.openHistoryPage();
|
| + } else {
|
| + mRecentTabsManager.openRecentlyClosedTab(getChild(childPosition),
|
| + WindowOpenDisposition.CURRENT_TAB);
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + @Override
|
| + public void onCreateContextMenuForGroup(ContextMenu menu, Activity activity) {
|
| + }
|
| +
|
| + @Override
|
| + public void onCreateContextMenuForChild(final int childPosition, ContextMenu menu,
|
| + Activity activity) {
|
| + final RecentlyClosedTab recentlyClosedTab = getChild(childPosition);
|
| + if (recentlyClosedTab == null) return;
|
| + OnMenuItemClickListener listener = new OnMenuItemClickListener() {
|
| + @Override
|
| + public boolean onMenuItemClick(MenuItem item) {
|
| + switch (item.getItemId()) {
|
| + case ID_REMOVE_ALL:
|
| + mRecentTabsManager.clearRecentlyClosedTabs();
|
| + break;
|
| + case ID_OPEN_IN_NEW_TAB:
|
| + mRecentTabsManager.openRecentlyClosedTab(recentlyClosedTab,
|
| + WindowOpenDisposition.NEW_BACKGROUND_TAB);
|
| + break;
|
| + default:
|
| + assert false;
|
| + }
|
| + return true;
|
| + }
|
| + };
|
| + menu.add(ContextMenu.NONE, ID_OPEN_IN_NEW_TAB, ContextMenu.NONE,
|
| + R.string.contextmenu_open_in_new_tab).setOnMenuItemClickListener(listener);
|
| + menu.add(ContextMenu.NONE, ID_REMOVE_ALL, ContextMenu.NONE,
|
| + R.string.remove_all).setOnMenuItemClickListener(listener);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * A group containing a blank separator.
|
| + */
|
| + class SeparatorGroup extends Group {
|
| + private final boolean mIsVisible;
|
| +
|
| + public SeparatorGroup(boolean isVisible) {
|
| + mIsVisible = isVisible;
|
| + }
|
| +
|
| + @Override
|
| + public GroupType getGroupType() {
|
| + return mIsVisible ? GroupType.VISIBLE_SEPARATOR : GroupType.INVISIBLE_SEPARATOR;
|
| + }
|
| +
|
| + @Override
|
| + public ChildType getChildType() {
|
| + return ChildType.NONE;
|
| + }
|
| +
|
| + @Override
|
| + public int getChildrenCount() {
|
| + return 0;
|
| + }
|
| +
|
| + @Override
|
| + public View getGroupView(boolean isExpanded, View convertView, ViewGroup parent) {
|
| + if (convertView == null) {
|
| + int layout = mIsVisible
|
| + ? R.layout.recent_tabs_group_separator_visible
|
| + : R.layout.recent_tabs_group_separator_invisible;
|
| + convertView = LayoutInflater.from(mActivity).inflate(layout, parent, false);
|
| + }
|
| + return convertView;
|
| + }
|
| +
|
| + @Override
|
| + public void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded) {
|
| + }
|
| +
|
| + @Override
|
| + public void configureChildView(int childPosition, ViewHolder viewHolder) {
|
| + }
|
| +
|
| + @Override
|
| + public Object getChild(int childPosition) {
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + public void setCollapsed(boolean isCollapsed) {
|
| + }
|
| +
|
| + @Override
|
| + public boolean isCollapsed() {
|
| + return false;
|
| + }
|
| +
|
| + @Override
|
| + public boolean onChildClick(int childPosition) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * A group containing the Sync Promo.
|
| + */
|
| + class SyncPromoGroup extends Group {
|
| + @Override
|
| + public GroupType getGroupType() {
|
| + return GroupType.CONTENT;
|
| + }
|
| +
|
| + @Override
|
| + public ChildType getChildType() {
|
| + return ChildType.SYNC_PROMO;
|
| + }
|
| +
|
| + @Override
|
| + public int getChildrenCount() {
|
| + return 1;
|
| + }
|
| +
|
| + @Override
|
| + public Object getChild(int childPosition) {
|
| + return null;
|
| + }
|
| +
|
| + @Override
|
| + View getChildView(int childPosition, boolean isLastChild, View convertView,
|
| + ViewGroup parent) {
|
| + if (convertView == null) {
|
| + convertView = new RecentTabsPromoView(mActivity, mRecentTabsManager, null);
|
| + }
|
| + return convertView;
|
| + }
|
| +
|
| + @Override
|
| + public void configureChildView(int childPosition, ViewHolder viewHolder) {
|
| + }
|
| +
|
| + @Override
|
| + public void configureGroupView(RecentTabsGroupView groupView, boolean isExpanded) {
|
| + groupView.configureForSyncPromo(isExpanded);
|
| + }
|
| +
|
| + @Override
|
| + public void setCollapsed(boolean isCollapsed) {
|
| + mRecentTabsManager.setSyncPromoCollapsed(isCollapsed);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isCollapsed() {
|
| + return mRecentTabsManager.isSyncPromoCollapsed();
|
| + }
|
| +
|
| + @Override
|
| + public boolean onChildClick(int childPosition) {
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + private static class FaviconCache {
|
| + private static final String SYNCED_FAVICON_PREFIX = "Synced";
|
| + private static final String LOCAL_FAVICON_PREFIX = "Local";
|
| +
|
| + private final LruCache<String, Drawable> mMemoryCache;
|
| +
|
| + public FaviconCache(int size) {
|
| + mMemoryCache = new LruCache<String, Drawable>(size);
|
| + }
|
| +
|
| + public Drawable getSyncedFaviconImage(String url) {
|
| + return mMemoryCache.get(SYNCED_FAVICON_PREFIX + url);
|
| + }
|
| +
|
| + public void putSycnedFaviconImage(String url, Drawable image) {
|
| + mMemoryCache.put(SYNCED_FAVICON_PREFIX + url, image);
|
| + }
|
| +
|
| + public Drawable getLocalFaviconImage(String url) {
|
| + return mMemoryCache.get(LOCAL_FAVICON_PREFIX + url);
|
| + }
|
| +
|
| + public void putLocalFaviconImage(String url, Drawable image) {
|
| + mMemoryCache.put(LOCAL_FAVICON_PREFIX + url, image);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Creates an RecentTabsRowAdapter used to populate an ExpandableList with other
|
| + * devices and foreign tab cells.
|
| + *
|
| + * @param activity The Android activity this adapter will work in.
|
| + * @param recentTabsManager The RecentTabsManager that will act as the data source.
|
| + */
|
| + public RecentTabsRowAdapter(Activity activity, RecentTabsManager recentTabsManager) {
|
| + mActivity = activity;
|
| + mRecentTabsManager = recentTabsManager;
|
| + mGroups = new ArrayList<Group>();
|
| + mInitializationTimestamp =
|
| + TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
|
| + mFaviconCache = buildFaviconCache(MAX_NUM_FAVICONS_TO_CACHE);
|
| +
|
| + Resources resources = activity.getResources();
|
| + mDefaultFavicon = ApiCompatibilityUtils.getDrawable(resources, R.drawable.default_favicon);
|
| + mFaviconSize = mDefaultFavicon.getIntrinsicHeight();
|
| + }
|
| +
|
| + private static FaviconCache buildFaviconCache(int size) {
|
| + return new FaviconCache(size);
|
| + }
|
| +
|
| + /**
|
| + * ViewHolder class optimizes looking up table row fields. findViewById is only called once
|
| + * per row view initialization, and the references are cached here. Also stores a reference to
|
| + * the favicon image callback; so that we can make sure we load the correct favicon.
|
| + */
|
| + private static class ViewHolder {
|
| + public TextView textView;
|
| + public FaviconImageCallback imageCallback;
|
| + }
|
| +
|
| + private Drawable faviconDrawable(Bitmap image) {
|
| + if (image == null) return null;
|
| + return new BitmapDrawable(mActivity.getResources(), Bitmap.createScaledBitmap(image,
|
| + mFaviconSize, mFaviconSize, true));
|
| + }
|
| +
|
| + private void loadSyncedFavicon(final ViewHolder viewHolder, final String url) {
|
| + Drawable image = mFaviconCache.getSyncedFaviconImage(url);
|
| + if (image == null) {
|
| + image = faviconDrawable(mRecentTabsManager.getSyncedFaviconImageForURL(url));
|
| + image = (image == null) ? mDefaultFavicon : image;
|
| + mFaviconCache.putSycnedFaviconImage(url, image);
|
| + }
|
| + ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(viewHolder.textView,
|
| + image, null, null, null);
|
| + }
|
| +
|
| + private void loadLocalFavicon(final ViewHolder viewHolder, final String url) {
|
| + Drawable image;
|
| + if (url == null) {
|
| + // URL is null for print jobs, for example.
|
| + image = mDefaultFavicon;
|
| + } else {
|
| + image = mFaviconCache.getLocalFaviconImage(url);
|
| + if (image == null) {
|
| + FaviconImageCallback imageCallback = new FaviconImageCallback() {
|
| + @Override
|
| + public void onFaviconAvailable(Bitmap bitmap, String iconUrl) {
|
| + if (this != viewHolder.imageCallback) return;
|
| + Drawable image = faviconDrawable(bitmap);
|
| + image = (image == null) ? mDefaultFavicon : image;
|
| + mFaviconCache.putLocalFaviconImage(url, image);
|
| + ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
| + viewHolder.textView, image, null, null, null);
|
| + }
|
| + };
|
| + viewHolder.imageCallback = imageCallback;
|
| + mRecentTabsManager.getLocalFaviconForUrl(url, mFaviconSize, imageCallback);
|
| + image = mDefaultFavicon;
|
| + }
|
| + }
|
| + ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(viewHolder.textView,
|
| + image, null, null, null);
|
| + }
|
| +
|
| + @Override
|
| + public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
|
| + View convertView, ViewGroup parent) {
|
| + return getGroup(groupPosition).getChildView(childPosition, isLastChild, convertView,
|
| + parent);
|
| + }
|
| +
|
| + // BaseExpandableListAdapter group related implementations
|
| + @Override
|
| + public int getGroupCount() {
|
| + return mGroups.size();
|
| + }
|
| +
|
| + @Override
|
| + public long getGroupId(int groupPosition) {
|
| + return groupPosition;
|
| + }
|
| +
|
| + @Override
|
| + public Group getGroup(int groupPosition) {
|
| + return mGroups.get(groupPosition);
|
| + }
|
| +
|
| + @Override
|
| + public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
|
| + ViewGroup parent) {
|
| + return getGroup(groupPosition).getGroupView(isExpanded, convertView, parent);
|
| + }
|
| +
|
| + // BaseExpandableListAdapter child related implementations
|
| + @Override
|
| + public int getChildrenCount(int groupPosition) {
|
| + return getGroup(groupPosition).getChildrenCount();
|
| + }
|
| +
|
| + @Override
|
| + public long getChildId(int groupPosition, int childPosition) {
|
| + return childPosition;
|
| + }
|
| +
|
| + @Override
|
| + public Object getChild(int groupPosition, int childPosition) {
|
| + return getGroup(groupPosition).getChild(childPosition);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isChildSelectable(int groupPosition, int childPosition) {
|
| + return true;
|
| + }
|
| +
|
| + // BaseExpandableListAdapter misc. implementation
|
| + @Override
|
| + public boolean hasStableIds() {
|
| + return false;
|
| + }
|
| +
|
| + @Override
|
| + public int getGroupType(int groupPosition) {
|
| + return getGroup(groupPosition).getGroupType().ordinal();
|
| + }
|
| +
|
| + @Override
|
| + public int getGroupTypeCount() {
|
| + return GroupType.values().length;
|
| + }
|
| +
|
| + private void addGroup(Group group) {
|
| + if (!DeviceFormFactor.isTablet(mActivity)) {
|
| + mGroups.add(group);
|
| + } else {
|
| + if (mGroups.size() == 0) {
|
| + mGroups.add(mInvisibleSeparatorGroup);
|
| + }
|
| + mGroups.add(group);
|
| + mGroups.add(mInvisibleSeparatorGroup);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public void notifyDataSetChanged() {
|
| + mGroups.clear();
|
| + List<CurrentlyOpenTab> tabList = mRecentTabsManager.getCurrentlyOpenTabs();
|
| + if (tabList != null && !tabList.isEmpty()) {
|
| + addGroup(new CurrentlyOpenTabsGroup(tabList));
|
| + }
|
| + addGroup(mRecentlyClosedTabsGroup);
|
| + for (ForeignSession session : mRecentTabsManager.getForeignSessions()) {
|
| + addGroup(new ForeignSessionGroup(session));
|
| + }
|
| + if (mRecentTabsManager.shouldDisplaySyncPromo()) {
|
| + addGroup(new SyncPromoGroup());
|
| + }
|
| +
|
| + // Add separator line after the recently closed tabs group.
|
| + int recentlyClosedIndex = mGroups.indexOf(mRecentlyClosedTabsGroup);
|
| + if (DeviceFormFactor.isTablet(mActivity)) {
|
| + if (recentlyClosedIndex != mGroups.size() - 2) {
|
| + mGroups.set(recentlyClosedIndex + 1, mVisibleSeparatorGroup);
|
| + }
|
| + } else if (recentlyClosedIndex != mGroups.size() - 1) {
|
| + mGroups.add(recentlyClosedIndex + 1, mVisibleSeparatorGroup);
|
| + }
|
| +
|
| + super.notifyDataSetChanged();
|
| + }
|
| +
|
| + @Override
|
| + public int getChildType(int groupPosition, int childPosition) {
|
| + return mGroups.get(groupPosition).getChildType().ordinal();
|
| + }
|
| +
|
| + @Override
|
| + public int getChildTypeCount() {
|
| + return ChildType.values().length;
|
| + }
|
| +}
|
|
|