| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/BookmarksPageView.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/BookmarksPageView.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/BookmarksPageView.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a950e5256512631577e6798fb71220104ff4b374
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/ntp/BookmarksPageView.java
|
| @@ -0,0 +1,384 @@
|
| +// 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.content.Context;
|
| +import android.graphics.Bitmap;
|
| +import android.graphics.BitmapFactory;
|
| +import android.text.TextUtils;
|
| +import android.util.AttributeSet;
|
| +import android.util.LruCache;
|
| +import android.view.View;
|
| +import android.view.ViewGroup;
|
| +import android.view.inputmethod.EditorInfo;
|
| +import android.view.inputmethod.InputConnection;
|
| +import android.widget.BaseAdapter;
|
| +import android.widget.HorizontalScrollView;
|
| +import android.widget.ImageView;
|
| +import android.widget.LinearLayout;
|
| +import android.widget.TextView;
|
| +
|
| +import com.google.android.apps.chrome.R;
|
| +
|
| +import org.chromium.chrome.browser.BookmarksBridge.BookmarkItem;
|
| +import org.chromium.chrome.browser.BookmarksBridge.BookmarksCallback;
|
| +import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
|
| +import org.chromium.components.bookmarks.BookmarkId;
|
| +import org.chromium.ui.base.LocalizationUtils;
|
| +
|
| +import java.util.Collections;
|
| +import java.util.List;
|
| +
|
| +/**
|
| + * The native bookmarks page, represented by some basic data such as folder contents,
|
| + * folder hierarchy, and an Android View that displays the page.
|
| + */
|
| +public class BookmarksPageView extends LinearLayout implements BookmarksCallback {
|
| +
|
| + private static final int MAX_NUM_FAVICONS_TO_CACHE = 256;
|
| +
|
| + private BookmarksPageManager mManager;
|
| + private HorizontalScrollView mHierarchyContainer;
|
| + private LinearLayout mHierarchyLayout;
|
| + private Bitmap mDefaultFavicon;
|
| + private BookmarkItemView.DrawingData mDrawingData;
|
| + private final int mDesiredFaviconSize;
|
| + private final LruCache<String, Bitmap> mFaviconCache;
|
| +
|
| + private final BookmarkListAdapter mAdapter;
|
| + private BookmarksListView mBookmarksList;
|
| + private TextView mEmptyView;
|
| + private int mSavedListPosition = 0;
|
| + private int mSavedListTop = 0;
|
| +
|
| + private boolean mSnapshotBookmarksChanged;
|
| + private int mSnapshotWidth;
|
| + private int mSnapshotHeight;
|
| + private int mSnapshotBookmarksListPosition;
|
| + private int mSnapshotBookmarksListTop;
|
| + private int mSnapshotBookmarksHierarchyScrollX;
|
| +
|
| + /**
|
| + * Manages the view interaction with the rest of the system.
|
| + */
|
| + public interface BookmarksPageManager {
|
| + /**
|
| + * @return True, if destroy() has been called.
|
| + */
|
| + boolean isDestroyed();
|
| +
|
| + /**
|
| + * @return Whether this bookmarks page should use incognito mode.
|
| + */
|
| + boolean isIncognito();
|
| +
|
| + /**
|
| + * @return Whether "Open in new tab" should be shown in the context menu
|
| + * when long pressing a bookmark.
|
| + */
|
| + boolean shouldShowOpenInNewTab();
|
| +
|
| + /**
|
| + * @return Whether "Open in new incognito tab" should be shown in the context menu
|
| + * when long pressing a bookmark.
|
| + */
|
| + boolean shouldShowOpenInNewIncognitoTab();
|
| +
|
| + /**
|
| + * @return Whether to show a context menu on long press.
|
| + */
|
| + boolean isContextMenuEnabled();
|
| +
|
| + /**
|
| + * Opens the bookmark item. If item is a bookmark then it opens the page else,
|
| + * if folder, it displays the folder contents.
|
| + * @param item BookmarkItem to be opened.
|
| + */
|
| + void open(BookmarkItemView item);
|
| +
|
| + /**
|
| + * Opens a bookmark item in a new tab.
|
| + * @param item The bookmark item to open.
|
| + */
|
| + void openInNewTab(BookmarkItemView item);
|
| +
|
| + /**
|
| + * Opens a bookmark item in a new incognito tab.
|
| + * @param item The bookmark item to open.
|
| + */
|
| + void openInNewIncognitoTab(BookmarkItemView item);
|
| +
|
| + /**
|
| + * Opens the bookmark folder to display the folder contents.
|
| + * @param item BookmarkFolderHierarchyItem to be opened.
|
| + */
|
| + void openFolder(BookmarkFolderHierarchyItem item);
|
| +
|
| + /**
|
| + * Deletes a bookmark entry.
|
| + * @param item The bookmark item to remove.
|
| + */
|
| + void delete(BookmarkItemView item);
|
| +
|
| + /**
|
| + * Edits a bookmark entry.
|
| + * @param item The bookmark item to be edited.
|
| + */
|
| + void edit(BookmarkItemView item);
|
| +
|
| + /**
|
| + * Gets the favicon image for a given URL.
|
| + * @param url The URL of the site whose favicon is being requested.
|
| + * @param size The desired size of the favicon in pixels.
|
| + * @param faviconCallback The callback to be notified when the favicon is available.
|
| + */
|
| + void getFaviconImageForUrl(String url, int size, FaviconImageCallback faviconCallback);
|
| + }
|
| +
|
| + /**
|
| + * Constructor for inflating from XML.
|
| + */
|
| + public BookmarksPageView(Context context, AttributeSet attrs) {
|
| + super(context, attrs);
|
| +
|
| + mDesiredFaviconSize = getResources().getDimensionPixelSize(
|
| + R.dimen.ntp_list_item_favicon_size);
|
| + mFaviconCache = new LruCache<String, Bitmap>(MAX_NUM_FAVICONS_TO_CACHE);
|
| + mAdapter = new BookmarkListAdapter();
|
| + }
|
| +
|
| + @Override
|
| + protected void onFinishInflate() {
|
| + super.onFinishInflate();
|
| +
|
| + mHierarchyContainer =
|
| + (HorizontalScrollView) findViewById(R.id.folder_structure_scroll_view);
|
| + mHierarchyContainer.setSmoothScrollingEnabled(true);
|
| + mHierarchyLayout = (LinearLayout) findViewById(R.id.bookmark_folder_structure);
|
| +
|
| + mBookmarksList = (BookmarksListView) findViewById(R.id.bookmarks_list_view);
|
| + mBookmarksList.setAdapter(mAdapter);
|
| +
|
| + mEmptyView = (TextView) findViewById(R.id.bookmarks_empty_view);
|
| + mBookmarksList.setEmptyView(mEmptyView);
|
| + }
|
| +
|
| + @Override
|
| + public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
| + // Fixes lanscape transitions when unfocusing the URL bar: crbug.com/288546
|
| + outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
|
| + return super.onCreateInputConnection(outAttrs);
|
| + }
|
| +
|
| + /**
|
| + * Handles initializing the view.
|
| + * @param manager The manager handling the external dependencies of this view.
|
| + */
|
| + void initialize(BookmarksPageManager manager) {
|
| + mManager = manager;
|
| + }
|
| +
|
| + @Override
|
| + protected void onDetachedFromWindow() {
|
| + mSavedListPosition = mBookmarksList.getFirstVisiblePosition();
|
| + View v = mBookmarksList.getChildAt(0);
|
| + mSavedListTop = (v == null) ? 0 : v.getTop();
|
| + super.onDetachedFromWindow();
|
| + }
|
| +
|
| + @Override
|
| + protected void onAttachedToWindow() {
|
| + super.onAttachedToWindow();
|
| + mBookmarksList.setSelectionFromTop(mSavedListPosition, mSavedListTop);
|
| + }
|
| +
|
| + /**
|
| + * @see org.chromium.chrome.browser.compositor.layouts.content
|
| + * .InvalidationAwareThumbnailProvider#shouldCaptureThumbnail()
|
| + */
|
| + boolean shouldCaptureThumbnail() {
|
| + if (getWidth() == 0 || getHeight() == 0) return false;
|
| +
|
| + View topItem = mBookmarksList.getChildAt(0);
|
| + return mSnapshotBookmarksChanged
|
| + || getWidth() != mSnapshotWidth
|
| + || getHeight() != mSnapshotHeight
|
| + || mSnapshotBookmarksListPosition != mBookmarksList.getFirstVisiblePosition()
|
| + || mSnapshotBookmarksListTop != (topItem == null ? 0 : topItem.getTop())
|
| + || mHierarchyContainer.getScrollX() != mSnapshotBookmarksHierarchyScrollX;
|
| + }
|
| +
|
| + /**
|
| + * Triggered after a thumbnail has been captured to update the thumbnail visual state used to
|
| + * determine dirtiness.
|
| + */
|
| + void updateThumbnailState() {
|
| + mSnapshotWidth = getWidth();
|
| + mSnapshotHeight = getHeight();
|
| + mSnapshotBookmarksListPosition = mBookmarksList.getFirstVisiblePosition();
|
| + View topItem = mBookmarksList.getChildAt(0);
|
| + mSnapshotBookmarksListTop = topItem == null ? 0 : topItem.getTop();
|
| + mSnapshotBookmarksHierarchyScrollX = mHierarchyContainer.getScrollX();
|
| + mSnapshotBookmarksChanged = false;
|
| + }
|
| +
|
| + // BookmarksCallback overrides
|
| +
|
| + @Override
|
| + public void onBookmarksAvailable(BookmarkId folderId, List<BookmarkItem> bookmarksList) {
|
| + if (mEmptyView.length() == 0) {
|
| + // Set the empty view's text now that the first bookmarks callback has happened. If we
|
| + // set the text earlier, the user will see the "No bookmarks here" message while we're
|
| + // waiting for the callback.
|
| + mEmptyView.setText(R.string.bookmarks_folder_empty);
|
| + }
|
| +
|
| + mAdapter.setBookmarksList(bookmarksList);
|
| + mAdapter.notifyDataSetChanged();
|
| +
|
| + // In theory, the adapter should trigger a re-layout when the bookmarks list changes. In
|
| + // practice, if the bookmarks page is in the background and hence not attached to the view
|
| + // hierarchy, this doesn't happen. So, trigger the re-layout explicitly.
|
| + mBookmarksList.requestLayout();
|
| + mBookmarksList.invalidate();
|
| +
|
| + // Cause the scroll bar to appear then fade out again if this folder is scrollable.
|
| + mBookmarksList.awakenScrollBars();
|
| +
|
| + mSnapshotBookmarksChanged = true;
|
| + }
|
| +
|
| + @Override
|
| + public void onBookmarksFolderHierarchyAvailable(BookmarkId folderId,
|
| + List<BookmarkItem> bookmarksList) {
|
| + if (mManager.isDestroyed()) return;
|
| + mHierarchyLayout.removeAllViews();
|
| + for (int i = bookmarksList.size() - 1; i >= 0; i--) {
|
| + BookmarkItem bookmark = bookmarksList.get(i);
|
| + addItemToHierarchyView(bookmark.getTitle(), bookmark.getId(), (i == 0) ? true : false);
|
| + }
|
| + mHierarchyLayout.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
| + @Override
|
| + public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
| + int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
| + mHierarchyLayout.removeOnLayoutChangeListener(this);
|
| + mHierarchyContainer.fullScroll(LocalizationUtils.isLayoutRtl()
|
| + ? View.FOCUS_LEFT : View.FOCUS_RIGHT);
|
| + }
|
| + });
|
| +
|
| + mSnapshotBookmarksChanged = true;
|
| + }
|
| +
|
| + /**
|
| + * Add a BookmarkFolderHierarchyItem item to the hierarchy layout.
|
| + * @param title Title of the folder
|
| + * @param id Id of the folder
|
| + * @param isCurrentFolder Whether the folder is the current folder.
|
| + */
|
| + private void addItemToHierarchyView(String title, final BookmarkId id,
|
| + boolean isCurrentFolder) {
|
| + if (TextUtils.isEmpty(title)) {
|
| + // TODO(cramya): Need to check why we cannot get "Bookmarks" folder information.
|
| + title = getResources().getString(R.string.ntp_bookmarks);
|
| + } else {
|
| + ImageView separator = new ImageView(getContext());
|
| + separator.setImageResource(R.drawable.breadcrumb_arrow);
|
| + mHierarchyLayout.addView(separator);
|
| + }
|
| + final BookmarkFolderHierarchyItem item = new BookmarkFolderHierarchyItem(
|
| + getContext(), mManager, id, title, isCurrentFolder);
|
| + mHierarchyLayout.addView(item);
|
| + }
|
| +
|
| + /**
|
| + * List Adapter for Bookmarks List View.
|
| + */
|
| + private class BookmarkListAdapter extends BaseAdapter {
|
| +
|
| + public List<BookmarkItem> mBookmarks = Collections.emptyList();
|
| +
|
| + /**
|
| + * Sets the bookmarks list for adapter.
|
| + * @param bookmarks BookmarkItem list.
|
| + */
|
| + public void setBookmarksList(List<BookmarkItem> bookmarks) {
|
| + mBookmarks = bookmarks;
|
| + }
|
| +
|
| + @Override
|
| + public View getView(int position, View convertView, ViewGroup parent) {
|
| + if (mDrawingData == null) mDrawingData = new BookmarkItemView.DrawingData(getContext());
|
| + final BookmarkItem bookmark = getItem(position);
|
| + final BookmarkItemView item;
|
| + if (convertView instanceof BookmarkItemView) {
|
| + item = (BookmarkItemView) convertView;
|
| + if (!item.reset(bookmark.getId(), bookmark.getTitle(), bookmark.getUrl(),
|
| + bookmark.isEditable(), bookmark.isManaged())) {
|
| + return item;
|
| + }
|
| + } else {
|
| + item = new BookmarkItemView(getContext(), mManager,
|
| + bookmark.getId(), bookmark.getTitle(), bookmark.getUrl(),
|
| + bookmark.isEditable(), bookmark.isManaged(), mDrawingData);
|
| + }
|
| + if (!bookmark.isFolder() && !TextUtils.isEmpty(bookmark.getUrl())) {
|
| + Bitmap favicon = mFaviconCache.get(bookmark.getUrl());
|
| + if (favicon != null) {
|
| + item.setFavicon(favicon);
|
| + } else if (!mManager.isDestroyed()) {
|
| + FaviconImageCallback faviconCallback = new FaviconImageCallback() {
|
| + @Override
|
| + public void onFaviconAvailable(Bitmap image, String iconUrl) {
|
| + if (image == null) {
|
| + if (mDefaultFavicon == null) {
|
| + mDefaultFavicon = BitmapFactory.decodeResource(
|
| + getResources(), R.drawable.default_favicon);
|
| + }
|
| + image = mDefaultFavicon;
|
| + }
|
| + mFaviconCache.put(bookmark.getUrl(), image);
|
| + // It's possible the BookmarkItemView has been recycled and is now
|
| + // displaying a different bookmark. Don't update the favicon in this
|
| + // case.
|
| + if (bookmark.getUrl().equals(item.getUrl())) {
|
| + item.setFavicon(image);
|
| + mSnapshotBookmarksChanged = true;
|
| + }
|
| + }
|
| + };
|
| + mManager.getFaviconImageForUrl(bookmark.getUrl(), mDesiredFaviconSize,
|
| + faviconCallback);
|
| + }
|
| + }
|
| + return item;
|
| + }
|
| +
|
| + @Override
|
| + public long getItemId(int position) {
|
| + return position;
|
| + }
|
| +
|
| + @Override
|
| + public int getCount() {
|
| + return mBookmarks.size();
|
| + }
|
| +
|
| + @Override
|
| + public BookmarkItem getItem(int position) {
|
| + return mBookmarks.get(position);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isEmpty() {
|
| + return mBookmarks.isEmpty();
|
| + }
|
| +
|
| + @Override
|
| + public boolean hasStableIds() {
|
| + return false;
|
| + }
|
| + }
|
| +}
|
|
|