Merge change 423 into donut

* changes:
  Show the saved picture for freed tabs.
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 3f79a2d..9d5130f 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -2132,6 +2132,9 @@
                     .setVisibility(View.VISIBLE);
         }
         mContentView.removeView(mTabOverview);
+        // Clear all the data for tab picker so next time it will be
+        // recreated.
+        mTabControl.wipeAllPickerData();
         mTabOverview.clear();
         mTabOverview = null;
         mTabListener = null;
@@ -4194,10 +4197,6 @@
                 }
             }
 
-            // Clear all the data for tab picker so next time it will be
-            // recreated.
-            mTabControl.wipeAllPickerData();
-
             // NEW_TAB means that the "New Tab" cell was clicked on.
             if (index == ImageGrid.NEW_TAB) {
                 openTabAndShow(mSettings.getHomePage(), null, false, null);
diff --git a/src/com/android/browser/FakeWebView.java b/src/com/android/browser/FakeWebView.java
index 633b799..da5ef5f 100644
--- a/src/com/android/browser/FakeWebView.java
+++ b/src/com/android/browser/FakeWebView.java
@@ -33,17 +33,9 @@
  *  overrides ImageView so it can be used for the new tab image as well.
  */
 public class FakeWebView extends ImageView {
-    private TabControl.Tab mTab;
-    private Picture        mPicture;
+    private TabControl.PickerData mPickerData;
     private boolean        mUsesResource;
 
-    private class Listener implements WebView.PictureListener {
-        public void onNewPicture(WebView view, Picture p) {
-            FakeWebView.this.mPicture = p;
-            FakeWebView.this.invalidate();
-        }
-    };
-
     public FakeWebView(Context context) {
         this(context, null);
     }
@@ -68,17 +60,21 @@
             // would be nice to know if the picture is empty so we can avoid
             // drawing white.
             canvas.drawColor(Color.WHITE);
-            if (mTab != null) {
-                final WebView w = mTab.getTopWindow();
-                if (w != null) {
-                    if (mPicture != null) {
-                        canvas.save();
-                        float scale = getWidth() * w.getScale() / w.getWidth();
-                        canvas.scale(scale, scale);
-                        canvas.translate(-w.getScrollX(), -w.getScrollY());
-                        canvas.drawPicture(mPicture);
-                        canvas.restore();
+            if (mPickerData != null) {
+                final Picture p = mPickerData.mPicture;
+                if (p != null) {
+                    canvas.save();
+                    float scale = getWidth() * mPickerData.mScale
+                            / mPickerData.mWidth;
+                    // Check for NaN and infinity.
+                    if (Float.isNaN(scale) || Float.isInfinite(scale)) {
+                        scale = 1.0f;
                     }
+                    canvas.scale(scale, scale);
+                    canvas.translate(-mPickerData.mScrollX,
+                            -mPickerData.mScrollY);
+                    canvas.drawPicture(p);
+                    canvas.restore();
                 }
             }
         }
@@ -87,25 +83,24 @@
     @Override
     public void setImageResource(int resId) {
         mUsesResource = true;
-        mTab = null;
+        mPickerData = null;
         super.setImageResource(resId);
     }
 
     /**
      *  Set a WebView for this FakeWebView to represent.
-     *  @param  v WebView whose picture and other data will be used in onDraw.
+     *  @param  t The tab whose picture and other data will be used in onDraw.
      */
     public void setTab(TabControl.Tab t) {
         mUsesResource = false;
-        mTab = t;
-        if (t != null && t.getWebView() != null) {
-            Listener l = new Listener();
-            if (t.getSubWebView() != null) {
-                t.getSubWebView().setPictureListener(l);
-            } else {
-                t.getWebView().setPictureListener(l);
-            }
-            mPicture = mTab.getTopWindow().capturePicture();
+        if (mPickerData != null) {
+            // Clear the old tab's view first
+            mPickerData.mFakeWebView = null;
+        }
+        mPickerData = null;
+        if (t != null && t.getPickerData() != null) {
+            mPickerData = t.getPickerData();
+            mPickerData.mFakeWebView = this;
         }
     }
 }
diff --git a/src/com/android/browser/ImageAdapter.java b/src/com/android/browser/ImageAdapter.java
index e957143..42d2224 100644
--- a/src/com/android/browser/ImageAdapter.java
+++ b/src/com/android/browser/ImageAdapter.java
@@ -27,7 +27,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.LayoutInflater;
-import android.webkit.WebView;
 import android.widget.ImageView;
 import android.widget.ListAdapter;
 import android.widget.TextView;
@@ -73,22 +72,10 @@
      * Clear the internal WebViews and remove their picture listeners.
      */
     public void clear() {
-        for (TabControl.Tab t : mItems) {
-            clearPictureListeners(t);
-        }
         mItems.clear();
         notifyObservers();
     }
 
-    private void clearPictureListeners(TabControl.Tab t) {
-        if (t.getWebView() != null) {
-            t.getWebView().setPictureListener(null);
-            if (t.getSubWebView() != null) {
-                t.getSubWebView().setPictureListener(null);
-            }
-        }
-    }
-
     /**
      * Add a new window web page to the grid
      * 
@@ -113,7 +100,6 @@
      */
     public void remove(int index) {
         if (index >= 0 && index < mItems.size()) {
-            clearPictureListeners(mItems.remove(index));
             notifyObservers();
             mMaxedOut = false;
         }
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 0b82676..0e93453 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -17,6 +17,7 @@
 package com.android.browser;
 
 import android.content.Context;
+import android.graphics.Picture;
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.os.Message;
@@ -39,6 +40,7 @@
 import android.widget.ImageButton;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.Vector;
 
@@ -142,10 +144,24 @@
         }
     }
 
+    // Extra saved information for displaying the tab in the picker.
+    public static class PickerData {
+        String  mUrl;
+        String  mTitle;
+        float   mScale;
+        int     mScrollX;
+        int     mScrollY;
+        int     mWidth;
+        Picture mPicture;
+        // This can be null. When a new picture comes in, this view should be
+        // invalidated to show the new picture.
+        FakeWebView mFakeWebView;
+    }
+
     /**
      * Private class for maintaining Tabs with a main WebView and a subwindow.
      */
-    public class Tab {
+    public class Tab implements WebView.PictureListener {
         // Main WebView
         private WebView mMainView;
         // Subwindow WebView
@@ -160,10 +176,9 @@
         // information needed to restore the WebView if the user goes back to
         // the tab.
         private Bundle mSavedState;
-        // Extra saved information for displaying the tab in the picker.
-        private String mUrl;
-        private String mTitle;
- 
+        // Data used when displaying the tab in the picker.
+        private PickerData mPickerData;
+
         // Parent Tab. This is the Tab that created this Tab, or null
         // if the Tab was created by the UI
         private Tab mParentTab;
@@ -234,7 +249,7 @@
          * @return The WebView's url or null.
          */
         public String getUrl() {
-            return mUrl;
+            return mPickerData.mUrl;
         }
 
         /**
@@ -245,7 +260,14 @@
          * @return The WebView's title (or url) or null.
          */
         public String getTitle() {
-            return mTitle;
+            return mPickerData.mTitle;
+        }
+
+        /**
+         * Returns the picker data.
+         */
+        public PickerData getPickerData() {
+            return mPickerData;
         }
 
         private void setParentTab(Tab parent) {
@@ -307,6 +329,18 @@
         public boolean closeOnExit() {
             return mCloseOnExit;
         }
+
+        public void onNewPicture(WebView view, Picture p) {
+            if (mPickerData == null) {
+                return;
+            }
+
+            mPickerData.mPicture = p;
+            // Tell the FakeWebView to redraw.
+            if (mPickerData.mFakeWebView != null) {
+                mPickerData.mFakeWebView.invalidate();
+            }
+        }
     };
 
     // Directory to store thumbnails for each WebView.
@@ -483,8 +517,8 @@
         // This tab may have been pushed in to the background and then closed.
         // If the saved state contains a picture file, delete the file.
         if (t.mSavedState != null) {
-            if (t.mSavedState.containsKey("picture")) {
-                new File(t.mSavedState.getString("picture")).delete();
+            if (t.mSavedState.containsKey(CURRPICTURE)) {
+                new File(t.mSavedState.getString(CURRPICTURE)).delete();
             }
         }
 
@@ -543,6 +577,8 @@
     private static final String CURRTAB = "currentTab";
     private static final String CURRURL = "currentUrl";
     private static final String CURRTITLE = "currentTitle";
+    private static final String CURRWIDTH = "currentWidth";
+    private static final String CURRPICTURE = "currentPicture";
     private static final String CLOSEONEXIT = "closeonexit";
     private static final String PARENTTAB = "parentTab";
     private static final String APPID = "appid";
@@ -595,8 +631,7 @@
                     Tab t = new Tab(null, false, null, null);
                     t.mSavedState = inState.getBundle(WEBVIEW + i);
                     if (t.mSavedState != null) {
-                        t.mUrl = t.mSavedState.getString(CURRURL);
-                        t.mTitle = t.mSavedState.getString(CURRTITLE);
+                        populatePickerDataFromSavedState(t);
                         // Need to maintain the app id and original url so we
                         // can possibly reuse this tab.
                         t.mAppId = t.mSavedState.getString(APPID);
@@ -792,8 +827,7 @@
         // Clear the saved state except for the app id and close-on-exit
         // values.
         t.mSavedState = null;
-        t.mUrl = null;
-        t.mTitle = null;
+        t.mPickerData = null;
         // Save the new url in order to avoid deleting the WebView.
         t.mOriginalUrl = url;
         return true;
@@ -918,30 +952,89 @@
     }
 
     /**
-     * Ensure that Tab t has a title, url, and favicon.
+     * Ensure that Tab t has data to display in the tab picker.
      * @param  t   Tab to populate.
      */
     /* package */ void populatePickerData(Tab t) {
-        if (t == null || t.mMainView == null) {
+        if (t == null) {
             return;
         }
+
+        // mMainView == null indicates that the tab has been freed.
+        if (t.mMainView == null) {
+            populatePickerDataFromSavedState(t);
+            return;
+        }
+
         // FIXME: The only place we cared about subwindow was for 
         // bookmarking (i.e. not when saving state). Was this deliberate?
         final WebBackForwardList list = t.mMainView.copyBackForwardList();
         final WebHistoryItem item =
                 list != null ? list.getCurrentItem() : null;
         populatePickerData(t, item);
+
+        // This method is only called during the tab picker creation. At this
+        // point we need to listen for new pictures since the WebView is still
+        // active.
+        final WebView w = t.getTopWindow();
+        w.setPictureListener(t);
+        // Capture the picture here instead of populatePickerData since it can
+        // be called when saving the state of a tab.
+        t.mPickerData.mPicture = w.capturePicture();
     }
 
-    // Populate the picker data
-    private void populatePickerData(Tab t, WebHistoryItem item) {
-        if (item != null) {
-            t.mUrl = item.getUrl();
-            t.mTitle = item.getTitle();
-            if (t.mTitle == null) {
-                t.mTitle = t.mUrl;
+    // Create the PickerData and populate it using the saved state of the tab.
+    private void populatePickerDataFromSavedState(Tab t) {
+        if (t.mSavedState == null) {
+            return;
+        }
+
+        final PickerData data = new PickerData();
+        final Bundle state = t.mSavedState;
+        data.mUrl = state.getString(CURRURL);
+        data.mTitle = state.getString(CURRTITLE);
+        data.mWidth = state.getInt(CURRWIDTH, 0);
+        // XXX: These keys are from WebView.savePicture so if they change, this
+        // will break.
+        data.mScale = state.getFloat("scale", 1.0f);
+        data.mScrollX = state.getInt("scrollX", 0);
+        data.mScrollY = state.getInt("scrollY", 0);
+
+        if (state.containsKey(CURRPICTURE)) {
+            final File f = new File(t.mSavedState.getString(CURRPICTURE));
+            try {
+                final FileInputStream in = new FileInputStream(f);
+                data.mPicture = Picture.createFromStream(in);
+                in.close();
+            } catch (Exception ex) {
+                // Ignore any problems with inflating the picture. We just
+                // won't draw anything.
             }
         }
+
+        // Set the tab's picker data.
+        t.mPickerData = data;
+    }
+
+    // Populate the picker data using the given history item and the current
+    // top WebView.
+    private void populatePickerData(Tab t, WebHistoryItem item) {
+        final PickerData data = new PickerData();
+        if (item != null) {
+            data.mUrl = item.getUrl();
+            data.mTitle = item.getTitle();
+            if (data.mTitle == null) {
+                data.mTitle = data.mUrl;
+            }
+        }
+        // We want to display the top window in the tab picker but use the url
+        // and title of the main window.
+        final WebView w = t.getTopWindow();
+        data.mWidth = w.getWidth();
+        data.mScale = w.getScale();
+        data.mScrollX = w.getScrollX();
+        data.mScrollY = w.getScrollY();
+        t.mPickerData = data;
     }
     
     /**
@@ -952,8 +1045,14 @@
         for (int i = 0; i < size; i++) {
             final Tab t = getTab(i);
             if (t != null && t.mSavedState == null) {
-                t.mUrl = null;
-                t.mTitle = null;
+                t.mPickerData = null;
+            }
+            if (t.mMainView != null) {
+                // Clear the picture listeners.
+                t.mMainView.setPictureListener(null);
+                if (t.mSubView != null) {
+                    t.mSubView.setPictureListener(null);
+                }
             }
         }
     }
@@ -975,7 +1074,7 @@
                 final File f = new File(mThumbnailDir, w.hashCode()
                         + "_pic.save");
                 if (w.savePicture(b, f)) {
-                    b.putString("picture", f.getPath());
+                    b.putString(CURRPICTURE, f.getPath());
                 }
             }
 
@@ -983,12 +1082,17 @@
             final WebHistoryItem item =
                     list != null ? list.getCurrentItem() : null;
             populatePickerData(t, item);
-            if (t.mUrl != null) {
-                b.putString(CURRURL, t.mUrl);
+
+            // XXX: WebView.savePicture stores the scale and scroll positions
+            // in the bundle so we don't have to do it here.
+            final PickerData data = t.mPickerData;
+            if (data.mUrl != null) {
+                b.putString(CURRURL, data.mUrl);
             }
-            if (t.mTitle != null) {
-                b.putString(CURRTITLE, t.mTitle);
+            if (data.mTitle != null) {
+                b.putString(CURRTITLE, data.mTitle);
             }
+            b.putInt(CURRWIDTH, data.mWidth);
             b.putBoolean(CLOSEONEXIT, t.mCloseOnExit);
             if (t.mAppId != null) {
                 b.putString(APPID, t.mAppId);
@@ -1019,8 +1123,7 @@
         // Restore the internal state even if the WebView fails to restore.
         // This will maintain the app id, original url and close-on-exit values.
         t.mSavedState = null;
-        t.mUrl = null;
-        t.mTitle = null;
+        t.mPickerData = null;
         t.mCloseOnExit = b.getBoolean(CLOSEONEXIT);
         t.mAppId = b.getString(APPID);
         t.mOriginalUrl = b.getString(ORIGINALURL);
@@ -1030,8 +1133,8 @@
         if (list == null) {
             return false;
         }
-        if (b.containsKey("picture")) {
-            final File f = new File(b.getString("picture"));
+        if (b.containsKey(CURRPICTURE)) {
+            final File f = new File(b.getString(CURRPICTURE));
             w.restorePicture(b, f);
             f.delete();
         }