OSDN Git Service

disable mr stretchy, but leave the support code around for now
[android-x86/packages-apps-Browser.git] / src / com / android / browser / TabControl.java
index f66df69..c03fdf4 100644 (file)
 package com.android.browser;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
+import android.graphics.Paint;
 import android.graphics.Picture;
+import android.graphics.Shader;
 import android.net.http.SslError;
 import android.os.Bundle;
 import android.os.Message;
@@ -38,6 +43,7 @@ import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
+import android.widget.LinearLayout;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -68,7 +74,7 @@ class TabControl {
     private final LayoutInflater mInflateService;
     // Subclass of WebViewClient used in subwindows to notify the main
     // WebViewClient of certain WebView activities.
-    private class SubWindowClient extends WebViewClient {
+    private static class SubWindowClient extends WebViewClient {
         // The main WebViewClient.
         private final WebViewClient mClient;
 
@@ -104,6 +110,16 @@ class TabControl {
                 String description, String failingUrl) {
             mClient.onReceivedError(view, errorCode, description, failingUrl);
         }
+        @Override
+        public boolean shouldOverrideKeyEvent(WebView view,
+                android.view.KeyEvent event) {
+            return mClient.shouldOverrideKeyEvent(view, event);
+        }
+        @Override
+        public void onUnhandledKeyEvent(WebView view,
+                android.view.KeyEvent event) {
+            mClient.onUnhandledKeyEvent(view, event);
+        }
     }
     // Subclass of WebChromeClient to display javascript dialogs.
     private class SubWindowChromeClient extends WebChromeClient {
@@ -139,7 +155,7 @@ class TabControl {
         public void onRequestFocus(WebView view) {
             Tab t = getTabFromView(view);
             if (t != getCurrentTab()) {
-                mActivity.showTab(t);
+                mActivity.switchToTab(getTabIndex(t));
             }
         }
     }
@@ -148,20 +164,19 @@ class TabControl {
     public static class PickerData {
         String  mUrl;
         String  mTitle;
+        Bitmap  mFavicon;
         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 implements WebView.PictureListener {
+    public class Tab {
+        // The Geolocation permissions prompt
+        private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
+        private View mContainer;
         // Main WebView
         private WebView mMainView;
         // Subwindow WebView
@@ -195,12 +210,103 @@ class TabControl {
         // url has not changed.
         private String mOriginalUrl;
 
+        private ErrorConsoleView mErrorConsole;
+        // the lock icon type and previous lock icon type for the tab
+        private int mSavedLockIconType;
+        private int mSavedPrevLockIconType;
+
         // Construct a new tab
-        private Tab(WebView w, boolean closeOnExit, String appId, String url) {
-            mMainView = w;
+        private Tab(WebView w, boolean closeOnExit, String appId, String url, Context context) {
             mCloseOnExit = closeOnExit;
             mAppId = appId;
             mOriginalUrl = url;
+            mSavedLockIconType = BrowserActivity.LOCK_ICON_UNSECURE;
+            mSavedPrevLockIconType = BrowserActivity.LOCK_ICON_UNSECURE;
+
+            // The tab consists of a container view, which contains the main
+            // WebView, as well as any other UI elements associated with the tab.
+            LayoutInflater factory = LayoutInflater.from(context);
+            mContainer = factory.inflate(R.layout.tab, null);
+
+            mGeolocationPermissionsPrompt =
+                (GeolocationPermissionsPrompt) mContainer.findViewById(
+                    R.id.geolocation_permissions_prompt);
+
+            setWebView(w);
+        }
+
+        /**
+         * Sets the WebView for this tab, correctly removing the old WebView
+         * from the container view.
+         */
+        public void setWebView(WebView w) {
+            if (mMainView == w) {
+                return;
+            }
+            // If the WebView is changing, the page will be reloaded, so any ongoing Geolocation
+            // permission requests are void.
+            mGeolocationPermissionsPrompt.hide();
+
+            // Just remove the old one.
+            FrameLayout wrapper =
+                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
+            wrapper.removeView(mMainView);
+            mMainView = w;
+        }
+
+        /**
+         * This method attaches both the WebView and any sub window to the
+         * given content view.
+         */
+        public void attachTabToContentView(ViewGroup content) {
+            if (mMainView == null) {
+                return;
+            }
+
+            // Attach the WebView to the container and then attach the
+            // container to the content view.
+            FrameLayout wrapper =
+                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
+            wrapper.addView(mMainView);
+            content.addView(mContainer, BrowserActivity.COVER_SCREEN_PARAMS);
+            attachSubWindow(content);
+        }
+
+        /**
+         * Remove the WebView and any sub window from the given content view.
+         */
+        public void removeTabFromContentView(ViewGroup content) {
+            if (mMainView == null) {
+                return;
+            }
+
+            // Remove the container from the content and then remove the
+            // WebView from the container. This will trigger a focus change
+            // needed by WebView.
+            FrameLayout wrapper =
+                    (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
+            wrapper.removeView(mMainView);
+            content.removeView(mContainer);
+            removeSubWindow(content);
+        }
+
+        /**
+         * Attach the sub window to the content view.
+         */
+        public void attachSubWindow(ViewGroup content) {
+            if (mSubView != null) {
+                content.addView(mSubViewContainer,
+                        BrowserActivity.COVER_SCREEN_PARAMS);
+            }
+        }
+
+        /**
+         * Remove the sub window from the content view.
+         */
+        public void removeSubWindow(ViewGroup content) {
+            if (mSubView != null) {
+                content.removeView(mSubViewContainer);
+            }
         }
 
         /**
@@ -226,20 +332,18 @@ class TabControl {
         }
 
         /**
-         * Return the subwindow of this tab or null if there is no subwindow.
-         * @return The subwindow of this tab or null.
+         * @return The geolocation permissions prompt for this tab.
          */
-        public WebView getSubWebView() {
-            return mSubView;
+        public GeolocationPermissionsPrompt getGeolocationPermissionsPrompt() {
+            return mGeolocationPermissionsPrompt;
         }
 
         /**
-         * Return the subwindow container of this tab or null if there is no
-         * subwindow.
-         * @return The subwindow's container View.
+         * Return the subwindow of this tab or null if there is no subwindow.
+         * @return The subwindow of this tab or null.
          */
-        public View getSubWebViewContainer() {
-            return mSubViewContainer;
+        public WebView getSubWebView() {
+            return mSubView;
         }
 
         /**
@@ -269,11 +373,11 @@ class TabControl {
             return null;
         }
 
-        /**
-         * Returns the picker data.
-         */
-        public PickerData getPickerData() {
-            return mPickerData;
+        public Bitmap getFavicon() {
+            if (mPickerData != null) {
+                return mPickerData.mFavicon;
+            }
+            return null;
         }
 
         private void setParentTab(Tab parent) {
@@ -336,16 +440,20 @@ class TabControl {
             return mCloseOnExit;
         }
 
-        public void onNewPicture(WebView view, Picture p) {
-            if (mPickerData == null) {
-                return;
-            }
+        void setLockIconType(int type) {
+            mSavedLockIconType = type;
+        }
 
-            mPickerData.mPicture = p;
-            // Tell the FakeWebView to redraw.
-            if (mPickerData.mFakeWebView != null) {
-                mPickerData.mFakeWebView.invalidate();
-            }
+        int getLockIconType() {
+            return mSavedLockIconType;
+        }
+
+        void setPrevLockIconType(int type) {
+            mSavedPrevLockIconType = type;
+        }
+
+        int getPrevLockIconType() {
+            return mSavedPrevLockIconType;
         }
     };
 
@@ -388,6 +496,28 @@ class TabControl {
     }
 
     /**
+     * Return the current tab's error console. Creates the console if createIfNEcessary
+     * is true and we haven't already created the console.
+     * @param createIfNecessary Flag to indicate if the console should be created if it has
+     *                          not been already.
+     * @return The current tab's error console, or null if one has not been created and
+     *         createIfNecessary is false.
+     */
+    ErrorConsoleView getCurrentErrorConsole(boolean createIfNecessary) {
+        Tab t = getTab(mCurrentTab);
+        if (t == null) {
+            return null;
+        }
+
+        if (createIfNecessary && t.mErrorConsole == null) {
+            t.mErrorConsole = new ErrorConsoleView(mActivity);
+            t.mErrorConsole.setWebView(t.mMainView);
+        }
+
+        return t.mErrorConsole;
+    }
+
+    /**
      * Return the current tab's top-level WebView. This can return a subwindow
      * if one exists.
      * @return The top-level WebView of the current tab.
@@ -464,8 +594,9 @@ class TabControl {
             return null;
         }
         final WebView w = createNewWebView();
+
         // Create a new tab and add it to the tab list
-        Tab t = new Tab(w, closeOnExit, appId, url);
+        Tab t = new Tab(w, closeOnExit, appId, url, mActivity);
         mTabs.add(t);
         // Initially put the tab in the background.
         putTabInBackground(t);
@@ -502,9 +633,10 @@ class TabControl {
             // observers.
             BrowserSettings.getInstance().deleteObserver(
                     t.mMainView.getSettings());
-            // Destroy the main view and subview
-            t.mMainView.destroy();
-            t.mMainView = null;
+            WebView w = t.mMainView;
+            t.setWebView(null);
+            // Destroy the main view
+            w.destroy();
         }
         // clear it's references to parent and children
         t.removeFromTree();
@@ -564,8 +696,9 @@ class TabControl {
             if (t.mMainView != null) {
                 dismissSubWindow(t);
                 s.deleteObserver(t.mMainView.getSettings());
-                t.mMainView.destroy();
-                t.mMainView = null;
+                WebView w = t.mMainView;
+                t.setWebView(null);
+                w.destroy();
             }
         }
         mTabs.clear();
@@ -586,7 +719,6 @@ 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";
@@ -637,7 +769,7 @@ class TabControl {
                 } else {
                     // Create a new tab and don't restore the state yet, add it
                     // to the tab list
-                    Tab t = new Tab(null, false, null, null);
+                    Tab t = new Tab(null, false, null, null, mActivity);
                     t.mSavedState = inState.getBundle(WEBVIEW + i);
                     if (t.mSavedState != null) {
                         populatePickerDataFromSavedState(t);
@@ -674,8 +806,10 @@ class TabControl {
      * WebView cache;
      */
     void freeMemory() {
+        if (getTabCount() == 0) return;
+
         // free the least frequently used background tab
-        Tab t = getLeastUsedTab();
+        Tab t = getLeastUsedTab(getCurrentTab());
         if (t != null) {
             Log.w(LOGTAG, "Free a tab in the browser");
             freeTab(t);
@@ -694,9 +828,10 @@ class TabControl {
         System.gc();
     }
 
-    private Tab getLeastUsedTab() {
-        // Don't do anything if we only have 1 tab.
-        if (getTabCount() == 1) {
+    private Tab getLeastUsedTab(Tab current) {
+        // Don't do anything if we only have 1 tab or if the current tab is
+        // null.
+        if (getTabCount() == 1 || current == null) {
             return null;
         }
 
@@ -710,10 +845,13 @@ class TabControl {
         }
         do {
             t = mTabQueue.get(i++);
-        } while (i < queueSize && t != null && t.mMainView == null);
+        } while (i < queueSize
+                && ((t != null && t.mMainView == null)
+                    || t == current.mParentTab));
 
-        // Don't do anything if the last remaining tab is the current one.
-        if (t == getCurrentTab()) {
+        // Don't do anything if the last remaining tab is the current one or if
+        // the last tab has been freed already.
+        if (t == current || t.mMainView == null) {
             return null;
         }
 
@@ -729,8 +867,9 @@ class TabControl {
         // Remove the WebView's settings from the BrowserSettings list of
         // observers.
         BrowserSettings.getInstance().deleteObserver(t.mMainView.getSettings());
-        t.mMainView.destroy();
-        t.mMainView = null;
+        WebView w = t.mMainView;
+        t.setWebView(null);
+        w.destroy();
     }
 
     /**
@@ -803,6 +942,45 @@ class TabControl {
         return null;
     }
 
+    // This method checks if a non-app tab (one created within the browser)
+    // matches the given url.
+    private boolean tabMatchesUrl(Tab t, String url) {
+        if (t.mAppId != null) {
+            return false;
+        } else if (t.mMainView == null) {
+            return false;
+        } else if (url.equals(t.mMainView.getUrl()) ||
+                url.equals(t.mMainView.getOriginalUrl())) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return the tab that has no app id associated with it and the url of the
+     * tab matches the given url.
+     * @param url The url to search for.
+     */
+    Tab findUnusedTabWithUrl(String url) {
+        if (url == null) {
+            return null;
+        }
+        // Check the current tab first.
+        Tab t = getCurrentTab();
+        if (t != null && tabMatchesUrl(t, url)) {
+            return t;
+        }
+        // Now check all the rest.
+        final int size = getTabCount();
+        for (int i = 0; i < size; i++) {
+            t = getTab(i);
+            if (tabMatchesUrl(t, url)) {
+                return t;
+            }
+        }
+        return null;
+    }
+
     /**
      * Recreate the main WebView of the given tab. Returns true if the WebView
      * was deleted.
@@ -829,7 +1007,7 @@ class TabControl {
         }
         // Create a new WebView. If this tab is the current tab, we need to put
         // back all the clients so force it to be the current tab.
-        t.mMainView = createNewWebView();
+        t.setWebView(createNewWebView());
         if (getCurrentTab() == t) {
             setCurrentTab(t, true);
         }
@@ -848,6 +1026,8 @@ class TabControl {
     private WebView createNewWebView() {
         // Create a new WebView
         WebView w = new WebView(mActivity);
+        w.setScrollbarFadingEnabled(true);
+        w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
         w.setMapTrackballToArrowKeys(false); // use trackball directly
         // Enable the built-in zoom
         w.getSettings().setBuiltInZoomControls(true);
@@ -855,6 +1035,18 @@ class TabControl {
         // settings
         final BrowserSettings s = BrowserSettings.getInstance();
         s.addObserver(w.getSettings()).update(s, null);
+
+        // pick a default
+        if (false) {
+            MeshTracker mt = new MeshTracker(2);
+            Paint paint = new Paint();
+            Bitmap bm = BitmapFactory.decodeResource(mActivity.getResources(),
+                                         R.drawable.pattern_carbon_fiber_dark);
+            paint.setShader(new BitmapShader(bm, Shader.TileMode.REPEAT,
+                                             Shader.TileMode.REPEAT));
+            mt.setBGPaint(paint);
+            w.setDragTracker(mt);
+        }
         return w;
     }
 
@@ -941,7 +1133,8 @@ class TabControl {
         boolean needRestore = (mainView == null);
         if (needRestore) {
             // Same work as in createNewTab() except don't do new Tab()
-            newTab.mMainView = mainView = createNewWebView();
+            mainView = createNewWebView();
+            newTab.setWebView(mainView);
         }
         putViewInForeground(mainView, mActivity.getWebViewClient(),
                             mActivity.getWebChromeClient());
@@ -1003,15 +1196,6 @@ class TabControl {
         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();
     }
 
     // Create the PickerData and populate it using the saved state of the tab.
@@ -1024,25 +1208,12 @@ class TabControl {
         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;
     }
@@ -1054,6 +1225,7 @@ class TabControl {
         if (item != null) {
             data.mUrl = item.getUrl();
             data.mTitle = item.getTitle();
+            data.mFavicon = item.getFavicon();
             if (data.mTitle == null) {
                 data.mTitle = data.mUrl;
             }
@@ -1061,10 +1233,10 @@ class TabControl {
         // 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;
     }
     
@@ -1078,13 +1250,6 @@ class TabControl {
             if (t != null && t.mSavedState == null) {
                 t.mPickerData = null;
             }
-            if (t.mMainView != null) {
-                // Clear the picture listeners.
-                t.mMainView.setPictureListener(null);
-                if (t.mSubView != null) {
-                    t.mSubView.setPictureListener(null);
-                }
-            }
         }
     }
 
@@ -1123,7 +1288,6 @@ class TabControl {
             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);