Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(984)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java

Issue 11743011: Add history popup when long pressing on the back key. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Use a padding drawable for null favicons to avoid jumping UI. Created 7 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba955616515535e0b97a58f903db19307037da8b
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
@@ -0,0 +1,245 @@
+// Copyright (c) 2013 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;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.HeaderViewListAdapter;
+import android.widget.ListPopupWindow;
+import android.widget.ListView;
+import android.widget.ListView.FixedViewInfo;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.ThreadUtils;
+import org.chromium.chrome.R;
+import org.chromium.content.browser.ContentViewCore;
+import org.chromium.content.browser.NavigationClient;
+import org.chromium.content.browser.NavigationEntry;
+import org.chromium.content.browser.NavigationHistory;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A popup that handles displaying the navigation history for a given tab.
+ */
+public class NavigationPopup extends ListPopupWindow implements AdapterView.OnItemClickListener {
+
+ private static final int LIST_ITEM_HEIGHT_DP = 48;
+ private static final int FAVICON_SIZE_DP = 16;
+ private static final int PADDING_DP = 8;
+ private static final int TEXT_SIZE_SP = 18;
+
+ private static final int MAXIMUM_HISTORY_ITEMS = 8;
+
+ private final Context mContext;
+ private final NavigationPopupDelegate mDelegate;
+ private final NavigationClient mNavigationClient;
+ private final NavigationHistory mHistory;
+ private final NavigationAdapter mAdapter;
+ private final TextView mShowHistoryView;
+
+ private final int mListItemHeight;
+ private final int mFaviconSize;
+ private final int mPadding;
+
+ private int mNativeNavigationPopup;
+
+ /**
+ * Delegate functionality required to operate on the history.
+ */
+ public interface NavigationPopupDelegate {
+ /** Open the complete browser history page */
+ void openHistory();
+ }
+
+ /**
+ * Constructs a new popup with the given history information.
+ *
+ * @param context The context used for building the popup.
+ * @param delegate The delegate that handles history actions outside of the given
+ * {@link ContentViewCore}.
+ * @param navigationClient The owner of the history being displayed.
+ * @param isForward Whether to request forward navigation entries.
+ */
+ public NavigationPopup(
+ Context context, NavigationPopupDelegate delegate,
+ NavigationClient navigationClient, boolean isForward) {
+ super(context, null, android.R.attr.popupMenuStyle);
+ mContext = context;
+ assert delegate != null : "NavigationPopup requires non-null delegate.";
+ mDelegate = delegate;
+ mNavigationClient = navigationClient;
+ mHistory = mNavigationClient.getDirectedNavigationHistory(
+ isForward, MAXIMUM_HISTORY_ITEMS);
+ mAdapter = new NavigationAdapter();
+
+ float density = mContext.getResources().getDisplayMetrics().density;
+ mListItemHeight = (int) (density * LIST_ITEM_HEIGHT_DP);
+ mFaviconSize = (int) (density * FAVICON_SIZE_DP);
+ mPadding = (int) (density * PADDING_DP);
+
+ setModal(true);
+ setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+ setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
+ setOnItemClickListener(this);
+
+ FixedViewInfo footerInfo = new ListView(context).new FixedViewInfo();
+ mShowHistoryView = createListItem();
+ mShowHistoryView.setText(R.string.show_history_label);
+ footerInfo.isSelectable = true;
+ footerInfo.view = mShowHistoryView;
+ ArrayList<FixedViewInfo> footerInfoList = new ArrayList<FixedViewInfo>(1);
+ footerInfoList.add(footerInfo);
+ setAdapter(new HeaderViewListAdapter(null, footerInfoList, mAdapter));
+ }
+
+ /**
+ * @return The URL of the page for managing history.
+ */
+ public static String getHistoryUrl() {
+ return nativeGetHistoryUrl();
+ }
+
+ /**
+ * @return Whether a navigation popup is valid for the given page.
+ */
+ public boolean shouldBeShown() {
+ return mHistory.getEntryCount() > 0;
+ }
+
+ @Override
+ public void show() {
+ if (mNativeNavigationPopup == 0) initializeNative();
+ super.show();
+ }
+
+ @Override
+ public void dismiss() {
+ if (mNativeNavigationPopup != 0) {
+ nativeDestroy(mNativeNavigationPopup);
+ mNativeNavigationPopup = 0;
+ }
+ super.dismiss();
+ }
+
+ private void initializeNative() {
+ ThreadUtils.assertOnUiThread();
+ mNativeNavigationPopup = nativeInit();
+
+ Set<String> requestedUrls = new HashSet<String>();
+ for (int i = 0; i < mHistory.getEntryCount(); i++) {
+ NavigationEntry entry = mHistory.getEntryAtIndex(i);
+ if (entry.getFavicon() != null) continue;
+ String url = entry.getUrl();
+ if (!requestedUrls.contains(url)) {
+ nativeFetchFaviconForUrl(mNativeNavigationPopup, url);
+ requestedUrls.add(url);
+ }
+ }
+ nativeFetchFaviconForUrl(mNativeNavigationPopup, nativeGetHistoryUrl());
+ }
+
+ @CalledByNative
+ private void onFaviconUpdated(String url, Object favicon) {
+ for (int i = 0; i < mHistory.getEntryCount(); i++) {
+ NavigationEntry entry = mHistory.getEntryAtIndex(i);
+ if (TextUtils.equals(url, entry.getUrl())) entry.updateFavicon((Bitmap) favicon);
+ }
+ if (TextUtils.equals(url, nativeGetHistoryUrl())) {
+ updateBitmapForTextView(mShowHistoryView, (Bitmap) favicon);
+ }
+ mAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if (position == mHistory.getEntryCount()) {
+ mDelegate.openHistory();
+ } else {
+ NavigationEntry entry = (NavigationEntry) parent.getItemAtPosition(position);
+ mNavigationClient.goToNavigationIndex(entry.getIndex());
+ }
+ dismiss();
+ }
+
+ private TextView createListItem() {
+ TextView view = new TextView(mContext);
+ view.setSingleLine();
+ view.setTextSize(TEXT_SIZE_SP);
+ view.setMinimumHeight(mListItemHeight);
+ view.setGravity(Gravity.CENTER_VERTICAL);
+ view.setCompoundDrawablePadding(mPadding);
+ view.setPadding(mPadding, 0, mPadding, 0);
+ return view;
+ }
+
+ private void updateBitmapForTextView(TextView view, Bitmap bitmap) {
+ Drawable faviconDrawable = null;
+ if (bitmap != null) {
+ faviconDrawable = new BitmapDrawable(mContext.getResources(), bitmap);
+ ((BitmapDrawable) faviconDrawable).setGravity(Gravity.FILL);
+ } else {
+ faviconDrawable = new ColorDrawable(Color.TRANSPARENT);
+ }
+ faviconDrawable.setBounds(0, 0, mFaviconSize, mFaviconSize);
+ view.setCompoundDrawables(faviconDrawable, null, null, null);
+ }
+
+ private class NavigationAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return mHistory.getEntryCount();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return mHistory.getEntryAtIndex(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return ((NavigationEntry) getItem(position)).getIndex();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+ if (convertView != null && convertView instanceof TextView) {
+ view = (TextView) convertView;
+ } else {
+ view = createListItem();
+ }
+ NavigationEntry entry = (NavigationEntry) getItem(position);
+
+ String entryText = entry.getTitle();
+ if (TextUtils.isEmpty(entryText)) entryText = entry.getVirtualUrl();
+ if (TextUtils.isEmpty(entryText)) entryText = entry.getUrl();
+ view.setText(entryText);
+ updateBitmapForTextView(view, entry.getFavicon());
+
+ return view;
+ }
+ }
+
+ private static native String nativeGetHistoryUrl();
+
+ private native int nativeInit();
+ private native void nativeDestroy(int nativeNavigationPopup);
+ private native void nativeFetchFaviconForUrl(int nativeNavigationPopup, String url);
+}

Powered by Google App Engine
This is Rietveld 408576698