summaryrefslogtreecommitdiffstats
path: root/src/com/android/browser
diff options
context:
space:
mode:
authorPankaj Garg <pgarg@codeaurora.org>2015-07-02 17:17:24 -0700
committerjrizzoli <joey@cyanogenmoditalia.it>2015-08-28 13:15:45 +0200
commit21dad566a57084c8c5eae66909f917ff7c1fd222 (patch)
tree6ad508be6d8cebba36c7521e01e8d80c9f285979 /src/com/android/browser
parent680d3981b289233b9ff3d60683e99880dc90559c (diff)
downloadandroid_packages_apps_Gello-21dad566a57084c8c5eae66909f917ff7c1fd222.tar.gz
android_packages_apps_Gello-21dad566a57084c8c5eae66909f917ff7c1fd222.tar.bz2
android_packages_apps_Gello-21dad566a57084c8c5eae66909f917ff7c1fd222.zip
Use tiles for bookmarks
- Use tile based bitmap for bookmarks and history - Settings UI cleanup Change-Id: If959cb0b8f110035b8dd2fefe8106e9c5d30f4f1
Diffstat (limited to 'src/com/android/browser')
-rw-r--r--src/com/android/browser/AddBookmarkPage.java7
-rw-r--r--src/com/android/browser/BookmarkItem.java36
-rw-r--r--src/com/android/browser/BrowserBookmarksAdapter.java14
-rw-r--r--src/com/android/browser/BrowserHistoryPage.java6
-rw-r--r--src/com/android/browser/Controller.java4
-rw-r--r--src/com/android/browser/HistoryItem.java25
-rw-r--r--src/com/android/browser/SiteTileView.java510
-rw-r--r--src/com/android/browser/Tab.java9
-rw-r--r--src/com/android/browser/preferences/SiteSpecificPreferencesFragment.java5
-rw-r--r--src/com/android/browser/view/BookmarkContainer.java19
10 files changed, 595 insertions, 40 deletions
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index 884cdc4d..a50a7d64 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -657,6 +657,7 @@ public class AddBookmarkPage extends Activity
String title = null;
String url = null;
+ mTouchIconUrl = null;
mFakeTitle = (TextView) findViewById(R.id.fake_title);
if (mMap != null) {
@@ -838,7 +839,7 @@ public class AddBookmarkPage extends Activity
Bookmarks.addBookmark(AddBookmarkPage.this, false, url,
title, thumbnail, mCurrentFolder);
if (touchIconUrl != null) {
- new DownloadTouchIcon(mContext, cr, url).execute(mTouchIconUrl);
+ new DownloadTouchIcon(mContext, cr, url).execute(touchIconUrl);
}
mMessage.arg1 = 1;
} catch (IllegalStateException e) {
@@ -1083,7 +1084,9 @@ public class AddBookmarkPage extends Activity
} else {
bundle.putParcelable(BrowserContract.Bookmarks.THUMBNAIL, thumbnail);
bundle.putBoolean(REMOVE_THUMBNAIL, !urlUnmodified);
- bundle.putString(TOUCH_ICON_URL, mTouchIconUrl);
+ if (mTouchIconUrl != null) {
+ bundle.putString(TOUCH_ICON_URL, mTouchIconUrl);
+ }
// Post a message to write to the DB.
Message msg = Message.obtain(mHandler, SAVE_BOOKMARK);
msg.setData(bundle);
diff --git a/src/com/android/browser/BookmarkItem.java b/src/com/android/browser/BookmarkItem.java
index b230de6c..12b2b705 100644
--- a/src/com/android/browser/BookmarkItem.java
+++ b/src/com/android/browser/BookmarkItem.java
@@ -16,18 +16,14 @@
package com.android.browser;
-import com.android.browser.R;
-
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;
-import android.widget.ImageView;
import android.widget.TextView;
/**
@@ -37,13 +33,14 @@ class BookmarkItem extends ScrollView {
final static int MAX_TEXTVIEW_LEN = 80;
- protected TextView mTextView;
- protected TextView mUrlText;
- protected ImageView mImageView;
- protected String mUrl;
- protected String mTitle;
+ protected TextView mTextView;
+ protected TextView mUrlText;
+ protected SiteTileView mTileView;
+ protected String mUrl;
+ protected String mTitle;
protected boolean mEnableScrolling = false;
+ protected Bitmap mBitmap;
/**
* Instantiate a bookmark item, including a default favicon.
*
@@ -58,22 +55,12 @@ class BookmarkItem extends ScrollView {
factory.inflate(R.layout.history_item, this);
mTextView = (TextView) findViewById(R.id.title);
mUrlText = (TextView) findViewById(R.id.url);
- mImageView = (ImageView) findViewById(R.id.favicon);
+ mTileView = (SiteTileView) findViewById(R.id.favicon);
View star = findViewById(R.id.star);
star.setVisibility(View.GONE);
}
/**
- * Copy this BookmarkItem to item.
- * @param item BookmarkItem to receive the info from this BookmarkItem.
- */
- /* package */ void copyTo(BookmarkItem item) {
- item.mTextView.setText(mTextView.getText());
- item.mUrlText.setText(mUrlText.getText());
- item.mImageView.setImageDrawable(mImageView.getDrawable());
- }
-
- /**
* Return the name assigned to this bookmark item.
*/
/* package */ String getName() {
@@ -92,18 +79,17 @@ class BookmarkItem extends ScrollView {
*/
/* package */ void setFavicon(Bitmap b) {
if (b != null) {
- mImageView.setImageBitmap(b);
- } else {
- mImageView.setImageResource(R.drawable.ic_deco_favicon_normal);
+ mTileView.replaceFavicon(b);
+ mBitmap = b;
}
}
public int getFavIconIntrinsicWidth() {
- return mImageView.getDrawable().getIntrinsicWidth();
+ return mTileView.getMeasuredWidth();
}
void setFaviconBackground(Drawable d) {
- mImageView.setBackgroundDrawable(d);
+ mTileView.setBackgroundDrawable(d);
}
/**
diff --git a/src/com/android/browser/BrowserBookmarksAdapter.java b/src/com/android/browser/BrowserBookmarksAdapter.java
index 38e07e07..cef6e626 100644
--- a/src/com/android/browser/BrowserBookmarksAdapter.java
+++ b/src/com/android/browser/BrowserBookmarksAdapter.java
@@ -24,6 +24,7 @@ import android.graphics.drawable.BitmapDrawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
import android.widget.TextView;
import com.android.browser.mdm.EditBookmarksRestriction;
@@ -85,7 +86,7 @@ public class BrowserBookmarksAdapter extends
.getDimensionPixelSize(R.dimen.combo_horizontalSpacing);
view.setPadding(padding, view.getPaddingTop(),
padding, view.getPaddingBottom());
- BookmarkThumbImageView thumb = (BookmarkThumbImageView) view.findViewById(R.id.thumb_image);
+ SiteTileView thumb = (SiteTileView) view.findViewById(R.id.thumb_image);
TextView tv = (TextView) view.findViewById(R.id.label);
tv.setText(item.title);
int containerWidth = thumb.getWidth() - thumb.getPaddingLeft() - thumb.getPaddingRight();
@@ -94,7 +95,8 @@ public class BrowserBookmarksAdapter extends
if (item.is_folder) {
b = BitmapFactory.decodeResource(mContext.getResources(),
- R.drawable.thumb_bookmark_widget_folder_holo);
+ R.drawable.ic_deco_folder_normal);
+ thumb.setFloating(true);
}
else if (item.thumbnail == null || !item.has_thumbnail) {
b = BitmapFactory.decodeResource(mContext.getResources(),
@@ -105,7 +107,8 @@ public class BrowserBookmarksAdapter extends
}
// If the item is managed by mdm or edit bookmark restriction enabled
- if (containerWidth != 0 && (item.is_mdm_managed || EditBookmarksRestriction.getInstance().isEnabled())) {
+ if (containerWidth != 0 && (item.is_mdm_managed ||
+ EditBookmarksRestriction.getInstance().isEnabled())) {
int iconResId;
float overlayScale, overlayVertPos;
@@ -122,11 +125,12 @@ public class BrowserBookmarksAdapter extends
float willScale = (float) containerWidth / (float) b.getWidth();
Bitmap bm = BrowserBookmarksPage.overlayBookmarkBitmap(b, iconResId, mContext,
overlayScale / willScale, (int) (overlayVertPos / willScale));
- thumb.setImageBitmap(bm);
+ thumb.replaceFavicon(bm);
}
else {
- thumb.setImageBitmap(b);
+ thumb.replaceFavicon(b);
}
+ thumb.setLongClickable(true);
}
@Override
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index f0cec84f..80e1da7e 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -652,8 +652,14 @@ public class BrowserHistoryPage extends Fragment
item.getPaddingRight(),
item.getPaddingBottom());
item.setFaviconBackground(mFaviconBackground);
+ item.setTag(R.id.group_position, groupPosition);
+ item.setTag(R.id.child_position, childPosition);
+ item.setTag(R.id.combo_view_container, mHistoryList);
} else {
item = (HistoryItem) convertView;
+ item.setTag(R.id.group_position, groupPosition);
+ item.setTag(R.id.child_position, childPosition);
+ item.setTag(R.id.combo_view_container, mHistoryList);
}
// Bail early if the Cursor is closed.
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index c7ceb681..5563b627 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -2028,10 +2028,12 @@ public class Controller
switch (item.getItemId()) {
// -- Main menu
case R.id.new_tab_menu_id:
+ getCurrentTab().capture();
openTabToHomePage();
break;
case R.id.incognito_menu_id:
+ getCurrentTab().capture();
openIncognitoTab();
break;
@@ -2543,7 +2545,7 @@ public class Controller
AddBookmarkPage.class);
i.putExtra(BrowserContract.Bookmarks.URL, w.getUrl());
i.putExtra(BrowserContract.Bookmarks.TITLE, w.getTitle());
- String touchIconUrl = w.getTouchIconUrl();
+ String touchIconUrl = getCurrentTab().getTouchIconUrl();
if (touchIconUrl != null) {
i.putExtra(AddBookmarkPage.TOUCH_ICON_URL, touchIconUrl);
WebSettings settings = w.getSettings();
diff --git a/src/com/android/browser/HistoryItem.java b/src/com/android/browser/HistoryItem.java
index 20efcb1f..5153d9ca 100644
--- a/src/com/android/browser/HistoryItem.java
+++ b/src/com/android/browser/HistoryItem.java
@@ -20,14 +20,14 @@ import android.content.Context;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ExpandableListView;
-import com.android.browser.R;
import com.android.browser.platformsupport.Browser;
/**
* Layout representing a history item in the classic history viewer.
*/
/* package */ class HistoryItem extends BookmarkItem
- implements OnCheckedChangeListener {
+ implements OnCheckedChangeListener, View.OnClickListener {
private CompoundButton mStar; // Star for bookmarking
/**
@@ -48,13 +48,15 @@ import com.android.browser.platformsupport.Browser;
} else {
mStar.setVisibility(View.GONE);
}
+
+ mTileView.setOnClickListener(this);
}
/* package */ void copyTo(HistoryItem item) {
item.mTextView.setText(mTextView.getText());
item.mUrlText.setText(mUrlText.getText());
item.setIsBookmark(mStar.isChecked());
- item.mImageView.setImageDrawable(mImageView.getDrawable());
+ item.mTileView.replaceFavicon(mBitmap);
}
/**
@@ -87,4 +89,21 @@ import com.android.browser.platformsupport.Browser;
getContext().getContentResolver(), mUrl, getName());
}
}
+
+ @Override
+ public void onClick(View v) {
+ if (v == mTileView) {
+ ExpandableListView list = (ExpandableListView) getTag(R.id.combo_view_container);
+ int group = (int) getTag(R.id.group_position);
+ int pos = (int) getTag(R.id.child_position);
+ if (list != null) {
+ long packedPos = list.getPackedPositionForChild(group, pos);
+ int flatPos = list.getFlatListPosition(packedPos);
+ list.performItemClick(
+ list.getAdapter().getView(flatPos, null, null),
+ flatPos, list.getAdapter().getItemId(flatPos));
+ }
+ performClick();
+ }
+ }
}
diff --git a/src/com/android/browser/SiteTileView.java b/src/com/android/browser/SiteTileView.java
new file mode 100644
index 00000000..36f21c9d
--- /dev/null
+++ b/src/com/android/browser/SiteTileView.java
@@ -0,0 +1,510 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package com.android.browser;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+
+/**
+ * This represents a WebSite Tile that is created from a Drawable and will scale across any
+ * area this is externally layouted to. There are 3 possible looks:
+ * - just the favicon (TYPE_SMALL)
+ * - drop-shadow plus a thin overlay border (1dp) (TYPE_MEDIUM)
+ * - centered favicon, extended color, rounded base (TYPE_LARGE)
+ *
+ * By centralizing everything in this class we make customization of looks much easier.
+ *
+ * NOTES:
+ * - do not set a background from the outside; this overrides it automatically
+ */
+public class SiteTileView extends View {
+
+ // external configuration constants
+ public static final int TYPE_SMALL = 1;
+ public static final int TYPE_MEDIUM = 2;
+ public static final int TYPE_LARGE = 3;
+ private static final int TYPE_AUTO = 0;
+ private static final int COLOR_AUTO = 0;
+
+
+ // static configuration
+ private static final int THRESHOLD_MEDIUM_DP = 32;
+ private static final int THRESHOLD_LARGE_DP = 64;
+ private static final int LARGE_FAVICON_SIZE_DP = 48;
+ private static final int BACKGROUND_DRAWABLE_RES = R.drawable.img_tile_background;
+ private static final float FILLER_RADIUS_DP = 2f; // sync with the bg image radius
+ private static final int FILLER_FALLBACK_COLOR = Color.WHITE; // in case there is no favicon
+ private static final int OVERLINE_WIDTH_RES = R.dimen.SiteTileOverline;
+ private static final int OVERLINE_COLOR_RES = R.color.SiteTileOverline;
+
+
+ // configuration
+ private Bitmap mFaviconBitmap = null;
+ private Paint mFundamentalPaint = null;
+ private int mFaviconWidth = 0;
+ private int mFaviconHeight = 0;
+ private int mForcedType = TYPE_AUTO;
+ private int mForcedFundamentalColor = COLOR_AUTO;
+
+ // static objects, to be recycled amongst instances (this is an optimization)
+ private static int sMediumPxThreshold = -1;
+ private static int sLargePxThreshold = -1;
+ private static int sLargeFaviconPx = -1;
+ private static float sRoundedRadius = -1;
+ private static Paint sBitmapPaint = null;
+ private static Rect sSrcRect = new Rect();
+ private static Rect sDstRect = new Rect();
+ private static RectF sRectF = new RectF();
+ private static Paint sOverlineOutlinePaint = null;
+ private static Drawable sBackgroundDrawable = null;
+ private static Rect sBackgroundDrawablePadding = new Rect();
+
+ // runtime params set on Layout
+ private int mCurrentWidth = 0;
+ private int mCurrentHeight = 0;
+ private int mCurrentType = TYPE_MEDIUM;
+ private boolean mCurrentBackgroundDrawn = false;
+ private boolean mFloating = false;
+ private int mPaddingLeft = 0;
+ private int mPaddingTop = 0;
+ private int mPaddingRight = 0;
+ private int mPaddingBottom = 0;
+
+
+
+ /* XML constructors */
+
+ public SiteTileView(Context context) {
+ super(context);
+ xmlInit(null, 0);
+ }
+
+ public SiteTileView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ xmlInit(attrs, 0);
+ }
+
+ public SiteTileView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ xmlInit(attrs, defStyle);
+ }
+
+
+ /* Programmatic Constructors */
+
+ public SiteTileView(Context context, Bitmap favicon) {
+ super(context);
+ init(favicon, COLOR_AUTO);
+ }
+
+ public SiteTileView(Context context, Bitmap favicon, int fundamentalColor) {
+ super(context);
+ init(favicon, fundamentalColor);
+ }
+
+
+ /**
+ * Changes the current favicon (and associated fundamental color) on the fly
+ */
+ public void replaceFavicon(Bitmap favicon) {
+ replaceFavicon(favicon, COLOR_AUTO);
+ }
+
+ /**
+ * Changes the current favicon (and associated fundamental color) on the fly
+ * @param favicon the new favicon
+ * @param fundamentalColor the new fudamental color, or COLOR_AUTO
+ */
+ public void replaceFavicon(Bitmap favicon, int fundamentalColor) {
+ init(favicon, fundamentalColor);
+ requestLayout();
+ }
+
+ /**
+ * Disables the automatic background and filling. Useful for things that are not really
+ * "Website Tiles", like folders.
+ * @param floating true to disable the background (defaults to false)
+ */
+ public void setFloating(boolean floating) {
+ mFloating = floating;
+ invalidate();
+ }
+
+
+ /**
+ * @return The fundamental color representing the site.
+ */
+ public int getFundamentalColor() {
+ if (mForcedFundamentalColor != COLOR_AUTO)
+ return mForcedFundamentalColor;
+ if (mFundamentalPaint == null)
+ mFundamentalPaint = createFundamentalPaint(mFaviconBitmap, COLOR_AUTO);
+ return mFundamentalPaint.getColor();
+ }
+
+
+ /*** private stuff ahead ***/
+
+ private void xmlInit(AttributeSet attrs, int defStyle) {
+ // load attributes
+ final TypedArray a = getContext().obtainStyledAttributes(attrs,
+ R.styleable.SiteTileView, defStyle, 0);
+
+ // fetch the drawable, if defined - then just extract and use the bitmap
+ final Drawable drawable = a.getDrawable(R.styleable.SiteTileView_android_src);
+ final Bitmap favicon = drawable instanceof BitmapDrawable ?
+ ((BitmapDrawable) drawable).getBitmap() : null;
+
+ // check if we disable shading (plain favicon)
+ if (a.getBoolean(R.styleable.SiteTileView_flat, false))
+ mForcedType = TYPE_SMALL;
+
+ // check if we want it floating (disable shadow and filler)
+ if (a.getBoolean(R.styleable.SiteTileView_floating, false))
+ mFloating = true;
+
+ // delete attribute resolution
+ a.recycle();
+
+ // proceed with real initialization
+ init(favicon, COLOR_AUTO);
+ }
+
+ private void init(Bitmap favicon, int fundamentalColor) {
+ mFaviconBitmap = favicon;
+ if (mFaviconBitmap != null) {
+ mFaviconWidth = mFaviconBitmap.getWidth();
+ mFaviconHeight = mFaviconBitmap.getHeight();
+ }
+
+ // don't compute the paint right now, just save any hint for later
+ mFundamentalPaint = null;
+ mForcedFundamentalColor = fundamentalColor;
+
+ // shared (static) resources initialization; except for background, inited on-demand
+ if (sMediumPxThreshold < 0) {
+ final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+
+ // heuristics thresholds
+ sMediumPxThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ THRESHOLD_MEDIUM_DP, displayMetrics);
+ sLargePxThreshold = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ THRESHOLD_LARGE_DP, displayMetrics);
+ sLargeFaviconPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ LARGE_FAVICON_SIZE_DP, displayMetrics);
+
+ // rounded radius
+ sRoundedRadius = FILLER_RADIUS_DP > 0 ? TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, FILLER_RADIUS_DP, displayMetrics) : 0;
+
+ // bitmap paint (copy, smooth scale)
+ sBitmapPaint = new Paint();
+ sBitmapPaint.setColor(Color.BLACK);
+ sBitmapPaint.setFilterBitmap(true);
+
+ // overline configuration (null if we don't need it)
+ int ovlColor = getResources().getColor(OVERLINE_COLOR_RES);
+ float ovlWidthPx = getResources().getDimension(OVERLINE_WIDTH_RES);
+ if (ovlWidthPx > 0.5 && ovlColor != Color.TRANSPARENT) {
+ sOverlineOutlinePaint = new Paint();
+ sOverlineOutlinePaint.setColor(ovlColor);
+ sOverlineOutlinePaint.setStrokeWidth(ovlWidthPx);
+ sOverlineOutlinePaint.setStyle(Paint.Style.STROKE);
+ }
+ }
+
+ // change when clicked
+ setClickable(true);
+ // disable by default the long click
+ setLongClickable(false);
+ }
+
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mCurrentWidth = right - left;
+ mCurrentHeight = bottom - top;
+
+ // auto-determine the "TYPE_" from the physical size of the layout
+ if (mForcedType == TYPE_AUTO) {
+ if (mCurrentWidth < sMediumPxThreshold && mCurrentHeight < sMediumPxThreshold)
+ mCurrentType = TYPE_SMALL;
+ else if (mCurrentWidth < sLargePxThreshold && mCurrentHeight < sLargePxThreshold)
+ mCurrentType = TYPE_MEDIUM;
+ else
+ mCurrentType = TYPE_LARGE;
+ } else {
+ // or use the forced one, if defined
+ mCurrentType = mForcedType;
+ }
+
+ // set or remove the background (if the need changed!)
+ boolean requiresBackground = mCurrentType >= TYPE_MEDIUM;
+ if (requiresBackground && !mCurrentBackgroundDrawn) {
+ // draw the background
+ mCurrentBackgroundDrawn = true;
+
+ // load the background just the first time, on demand (it may fail too)
+ if (sBackgroundDrawable == null) {
+ sBackgroundDrawable = getResources().getDrawable(BACKGROUND_DRAWABLE_RES);
+ if (sBackgroundDrawable != null)
+ sBackgroundDrawable.getPadding(sBackgroundDrawablePadding);
+ }
+
+ // background -> padding
+ mPaddingLeft = sBackgroundDrawablePadding.left;
+ mPaddingTop = sBackgroundDrawablePadding.top;
+ mPaddingRight = sBackgroundDrawablePadding.right;
+ mPaddingBottom = sBackgroundDrawablePadding.bottom;
+ } else if (!requiresBackground && mCurrentBackgroundDrawn) {
+ // turn off background drawing
+ mCurrentBackgroundDrawn = false;
+
+ // no background -> no padding
+ mPaddingLeft = 0;
+ mPaddingTop = 0;
+ mPaddingRight = 0;
+ mPaddingBottom = 0;
+ }
+
+ // just proceed, do nothing here
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ @Override
+ public void setPressed(boolean pressed) {
+ super.setPressed(pressed);
+ // schedule a repaint to show pressed/released
+ invalidate();
+ }
+
+ @Override
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ // schedule a repaint to show selected
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // Selection State: make everything smaller
+ if (isSelected()) {
+ float scale = 0.8f;
+ canvas.translate(mCurrentWidth * (1 - scale) / 2, mCurrentHeight * (1 - scale) / 2);
+ canvas.scale(scale, scale);
+ }
+
+ // Pressed state: make the button reach the finger
+ if (isPressed()) {
+ float scale = 1.1f;
+ canvas.translate(mCurrentWidth * (1 - scale) / 2, mCurrentHeight * (1 - scale) / 2);
+ canvas.scale(scale, scale);
+ }
+
+ final int left = mPaddingLeft;
+ final int top = mPaddingTop;
+ final int right = mCurrentWidth - mPaddingRight;
+ final int bottom = mCurrentHeight - mPaddingBottom;
+ final int contentWidth = right - left;
+ final int contentHeight = bottom - top;
+
+ // A. the background drawable (if set)
+ boolean requiresBackground = mCurrentBackgroundDrawn && sBackgroundDrawable != null
+ && !isPressed() && !mFloating;
+ if (requiresBackground) {
+ sBackgroundDrawable.setBounds(0, 0, mCurrentWidth, mCurrentHeight);
+ sBackgroundDrawable.draw(canvas);
+ }
+
+ // B. (when needed) draw the background rectangle; sharp our rounded
+ boolean requiresFundamentalFiller = mCurrentType >= TYPE_LARGE && !mFloating;
+ if (requiresFundamentalFiller) {
+ // create the filler paint on demand (not all icons need it)
+ if (mFundamentalPaint == null)
+ mFundamentalPaint = createFundamentalPaint(mFaviconBitmap, mForcedFundamentalColor);
+
+ // paint if not white, since requiresBackground already painted it white
+ int fundamentalColor = mFundamentalPaint.getColor();
+ if (fundamentalColor != COLOR_AUTO &&
+ (fundamentalColor != Color.WHITE || !requiresBackground)) {
+ if (sRoundedRadius >= 1.) {
+ sRectF.set(left, top, right, bottom);
+ canvas.drawRoundRect(sRectF, sRoundedRadius, sRoundedRadius, mFundamentalPaint);
+ } else
+ canvas.drawRect(left, top, right, bottom, mFundamentalPaint);
+ }
+ }
+
+ // C. (if present) draw the favicon
+ boolean requiresFavicon = mFaviconBitmap != null
+ && mFaviconWidth > 1 && mFaviconHeight > 1;
+ if (requiresFavicon) {
+ // destination can either fill, or auto-center
+ boolean fillSpace = mCurrentType <= TYPE_MEDIUM;
+ if (fillSpace || contentWidth < sLargeFaviconPx || contentHeight < sLargeFaviconPx) {
+ sDstRect.set(left, top, right, bottom);
+ } else {
+ int dstLeft = left + (contentWidth - sLargeFaviconPx) / 2;
+ int dstTop = top + (contentHeight - sLargeFaviconPx) / 2;
+ sDstRect.set(dstLeft, dstTop, dstLeft + sLargeFaviconPx, dstTop + sLargeFaviconPx);
+ }
+
+ // source has to 'crop proportionally' to keep the dest aspect ratio
+ sSrcRect.set(0, 0, mFaviconWidth, mFaviconHeight);
+ int sW = sSrcRect.width();
+ int sH = sSrcRect.height();
+ int dW = sDstRect.width();
+ int dH = sDstRect.height();
+ if (sW > 4 && sH > 4 && dW > 4 && dH > 4) {
+ float hScale = (float) dW / (float) sW;
+ float vScale = (float) dH / (float) sH;
+ if (hScale == vScale) {
+ // no transformation needed, just zoom
+ } else if (hScale < vScale) {
+ // horizontal crop
+ float hCrop = 1 - hScale / vScale;
+ int hCropPx = (int) (sW * hCrop / 2 + 0.5);
+ sSrcRect.left += hCropPx;
+ sSrcRect.right -= hCropPx;
+ canvas.drawBitmap(mFaviconBitmap, sSrcRect, sDstRect, sBitmapPaint);
+ } else {
+ // vertical crop
+ float vCrop = 1 - vScale / hScale;
+ int vCropPx = (int) (sH * vCrop / 2 + 0.5);
+ sSrcRect.top += vCropPx;
+ sSrcRect.bottom -= vCropPx;
+ }
+ }
+
+ // blit favicon, croppped, scaled
+ canvas.drawBitmap(mFaviconBitmap, sSrcRect, sDstRect, sBitmapPaint);
+ }
+
+ // D. (when needed) draw the thin over-line
+ boolean requiresOverline = mCurrentType == TYPE_MEDIUM
+ && sOverlineOutlinePaint != null;
+ if (requiresOverline) {
+ canvas.drawRect(left, top, right, bottom, sOverlineOutlinePaint);
+ }
+
+ /*if (true) { // DEBUG TYPE
+ Paint paint = new Paint();
+ paint.setColor(Color.BLACK);
+ paint.setTextSize(20);
+ canvas.drawText(String.valueOf(mCurrentType), 30, 30, paint);
+ }*/
+ }
+
+
+ /**
+ * Creates a fill Paint from the favicon, or using the forced color (if not COLOR_AUTO)
+ */
+ private static Paint createFundamentalPaint(Bitmap favicon, int forceFillColor) {
+ final Paint fillPaint = new Paint();
+ if (forceFillColor != COLOR_AUTO)
+ fillPaint.setColor(forceFillColor);
+ else
+ fillPaint.setColor(guessFundamentalColor(favicon));
+ return fillPaint;
+ }
+
+ /**
+ * This uses very stupid mechanism - a 9x9 grid sample on the borders and center - and selects
+ * the color with the most frequency, or the center.
+ *
+ * @param bitmap the bitmap to guesss the color about
+ * @return a Color
+ */
+ private static int guessFundamentalColor(Bitmap bitmap) {
+ if (bitmap == null)
+ return FILLER_FALLBACK_COLOR;
+ int height = bitmap.getHeight();
+ int width = bitmap.getWidth();
+ if (height < 2 || width < 2)
+ return FILLER_FALLBACK_COLOR;
+
+ // pick up to 9 colors
+ // NOTE: the order of sampling sets the precendece, in case of ties
+ int[] pxColors = new int[9];
+ int idx = 0;
+ if ((pxColors[idx] = sampleColor(bitmap, width / 2, height / 2)) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, width / 2, height - 1)) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, width - 1, height - 1)) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, width - 1, height / 2)) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, 0, 0 )) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, width / 2, 0 )) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, width - 1, 0 )) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, 0 , height / 2)) != 0) idx++;
+ if ((pxColors[idx] = sampleColor(bitmap, 0 , height - 1)) != 0) idx++;
+
+ // find the most popular
+ int popColor = -1;
+ int popCount = -1;
+ for (int i = 0; i < idx; i++) {
+ int thisColor = pxColors[i];
+ int thisCount = 0;
+ for (int j = 0; j < idx; j++) {
+ if (pxColors[j] == thisColor)
+ thisCount++;
+ }
+ if (thisCount > popCount) {
+ popColor = thisColor;
+ popCount = thisCount;
+ }
+ }
+ return popCount > -1 ? popColor : FILLER_FALLBACK_COLOR;
+ }
+
+ /**
+ * @return Color, but if it's 0, you should discard it (not representative)
+ */
+ private static int sampleColor(Bitmap bitmap, int x, int y) {
+ int color = bitmap.getPixel(x, y);
+ // discard semi-transparent pixels, because they're probably from a spurious border
+ // discard black pixels, because black is not a color (well, not a good looking one)
+ if ((color >>> 24) <= 128 || (color & 0xFFFFFF) == 0)
+ return 0;
+ return color;
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 3e3c9aaf..ef4c3806 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -193,6 +193,8 @@ class Tab implements PictureListener {
// determine if webview is destroyed to MemoryMonitor
private boolean mWebViewDestroyedByMemoryMonitor;
+ private String mTouchIconUrl;
+
private Observable mFirstPixelObservable;
private Observable mTabHistoryUpdateObservable;
@@ -634,6 +636,7 @@ class Tab implements PictureListener {
@Override
public void beforeNavigation(WebView view, String url) {
+ mTouchIconUrl = null;
if (BrowserCommandLine.hasSwitch("ui-low-power-mode")) {
return;
}
@@ -726,6 +729,9 @@ class Tab implements PictureListener {
mCurrentState.mIncognito = view.isPrivateBrowsingEnabled();
}
+ public String getTouchIconUrl() {
+ return mTouchIconUrl;
+ }
public boolean isTabFullScreen() {
return mFullScreen;
@@ -771,6 +777,8 @@ class Tab implements PictureListener {
mWebViewController.attachSubWindow(Tab.this);
transport.setWebView(mSubView);
} else {
+ capture();
+
final Tab newTab = mWebViewController.openTab(url,
Tab.this, true, true);
// This is special case for rendering links on a webpage in
@@ -919,6 +927,7 @@ class Tab implements PictureListener {
mContext, cr, view);
mTouchIconLoader.execute(url);
}
+ mTouchIconUrl = url;
}
@Override
diff --git a/src/com/android/browser/preferences/SiteSpecificPreferencesFragment.java b/src/com/android/browser/preferences/SiteSpecificPreferencesFragment.java
index 329f66cd..10595074 100644
--- a/src/com/android/browser/preferences/SiteSpecificPreferencesFragment.java
+++ b/src/com/android/browser/preferences/SiteSpecificPreferencesFragment.java
@@ -229,6 +229,11 @@ public class SiteSpecificPreferencesFragment extends SWEPreferenceFragment
mSslCert = (parcel != null) ? SslCertificate.restoreState(parcel) : null;
if (mSslCert != null) {
+ Preference pref = findPreference("site_security_info");
+ if (pref != null) {
+ pref.setSelectable(true);
+ }
+
int certErrors = args.getInt(EXTRA_SECURITY_CERT_ERR, 0);
if (certErrors == 0) {
diff --git a/src/com/android/browser/view/BookmarkContainer.java b/src/com/android/browser/view/BookmarkContainer.java
index 54f281cc..730f1278 100644
--- a/src/com/android/browser/view/BookmarkContainer.java
+++ b/src/com/android/browser/view/BookmarkContainer.java
@@ -26,6 +26,9 @@ import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
+import com.android.browser.R;
+import com.android.browser.SiteTileView;
+
public class BookmarkContainer extends LinearLayout implements OnClickListener {
private OnClickListener mClickListener;
@@ -53,13 +56,21 @@ public class BookmarkContainer extends LinearLayout implements OnClickListener {
}
@Override
- public void setBackgroundDrawable(Drawable d) {
- super.setBackgroundDrawable(d);
+ public void setOnClickListener(OnClickListener l) {
+ mClickListener = l;
+ View thumb = findViewById(R.id.thumb_image);
+ if (thumb != null) {
+ thumb.setOnClickListener(l);
+ }
}
@Override
- public void setOnClickListener(OnClickListener l) {
- mClickListener = l;
+ public void setTag(int key, final Object tag) {
+ super.setTag(key, tag);
+ View thumb = findViewById(R.id.thumb_image);
+ if (thumb != null) {
+ thumb.setTag(key, tag);
+ }
}
@Override