Prevent webview reuse

 Bug: 4742007
 Bug: 4770356
 Also pipe all loadUrl's through Tab so that it can immediately
 update its internal state. This is necessary as javascript:
 uris do not cause onPageStarted/finished callbacks to happen,
 thus the url and title of the Tab do not update.

Change-Id: I6d17e8627db505eaa9158339fdfc7afd2c6672a2
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index e3ca09a..9a015b2 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -38,7 +38,6 @@
 import android.graphics.Picture;
 import android.net.Uri;
 import android.net.http.SslError;
-import android.nfc.NfcAdapter;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Environment;
@@ -84,14 +83,13 @@
 import com.android.browser.search.SearchEngine;
 import com.android.common.Search;
 
-import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.IOException;
 import java.net.URLEncoder;
 import java.util.Calendar;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Controller for browser
@@ -481,10 +479,10 @@
                         }
                         switch (msg.arg1) {
                             case R.id.open_context_menu_id:
-                                loadUrlFromContext(getCurrentTopWebView(), url);
+                                loadUrlFromContext(url);
                                 break;
                             case R.id.view_image_context_menu_id:
-                                loadUrlFromContext(getCurrentTopWebView(), src);
+                                loadUrlFromContext(src);
                                 break;
                             case R.id.open_newtab_context_menu_id:
                                 final Tab parent = mTabControl.getCurrentTab();
@@ -505,7 +503,7 @@
                     }
 
                     case LOAD_URL:
-                        loadUrlFromContext(getCurrentTopWebView(), (String) msg.obj);
+                        loadUrlFromContext((String) msg.obj);
                         break;
 
                     case STOP_LOAD:
@@ -1204,8 +1202,7 @@
                         true);
             } else {
                 final Tab currentTab = mTabControl.getCurrentTab();
-                dismissSubWindow(currentTab);
-                loadUrl(getCurrentTopWebView(), url);
+                loadUrl(currentTab, url);
             }
         }
     }
@@ -1604,10 +1601,7 @@
 
             case R.id.homepage_menu_id:
                 Tab current = mTabControl.getCurrentTab();
-                if (current != null) {
-                    dismissSubWindow(current);
-                    loadUrl(current.getWebView(), mSettings.getHomePage());
-                }
+                loadUrl(current, mSettings.getHomePage());
                 break;
 
             case R.id.preferences_menu_id:
@@ -2204,7 +2198,7 @@
         }
     }
 
-    protected void reuseTab(Tab appTab, String appId, UrlData urlData) {
+    protected void reuseTab(Tab appTab, UrlData urlData) {
         // Dismiss the subwindow if applicable.
         dismissSubWindow(appTab);
         // Since we might kill the WebView, remove it from the
@@ -2289,9 +2283,8 @@
             if (parent != null && parent != tab) {
                 parent.addChildTab(tab);
             }
-            WebView w = tab.getWebView();
             if (url != null) {
-                loadUrl(w, url);
+                loadUrl(tab, url);
             }
         }
         return tab;
@@ -2313,8 +2306,7 @@
         } else {
             if (useCurrent) {
                 tab = mTabControl.getCurrentTab();
-                // Get rid of the subwindow if it exists
-                dismissSubWindow(tab);
+                reuseTab(tab, null);
             } else {
                 mUi.showMaxTabsWarning();
             }
@@ -2383,15 +2375,15 @@
         removeTab(tab);
     }
 
-    /**************** TODO: Url loading clean up *******************************/
-
     // Called when loading from context menu or LOAD_URL message
-    protected void loadUrlFromContext(WebView view, String url) {
+    protected void loadUrlFromContext(String url) {
+        Tab tab = getCurrentTab();
+        WebView view = tab != null ? tab.getWebView() : null;
         // In case the user enters nothing.
-        if (url != null && url.length() != 0 && view != null) {
+        if (url != null && url.length() != 0 && tab != null && view != null) {
             url = UrlUtils.smartUrlFilter(url);
             if (!view.getWebViewClient().shouldOverrideUrlLoading(view, url)) {
-                loadUrl(view, url);
+                loadUrl(tab, url);
             }
         }
     }
@@ -2403,8 +2395,15 @@
      * @param view The WebView used to load url.
      * @param url The URL to load.
      */
-    protected void loadUrl(WebView view, String url) {
-        view.loadUrl(url);
+    protected void loadUrl(Tab tab, String url) {
+        loadUrl(tab, url, null);
+    }
+
+    protected void loadUrl(Tab tab, String url, Map<String, String> headers) {
+        if (tab != null) {
+            dismissSubWindow(tab);
+            tab.loadUrl(url, headers);
+        }
     }
 
     /**
@@ -2414,7 +2413,13 @@
      * @param data The UrlData being loaded.
      */
     protected void loadUrlDataIn(Tab t, UrlData data) {
-        data.loadIn(t);
+        if (data != null) {
+            if (data.mVoiceIntent != null) {
+                t.activateVoiceSearchMode(data.mVoiceIntent);
+            } else {
+                loadUrl(t, data.mUrl, data.mHeaders);
+            }
+        }
     }
 
     @Override
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index 4a8fa22..54711d9 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -141,6 +141,12 @@
             }
             final String appId = intent
                     .getStringExtra(Browser.EXTRA_APPLICATION_ID);
+            if (!TextUtils.isEmpty(urlData.mUrl) &&
+                    urlData.mUrl.startsWith("javascript:")) {
+                // Always open javascript: URIs in new tabs
+                mController.openTab(urlData);
+                return;
+            }
             if ((Intent.ACTION_VIEW.equals(action)
                     // If a voice search has no appId, it means that it came
                     // from the browser.  In that case, reuse the current tab.
@@ -150,7 +156,7 @@
                 if (activateVoiceSearch) {
                     Tab appTab = mTabControl.getTabFromAppId(appId);
                     if (appTab != null) {
-                        mController.reuseTab(appTab, appId, urlData);
+                        mController.reuseTab(appTab, urlData);
                         return;
                     } else {
                         Tab tab = mController.openTab(urlData);
@@ -359,18 +365,6 @@
         boolean isEmpty() {
             return mVoiceIntent == null && (mUrl == null || mUrl.length() == 0);
         }
-
-        /**
-         * Load this UrlData into the given Tab.  Use loadUrlDataIn to update
-         * the title bar as well.
-         */
-        public void loadIn(Tab t) {
-            if (mVoiceIntent != null) {
-                t.activateVoiceSearchMode(mVoiceIntent);
-            } else {
-                t.getWebView().loadUrl(mUrl, mHeaders);
-            }
-        }
     }
 
 }
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 58a7491..bc5868f 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -20,14 +20,12 @@
 import android.app.AlertDialog;
 import android.app.SearchManager;
 import android.content.ContentResolver;
-import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.CompressFormat;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.net.http.SslError;
@@ -69,11 +67,6 @@
 import com.android.common.speech.LoggingEvents;
 
 import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -1861,7 +1854,6 @@
             return null;
         }
         byte[] data = stream.toByteArray();
-        ContentResolver cr = mActivity.getContentResolver();
         ContentValues values = new ContentValues();
         values.put(Snapshots.TITLE, mCurrentState.mTitle);
         values.put(Snapshots.URL, mCurrentState.mUrl);
@@ -1870,4 +1862,12 @@
         return values;
     }
 
+    public void loadUrl(String url, Map<String, String> headers) {
+        if (mMainView != null) {
+            mCurrentState = new PageState(mActivity, false, url, null);
+            mWebViewController.onPageStarted(this, mMainView, null);
+            mMainView.loadUrl(url, headers);
+        }
+    }
+
 }
diff --git a/src/com/android/browser/UrlHandler.java b/src/com/android/browser/UrlHandler.java
index 02a080f..17d4062 100644
--- a/src/com/android/browser/UrlHandler.java
+++ b/src/com/android/browser/UrlHandler.java
@@ -262,7 +262,7 @@
                 // If the Activity Manager is not invoked, load the URL directly
                 if (!startActivityForUrl(result)) {
                     if (!handleMenuClick(mTab, result)) {
-                            mController.loadUrl(mWebView, result);
+                        mController.loadUrl(mTab, result);
                     }
                 }
             }