OSDN Git Service

Show the saved picture for freed tabs.
authorPatrick Scott <phanna@android.com>
Wed, 22 Apr 2009 14:07:45 +0000 (10:07 -0400)
committerPatrick Scott <phanna@android.com>
Wed, 22 Apr 2009 14:07:45 +0000 (10:07 -0400)
Create a small class containing the data needed to display the saved or current
picture. For freed tabs, inflate the picture and use the saved state from
mSavedState. Reorganize populatePickerData to use the current top window or the
saved state depending on if the tab has been freed.

There was another bug where onNewPicture would update the wrong FakeWebView due
to ListViews reusing the same view. Have the tab manage the new picture and
invalidate the FakeWebView. When reusing the view, clear out the tab's
FakeWebView field.

Wipe all the picker data at the same time the ImageGrid and ImageAdapter are
cleared.

src/com/android/browser/BrowserActivity.java
src/com/android/browser/FakeWebView.java
src/com/android/browser/ImageAdapter.java
src/com/android/browser/TabControl.java

index 3f79a2d..9d5130f 100644 (file)
@@ -2132,6 +2132,9 @@ public class BrowserActivity extends Activity
                     .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 @@ public class BrowserActivity extends Activity
                 }
             }
 
-            // 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);
index 633b799..da5ef5f 100644 (file)
@@ -33,17 +33,9 @@ import android.util.Log;
  *  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 @@ public class FakeWebView extends ImageView {
             // 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 @@ public class FakeWebView extends ImageView {
     @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;
         }
     }
 }
index e957143..42d2224 100644 (file)
@@ -27,7 +27,6 @@ import android.view.KeyEvent;
 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 @@ public class ImageAdapter implements ListAdapter {
      * 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 class ImageAdapter implements ListAdapter {
      */
     public void remove(int index) {
         if (index >= 0 && index < mItems.size()) {
-            clearPictureListeners(mItems.remove(index));
             notifyObservers();
             mMaxedOut = false;
         }
index 0b82676..0e93453 100644 (file)
@@ -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.FrameLayout;
 import android.widget.ImageButton;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.util.ArrayList;
 import java.util.Vector;
 
@@ -142,10 +144,24 @@ class TabControl {
         }
     }
 
+    // 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 @@ class TabControl {
         // 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 @@ class TabControl {
          * @return The WebView's url or null.
          */
         public String getUrl() {
-            return mUrl;
+            return mPickerData.mUrl;
         }
 
         /**
@@ -245,7 +260,14 @@ class TabControl {
          * @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 @@ class TabControl {
         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 @@ class TabControl {
         // 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 @@ class TabControl {
     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 @@ class TabControl {
                     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 @@ class TabControl {
         // 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 @@ class TabControl {
     }
 
     /**
-     * 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
+    // 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) {
-            t.mUrl = item.getUrl();
-            t.mTitle = item.getTitle();
-            if (t.mTitle == null) {
-                t.mTitle = t.mUrl;
+            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 @@ class TabControl {
         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 @@ class TabControl {
                 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 @@ class TabControl {
             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 @@ class TabControl {
         // 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 @@ class TabControl {
         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();
         }