OSDN Git Service

Treat voice searches from within the browser differently
[android-x86/packages-apps-Browser.git] / src / com / android / browser / BrowserActivity.java
index 0688e36..1f969af 100644 (file)
@@ -73,6 +73,7 @@ import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Patterns;
 import android.view.ContextMenu;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -110,12 +111,9 @@ import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
 import android.accounts.AccountManagerCallback;
 
-import com.android.common.Patterns;
 import com.android.common.Search;
 import com.android.common.speech.LoggingEvents;
 
-import com.google.android.gsf.GoogleLoginServiceConstants;
-
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -137,8 +135,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public class BrowserActivity extends Activity
-    implements View.OnCreateContextMenuListener, DownloadListener,
-        AccountManagerCallback<Account[]> {
+    implements View.OnCreateContextMenuListener, DownloadListener {
 
     /* Define some aliases to make these debugging flags easier to refer to.
      * This file imports android.provider.Browser, so we can't just refer to "Browser.DEBUG".
@@ -154,75 +151,6 @@ public class BrowserActivity extends Activity
     private static final int SHORTCUT_DICTIONARY_SEARCH = 3;
     private static final int SHORTCUT_GOOGLE_MOBILE_LOCAL_SEARCH = 4;
 
-    private Account[] mAccountsGoogle;
-    private Account[] mAccountsPreferHosted;
-
-    private void startReadOfGoogleAccounts() {
-        mAccountsGoogle = null;
-        mAccountsPreferHosted = null;
-
-        AccountManager.get(this).getAccountsByTypeAndFeatures(
-                GoogleLoginServiceConstants.ACCOUNT_TYPE,
-                new String[]{GoogleLoginServiceConstants.FEATURE_LEGACY_HOSTED_OR_GOOGLE},
-                this, null);
-    }
-
-    /** This implements AccountManagerCallback<Account[]> */
-    public void run(AccountManagerFuture<Account[]> accountManagerFuture) {
-        try {
-            if (mAccountsGoogle == null) {
-                mAccountsGoogle = accountManagerFuture.getResult();
-
-                AccountManager.get(this).getAccountsByTypeAndFeatures(
-                        GoogleLoginServiceConstants.ACCOUNT_TYPE,
-                        new String[]{GoogleLoginServiceConstants.FEATURE_LEGACY_GOOGLE},
-                        this, null);
-            } else {
-                mAccountsPreferHosted = accountManagerFuture.getResult();
-                setupHomePage();
-            }
-        } catch (OperationCanceledException e) {
-            setupHomePage();
-        } catch (IOException e) {
-            setupHomePage();
-        } catch (AuthenticatorException e) {
-            setupHomePage();
-        }
-    }
-
-    private void setupHomePage() {
-        // get the default home page
-        String homepage = mSettings.getHomePage();
-
-        if (mAccountsPreferHosted != null && mAccountsGoogle != null) {
-            // three cases:
-            //
-            //   hostedUser == googleUser
-            //      The device has only a google account
-            //
-            //   hostedUser != googleUser
-            //      The device has a hosted account and a google account
-            //
-            //   hostedUser != null, googleUser == null
-            //      The device has only a hosted account (so far)
-            String hostedUser = mAccountsPreferHosted.length == 0 
-                    ? null
-                    : mAccountsPreferHosted[0].name;
-            String googleUser = mAccountsGoogle.length == 0 ? null : mAccountsGoogle[0].name;
-
-            // developers might have no accounts at all
-            if (hostedUser == null) return;
-
-            if (googleUser == null || !hostedUser.equals(googleUser)) {
-                String domain = hostedUser.substring(hostedUser.lastIndexOf('@')+1);
-                homepage = homepage.replace("?", "/a/" + domain + "?");
-            }
-        }
-
-        mSettings.setHomePage(BrowserActivity.this, homepage);
-        resumeAfterCredentials();
-    }
-
     private static class ClearThumbnails extends AsyncTask<File, Void, Void> {
         @Override
         public Void doInBackground(File... files) {
@@ -286,6 +214,8 @@ public class BrowserActivity extends Activity
                 .findViewById(R.id.fullscreen_custom_content);
         frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
         mTitleBar = new TitleBar(this);
+        // mTitleBar will be always shown in the fully loaded mode
+        mTitleBar.setProgress(100);
         mFakeTitleBar = new TitleBar(this);
 
         // Create the tab control and our initial tab
@@ -297,11 +227,18 @@ public class BrowserActivity extends Activity
         // Keep a settings instance handy.
         mSettings = BrowserSettings.getInstance();
         mSettings.setTabControl(mTabControl);
-        mSettings.loadFromDb(this);
 
         PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
 
+        // Find out if the network is currently up.
+        ConnectivityManager cm = (ConnectivityManager) getSystemService(
+                Context.CONNECTIVITY_SERVICE);
+        NetworkInfo info = cm.getActiveNetworkInfo();
+        if (info != null) {
+            mIsNetworkUp = info.isAvailable();
+        }
+
         /* enables registration for changes in network status from
            http stack */
         mNetworkStateChangedFilter = new IntentFilter();
@@ -312,17 +249,15 @@ public class BrowserActivity extends Activity
                 public void onReceive(Context context, Intent intent) {
                     if (intent.getAction().equals(
                             ConnectivityManager.CONNECTIVITY_ACTION)) {
-                        boolean noConnectivity = intent.getBooleanExtra(
-                                ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
-                        if (!noConnectivity) {
-                            NetworkInfo info = intent.getParcelableExtra(
-                                    ConnectivityManager.EXTRA_NETWORK_INFO);
-                            String typeName = info.getTypeName();
-                            String subtypeName = info.getSubtypeName();
-                            sendNetworkType(typeName.toLowerCase(),
-                                    (subtypeName != null ? subtypeName.toLowerCase() : ""));
-                        }
-                        onNetworkToggle(!noConnectivity);
+
+                        NetworkInfo info = intent.getParcelableExtra(
+                                ConnectivityManager.EXTRA_NETWORK_INFO);
+                        String typeName = info.getTypeName();
+                        String subtypeName = info.getSubtypeName();
+                        sendNetworkType(typeName.toLowerCase(),
+                                (subtypeName != null ? subtypeName.toLowerCase() : ""));
+
+                        onNetworkToggle(info.isAvailable());
                     }
                 }
             };
@@ -411,23 +346,11 @@ public class BrowserActivity extends Activity
                     webView.setInitialScale(scale);
                 }
             }
-            // If we are not restoring from an icicle, then there is a high
-            // likely hood this is the first run. So, check to see if the
-            // homepage needs to be configured and copy any plugins from our
-            // asset directory to the data partition.
-            if ((extra == null || !extra.getBoolean("testing"))
-                    && !mSettings.isLoginInitialized()) {
-                startReadOfGoogleAccounts();
-            }
 
             if (urlData.isEmpty()) {
-                if (mSettings.isLoginInitialized()) {
-                    webView.loadUrl(mSettings.getHomePage());
-                } else {
-                    waitForCredentials();
-                }
+                loadUrl(webView, mSettings.getHomePage());
             } else {
-                urlData.loadIn(t);
+                loadUrlDataIn(t, urlData);
             }
         } else {
             // TabControl.restoreState() will create a new tab even if
@@ -442,6 +365,11 @@ public class BrowserActivity extends Activity
         }
         // Work out which packages are installed on the system.
         getInstalledPackages();
+
+        // Start watching the default geolocation permissions
+        mSystemAllowGeolocationOrigins
+                = new SystemAllowGeolocationOrigins(getApplicationContext());
+        mSystemAllowGeolocationOrigins.start();
     }
 
     /**
@@ -457,9 +385,10 @@ public class BrowserActivity extends Activity
         bp.setQueryResults(mTabControl.getCurrentTab().getVoiceSearchResults());
         client.release();
 
-        startSearch(result, false,
-                createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY),
-                false);
+        Bundle bundle = createGoogleSearchSourceBundle(
+                GOOGLE_SEARCH_SOURCE_SEARCHKEY);
+        bundle.putBoolean(SearchManager.CONTEXT_IS_VOICE, true);
+        startSearch(result, false, bundle, false);
     }
 
     @Override
@@ -485,6 +414,9 @@ public class BrowserActivity extends Activity
             // just resume the browser
             return;
         }
+        // In case the SearchDialog is open.
+        ((SearchManager) getSystemService(Context.SEARCH_SERVICE))
+                .stopSearch();
         boolean activateVoiceSearch = RecognizerResultsIntent
                 .ACTION_VOICE_SEARCH_RESULTS.equals(action);
         if (Intent.ACTION_VIEW.equals(action)
@@ -528,7 +460,10 @@ public class BrowserActivity extends Activity
 
             final String appId = intent
                     .getStringExtra(Browser.EXTRA_APPLICATION_ID);
-            if ((Intent.ACTION_VIEW.equals(action) || activateVoiceSearch)
+            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.
+                    || (activateVoiceSearch && appId != null))
                     && !getPackageName().equals(appId)
                     && (flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
                 Tab appTab = mTabControl.getTabFromId(appId);
@@ -543,19 +478,19 @@ public class BrowserActivity extends Activity
                     // If the WebView has the same original url and is on that
                     // page, it can be reused.
                     boolean needsLoad =
-                            mTabControl.recreateWebView(appTab, urlData.mUrl);
+                            mTabControl.recreateWebView(appTab, urlData);
 
                     if (current != appTab) {
                         switchToTab(mTabControl.getTabIndex(appTab));
                         if (needsLoad) {
-                            urlData.loadIn(appTab);
+                            loadUrlDataIn(appTab, urlData);
                         }
                     } else {
                         // If the tab was the current tab, we have to attach
                         // it to the view system again.
                         attachTabToContentView(appTab);
                         if (needsLoad) {
-                            urlData.loadIn(appTab);
+                            loadUrlDataIn(appTab, urlData);
                         }
                     }
                     return;
@@ -604,7 +539,7 @@ public class BrowserActivity extends Activity
                 }
                 // Get rid of the subwindow if it exists
                 dismissSubWindow(current);
-                urlData.loadIn(current);
+                loadUrlDataIn(current, urlData);
             }
         }
     }
@@ -670,8 +605,15 @@ public class BrowserActivity extends Activity
             return false;
         }
 
-        Browser.updateVisitedHistory(mResolver, url, false);
-        Browser.addSearchUrl(mResolver, url);
+        final ContentResolver cr = mResolver;
+        final String newUrl = url;
+        new AsyncTask<Void, Void, Void>() {
+            protected Void doInBackground(Void... unused) {
+                Browser.updateVisitedHistory(cr, newUrl, false);
+                Browser.addSearchUrl(cr, newUrl);
+                return null;
+            }
+        }.execute();
 
         Intent intent = new Intent(Intent.ACTION_WEB_SEARCH);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
@@ -720,11 +662,18 @@ public class BrowserActivity extends Activity
                 url = intent.getStringExtra(SearchManager.QUERY);
                 if (url != null) {
                     mLastEnteredUrl = url;
-                    Browser.updateVisitedHistory(mResolver, url, false);
                     // In general, we shouldn't modify URL from Intent.
                     // But currently, we get the user-typed URL from search box as well.
                     url = fixUrl(url);
                     url = smartUrlFilter(url);
+                    final ContentResolver cr = mResolver;
+                    final String newUrl = url;
+                    new AsyncTask<Void, Void, Void>() {
+                        protected Void doInBackground(Void... unused) {
+                            Browser.updateVisitedHistory(cr, newUrl, false);
+                            return null;
+                        }
+                    }.execute();
                     String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&";
                     if (url.contains(searchSource)) {
                         String source = null;
@@ -753,8 +702,8 @@ public class BrowserActivity extends Activity
         mTitleBar.setInVoiceMode(false);
         mFakeTitleBar.setInVoiceMode(false);
 
-        mTitleBar.setDisplayTitle(mTitle);
-        mFakeTitleBar.setDisplayTitle(mTitle);
+        mTitleBar.setDisplayTitle(mUrl);
+        mFakeTitleBar.setDisplayTitle(mUrl);
     }
     /* package */ static String fixUrl(String inUrl) {
         // FIXME: Converting the url to lower case
@@ -807,13 +756,6 @@ public class BrowserActivity extends Activity
             mWakeLock.release();
         }
 
-        if (mCredsDlg != null) {
-            if (!mHandler.hasMessages(CANCEL_CREDS_REQUEST)) {
-             // In case credential request never comes back
-                mHandler.sendEmptyMessageDelayed(CANCEL_CREDS_REQUEST, 6000);
-            }
-        }
-
         registerReceiver(mNetworkStateIntentReceiver,
                          mNetworkStateChangedFilter);
         WebView.enablePlatformNotifications();
@@ -827,19 +769,6 @@ public class BrowserActivity extends Activity
     private TitleBar mFakeTitleBar;
 
     /**
-     * Holder for the fake title bar.  It will have a foreground shadow, as well
-     * as a white background, so the fake title bar looks like the real one.
-     */
-    private ViewGroup mFakeTitleBarHolder;
-
-    /**
-     * Layout parameters for the fake title bar within mFakeTitleBarHolder
-     */
-    private FrameLayout.LayoutParams mFakeTitleBarParams
-            = new FrameLayout.LayoutParams(
-            ViewGroup.LayoutParams.MATCH_PARENT,
-            ViewGroup.LayoutParams.WRAP_CONTENT);
-    /**
      * Keeps track of whether the options menu is open.  This is important in
      * determining whether to show or hide the title bar overlay.
      */
@@ -893,46 +822,12 @@ public class BrowserActivity extends Activity
         return true;
     }
 
-    /**
-     * Special class used exclusively for the shadow drawn underneath the fake
-     * title bar.  The shadow does not need to be drawn if the WebView
-     * underneath is scrolled to the top, because it will draw directly on top
-     * of the embedded shadow.
-     */
-    private static class Shadow extends View {
-        private WebView mWebView;
-
-        public Shadow(Context context, AttributeSet attrs) {
-            super(context, attrs);
-        }
-
-        public void setWebView(WebView view) {
-            mWebView = view;
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            // In general onDraw is the method to override, but we care about
-            // whether or not the background gets drawn, which happens in draw()
-            if (mWebView == null || mWebView.getScrollY() > getHeight()) {
-                super.draw(canvas);
-            }
-            // Need to invalidate so that if the scroll position changes, we
-            // still draw as appropriate.
-            invalidate();
-        }
-    }
-
     private void showFakeTitleBar() {
-        final View decor = getWindow().peekDecorView();
         if (mFakeTitleBar.getParent() == null && mActiveTabsPage == null
-                && !mActivityInPause && decor != null
-                && decor.getWindowToken() != null) {
-            Rect visRect = new Rect();
-            if (!mBrowserFrameLayout.getGlobalVisibleRect(visRect)) {
-                if (LOGD_ENABLED) {
-                    Log.d(LOGTAG, "showFakeTitleBar visRect failed");
-                }
+                && !mActivityInPause) {
+            WebView mainView = mTabControl.getCurrentWebView();
+            // if there is no current WebView, don't show the faked title bar;
+            if (mainView == null) {
                 return;
             }
 
@@ -945,28 +840,13 @@ public class BrowserActivity extends Activity
                     = new WindowManager.LayoutParams(
                     ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT,
-                    WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL,
+                    WindowManager.LayoutParams.TYPE_APPLICATION,
                     WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                     PixelFormat.TRANSLUCENT);
             params.gravity = Gravity.TOP;
-            WebView mainView = mTabControl.getCurrentWebView();
-            boolean atTop = mainView != null && mainView.getScrollY() == 0;
+            boolean atTop = mainView.getScrollY() == 0;
             params.windowAnimations = atTop ? 0 : R.style.TitleBar;
-            // XXX : Without providing an offset, the fake title bar will be
-            // placed underneath the status bar.  Use the global visible rect
-            // of mBrowserFrameLayout to determine the bottom of the status bar
-            params.y = visRect.top;
-            // Add a holder for the title bar.  It also holds a shadow to show
-            // below the title bar.
-            if (mFakeTitleBarHolder == null) {
-                mFakeTitleBarHolder = (ViewGroup) LayoutInflater.from(this)
-                    .inflate(R.layout.title_bar_bg, null);
-            }
-            Shadow shadow = (Shadow) mFakeTitleBarHolder.findViewById(
-                    R.id.shadow);
-            shadow.setWebView(mainView);
-            mFakeTitleBarHolder.addView(mFakeTitleBar, 0, mFakeTitleBarParams);
-            manager.addView(mFakeTitleBarHolder, params);
+            manager.addView(mFakeTitleBar, params);
         }
     }
 
@@ -986,7 +866,7 @@ public class BrowserActivity extends Activity
     private void hideFakeTitleBar() {
         if (mFakeTitleBar.getParent() == null) return;
         WindowManager.LayoutParams params = (WindowManager.LayoutParams)
-                mFakeTitleBarHolder.getLayoutParams();
+                mFakeTitleBar.getLayoutParams();
         WebView mainView = mTabControl.getCurrentWebView();
         // Although we decided whether or not to animate based on the current
         // scroll position, the scroll position may have changed since the
@@ -996,9 +876,8 @@ public class BrowserActivity extends Activity
                 ? 0 : R.style.TitleBar;
         WindowManager manager
                     = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
-        manager.updateViewLayout(mFakeTitleBarHolder, params);
-        mFakeTitleBarHolder.removeView(mFakeTitleBar);
-        manager.removeView(mFakeTitleBarHolder);
+        manager.updateViewLayout(mFakeTitleBar, params);
+        manager.removeView(mFakeTitleBar);
     }
 
     /**
@@ -1058,12 +937,6 @@ public class BrowserActivity extends Activity
                     .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
         }
 
-        // Clear the credentials toast if it is up
-        if (mCredsDlg != null && mCredsDlg.isShowing()) {
-            mCredsDlg.dismiss();
-        }
-        mCredsDlg = null;
-
         // FIXME: This removes the active tabs page and resets the menu to
         // MAIN_MENU.  A better solution might be to do this work in onNewIntent
         // but then we would need to save it in onSaveInstanceState and restore
@@ -1107,6 +980,10 @@ public class BrowserActivity extends Activity
         WebIconDatabase.getInstance().close();
 
         unregisterReceiver(mPackageInstallationReceiver);
+
+        // Stop watching the default geolocation permissions
+        mSystemAllowGeolocationOrigins.stop();
+        mSystemAllowGeolocationOrigins = null;
     }
 
     @Override
@@ -1154,8 +1031,9 @@ public class BrowserActivity extends Activity
         mTabControl.freeMemory();
     }
 
-    private boolean resumeWebViewTimers() {
+    private void resumeWebViewTimers() {
         Tab tab = mTabControl.getCurrentTab();
+        if (tab == null) return; // monkey can trigger this
         boolean inLoad = tab.inLoad();
         if ((!mActivityInPause && !inLoad) || (mActivityInPause && inLoad)) {
             CookieSyncManager.getInstance().startSync();
@@ -1163,9 +1041,6 @@ public class BrowserActivity extends Activity
             if (w != null) {
                 w.resumeTimers();
             }
-            return true;
-        } else {
-            return false;
         }
     }
 
@@ -1184,75 +1059,24 @@ public class BrowserActivity extends Activity
         }
     }
 
-    // FIXME: Do we want to call this when loading google for the first time?
-    /*
-     * This function is called when we are launching for the first time. We
-     * are waiting for the login credentials before loading Google home
-     * pages. This way the user will be logged in straight away.
-     */
-    private void waitForCredentials() {
-        // Show a toast
-        mCredsDlg = new ProgressDialog(this);
-        mCredsDlg.setIndeterminate(true);
-        mCredsDlg.setMessage(getText(R.string.retrieving_creds_dlg_msg));
-        // If the user cancels the operation, then cancel the Google
-        // Credentials request.
-        mCredsDlg.setCancelMessage(mHandler.obtainMessage(CANCEL_CREDS_REQUEST));
-        mCredsDlg.show();
-
-        // We set a timeout for the retrieval of credentials in onResume()
-        // as that is when we have freed up some CPU time to get
-        // the login credentials.
-    }
-
-    /*
-     * If we have received the credentials or we have timed out and we are
-     * showing the credentials dialog, then it is time to move on.
-     */
-    private void resumeAfterCredentials() {
-        if (mCredsDlg == null) {
-            return;
-        }
-
-        // Clear the toast
-        if (mCredsDlg.isShowing()) {
-            mCredsDlg.dismiss();
-        }
-        mCredsDlg = null;
-
-        // Clear any pending timeout
-        mHandler.removeMessages(CANCEL_CREDS_REQUEST);
-
-        // Load the page
-        WebView w = mTabControl.getCurrentWebView();
-        if (w != null) {
-            w.loadUrl(mSettings.getHomePage());
-        }
-
-        // Update the settings, need to do this last as it can take a moment
-        // to persist the settings. In the mean time we could be loading
-        // content.
-        mSettings.setLoginInitialized(this);
-    }
-
     // Open the icon database and retain all the icons for visited sites.
     private void retainIconsOnStartup() {
         final WebIconDatabase db = WebIconDatabase.getInstance();
         db.open(getDir("icons", 0).getPath());
+        Cursor c = null;
         try {
-            Cursor c = Browser.getAllBookmarks(mResolver);
-            if (!c.moveToFirst()) {
-                c.deactivate();
-                return;
+            c = Browser.getAllBookmarks(mResolver);
+            if (c.moveToFirst()) {
+                int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
+                do {
+                    String url = c.getString(urlIndex);
+                    db.retainIconForPageUrl(url);
+                } while (c.moveToNext());
             }
-            int urlIndex = c.getColumnIndex(Browser.BookmarkColumns.URL);
-            do {
-                String url = c.getString(urlIndex);
-                db.retainIconForPageUrl(url);
-            } while (c.moveToNext());
-            c.deactivate();
         } catch (IllegalStateException e) {
             Log.e(LOGTAG, "retainIconsOnStartup", e);
+        } finally {
+            if (c!= null) c.close();
         }
     }
 
@@ -1523,7 +1347,7 @@ public class BrowserActivity extends Activity
                 Tab current = mTabControl.getCurrentTab();
                 if (current != null) {
                     dismissSubWindow(current);
-                    current.getWebView().loadUrl(mSettings.getHomePage());
+                    loadUrl(current.getWebView(), mSettings.getHomePage());
                 }
                 break;
 
@@ -1541,6 +1365,7 @@ public class BrowserActivity extends Activity
                 }
                 mFindDialog.setWebView(getTopWindow());
                 mFindDialog.show();
+                getTopWindow().setFindIsUp(true);
                 mMenuState = EMPTY_MENU;
                 break;
 
@@ -1695,6 +1520,9 @@ public class BrowserActivity extends Activity
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v,
             ContextMenuInfo menuInfo) {
+        if (v instanceof TitleBar) {
+            return;
+        }
         WebView webview = (WebView) v;
         WebView.HitTestResult result = webview.getHitTestResult();
         if (result == null) {
@@ -1896,7 +1724,7 @@ public class BrowserActivity extends Activity
             mTabControl.setCurrentTab(tab);
             attachTabToContentView(tab);
             if (!urlData.isEmpty()) {
-                urlData.loadIn(tab);
+                loadUrlDataIn(tab, urlData);
             }
             return tab;
         } else {
@@ -1904,7 +1732,7 @@ public class BrowserActivity extends Activity
             dismissSubWindow(currentTab);
             if (!urlData.isEmpty()) {
                 // Load the given url.
-                urlData.loadIn(currentTab);
+                loadUrlDataIn(currentTab, urlData);
             }
             return currentTab;
         }
@@ -1915,7 +1743,7 @@ public class BrowserActivity extends Activity
             Tab t = mTabControl.createNewTab();
             if (t != null) {
                 WebView view = t.getWebView();
-                view.loadUrl(url);
+                loadUrl(view, url);
             }
             return t;
         } else {
@@ -2148,7 +1976,7 @@ public class BrowserActivity extends Activity
         resetTitleIconAndProgress();
     }
 
-    private void goBackOnePageOrQuit() {
+    /* package */ void goBackOnePageOrQuit() {
         Tab current = mTabControl.getCurrentTab();
         if (current == null) {
             /*
@@ -2333,7 +2161,6 @@ public class BrowserActivity extends Activity
 
     // Message Ids
     private static final int FOCUS_NODE_HREF         = 102;
-    private static final int CANCEL_CREDS_REQUEST    = 103;
     private static final int RELEASE_WAKELOCK        = 107;
 
     static final int UPDATE_BOOKMARK_THUMBNAIL       = 108;
@@ -2359,7 +2186,7 @@ public class BrowserActivity extends Activity
                     switch (msg.arg1) {
                         case R.id.open_context_menu_id:
                         case R.id.view_image_context_menu_id:
-                            loadURL(getTopWindow(), url);
+                            loadUrlFromContext(getTopWindow(), url);
                             break;
                         case R.id.open_newtab_context_menu_id:
                             final Tab parent = mTabControl.getCurrentTab();
@@ -2424,17 +2251,13 @@ public class BrowserActivity extends Activity
                 }
 
                 case LOAD_URL:
-                    loadURL(getTopWindow(), (String) msg.obj);
+                    loadUrlFromContext(getTopWindow(), (String) msg.obj);
                     break;
 
                 case STOP_LOAD:
                     stopLoading();
                     break;
 
-                case CANCEL_CREDS_REQUEST:
-                    resumeAfterCredentials();
-                    break;
-
                 case RELEASE_WAKELOCK:
                     if (mWakeLock.isHeld()) {
                         mWakeLock.release();
@@ -2460,7 +2283,7 @@ public class BrowserActivity extends Activity
      * an {@link Intent} to launch the Activity chooser.
      * @param c Context used to launch a new Activity.
      * @param title Title of the page.  Stored in the Intent with
-     *          {@link Browser#EXTRA_SHARE_TITLE}
+     *          {@link Intent#EXTRA_SUBJECT}
      * @param url URL of the page.  Stored in the Intent with
      *          {@link Intent#EXTRA_TEXT}
      * @param favicon Bitmap of the favicon for the page.  Stored in the Intent
@@ -2473,7 +2296,7 @@ public class BrowserActivity extends Activity
         Intent send = new Intent(Intent.ACTION_SEND);
         send.setType("text/plain");
         send.putExtra(Intent.EXTRA_TEXT, url);
-        send.putExtra(Browser.EXTRA_SHARE_TITLE, title);
+        send.putExtra(Intent.EXTRA_SUBJECT, title);
         send.putExtra(Browser.EXTRA_SHARE_FAVICON, favicon);
         send.putExtra(Browser.EXTRA_SHARE_SCREENSHOT, screenshot);
         try {
@@ -2560,7 +2383,7 @@ public class BrowserActivity extends Activity
             return null;
         }
         Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(this),
-                getDesiredThumbnailHeight(this), Bitmap.Config.ARGB_4444);
+                getDesiredThumbnailHeight(this), Bitmap.Config.RGB_565);
         Canvas canvas = new Canvas(bm);
         // May need to tweak these values to determine what is the
         // best scale factor
@@ -2603,6 +2426,10 @@ public class BrowserActivity extends Activity
     /* package */ final static String SCHEME_WTAI_SD = "wtai://wp/sd;";
     /* package */ final static String SCHEME_WTAI_AP = "wtai://wp/ap;";
 
+    // Keep this initial progress in sync with initialProgressValue (* 100)
+    // in ProgressTracker.cpp
+    private final static int INITIAL_PROGRESS = 10;
+
     void onPageStarted(WebView view, String url, Bitmap favicon) {
         // when BrowserActivity just starts, onPageStarted may be called before
         // onResume as it is triggered from onCreate. Call resumeWebViewTimers
@@ -2613,11 +2440,9 @@ public class BrowserActivity extends Activity
         resetLockIcon(url);
         setUrlTitle(url, null);
         setFavicon(favicon);
-        // Keep this initial progress in sync with initialProgressValue (* 100)
-        // in ProgressTracker.cpp
         // Show some progress so that the user knows the page is beginning to
         // load
-        onProgressChanged(view, 10);
+        onProgressChanged(view, INITIAL_PROGRESS);
         mDidStopLoad = false;
         if (!mIsNetworkUp) createAndShowNetworkDialog();
 
@@ -2800,7 +2625,6 @@ public class BrowserActivity extends Activity
     // -------------------------------------------------------------------------
 
     void onProgressChanged(WebView view, int newProgress) {
-        mTitleBar.setProgress(newProgress);
         mFakeTitleBar.setProgress(newProgress);
 
         if (newProgress == 100) {
@@ -2819,12 +2643,19 @@ public class BrowserActivity extends Activity
                     hideFakeTitleBar();
                 }
             }
-        } else if (!mInLoad) {
-            // onPageFinished may have already been called but a subframe is
-            // still loading and updating the progress. Reset mInLoad and update
-            // the menu items.
-            mInLoad = true;
-            updateInLoadMenuItems();
+        } else {
+            if (!mInLoad) {
+                // onPageFinished may have already been called but a subframe is
+                // still loading and updating the progress. Reset mInLoad and
+                // update the menu items.
+                mInLoad = true;
+                updateInLoadMenuItems();
+            }
+            // When the page first begins to load, the Activity may still be
+            // paused, in which case showFakeTitleBar will do nothing.  Call
+            // again as the page continues to load so that it will be shown.
+            // (Calling it will the fake title bar is already showing will also
+            // do nothing.
             if (!mOptionsMenuOpen || mIconView) {
                 // This page has begun to load, so show the title bar
                 showFakeTitleBar();
@@ -2960,6 +2791,36 @@ public class BrowserActivity extends Activity
         onDownloadStartNoStream(url, userAgent, contentDisposition, mimetype, contentLength);
     }
 
+    // This is to work around the fact that java.net.URI throws Exceptions
+    // instead of just encoding URL's properly
+    // Helper method for onDownloadStartNoStream
+    private static String encodePath(String path) {
+        char[] chars = path.toCharArray();
+
+        boolean needed = false;
+        for (char c : chars) {
+            if (c == '[' || c == ']') {
+                needed = true;
+                break;
+            }
+        }
+        if (needed == false) {
+            return path;
+        }
+
+        StringBuilder sb = new StringBuilder("");
+        for (char c : chars) {
+            if (c == '[' || c == ']') {
+                sb.append('%');
+                sb.append(Integer.toHexString(c));
+            } else {
+                sb.append(c);
+            }
+        }
+
+        return sb.toString();
+    }
+
     /**
      * Notify the host application a download should be done, even if there
      * is a streaming viewer available for thise type.
@@ -2999,35 +2860,16 @@ public class BrowserActivity extends Activity
             return;
         }
 
-        // java.net.URI is a lot stricter than KURL so we have to undo
-        // KURL's percent-encoding and redo the encoding using java.net.URI.
-        URI uri = null;
+        // java.net.URI is a lot stricter than KURL so we have to encode some
+        // extra characters. Fix for b 2538060 and b 1634719
+        WebAddress webAddress;
         try {
-            // Undo the percent-encoding that KURL may have done.
-            String newUrl = new String(URLUtil.decode(url.getBytes()));
-            // Parse the url into pieces
-            WebAddress w = new WebAddress(newUrl);
-            String frag = null;
-            String query = null;
-            String path = w.mPath;
-            // Break the path into path, query, and fragment
-            if (path.length() > 0) {
-                // Strip the fragment
-                int idx = path.lastIndexOf('#');
-                if (idx != -1) {
-                    frag = path.substring(idx + 1);
-                    path = path.substring(0, idx);
-                }
-                idx = path.lastIndexOf('?');
-                if (idx != -1) {
-                    query = path.substring(idx + 1);
-                    path = path.substring(0, idx);
-                }
-            }
-            uri = new URI(w.mScheme, w.mAuthInfo, w.mHost, w.mPort, path,
-                    query, frag);
+            webAddress = new WebAddress(url);
+            webAddress.mPath = encodePath(webAddress.mPath);
         } catch (Exception e) {
-            Log.e(LOGTAG, "Could not parse url for download: " + url, e);
+            // This only happens for very bad urls, we want to chatch the
+            // exception here
+            Log.e(LOGTAG, "Exception trying to parse url:" + url);
             return;
         }
 
@@ -3036,7 +2878,7 @@ public class BrowserActivity extends Activity
         String cookies = CookieManager.getInstance().getCookie(url);
 
         ContentValues values = new ContentValues();
-        values.put(Downloads.Impl.COLUMN_URI, uri.toString());
+        values.put(Downloads.Impl.COLUMN_URI, webAddress.toString());
         values.put(Downloads.Impl.COLUMN_COOKIE_DATA, cookies);
         values.put(Downloads.Impl.COLUMN_USER_AGENT, userAgent);
         values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE,
@@ -3047,7 +2889,7 @@ public class BrowserActivity extends Activity
                 Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
         values.put(Downloads.Impl.COLUMN_MIME_TYPE, mimetype);
         values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, filename);
-        values.put(Downloads.Impl.COLUMN_DESCRIPTION, uri.getHost());
+        values.put(Downloads.Impl.COLUMN_DESCRIPTION, webAddress.mHost);
         if (contentLength > 0) {
             values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, contentLength);
         }
@@ -3059,7 +2901,8 @@ public class BrowserActivity extends Activity
             final Uri contentUri =
                     getContentResolver().insert(Downloads.Impl.CONTENT_URI, values);
         }
-
+        Toast.makeText(this, R.string.download_pending, Toast.LENGTH_SHORT)
+                .show();
     }
 
     // -------------------------------------------------------------------------
@@ -3402,14 +3245,14 @@ public class BrowserActivity extends Activity
         }
 
         // issued on:
-        String issuedOn = reformatCertificateDate(
-            certificate.getValidNotBefore());
+        String issuedOn = formatCertificateDate(
+            certificate.getValidNotBeforeDate());
         ((TextView) certificateView.findViewById(R.id.issued_on))
             .setText(issuedOn);
 
         // expires on:
-        String expiresOn = reformatCertificateDate(
-            certificate.getValidNotAfter());
+        String expiresOn = formatCertificateDate(
+            certificate.getValidNotAfterDate());
         ((TextView) certificateView.findViewById(R.id.expires_on))
             .setText(expiresOn);
 
@@ -3417,31 +3260,19 @@ public class BrowserActivity extends Activity
     }
 
     /**
-     * Re-formats the certificate date (Date.toString()) string to
-     * a properly localized date string.
+     * Formats the certificate date to a properly localized date string.
      * @return Properly localized version of the certificate date string and
-     * the original certificate date string if fails to localize.
-     * If the original string is null, returns an empty string "".
+     * the "" if it fails to localize.
      */
-    private String reformatCertificateDate(String certificateDate) {
-      String reformattedDate = null;
-
-      if (certificateDate != null) {
-          Date date = null;
-          try {
-              date = java.text.DateFormat.getInstance().parse(certificateDate);
-          } catch (ParseException e) {
-              date = null;
-          }
-
-          if (date != null) {
-              reformattedDate =
-                  DateFormat.getDateFormat(this).format(date);
-          }
+    private String formatCertificateDate(Date certificateDate) {
+      if (certificateDate == null) {
+          return "";
       }
-
-      return reformattedDate != null ? reformattedDate :
-          (certificateDate != null ? certificateDate : "");
+      String formattedDate = DateFormat.getDateFormat(this).format(certificateDate);
+      if (formattedDate == null) {
+          return "";
+      }
+      return formattedDate;
     }
 
     /**
@@ -3537,7 +3368,7 @@ public class BrowserActivity extends Activity
     public void setHttpAuthUsernamePassword(String host, String realm,
                                             String username,
                                             String password) {
-        WebView w = mTabControl.getCurrentWebView();
+        WebView w = getTopWindow();
         if (w != null) {
             w.setHttpAuthUsernamePassword(host, realm, username, password);
         }
@@ -3601,7 +3432,7 @@ public class BrowserActivity extends Activity
                                 mTabControl.getCurrentTab();
                         dismissSubWindow(currentTab);
                         if (data != null && data.length() != 0) {
-                            getTopWindow().loadUrl(data);
+                            loadUrl(getTopWindow(), data);
                         }
                     }
                 }
@@ -3685,16 +3516,56 @@ public class BrowserActivity extends Activity
     }
 
     // Called when loading from context menu or LOAD_URL message
-    private void loadURL(WebView view, String url) {
+    private void loadUrlFromContext(WebView view, String url) {
         // In case the user enters nothing.
         if (url != null && url.length() != 0 && view != null) {
             url = smartUrlFilter(url);
             if (!view.getWebViewClient().shouldOverrideUrlLoading(view, url)) {
-                view.loadUrl(url);
+                loadUrl(view, url);
             }
         }
     }
 
+    /**
+     * Load the URL into the given WebView and update the title bar
+     * to reflect the new load.  Call this instead of WebView.loadUrl
+     * directly.
+     * @param view The WebView used to load url.
+     * @param url The URL to load.
+     */
+    private void loadUrl(WebView view, String url) {
+        updateTitleBarForNewLoad(view, url);
+        view.loadUrl(url);
+    }
+
+    /**
+     * Load UrlData into a Tab and update the title bar to reflect the new
+     * load.  Call this instead of UrlData.loadIn directly.
+     * @param t The Tab used to load.
+     * @param data The UrlData being loaded.
+     */
+    private void loadUrlDataIn(Tab t, UrlData data) {
+        updateTitleBarForNewLoad(t.getWebView(), data.mUrl);
+        data.loadIn(t);
+    }
+
+    /**
+     * If the WebView is the top window, update the title bar to reflect
+     * loading the new URL.  i.e. set its text, clear the favicon (which
+     * will be set once the page begins loading), and set the progress to
+     * INITIAL_PROGRESS to show that the page has begun to load. Called
+     * by loadUrl and loadUrlDataIn.
+     * @param view The WebView that is starting a load.
+     * @param url The URL that is being loaded.
+     */
+    private void updateTitleBarForNewLoad(WebView view, String url) {
+        if (view == getTopWindow()) {
+            setUrlTitle(url, null);
+            setFavicon(null);
+            onProgressChanged(view, INITIAL_PROGRESS);
+        }
+    }
+
     private String smartUrlFilter(Uri inUri) {
         if (inUri != null) {
             return smartUrlFilter(inUri.toString());
@@ -3890,7 +3761,7 @@ public class BrowserActivity extends Activity
     private boolean mIsNetworkUp;
     private boolean mDidStopLoad;
 
-    private boolean mActivityInPause = true;
+    /* package */ boolean mActivityInPause = true;
 
     private boolean mMenuIsDown;
 
@@ -3923,9 +3794,6 @@ public class BrowserActivity extends Activity
     /* hold a ref so we can auto-cancel if necessary */
     private AlertDialog mAlertDialog;
 
-    // Wait for credentials before loading google.com
-    private ProgressDialog mCredsDlg;
-
     // The up-to-date URL and title (these can be different from those stored
     // in WebView, since it takes some time for the information in WebView to
     // get updated)
@@ -4016,6 +3884,8 @@ public class BrowserActivity extends Activity
 
     private BroadcastReceiver mPackageInstallationReceiver;
 
+    private SystemAllowGeolocationOrigins mSystemAllowGeolocationOrigins;
+
     // activity requestCode
     final static int COMBO_PAGE                 = 1;
     final static int DOWNLOAD_PAGE              = 2;
@@ -4039,7 +3909,7 @@ public class BrowserActivity extends Activity
      * A UrlData class to abstract how the content will be set to WebView.
      * This base class uses loadUrl to show the content.
      */
-    private static class UrlData {
+    /* package */ static class UrlData {
         final String mUrl;
         final Map<String, String> mHeaders;
         final Intent mVoiceIntent;
@@ -4065,6 +3935,10 @@ public class BrowserActivity extends Activity
             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);