Multiple fixes for Favicons

- Per Site Settings now uses SiteTiles and shows favicons
- New default Favicon
- Fixed missing Favicons on History items

Change-Id: Ia0317694ede81d62ce04e0693f9779f65030165c
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 481f10c..374bc15 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -228,7 +228,6 @@
     @Override
     public void onTabDataChanged(Tab tab) {
         setUrlTitle(tab);
-        setFavicon(tab);
         updateTabSecurityState(tab);
         updateNavigationState(tab);
         mTitleBar.onTabDataChanged(tab);
@@ -305,6 +304,7 @@
         mTitleBar.bringToFront();
         tab.getTopWindow().requestFocus();
         onTabDataChanged(tab);
+        setFavicon(tab);
         onProgressChanged(tab);
         mNavigationBar.setIncognitoMode(tab.isPrivateBrowsingEnabled());
         mBlockFocusAnimations = false;
@@ -722,10 +722,8 @@
     }
 
     // Set the favicon in the title bar.
-    protected void setFavicon(Tab tab) {
-        if (tab.inForeground()) {
-            mNavigationBar.setFavicon(tab.getWebView().getFavicon());
-        }
+    public void setFavicon(Tab tab) {
+        mNavigationBar.showCurrentFavicon(tab);
     }
 
     // active tabs page
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 80e1da7..282ad6c 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -35,6 +35,7 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.DataSetObserver;
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -87,6 +88,7 @@
     private ViewGroup mPrefsContainer;
     private FragmentBreadCrumbs mFragmentBreadCrumbs;
     private ExpandableListView mHistoryList;
+    private static Bitmap sDefaultFavicon;
 
     private View mRoot;
 
@@ -211,6 +213,10 @@
                 mCallback = (CombinedBookmarksCallbacks) cb;
             }
         }
+        if (sDefaultFavicon == null) {
+            sDefaultFavicon = BitmapFactory.decodeResource(
+                    this.getResources(), R.drawable.ic_deco_favicon_normal);
+        }
     }
 
     @Override
@@ -676,7 +682,7 @@
                 item.setFavicon(BitmapFactory.decodeByteArray(data, 0,
                         data.length));
             } else {
-                item.setFavicon(null);
+                item.setFavicon(sDefaultFavicon);
             }
             item.setIsBookmark(cursor.getInt(HistoryQuery.INDEX_IS_BOOKMARK) == 1);
             return item;
diff --git a/src/com/android/browser/BrowserSnapshotPage.java b/src/com/android/browser/BrowserSnapshotPage.java
index c01691f..a5a3519 100644
--- a/src/com/android/browser/BrowserSnapshotPage.java
+++ b/src/com/android/browser/BrowserSnapshotPage.java
@@ -77,6 +77,7 @@
     private static final int SNAPSHOT_FAVICON = 4;
     private static final int SNAPSHOT_URL = 5;
     private static final int SNAPSHOT_DATE_CREATED = 6;
+    private static Bitmap sDefaultFavicon;
 
     GridView mGrid;
     View mEmpty;
@@ -98,6 +99,9 @@
             }
         }
         mAnimateId = getArguments().getLong(EXTRA_ANIMATE_ID);
+        if (sDefaultFavicon == null)
+            sDefaultFavicon = BitmapFactory.decodeResource(getResources(),
+                    R.drawable.ic_deco_favicon_normal);
     }
 
     @Override
@@ -190,7 +194,13 @@
     private void populateBookmarkItem(Cursor cursor, BookmarkItem item) {
         item.setName(cursor.getString(SNAPSHOT_TITLE));
         item.setUrl(cursor.getString(SNAPSHOT_URL));
-        item.setFavicon(getBitmap(cursor, SNAPSHOT_FAVICON));
+        Bitmap favicon = getBitmap(cursor, SNAPSHOT_FAVICON);
+        if (favicon != null) {
+            item.setFavicon(favicon);
+        } else {
+            item.setFavicon(sDefaultFavicon);
+        }
+
     }
 
     static Bitmap getBitmap(Cursor cursor, int columnIndex) {
diff --git a/src/com/android/browser/BrowserWebView.java b/src/com/android/browser/BrowserWebView.java
index 9aa044c..afcca1a 100644
--- a/src/com/android/browser/BrowserWebView.java
+++ b/src/com/android/browser/BrowserWebView.java
@@ -17,6 +17,8 @@
 package com.android.browser;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.content.res.Resources;
 import android.util.AttributeSet;
@@ -200,6 +202,16 @@
     }
 
     @Override
+    public Bitmap getFavicon() {
+        Tab currentTab = mTitleBar.getUiController().getCurrentTab();
+        if (currentTab != null){
+            return currentTab.getFavicon();
+        }
+        else return BitmapFactory.decodeResource(
+                this.getResources(), R.drawable.ic_deco_favicon_normal);
+    }
+
+    @Override
     public boolean dispatchKeyEventPreIme(KeyEvent event) {
         Tab currentTab = mTitleBar.getUiController().getCurrentTab();
         if (currentTab != null && currentTab.isKeyboardShowing()){
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 3678608..2b66988 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -47,7 +47,6 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
-import android.net.http.SslError;
 import android.net.wifi.WifiManager;
 import android.net.wifi.ScanResult;
 import android.os.AsyncTask;
@@ -978,7 +977,7 @@
 
         String url = tab.getUrl();
         // update the bookmark database for favicon
-        maybeUpdateFavicon(tab, null, url, favicon);
+        syncBookmarkFavicon(tab, null, url, favicon);
 
         Performance.tracePageStart(url);
 
@@ -1000,7 +999,7 @@
          }
 
         tab.onPageFinished();
-        maybeUpdateFavicon(tab, tab.getOriginalUrl(), tab.getUrl(), tab.getFavicon());
+        syncBookmarkFavicon(tab, tab.getOriginalUrl(), tab.getUrl(), tab.getFavicon());
 
         Performance.tracePageFinished();
     }
@@ -1068,8 +1067,8 @@
 
     @Override
     public void onFavicon(Tab tab, WebView view, Bitmap icon) {
-        mUi.onTabDataChanged(tab);
-        maybeUpdateFavicon(tab, view.getOriginalUrl(), view.getUrl(), icon);
+        syncBookmarkFavicon(tab, view.getOriginalUrl(), view.getUrl(), icon);
+        ((BaseUi)mUi).setFavicon(tab);
     }
 
     @Override
@@ -1263,8 +1262,8 @@
      * Update the favorites icon if the private browsing isn't enabled and the
      * icon is valid.
      */
-    private void maybeUpdateFavicon(Tab tab, final String originalUrl,
-            final String url, Bitmap favicon) {
+    private void syncBookmarkFavicon(Tab tab, final String originalUrl,
+                                     final String url, Bitmap favicon) {
         if (favicon == null) {
             return;
         }
diff --git a/src/com/android/browser/NavigationBarBase.java b/src/com/android/browser/NavigationBarBase.java
index d1054b9..973094c 100644
--- a/src/com/android/browser/NavigationBarBase.java
+++ b/src/com/android/browser/NavigationBarBase.java
@@ -256,16 +256,20 @@
         return mDefaultStatusBarColor;
     }
 
-    public void setFavicon(Bitmap icon) {
-        int color = ColorUtils.getDominantColorForBitmap(icon);
-        Tab tab = mUiController.getCurrentTab();
+    // Sets the favicon for the given tab if it's in the foreground
+    // If the tab doesn't have a favicon, it sets the default favicon
+    public void showCurrentFavicon(Tab tab) {
+        int color;
+        if (tab == null) { return; }
 
-        if (tab != null) {
+        if (tab.inForeground()) {
             if (tab.hasFavicon()) {
+                color = ColorUtils.getDominantColorForBitmap(tab.getFavicon());
                 updateSiteIconColor(tab.getUrl(), color);
                 setStatusAndNavigationBarColor(mUiController.getActivity(),
                         adjustColor(color, 1, 1, 0.7f));
-            } else {
+
+            }   else {
                 color = getSiteIconColor(tab.getUrl());
                 if (color != 0) {
                     setStatusAndNavigationBarColor(mUiController.getActivity(),
@@ -275,14 +279,9 @@
                             mDefaultStatusBarColor);
                 }
             }
-        } else {
-            setStatusAndNavigationBarColor(mUiController.getActivity(), mDefaultStatusBarColor);
-        }
-
-        //Bitmap favicon = mUiController.getCurrentTopWebView().getFavicon();
-
-        if (mFaviconTile != null) {
-            mFaviconTile.replaceFavicon(mUiController.getCurrentTopWebView().getFavicon());
+            if (mFaviconTile != null) {
+                mFaviconTile.replaceFavicon(tab.getFavicon()); // Always set the tab's favicon
+            }
         }
     }
 
@@ -337,7 +336,7 @@
         Bitmap favicon = mUiController.getCurrentTopWebView().getFavicon();
         if (favicon != null) {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            favicon.compress(Bitmap.CompressFormat.PNG, 50, baos);
+            favicon.compress(Bitmap.CompressFormat.PNG, 100, baos);
             bundle.putByteArray(SiteSpecificPreferencesFragment.EXTRA_FAVICON,
                     baos.toByteArray());
         }
@@ -722,7 +721,6 @@
         mFaviconTile.setBadgeBlockedObjectsCount(0);
         mFaviconTile.setTrustLevel(SiteTileView.TRUST_UNKNOWN);
         mFaviconTile.setBadgeHasCertIssues(false);
-        mFaviconTile.replaceFavicon(mDefaultFavicon);
         setSecurityState(Tab.SecurityState.SECURITY_STATE_NOT_SECURE);
         mHandler.removeMessages(WEBREFINER_COUNTER_MSG);
         mHandler.sendEmptyMessageDelayed(WEBREFINER_COUNTER_MSG,
diff --git a/src/com/android/browser/SiteTileView.java b/src/com/android/browser/SiteTileView.java
index e2951ae..8d69dba 100644
--- a/src/com/android/browser/SiteTileView.java
+++ b/src/com/android/browser/SiteTileView.java
@@ -41,12 +41,12 @@
 import android.graphics.Typeface;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 import android.view.View;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -359,7 +359,7 @@
             sBackgroundDrawable.getPadding(sBackgroundDrawablePadding);
 
         // load all the badge drawables
-        sBadges = new ArrayMap<>();
+        sBadges = new HashMap<>();
         loadBadgeResources(r, TRUST_AVOID, R.drawable.img_deco_tile_avoid,
                 R.drawable.img_deco_tile_avoid_accent, R.color.TileBadgeTextAvoid);
         loadBadgeResources(r, TRUST_UNTRUSTED, R.drawable.img_deco_tile_untrusted,
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index d3621ef..8121ba4 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -220,8 +220,9 @@
         String mUrl;
         String mOriginalUrl;
         String mTitle;
-        SecurityState mSecurityState;
         // This is non-null only when mSecurityState is SECURITY_STATE_BAD_CERTIFICATE.
+        SecurityState mSecurityState;
+        // This is non-null only when onReceivedIcon is called or SnapshotTab restores it.
         Bitmap mFavicon;
         boolean mIsBookmarkedSite;
         boolean mIncognito;
@@ -237,14 +238,13 @@
             mSecurityState = SecurityState.SECURITY_STATE_NOT_SECURE;
         }
 
-        PageState(Context c, boolean incognito, String url, Bitmap favicon) {
+        PageState(Context c, boolean incognito, String url) {
             mIncognito = incognito;
             if (mIncognito)
                 mOriginalUrl = mUrl = "";
             else
                 mOriginalUrl = mUrl = url;
             mSecurityState = SecurityState.SECURITY_STATE_NOT_SECURE;
-            mFavicon = favicon;
         }
 
     }
@@ -335,7 +335,7 @@
             mUpdateThumbnail = true;
             mPageLoadProgress = INITIAL_PROGRESS;
             mCurrentState = new PageState(mContext,
-                    view.isPrivateBrowsingEnabled(), url, favicon);
+                    view.isPrivateBrowsingEnabled(), url);
             mLoadStartTime = SystemClock.uptimeMillis();
             // Need re-enable FullScreenMode on Page navigation if needed
             if (BrowserSettings.getInstance().useFullscreen()){
@@ -549,6 +549,18 @@
         @Override
         public void beforeNavigation(WebView view, String url) {
             mTouchIconUrl = null;
+            TitleBar titleBar = null;
+            Controller controller = (Controller)mWebViewController;
+            UI ui = controller.getUi();
+
+            if (ui instanceof BaseUi) {
+                titleBar = ((BaseUi)ui).getTitleBar();
+                if (titleBar != null) {
+                    NavigationBarBase navBar = titleBar.getNavigationBar();
+                    navBar.showCurrentFavicon(Tab.this); // Show the default Favicon while loading a new page
+                }
+            }
+
             if (BaseUi.isUiLowPowerMode()) {
                 return;
             }
@@ -561,19 +573,11 @@
                 return;
             }
 
-            if (view.getUrl().equals(url)) {
-                return;
-            }
-
             final int idx = view.copyBackForwardList().getCurrentIndex();
             boolean bitmapExists = view.hasSnapshot(idx);
 
             int progress = 100;
-            Controller controller = (Controller)mWebViewController;
-            UI ui = controller.getUi();
-            if (ui instanceof BaseUi) {
-                BaseUi baseUi = (BaseUi) ui;
-                TitleBar titleBar = baseUi.getTitleBar();
+            if (titleBar != null) {
                 progress = titleBar.getProgressView().getProgressPercent();
             }
 
@@ -657,10 +661,10 @@
                    url.contains(Controller.INCOGNITO_URI)) {
             mCurrentState.mUrl = mCurrentState.mOriginalUrl = "";
         }
+
         else {
             mCurrentState.mUrl = view.getUrl();
             mCurrentState.mOriginalUrl = view.getOriginalUrl();
-            mCurrentState.mFavicon = view.getFavicon();
         }
 
         if (mCurrentState.mUrl == null) {
@@ -1195,6 +1199,16 @@
             mId = TabControl.getNextId();
         }
         setWebView(w);
+
+        UI ui = ((Controller)mWebViewController).getUi();
+        if (ui instanceof BaseUi) {
+            TitleBar titleBar = ((BaseUi)ui).getTitleBar();
+            if (titleBar != null) {
+                NavigationBarBase navBar = titleBar.getNavigationBar();
+                navBar.showCurrentFavicon(this); // Show the default Favicon while loading a new page
+            }
+        }
+
         mHandler = new Handler() {
             @Override
             public void handleMessage(Message m) {
@@ -1783,7 +1797,7 @@
         String url = b.getString(CURRURL);
         String title = b.getString(CURRTITLE);
         boolean incognito = b.getBoolean(INCOGNITO);
-        mCurrentState = new PageState(mContext, incognito, url, null);
+        mCurrentState = new PageState(mContext, incognito, url);
         mCurrentState.mTitle = title;
         synchronized (Tab.this) {
             if (mCapture != null) {
@@ -1914,7 +1928,7 @@
         if (mMainView != null) {
             mPageLoadProgress = INITIAL_PROGRESS;
             mCurrentState = new PageState(
-                                mContext, mMainView.isPrivateBrowsingEnabled(), url, null);
+                                mContext, mMainView.isPrivateBrowsingEnabled(), url);
             mMainView.loadUrl(url, headers);
         }
     }
diff --git a/src/com/android/browser/preferences/WebsiteSettingsFragment.java b/src/com/android/browser/preferences/WebsiteSettingsFragment.java
index 2b5c9eb..bb4a8d3 100644
--- a/src/com/android/browser/preferences/WebsiteSettingsFragment.java
+++ b/src/com/android/browser/preferences/WebsiteSettingsFragment.java
@@ -43,8 +43,10 @@
 import android.widget.TextView;
 
 import com.android.browser.R;
+import com.android.browser.SiteTileView;
 import com.android.browser.WebStorageSizeManager;
 
+import java.io.ByteArrayOutputStream;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
@@ -63,24 +65,37 @@
 public class WebsiteSettingsFragment extends ListFragment implements OnClickListener {
     private SiteAdapter mAdapter = null;
 
-    private class Site {
+    private class Site implements OnClickListener {
         private String mOrigin;
         private String mTitle;
         private Bitmap mIcon;
+        private View mView;
+        private Bitmap mDefaultIcon = mAdapter.mDefaultIcon;
 
         public Site(String origin) {
             mOrigin = origin;
             mTitle = null;
             mIcon = null;
-            PermissionsServiceFactory.getFavicon(origin, getActivity(),
+            fetchFavicon();
+        }
+
+        private void fetchFavicon() {
+            // Fetch favicon and set it
+            PermissionsServiceFactory.getFavicon(mOrigin, getActivity(),
                     new ValueCallback<Bitmap>() {
                         @Override
                         public void onReceiveValue(Bitmap value) {
-                            mIcon = value;
+                            setIcon(value);
+
                         }
                     });
         }
 
+        public void updateView(View view){
+            mView = view;
+            fetchFavicon();
+        }
+
         public String getOrigin() {
             return mOrigin;
         }
@@ -89,8 +104,14 @@
             mTitle = title;
         }
 
-        public void setIcon(Bitmap icon) {
-            mIcon = icon;
+        public void setIcon(Bitmap image) {
+            mIcon = image;
+            if (mView != null) {
+                SiteTileView icon = (SiteTileView) mView.findViewById(R.id.icon);
+                icon.replaceFavicon((image == null) ? mDefaultIcon : image);
+                icon.setVisibility(View.VISIBLE);
+                icon.setOnClickListener(this);
+            }
         }
 
         public Bitmap getIcon() {
@@ -111,6 +132,11 @@
             Uri uri = Uri.parse(str);
             return "http".equals(uri.getScheme()) ?  str.substring(7) : str;
         }
+
+        @Override
+        public void onClick(View v) {
+            clickHandler(this);
+        }
     }
 
     class SiteAdapter extends ArrayAdapter<Site>
@@ -127,7 +153,6 @@
             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             mDefaultIcon = BitmapFactory.decodeResource(getResources(),
                     R.drawable.ic_deco_favicon_normal);
-
             mReady = false;
             askForOrigins();
         }
@@ -207,7 +232,6 @@
             View view;
             final TextView title;
             final TextView subtitle;
-            final ImageView icon;
 
             if (convertView == null) {
                 view = mInflater.inflate(mResource, parent, false);
@@ -217,9 +241,9 @@
 
             title = (TextView) view.findViewById(R.id.title);
             subtitle = (TextView) view.findViewById(R.id.subtitle);
-            icon = (ImageView) view.findViewById(R.id.icon);
 
             Site site = getItem(position);
+            site.updateView(view);
             title.setText(site.getPrettyTitle());
             String subtitleText = site.getPrettyOrigin();
             if (subtitleText != null) {
@@ -232,13 +256,6 @@
                 title.setMaxLines(2);
                 title.setSingleLine(false);
             }
-
-            icon.setVisibility(View.VISIBLE);
-            Bitmap bmp = site.getIcon();
-            if (bmp == null) {
-                bmp = mDefaultIcon;
-            }
-            icon.setImageBitmap(bmp);
             // We set the site as the view's tag,
             // so that we can get it in onItemClick()
             view.setTag(site);
@@ -250,21 +267,29 @@
                                 View view,
                                 int position,
                                 long id) {
-            Site site = (Site) view.getTag();
-            Activity activity = getActivity();
-            if (activity != null) {
-                Bundle args = new Bundle();
-                args.putString(SiteSpecificPreferencesFragment.EXTRA_ORIGIN, site.getOrigin());
+            clickHandler((Site) view.getTag());
+        }
+    }
 
-                FragmentManager fragmentManager = activity.getFragmentManager();
-                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
-
-                Fragment newFragment = new SiteSpecificPreferencesFragment();
-                newFragment.setArguments(args);
-                fragmentTransaction.replace(getId(), newFragment);
-                fragmentTransaction.addToBackStack(null);
-                fragmentTransaction.commit();
+    private void clickHandler(Site site) {
+        Activity activity = getActivity();
+        if (activity != null) {
+            Bundle args = new Bundle();
+            args.putString(SiteSpecificPreferencesFragment.EXTRA_ORIGIN, site.getOrigin());
+            if(site.getIcon() != null) {
+                ByteArrayOutputStream favicon = new ByteArrayOutputStream();
+                site.getIcon().compress(Bitmap.CompressFormat.PNG, 100, favicon);
+                args.putByteArray(SiteSpecificPreferencesFragment.EXTRA_FAVICON,
+                        favicon.toByteArray());
             }
+            FragmentManager fragmentManager = activity.getFragmentManager();
+            FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
+
+            Fragment newFragment = new SiteSpecificPreferencesFragment();
+            newFragment.setArguments(args);
+            fragmentTransaction.replace(getId(), newFragment);
+            fragmentTransaction.addToBackStack(null);
+            fragmentTransaction.commit();
         }
     }