Code drop from //branches/cupcake/...@124589
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index fc4acfc..fe27f8d 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -62,6 +62,7 @@
import android.net.http.RequestQueue;
import android.net.http.SslCertificate;
import android.net.http.SslError;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Debug;
@@ -75,13 +76,16 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.pim.DateFormat;
+import android.preference.PreferenceManager;
import android.provider.Browser;
import android.provider.Checkin;
import android.provider.Contacts.Intents.Insert;
import android.provider.Contacts;
import android.provider.Downloads;
+import android.provider.MediaStore;
import android.text.IClipboard;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
import android.text.util.Regex;
import android.util.Config;
import android.util.Log;
@@ -94,7 +98,6 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
@@ -142,6 +145,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
+import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Vector;
@@ -179,6 +183,8 @@
private void setupHomePage() {
final Runnable getAccount = new Runnable() {
public void run() {
+ // Lower priority
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
// get the default home page
String homepage = mSettings.getHomePage();
@@ -242,7 +248,9 @@
mGls = IGoogleLoginService.Stub.asInterface(service);
if (done[0] == false) {
done[0] = true;
- new Thread(getAccount).start();
+ Thread account = new Thread(getAccount);
+ account.setName("GLSAccount");
+ account.start();
}
}
public void onServiceDisconnected(ComponentName className) {
@@ -513,6 +521,8 @@
* as there is a limit of 1Mb (see Asset.h)
*/
public void run() {
+ // Lower the priority
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
try {
if (pluginsPath == null) {
Log.e(TAG, "No plugins path found!");
@@ -598,11 +608,24 @@
if (copyPluginsFromAssets.newSystemImage()) {
if (copyPluginsFromAssets.checkIsDifferentVersions()) {
copyPluginsFromAssets.cleanPluginsDirectory();
- new Thread(copyPluginsFromAssets).start();
+ Thread copyplugins = new Thread(copyPluginsFromAssets);
+ copyplugins.setName("CopyPlugins");
+ copyplugins.start();
}
}
}
+ private class ClearThumbnails extends AsyncTask<File, Void, Void> {
+ @Override
+ public Void doInBackground(File... files) {
+ if (files != null) {
+ for (File f : files) {
+ f.delete();
+ }
+ }
+ return null;
+ }
+ }
@Override public void onCreate(Bundle icicle) {
if (Config.LOGV) {
@@ -621,6 +644,9 @@
mResolver = getContentResolver();
+ setBaseSearchUrl(PreferenceManager.getDefaultSharedPreferences(this)
+ .getString("search_url", ""));
+
//
// start MASF proxy service
//
@@ -658,10 +684,19 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
if (!mTabControl.restoreState(icicle)) {
+ // clear up the thumbnail directory if we can't restore the state as
+ // none of the files in the directory are referenced any more.
+ new ClearThumbnails().execute(
+ mTabControl.getThumbnailDir().listFiles());
final Intent intent = getIntent();
final Bundle extra = intent.getExtras();
// Create an initial tab.
- final TabControl.Tab t = mTabControl.createNewTab();
+ // If the intent is ACTION_VIEW and data is not null, the Browser is
+ // invoked to view the content by another application. In this case,
+ // the tab will be close when exit.
+ final TabControl.Tab t = mTabControl.createNewTab(
+ Intent.ACTION_VIEW.equals(intent.getAction()) &&
+ intent.getData() != null);
mTabControl.setCurrentTab(t);
// This is one of the only places we call attachTabToContentView
// without animating from the tab picker.
@@ -722,6 +757,15 @@
@Override
protected void onNewIntent(Intent intent) {
+ // When a tab is closed on exit, the current tab index is set to -1.
+ // Reset before proceed as Browser requires the current tab to be set.
+ if (mTabControl.getCurrentIndex() == -1) {
+ TabControl.Tab current = mTabControl.getTab(0);
+ mTabControl.setCurrentTab(current);
+ attachTabToContentView(current);
+ mWebView = current.getWebView();
+ resetTitleAndIcon(mWebView);
+ }
if (mWebView == null) {
return;
}
@@ -734,6 +778,7 @@
}
if (Intent.ACTION_VIEW.equals(action)
|| Intent.ACTION_SEARCH.equals(action)
+ || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
|| Intent.ACTION_WEB_SEARCH.equals(action)) {
String url = getUrlFromIntent(intent);
if (url == null || url.length() == 0) {
@@ -742,9 +787,10 @@
if (Intent.ACTION_VIEW.equals(action) &&
(flags & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
// if FLAG_ACTIVITY_BROUGHT_TO_FRONT flag is on, the url will be
- // opened in a new tab unless we have reached MAX_TABS and the
- // url will be opened in the current tab
- openTabAndShow(url, null);
+ // opened in a new tab unless we have reached MAX_TABS. Then the
+ // url will be opened in the current tab. If a new tab is
+ // created, it will have "true" for exit on close.
+ openTabAndShow(url, null, true);
} else {
if ("about:debug".equals(url)) {
mSettings.toggleDebugSettings();
@@ -779,24 +825,39 @@
}
}
} else if (Intent.ACTION_SEARCH.equals(action)
+ || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action)
|| Intent.ACTION_WEB_SEARCH.equals(action)) {
url = intent.getStringExtra(SearchManager.QUERY);
- mLastEnteredUrl = url;
- // Don't add Urls, just search terms.
- // Urls will get added when the page is loaded.
- if (!Regex.WEB_URL_PATTERN.matcher(url).matches()) {
- Browser.updateVisitedHistory(mResolver, url, false);
+ if (url != null) {
+ mLastEnteredUrl = url;
+ // Don't add Urls, just search terms.
+ // Urls will get added when the page is loaded.
+ if (!Regex.WEB_URL_PATTERN.matcher(url).matches()) {
+ 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);
+ String searchSource = "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&";
+ if (url.contains(searchSource)) {
+ String source = null;
+ final Bundle appData = intent.getBundleExtra(SearchManager.APP_DATA);
+ if (appData != null) {
+ source = appData.getString(SearchManager.SOURCE);
+ }
+ if (TextUtils.isEmpty(source)) {
+ source = GOOGLE_SEARCH_SOURCE_UNKNOWN;
+ }
+ url = url.replace(searchSource, "&source=android-"+source+"&");
+ }
}
- // 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);
}
}
return url;
}
- private String fixUrl(String inUrl) {
+ /* package */ static String fixUrl(String inUrl) {
if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
return inUrl;
if (inUrl.startsWith("http:") ||
@@ -970,7 +1031,7 @@
}
mActivityInPause = true;
- if (!pauseWebView()) {
+ if (mTabControl.getCurrentIndex() >= 0 && !pauseWebView()) {
mWakeLock.acquire();
mHandler.sendMessageDelayed(mHandler
.obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
@@ -1057,6 +1118,9 @@
showHttpAuthentication(mHttpAuthHandler, null, null, title,
name, password, focusId);
}
+ if (mFindDialog != null && mFindDialog.isShowing()) {
+ mFindDialog.onConfigurationChanged(newConfig);
+ }
}
@Override public void onLowMemory() {
@@ -1192,6 +1256,11 @@
// options selector, so set mCanChord to true so we can access them.
mCanChord = true;
int id = item.getItemId();
+ final WebView webView = getTopWindow();
+ final HashMap hrefMap = new HashMap();
+ hrefMap.put("webview", webView);
+ final Message msg = mHandler.obtainMessage(
+ FOCUS_NODE_HREF, id, 0, hrefMap);
switch (id) {
// -- Browser context menu
case R.id.open_context_menu_id:
@@ -1200,21 +1269,9 @@
case R.id.save_link_context_menu_id:
case R.id.share_link_context_menu_id:
case R.id.copy_link_context_menu_id:
- Message msg = mHandler.obtainMessage(
- FOCUS_NODE_HREF, id, 0);
- WebView webview = getTopWindow();
- msg.obj = webview;
- webview.requestFocusNodeHref(msg);
+ webView.requestFocusNodeHref(msg);
break;
- case R.id.download_context_menu_id:
- case R.id.view_image_context_menu_id:
- Message m = mHandler.obtainMessage(
- FOCUS_NODE_HREF, id, 0);
- WebView w = getTopWindow();
- m.obj = w;
- w.requestImageRef(m);
- break;
default:
// For other context menus
return onOptionsItemSelected(item);
@@ -1222,18 +1279,34 @@
mCanChord = false;
return true;
}
-
+
+ private Bundle createGoogleSearchSourceBundle(String source) {
+ Bundle bundle = new Bundle();
+ bundle.putString(SearchManager.SOURCE, source);
+ return bundle;
+ }
+
/**
* Overriding this forces the search key to launch global search. The difference
* is the final "true" which requests global search.
*/
@Override
public boolean onSearchRequested() {
- startSearch(null, false, null, true);
+ startSearch(null, false,
+ createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHKEY), true);
return true;
}
@Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery,
+ Bundle appSearchData, boolean globalSearch) {
+ if (appSearchData == null) {
+ appSearchData = createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_TYPE);
+ }
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ }
+
+ @Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!mCanChord) {
// The user has already fired a shortcut with this hold down of the
@@ -1244,23 +1317,27 @@
// -- Main menu
case R.id.goto_menu_id: {
String url = getTopWindow().getUrl();
- // TODO: Activities are requested to call onSearchRequested, and to override
- // that function in order to insert custom fields (e.g. the search query).
- startSearch(mSettings.getHomePage().equals(url) ? null : url, true, null, false);
+ startSearch(mSettings.getHomePage().equals(url) ? null : url, true,
+ createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_GOTO), false);
}
break;
-
+
case R.id.search_menu_id:
// launch using "global" search, which will bring up the Google search box
- onSearchRequested();
+ startSearch(null, false,
+ createGoogleSearchSourceBundle(GOOGLE_SEARCH_SOURCE_SEARCHMENU), true);
break;
-
+
case R.id.bookmarks_menu_id:
bookmarksPicker();
break;
case R.id.windows_menu_id:
- tabPicker(true, mTabControl.getCurrentIndex(), false);
+ if (mTabControl.getTabCount() == 1) {
+ openTabAndShow(mSettings.getHomePage(), null, false);
+ } else {
+ tabPicker(true, mTabControl.getCurrentIndex(), false);
+ }
break;
case R.id.stop_reload_menu_id:
@@ -1299,7 +1376,7 @@
indexToShow--;
}
}
- removeTabAndShow(currentIndex, indexToShow);
+ switchTabs(currentIndex, indexToShow, true);
break;
case R.id.homepage_menu_id:
@@ -1313,39 +1390,21 @@
startActivityForResult(intent, PREFERENCES_PAGE);
break;
-/*
- Disable Find for version 1.0
case R.id.find_menu_id:
if (null == mFindDialog) {
mFindDialog = new FindDialog(this);
- FrameLayout.LayoutParams lp =
- new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.FILL_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- Gravity.BOTTOM);
- mFindDialog.setLayoutParams(lp);
}
mFindDialog.setWebView(getTopWindow());
- mContentView.addView(mFindDialog);
mFindDialog.show();
- Animation anim =AnimationUtils.loadAnimation(this,
- R.anim.find_dialog_enter);
- mFindDialog.startAnimation(anim);
mMenuState = EMPTY_MENU;
break;
-*/
case R.id.page_info_menu_id:
- showPageInfo(mWebView, false);
+ showPageInfo(mTabControl.getCurrentTab(), false);
break;
- case R.id.classic_history_menu_id: {
- Intent i = new Intent(this, BrowserHistoryPage.class);
- i.putExtra("maxTabsOpen",
- mTabControl.getTabCount() >=
- TabControl.MAX_TABS);
- startActivityForResult(i, CLASSIC_HISTORY_PAGE);
- }
+ case R.id.classic_history_menu_id:
+ loadHistory();
break;
case R.id.bookmark_page_menu_id:
@@ -1448,15 +1507,33 @@
case R.id.properties_tab_menu_id:
if (mTabListener != null && mTabOverview != null) {
int pos = mTabOverview.getContextMenuPosition(item);
- TabControl.Tab t = mTabControl.getTab(pos);
- // Use the tab's data for the page info dialog.
- if (t.getWebView() != null) {
- showPageInfo(t.getWebView(), false);
- }
- // FIXME: what should we display if the WebView is null?
+ showPageInfo(mTabControl.getTab(pos), false);
}
break;
+ case R.id.window_one_menu_id:
+ case R.id.window_two_menu_id:
+ case R.id.window_three_menu_id:
+ case R.id.window_four_menu_id:
+ case R.id.window_five_menu_id:
+ case R.id.window_six_menu_id:
+ case R.id.window_seven_menu_id:
+ case R.id.window_eight_menu_id:
+ {
+ int menuid = item.getItemId();
+ for (int id = 0; id < WINDOW_SHORTCUT_ID_ARRAY.length; id++) {
+ if (WINDOW_SHORTCUT_ID_ARRAY[id] == menuid) {
+ TabControl.Tab desiredTab = mTabControl.getTab(id);
+ if (desiredTab != null &&
+ desiredTab != mTabControl.getCurrentTab()) {
+ switchTabs(mTabControl.getCurrentIndex(), id, false);
+ }
+ break;
+ }
+ }
+ }
+ break;
+
default:
if (!super.onOptionsItemSelected(item)) {
return false;
@@ -1468,29 +1545,9 @@
}
public void closeFind() {
- Animation anim = AnimationUtils.loadAnimation(this,
- R.anim.find_dialog_exit);
- mFindDialog.startAnimation(anim);
- mContentView.removeView(mFindDialog);
- getTopWindow().requestFocus();
mMenuState = R.id.MAIN_MENU;
}
- @Override
- public boolean dispatchTouchEvent(MotionEvent event) {
- if (super.dispatchTouchEvent(event)) {
- return true;
- } else {
- // We do not use the Dialog class because it places dialogs in the
- // middle of the screen. It would take care of dismissing find if
- // were using it, but we are doing it manually since we are not.
- if (mFindDialog != null && mFindDialog.hasFocus()) {
- mFindDialog.dismiss();
- }
- return false;
- }
- }
-
@Override public boolean onPrepareOptionsMenu(Menu menu)
{
// This happens when the user begins to hold down the menu key, so
@@ -1533,14 +1590,11 @@
final MenuItem back = menu.findItem(R.id.back_menu_id);
back.setVisible(canGoBack);
back.setEnabled(canGoBack);
- final MenuItem close = menu.findItem(R.id.close_menu_id);
- close.setVisible(!canGoBack);
- close.setEnabled(!canGoBack);
final MenuItem flip =
menu.findItem(R.id.flip_orientation_menu_id);
boolean keyboardClosed =
- getResources().getConfiguration().keyboardHidden ==
- Configuration.KEYBOARDHIDDEN_YES;
+ getResources().getConfiguration().hardKeyboardHidden ==
+ Configuration.HARDKEYBOARDHIDDEN_YES;
flip.setEnabled(keyboardClosed);
boolean isHome = mSettings.getHomePage().equals(w.getUrl());
@@ -1562,6 +1616,19 @@
PackageManager.MATCH_DEFAULT_ONLY);
menu.findItem(R.id.share_page_menu_id).setVisible(
list.size() > 0);
+
+ // Hide the menu+<window number> items
+ // Can't set visibility in menu xml file b/c when a
+ // group is set visible, all items are set visible.
+ for (int i = 0; i < WINDOW_SHORTCUT_ID_ARRAY.length; i++) {
+ menu.findItem(WINDOW_SHORTCUT_ID_ARRAY[i]).setVisible(false);
+ }
+
+ // If there is only 1 window, the text will be "New window"
+ final MenuItem windows = menu.findItem(R.id.windows_menu_id);
+ windows.setTitleCondensed(mTabControl.getTabCount() > 1 ?
+ getString(R.string.view_tabs_condensed) :
+ getString(R.string.tab_picker_new_tab));
boolean isNavDump = mSettings.isNavDump();
final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id);
@@ -1608,26 +1675,22 @@
menu.setGroupVisible(R.id.GEO_MENU,
type == WebView.HitTestResult.GEO_TYPE);
menu.setGroupVisible(R.id.IMAGE_MENU,
- type == WebView.HitTestResult.IMAGE_TYPE ||
- type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE
+ type == WebView.HitTestResult.IMAGE_TYPE
|| type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
menu.setGroupVisible(R.id.ANCHOR_MENU,
- type == WebView.HitTestResult.ANCHOR_TYPE ||
- type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE
- || type == WebView.HitTestResult.SRC_ANCHOR_TYPE
+ type == WebView.HitTestResult.SRC_ANCHOR_TYPE
|| type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
// Setup custom handling depending on the type
switch (type) {
case WebView.HitTestResult.PHONE_TYPE:
- menu.setHeaderTitle(extra);
+ menu.setHeaderTitle(Uri.decode(extra));
menu.findItem(R.id.dial_context_menu_id).setIntent(
new Intent(Intent.ACTION_VIEW, Uri
.parse(WebView.SCHEME_TEL + extra)));
- Intent addIntent = new Intent(Intent.ACTION_INSERT,
- Contacts.People.CONTENT_URI);
- addIntent.putExtra(Insert.FULL_MODE, true);
- addIntent.putExtra(Insert.PHONE, extra);
+ Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
+ addIntent.putExtra(Insert.PHONE, Uri.decode(extra));
+ addIntent.setType(Contacts.People.CONTENT_ITEM_TYPE);
menu.findItem(R.id.add_contact_context_menu_id).setIntent(
addIntent);
menu.findItem(R.id.copy_phone_context_menu_id).setOnMenuItemClickListener(
@@ -1653,35 +1716,16 @@
new Copy(extra));
break;
- case WebView.HitTestResult.ANCHOR_TYPE:
- case WebView.HitTestResult.IMAGE_ANCHOR_TYPE:
case WebView.HitTestResult.SRC_ANCHOR_TYPE:
case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
- mTitleView = (TextView) LayoutInflater.from(this)
+ TextView titleView = (TextView) LayoutInflater.from(this)
.inflate(android.R.layout.browser_link_context_header,
null);
- menu.setHeaderView(mTitleView);
+ titleView.setText(extra);
+ menu.setHeaderView(titleView);
// decide whether to show the open link in new tab option
menu.findItem(R.id.open_newtab_context_menu_id).setVisible(
mTabControl.getTabCount() < TabControl.MAX_TABS);
- if (type == WebView.HitTestResult.ANCHOR_TYPE
- || type == WebView.HitTestResult.IMAGE_ANCHOR_TYPE){
- menu.findItem(R.id.bookmark_context_menu_id).setVisible(
- false);
- menu.findItem(R.id.save_link_context_menu_id).setVisible(
- false);
- menu.findItem(R.id.copy_link_context_menu_id).setVisible(
- false);
- menu.findItem(R.id.share_link_context_menu_id).setVisible(
- false);
- mTitleView.setText(R.string.contextmenu_javascript);
- break;
- }
- Message headerMessage = mHandler.obtainMessage(FOCUS_NODE_HREF,
- HEADER_FLAG, 0);
- headerMessage.obj = webview;
- webview.requestFocusNodeHref(headerMessage);
- // decide whether to show the share link option
PackageManager pm = getPackageManager();
Intent send = new Intent(Intent.ACTION_SEND);
send.setType("text/plain");
@@ -1689,12 +1733,14 @@
PackageManager.MATCH_DEFAULT_ONLY);
menu.findItem(R.id.share_link_context_menu_id).setVisible(
list.size() > 0);
- if (type == WebView.HitTestResult.ANCHOR_TYPE) {
- break;
- }
- //fall through
+ break;
case WebView.HitTestResult.IMAGE_TYPE:
+ menu.setHeaderTitle(extra);
+ menu.findItem(R.id.view_image_context_menu_id).setIntent(
+ new Intent(Intent.ACTION_VIEW, Uri.parse(extra)));
+ menu.findItem(R.id.download_context_menu_id).
+ setOnMenuItemClickListener(new Download(extra));
break;
default:
@@ -1793,10 +1839,10 @@
// Increment the count to indicate that we are in an animation.
mAnimationCount++;
// Remove the listener so we don't get any more tab changes.
- if (mTabOverview != null) {
- mTabOverview.setListener(null);
- }
+ mTabOverview.setListener(null);
mTabListener = null;
+ // Make the menu empty until the animation completes.
+ mMenuState = EMPTY_MENU;
}
@@ -1828,7 +1874,8 @@
// the given Message. If the tab overview is already showing (i.e. this
// method is called from TabListener.onClick(), the method will animate
// away from the tab overview.
- private void openTabAndShow(String url, final Message msg) {
+ private void openTabAndShow(String url, final Message msg,
+ boolean closeOnExit) {
final boolean newTab = mTabControl.getTabCount() != TabControl.MAX_TABS;
final TabControl.Tab currentTab = mTabControl.getCurrentTab();
if (newTab) {
@@ -1856,7 +1903,7 @@
}
// Animate from the Tab overview after any animations have
// finished.
- sendAnimateFromOverview(mTabControl.createNewTab(),
+ sendAnimateFromOverview(mTabControl.createNewTab(closeOnExit),
true, url, delay, msg);
}
} else if (url != null) {
@@ -1900,10 +1947,6 @@
// be displayed to the user.
private void animateToTabOverview(final int newIndex, final boolean remove,
final AnimatingView view) {
- if (mTabOverview == null) {
- return;
- }
-
// Find the view in the ImageGrid allowing for the "New Tab" cell.
int position = mTabControl.getTabIndex(view.mTab);
if (!((ImageAdapter) mTabOverview.getAdapter()).maxedOut()) {
@@ -1920,12 +1963,10 @@
final Animation.AnimationListener l =
new Animation.AnimationListener() {
public void onAnimationStart(Animation a) {
- if (mTabOverview != null) {
- mTabOverview.requestFocus();
- // Clear the listener so we don't trigger a tab
- // selection.
- mTabOverview.setListener(null);
- }
+ mTabOverview.requestFocus();
+ // Clear the listener so we don't trigger a tab
+ // selection.
+ mTabOverview.setListener(null);
}
public void onAnimationRepeat(Animation a) {}
public void onAnimationEnd(Animation a) {
@@ -1940,17 +1981,15 @@
public void run() {
// Remove the AnimatingView.
mContentView.removeView(view);
- if (mTabOverview != null) {
- // Make newIndex visible.
- mTabOverview.setCurrentIndex(newIndex);
- // Restore the listener.
- mTabOverview.setListener(mTabListener);
- // Change the menu to TAB_MENU if the
- // ImageGrid is interactive.
- if (mTabOverview.isLive()) {
- mMenuState = R.id.TAB_MENU;
- mTabOverview.requestFocus();
- }
+ // Make newIndex visible.
+ mTabOverview.setCurrentIndex(newIndex);
+ // Restore the listener.
+ mTabOverview.setListener(mTabListener);
+ // Change the menu to TAB_MENU if the
+ // ImageGrid is interactive.
+ if (mTabOverview.isLive()) {
+ mMenuState = R.id.TAB_MENU;
+ mTabOverview.requestFocus();
}
// If a remove was requested, remove the tab.
if (remove) {
@@ -1968,12 +2007,10 @@
if (currentTab != tab) {
mTabControl.setCurrentTab(currentTab);
}
- if (mTabOverview != null) {
- mTabOverview.remove(newIndex);
- // Make the current tab visible.
- mTabOverview.setCurrentIndex(
- mTabControl.getCurrentIndex());
- }
+ mTabOverview.remove(newIndex);
+ // Make the current tab visible.
+ mTabOverview.setCurrentIndex(
+ mTabControl.getCurrentIndex());
}
}
});
@@ -1999,11 +2036,6 @@
// from.
private void animateFromTabOverview(final AnimatingView view,
final boolean newTab, final String url, final Message msg) {
- // mTabOverview may have been dismissed
- if (mTabOverview == null) {
- return;
- }
-
// firstVisible is the first visible tab on the screen. This helps
// to know which corner of the screen the selected tab is.
int firstVisible = mTabOverview.getFirstVisiblePosition();
@@ -2025,32 +2057,19 @@
// Find the view at this location.
final View v = mTabOverview.getChildAt(location);
- // Use a delay of 1 second in case we get a bad position
- long delay = 1000;
- boolean fade = false;
-
// Wait until the animation completes to load the url.
final Animation.AnimationListener l =
new Animation.AnimationListener() {
public void onAnimationStart(Animation a) {}
public void onAnimationRepeat(Animation a) {}
public void onAnimationEnd(Animation a) {
- // The animation is done so allow key events and other
- // animations to begin.
- mAnimationCount--;
mHandler.post(new Runnable() {
public void run() {
- if (v != null) {
- mContentView.removeView(view);
- mWebView.setVisibility(View.VISIBLE);
- // Make the sub window container visible if
- // there is one.
- if (mTabControl.getCurrentSubWindow() != null) {
- mTabControl.getCurrentTab()
- .getSubWebViewContainer()
- .setVisibility(View.VISIBLE);
- }
- }
+ mContentView.removeView(view);
+ // Dismiss the tab overview. If the cell at the
+ // given location is null, set the fade
+ // parameter to true.
+ dismissTabOverview(v == null);
if (url != null) {
// Dismiss the subwindow if one exists.
dismissSubWindow(
@@ -2065,6 +2084,12 @@
if (msg != null) {
msg.sendToTarget();
}
+ // The animation is done and the tab overview is
+ // gone so allow key events and other animations
+ // to begin.
+ mAnimationCount--;
+ // Reset all the title bar info.
+ resetTitle();
}
});
}
@@ -2077,32 +2102,42 @@
view.startAnimation(anim);
// Make the view VISIBLE during the animation.
view.setVisibility(View.VISIBLE);
- // Dismiss the tab overview after the animation completes.
- delay = anim.getDuration();
} else {
- // dismiss mTabOverview and have it fade out just in case we get a
- // bad location.
- fade = true;
// Go ahead and load the url.
l.onAnimationEnd(null);
}
- // Reset all the title bar info.
- resetTitle();
- // Dismiss the tab overview either after the animation or after a
- // second.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- DISMISS_TAB_OVERVIEW, fade ? 1 : 0, 0), delay);
+ }
+
+ // Dismiss the tab overview applying a fade if needed.
+ private void dismissTabOverview(final boolean fade) {
+ if (fade) {
+ AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
+ anim.setDuration(500);
+ anim.startNow();
+ mTabOverview.startAnimation(anim);
+ }
+ // Just in case there was a problem with animating away from the tab
+ // overview
+ mWebView.setVisibility(View.VISIBLE);
+ // Make the sub window container visible.
+ if (mTabControl.getCurrentSubWindow() != null) {
+ mTabControl.getCurrentTab().getSubWebViewContainer()
+ .setVisibility(View.VISIBLE);
+ }
+ mContentView.removeView(mTabOverview);
+ mTabOverview.clear();
+ mTabOverview = null;
+ mTabListener = null;
}
private void openTab(String url) {
if (mSettings.openInBackground()) {
- TabControl.Tab t = mTabControl.createNewTab();
+ TabControl.Tab t = mTabControl.createNewTab(false);
if (t != null) {
- WebView w = t.getWebView();
- w.loadUrl(url);
+ t.getWebView().loadUrl(url);
}
} else {
- openTabAndShow(url, null);
+ openTabAndShow(url, null, false);
}
}
@@ -2118,6 +2153,19 @@
mText = toCopy;
}
}
+
+ private class Download implements OnMenuItemClickListener {
+ private String mText;
+
+ public boolean onMenuItemClick(MenuItem item) {
+ onDownloadStartNoStream(mText, null, null, null, -1);
+ return true;
+ }
+
+ public Download(String toDownload) {
+ mText = toDownload;
+ }
+ }
private void copy(CharSequence text) {
try {
@@ -2184,7 +2232,11 @@
mUrl = url;
mTitle = title;
- setTitle(buildUrlTitle(url, title));
+ // While the tab overview is animating or being shown, block changes
+ // to the title.
+ if (mAnimationCount == 0 && mTabOverview == null) {
+ setTitle(buildUrlTitle(url, title));
+ }
}
/**
@@ -2255,6 +2307,11 @@
// Set the favicon in the title bar.
private void setFavicon(Bitmap icon) {
+ // While the tab overview is animating or being shown, block changes to
+ // the favicon.
+ if (mAnimationCount > 0 || mTabOverview != null) {
+ return;
+ }
Drawable[] array = new Drawable[2];
PaintDrawable p = new PaintDrawable(Color.WHITE);
p.setCornerRadius(3f);
@@ -2294,11 +2351,11 @@
updateLockIconImage(mLockIconType);
}
- private void removeTabAndShow(int indexToRemove, int indexToShow) {
+ private void switchTabs(int indexFrom, int indexToShow, boolean remove) {
int delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY;
// Animate to the tab picker, remove the current tab, then
// animate away from the tab picker to the parent WebView.
- tabPicker(false, indexToRemove, true);
+ tabPicker(false, indexFrom, remove);
// Change to the parent tab
final TabControl.Tab tab = mTabControl.getTab(indexToShow);
if (tab != null) {
@@ -2315,13 +2372,25 @@
if (mWebView.canGoBack()) {
mWebView.goBack();
} else {
+ TabControl.Tab self = mTabControl.getCurrentTab();
// Check to see if we are closing a window that was created by
// another window. If so, we switch back to that window.
- TabControl.Tab parent = mTabControl.getCurrentTab().getParentTab();
+ TabControl.Tab parent = self.getParentTab();
if (parent != null) {
- removeTabAndShow(mTabControl.getCurrentIndex(),
- mTabControl.getTabIndex(parent));
+ switchTabs(mTabControl.getCurrentIndex(),
+ mTabControl.getTabIndex(parent), true);
} else {
+ if (self.closeOnExit()) {
+ if (mTabControl.getTabCount() == 1) {
+ finish();
+ return;
+ }
+ // call pauseWebView() now, we won't be able to call it in
+ // onPause() as the mWebView won't be valid.
+ pauseWebView();
+ removeTabFromContentView(self);
+ mTabControl.removeTab(self);
+ }
/*
* Instead of finishing the activity, simply push this to the back
* of the stack and let ActivityManager to choose the foreground
@@ -2352,7 +2421,10 @@
if (mAnimationCount > 0) {
return KeyTracker.State.DONE_TRACKING;
}
- if (stage == KeyTracker.Stage.UP) {
+ if (stage == KeyTracker.Stage.LONG_REPEAT) {
+ loadHistory();
+ return KeyTracker.State.DONE_TRACKING;
+ } else if (stage == KeyTracker.Stage.UP) {
// FIXME: Currently, we do not have a notion of the
// history picker for the subwindow, but maybe we
// should?
@@ -2381,14 +2453,12 @@
if (!handled) {
switch (keyCode) {
case KeyEvent.KEYCODE_SPACE:
- if (mMenuState == R.id.MAIN_MENU){
- if (event.isShiftPressed()) {
- getTopWindow().pageUp(false);
- } else {
- getTopWindow().pageDown(false);
- }
- handled = true;
+ if (event.isShiftPressed()) {
+ getTopWindow().pageUp(false);
+ } else {
+ getTopWindow().pageDown(false);
}
+ handled = true;
break;
default:
@@ -2424,6 +2494,13 @@
}
}
+ private void loadHistory() {
+ Intent intent = new Intent(this, BrowserHistoryPage.class);
+ intent.putExtra("maxTabsOpen",
+ mTabControl.getTabCount() >= TabControl.MAX_TABS);
+ startActivityForResult(intent, CLASSIC_HISTORY_PAGE);
+ }
+
// called by a non-UI thread to post the message
public void postMessage(int what, int arg1, int arg2, Object obj) {
mHandler.sendMessage(mHandler.obtainMessage(what, arg1, arg2, obj));
@@ -2436,13 +2513,12 @@
// Message Ids
private static final int JS_CONFIRM = 101;
private static final int FOCUS_NODE_HREF = 102;
- private static final int DISMISS_TAB_OVERVIEW = 103;
- private static final int CANCEL_CREDS_REQUEST = 104;
- private static final int ANIMATE_FROM_OVERVIEW = 105;
- private static final int ANIMATE_TO_OVERVIEW = 106;
- private static final int OPEN_TAB_AND_SHOW = 107;
- private static final int CHECK_MEMORY = 108;
- private static final int RELEASE_WAKELOCK = 109;
+ private static final int CANCEL_CREDS_REQUEST = 103;
+ private static final int ANIMATE_FROM_OVERVIEW = 104;
+ private static final int ANIMATE_TO_OVERVIEW = 105;
+ private static final int OPEN_TAB_AND_SHOW = 106;
+ private static final int CHECK_MEMORY = 107;
+ private static final int RELEASE_WAKELOCK = 108;
// Private handler for handling javascript and saving passwords
private Handler mHandler = new Handler() {
@@ -2458,37 +2534,6 @@
}
break;
- case DISMISS_TAB_OVERVIEW:
- if (mTabOverview != null) {
- if (msg.arg1 == 1) {
- AlphaAnimation anim =
- new AlphaAnimation(1.0f, 0.0f);
- anim.setDuration(500);
- anim.startNow();
- mTabOverview.startAnimation(anim);
- }
- // Just in case there was a problem with animating away
- // from the tab overview
- mWebView.setVisibility(View.VISIBLE);
- // Make the sub window container visible.
- if (mTabControl.getCurrentSubWindow() != null) {
- mTabControl.getCurrentTab().getSubWebViewContainer()
- .setVisibility(View.VISIBLE);
- }
- mContentView.removeView(mTabOverview);
- mTabOverview.clear();
- // XXX: There are checks for mTabOverview throughout
- // this file because this message can be received
- // before it is expected. This is because we are not
- // enforcing the order of animations properly. In order
- // to get this right, we would need to rewrite a lot of
- // the code to dispatch this messages after all
- // animations have completed.
- mTabOverview = null;
- mTabListener = null;
- }
- break;
-
case ANIMATE_FROM_OVERVIEW:
final HashMap map = (HashMap) msg.obj;
animateFromTabOverview((AnimatingView) map.get("view"),
@@ -2502,7 +2547,7 @@
break;
case OPEN_TAB_AND_SHOW:
- openTabAndShow((String) msg.obj, null);
+ openTabAndShow((String) msg.obj, null, false);
break;
case FOCUS_NODE_HREF:
@@ -2510,18 +2555,16 @@
if (url == null || url.length() == 0) {
break;
}
- WebView view = (WebView) msg.obj;
+ HashMap focusNodeMap = (HashMap) msg.obj;
+ WebView view = (WebView) focusNodeMap.get("webview");
// Only apply the action if the top window did not change.
if (getTopWindow() != view) {
break;
}
switch (msg.arg1) {
- case HEADER_FLAG:
- mTitleView.setText(url);
- break;
case R.id.open_context_menu_id:
case R.id.view_image_context_menu_id:
- loadURL(url);
+ loadURL(getTopWindow(), url);
break;
case R.id.open_newtab_context_menu_id:
openTab(url);
@@ -2546,7 +2589,7 @@
break;
case LOAD_URL:
- loadURL((String) msg.obj);
+ loadURL(getTopWindow(), (String) msg.obj);
break;
case STOP_LOAD:
@@ -2574,9 +2617,6 @@
}
};
- private static final int HEADER_FLAG = Integer.MIN_VALUE;
- private TextView mTitleView = null;
-
// -------------------------------------------------------------------------
// WebViewClient implementation.
//-------------------------------------------------------------------------
@@ -2591,14 +2631,22 @@
return mWebViewClient;
}
+ private void updateIcon(String url, Bitmap icon) {
+ if (icon != null) {
+ BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
+ url, icon);
+ }
+ setFavicon(icon);
+ }
+
private final WebViewClient mWebViewClient = new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
resetLockIcon(url);
setUrlTitle(url, null);
- // Call onReceivedIcon instead of setFavicon so the bookmark
+ // Call updateIcon instead of setFavicon so the bookmark
// database can be updated.
- mWebChromeClient.onReceivedIcon(view, favicon);
+ updateIcon(url, favicon);
if (mSettings.isTracing() == true) {
// FIXME: we should save the trace file somewhere other than data.
@@ -2664,8 +2712,6 @@
// Reset the title and icon in case we stopped a provisional
// load.
resetTitleAndIcon(view);
- // Make the progress full.
- getWindow().setFeatureInt(Window.FEATURE_PROGRESS, 10000);
// Update the lock icon image only once we are done loading
updateLockIconImage(mLockIconType);
@@ -2891,6 +2937,7 @@
if (errorCode != EventHandler.ERROR_LOOKUP &&
errorCode != EventHandler.ERROR_CONNECT &&
errorCode != EventHandler.ERROR_BAD_URL &&
+ errorCode != EventHandler.ERROR_UNSUPPORTED_SCHEME &&
errorCode != EventHandler.FILE_ERROR) {
new AlertDialog.Builder(BrowserActivity.this)
.setTitle((errorCode == EventHandler.FILE_NOT_FOUND_ERROR) ?
@@ -3106,7 +3153,7 @@
// openTabAndShow will dispatch the message after creating the
// new WebView. This will prevent another request from coming
// in during the animation.
- openTabAndShow(null, msg);
+ openTabAndShow(null, msg, false);
parent.addChildTab(mTabControl.getCurrentTab());
WebView.WebViewTransport transport =
(WebView.WebViewTransport) msg.obj;
@@ -3204,13 +3251,18 @@
mTabControl.getCurrentTab().getParentTab();
if (parent != null) {
// JavaScript can only close popup window.
- removeTabAndShow(currentIndex, mTabControl.getTabIndex(parent));
+ switchTabs(currentIndex, mTabControl.getTabIndex(parent), true);
}
}
@Override
public void onProgressChanged(WebView view, int newProgress) {
- getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress*100);
+ // Block progress updates to the title bar while the tab overview
+ // is animating or being displayed.
+ if (mAnimationCount == 0 && mTabOverview == null) {
+ getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+ newProgress * 100);
+ }
if (newProgress == 100) {
// onProgressChanged() is called for sub-frame too while
@@ -3222,7 +3274,7 @@
@Override
public void onReceivedTitle(WebView view, String title) {
- String url = view.getUrl();
+ String url = view.getOriginalUrl();
// here, if url is null, we want to reset the title
setUrlTitle(url, title);
@@ -3245,7 +3297,9 @@
Cursor c = mResolver.query(Browser.BOOKMARKS_URI,
Browser.HISTORY_PROJECTION, where, selArgs, null);
if (c.moveToFirst()) {
- Log.d(LOGTAG, "updating cursor");
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "updating cursor");
+ }
// Current implementation of database only has one entry per
// url.
int titleIndex =
@@ -3263,11 +3317,7 @@
@Override
public void onReceivedIcon(WebView view, Bitmap icon) {
- if (icon != null) {
- BrowserBookmarksAdapter.updateBookmarkFavicon(mResolver,
- view.getUrl(), icon);
- }
- setFavicon(icon);
+ updateIcon(view.getUrl(), icon);
}
//----------------------------------------------------------------------
@@ -3470,20 +3520,29 @@
* @param mimetype The mimetype of the content reported by the server
* @param contentLength The file size reported by the server
*/
- public void onDownloadStartNoStream(String url, String userAgent,
+ /*package */ void onDownloadStartNoStream(String url, String userAgent,
String contentDisposition, String mimetype, long contentLength) {
String filename = URLUtil.guessFileName(url,
contentDisposition, mimetype);
// Check to see if we have an SDCard
- if (!Environment.getExternalStorageState().
- equals(Environment.MEDIA_MOUNTED)) {
- String msg =
- getString(R.string.download_no_sdcard_dlg_msg, filename);
+ String status = Environment.getExternalStorageState();
+ if (!status.equals(Environment.MEDIA_MOUNTED)) {
+ int title;
+ String msg;
+
+ // Check to see if the SDCard is busy, same as the music app
+ if (status.equals(Environment.MEDIA_SHARED)) {
+ msg = getString(R.string.download_sdcard_busy_dlg_msg);
+ title = R.string.download_sdcard_busy_dlg_title;
+ } else {
+ msg = getString(R.string.download_no_sdcard_dlg_msg, filename);
+ title = R.string.download_no_sdcard_dlg_title;
+ }
new AlertDialog.Builder(this)
- .setTitle(R.string.download_no_sdcard_dlg_title)
+ .setTitle(title)
.setIcon(R.drawable.ic_dialog_alert)
.setMessage(msg)
.setPositiveButton(R.string.ok, null)
@@ -3508,9 +3567,15 @@
if (contentLength > 0) {
values.put(Downloads.TOTAL_BYTES, contentLength);
}
- final Uri contentUri =
- getContentResolver().insert(Downloads.CONTENT_URI, values);
- viewDownloads(contentUri);
+ if (mimetype == null) {
+ // We must have long pressed on a link or image to download it. We
+ // are not sure of the mimetype in this case, so do a head request
+ new FetchUrlMimeType(this).execute(values);
+ } else {
+ final Uri contentUri =
+ getContentResolver().insert(Downloads.CONTENT_URI, values);
+ viewDownloads(contentUri);
+ }
}
@@ -3563,29 +3628,38 @@
} else if (lockIconType == LOCK_ICON_MIXED) {
d = mMixLockIcon;
}
- getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+ // If the tab overview is animating or being shown, do not update the
+ // lock icon.
+ if (mAnimationCount == 0 && mTabOverview == null) {
+ getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+ }
}
/**
* Displays a page-info dialog.
- * @param view The target web-view.
+ * @param tab The tab to show info about
* @param fromShowSSLCertificateOnError The flag that indicates whether
* this dialog was opened from the SSL-certificate-on-error dialog or
* not. This is important, since we need to know whether to return to
* the parent dialog or simply dismiss.
*/
- private void showPageInfo(final WebView view,
+ private void showPageInfo(final TabControl.Tab tab,
final boolean fromShowSSLCertificateOnError) {
final LayoutInflater factory = LayoutInflater
.from(this);
final View pageInfoView = factory.inflate(R.layout.page_info, null);
+
+ final WebView view = tab.getWebView();
String url = null;
String title = null;
- // Use the cached title and url if this is the current WebView
- if (view == mWebView) {
+ if (view == null) {
+ url = tab.getUrl();
+ title = tab.getTitle();
+ }else if (view == mWebView) {
+ // Use the cached title and url if this is the current WebView
url = mUrl;
title = mTitle;
} else {
@@ -3603,7 +3677,7 @@
((TextView) pageInfoView.findViewById(R.id.address)).setText(url);
((TextView) pageInfoView.findViewById(R.id.title)).setText(title);
- mPageInfoView = view;
+ mPageInfoView = tab;
mPageInfoFromShowSSLCertificateOnError = new Boolean(fromShowSSLCertificateOnError);
AlertDialog.Builder alertDialogBuilder =
@@ -3649,7 +3723,8 @@
// if we have a main top-level page SSL certificate set or a certificate
// error
- if (fromShowSSLCertificateOnError || view.getCertificate() != null) {
+ if (fromShowSSLCertificateOnError ||
+ (view != null && view.getCertificate() != null)) {
// add a 'View Certificate' button
alertDialogBuilder.setNeutralButton(
R.string.view_certificate,
@@ -3671,7 +3746,7 @@
// otherwise, display the top-most certificate from
// the chain
if (view.getCertificate() != null) {
- showSSLCertificate(view);
+ showSSLCertificate(tab);
}
}
}
@@ -3684,9 +3759,9 @@
/**
* Displays the main top-level page SSL certificate dialog
* (accessible from the Page-Info dialog).
- * @param view The target web-view.
+ * @param tab The tab to show certificate for.
*/
- private void showSSLCertificate(final WebView view) {
+ private void showSSLCertificate(final TabControl.Tab tab) {
final View certificateView =
inflateCertificateView(mWebView.getCertificate());
if (certificateView == null) {
@@ -3703,7 +3778,7 @@
((TextView)ll.findViewById(R.id.success))
.setText(R.string.ssl_certificate_is_valid);
- mSSLCertificateView = view;
+ mSSLCertificateView = tab;
mSSLCertificateDialog =
new AlertDialog.Builder(this)
.setTitle(R.string.ssl_certificate).setIcon(
@@ -3716,7 +3791,7 @@
mSSLCertificateDialog = null;
mSSLCertificateView = null;
- showPageInfo(view, false);
+ showPageInfo(tab, false);
}
})
.setOnCancelListener(
@@ -3725,7 +3800,7 @@
mSSLCertificateDialog = null;
mSSLCertificateView = null;
- showPageInfo(view, false);
+ showPageInfo(tab, false);
}
})
.show();
@@ -3811,7 +3886,8 @@
// need to show the dialog again once the
// user is done exploring the page-info details
- showPageInfo(view, true);
+ showPageInfo(mTabControl.getTabFromView(view),
+ true);
}
})
.setOnCancelListener(
@@ -4016,6 +4092,7 @@
.show();
}
}
+ mTabControl.getCurrentWebView().setNetworkAvailable(up);
}
@Override
@@ -4030,14 +4107,19 @@
if (extras != null && extras.getBoolean("new_window", false)) {
openTab(data);
} else {
+ final TabControl.Tab currentTab =
+ mTabControl.getCurrentTab();
// If the Window overview is up and we are not in the
// middle of an animation, animate away from it to the
// current tab.
if (mTabOverview != null && mAnimationCount == 0) {
- sendAnimateFromOverview(mTabControl.getCurrentTab(),
- false, data, TAB_OVERVIEW_DELAY, null);
+ sendAnimateFromOverview(currentTab, false, data,
+ TAB_OVERVIEW_DELAY, null);
} else {
- loadURL(data);
+ dismissSubWindow(currentTab);
+ if (data != null && data.length() != 0) {
+ getTopWindow().loadUrl(data);
+ }
}
}
}
@@ -4053,7 +4135,7 @@
* menu to see the download window, or when a download changes state. It
* shows the download window ontop of the current window.
*/
- private void viewDownloads(Uri downloadRecord) {
+ /* package */ void viewDownloads(Uri downloadRecord) {
Intent intent = new Intent(this,
BrowserDownloadPage.class);
intent.setData(downloadRecord);
@@ -4071,30 +4153,41 @@
throw new AssertionError();
}
- mTabControl.removeTab(mTabControl.getTab(position));
+ // Remember the current tab.
+ TabControl.Tab current = mTabControl.getCurrentTab();
+ final TabControl.Tab remove = mTabControl.getTab(position);
+ mTabControl.removeTab(remove);
+ // If we removed the current tab, use the tab at position - 1 if
+ // possible.
+ if (current == remove) {
+ // If the user removes the last tab, act like the New Tab item
+ // was clicked on.
+ if (mTabControl.getTabCount() == 0) {
+ current = mTabControl.createNewTab(false);
+ sendAnimateFromOverview(current, true,
+ mSettings.getHomePage(), TAB_OVERVIEW_DELAY, null);
+ } else {
+ final int index = position > 0 ? (position - 1) : 0;
+ current = mTabControl.getTab(index);
+ }
+ }
+
// The tab overview could have been dismissed before this method is
// called.
if (mTabOverview != null) {
// Remove the tab and change the index.
- mTabOverview.remove(position--);
- mTabOverview.setCurrentIndex(position);
- } else {
- position--;
+ mTabOverview.remove(position);
+ mTabOverview.setCurrentIndex(mTabControl.getTabIndex(current));
}
// FIXME: This isn't really right. We don't have a current WebView
// since we are switching between tabs and haven't selected a new
// one. This just prevents a NPE in case the user hits home from the
// tab switcher.
- int index = position;
- if (index == ImageGrid.NEW_TAB) {
- index = 0;
- }
- final TabControl.Tab t = mTabControl.getTab(index);
// Only the current tab ensures its WebView is non-null. This
// implies that we are reloading the freed tab.
- mTabControl.setCurrentTab(t);
- mWebView = t.getWebView();
+ mTabControl.setCurrentTab(current);
+ mWebView = current.getWebView();
}
public void onClick(int index) {
// Change the tab if necessary.
@@ -4112,13 +4205,10 @@
// Clear all the data for tab picker so next time it will be
// recreated.
mTabControl.wipeAllPickerData();
- BrowserActivity.this.getWindow().setFeatureInt(
- Window.FEATURE_PROGRESS, Window.PROGRESS_VISIBILITY_ON);
- BrowserActivity.this.mMenuState = EMPTY_MENU;
// NEW_TAB means that the "New Tab" cell was clicked on.
if (index == ImageGrid.NEW_TAB) {
- openTabAndShow(mSettings.getHomePage(), null);
+ openTabAndShow(mSettings.getHomePage(), null, false);
} else {
sendAnimateFromOverview(mTabControl.getTab(index),
false, null, 0, null);
@@ -4156,11 +4246,13 @@
protected void onDraw(Canvas canvas) {
canvas.save();
canvas.drawColor(Color.WHITE);
- canvas.setDrawFilter(sZoomFilter);
- float scale = getWidth() * mScale;
- canvas.scale(scale, scale);
- canvas.translate(-mScrollX, -mScrollY);
- canvas.drawPicture(mPicture);
+ if (mPicture != null) {
+ canvas.setDrawFilter(sZoomFilter);
+ float scale = getWidth() * mScale;
+ canvas.scale(scale, scale);
+ canvas.translate(-mScrollX, -mScrollY);
+ canvas.drawPicture(mPicture);
+ }
canvas.restore();
}
}
@@ -4219,12 +4311,13 @@
// set it here to prevent another request to animate from coming in
// between now and when ANIMATE_TO_OVERVIEW is handled.
mAnimationCount++;
- if (stay) {
- getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
- getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
- Window.PROGRESS_VISIBILITY_OFF);
- setTitle(R.string.tab_picker_title);
- }
+ // Always change the title bar to the window overview title while
+ // animating.
+ getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
+ getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null);
+ getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+ Window.PROGRESS_VISIBILITY_OFF);
+ setTitle(R.string.tab_picker_title);
// Make the menu empty until the animation completes.
mMenuState = EMPTY_MENU;
}
@@ -4254,14 +4347,13 @@
startActivityForResult(intent, BOOKMARKS_PAGE);
}
- // Called when loading from bookmarks or goto.
- private void loadURL(String url) {
+ // Called when loading from context menu or LOAD_URL message
+ private void loadURL(WebView view, String url) {
// In case the user enters nothing.
- if (url != null && url.length() != 0) {
+ if (url != null && url.length() != 0 && view != null) {
url = smartUrlFilter(url);
- WebView w = getTopWindow();
- if (!mWebViewClient.shouldOverrideUrlLoading(w, url)) {
- w.loadUrl(url);
+ if (!mWebViewClient.shouldOverrideUrlLoading(view, url)) {
+ view.loadUrl(url);
}
}
}
@@ -4316,21 +4408,23 @@
* @return Original or modified URL
*
*/
- String smartUrlFilter(String inUrl) {
+ String smartUrlFilter(String url) {
+ String inUrl = url.trim();
boolean hasSpace = inUrl.indexOf(' ') != -1;
- if (!hasSpace) {
- Matcher matcher = ACCEPTED_URI_SCHEMA.matcher(inUrl);
- if (matcher.matches()) {
- // force scheme to lowercase
- String scheme = matcher.group(1);
- String lcScheme = scheme.toLowerCase();
- if (!lcScheme.equals(scheme)) {
- return lcScheme + matcher.group(2);
- }
- return inUrl;
+ Matcher matcher = ACCEPTED_URI_SCHEMA.matcher(inUrl);
+ if (matcher.matches()) {
+ if (hasSpace) {
+ inUrl = inUrl.replace(" ", "%20");
}
+ // force scheme to lowercase
+ String scheme = matcher.group(1);
+ String lcScheme = scheme.toLowerCase();
+ if (!lcScheme.equals(scheme)) {
+ return lcScheme + matcher.group(2);
+ }
+ return inUrl;
}
if (hasSpace) {
// FIXME: quick search, need to be customized by setting
@@ -4378,6 +4472,33 @@
QUERY_PLACE_HOLDER);
}
+ /* package */void setBaseSearchUrl(String url) {
+ if (url == null || url.length() == 0) {
+ /*
+ * get the google search url based on the SIM. Default is US. NOTE:
+ * This code uses resources to optionally select the search Uri,
+ * based on the MCC value from the SIM. The default string will most
+ * likely be fine. It is parameterized to accept info from the
+ * Locale, the language code is the first parameter (%1$s) and the
+ * country code is the second (%2$s). This code must function in the
+ * same way as a similar lookup in
+ * com.android.googlesearch.SuggestionProvider#onCreate(). If you
+ * change either of these functions, change them both. (The same is
+ * true for the underlying resource strings, which are stored in
+ * mcc-specific xml files.)
+ */
+ Locale l = Locale.getDefault();
+ QuickSearch_G = getResources().getString(
+ R.string.google_search_base, l.getLanguage(),
+ l.getCountry().toLowerCase())
+ + "client=ms-"
+ + SystemProperties.get("ro.com.google.clientid", "unknown")
+ + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s";
+ } else {
+ QuickSearch_G = url;
+ }
+ }
+
private final static int LOCK_ICON_UNSECURE = 0;
private final static int LOCK_ICON_SECURE = 1;
private final static int LOCK_ICON_MIXED = 2;
@@ -4458,7 +4579,7 @@
// As PageInfo has different style for landscape / portrait, we have
// to re-open it when configuration changed
private AlertDialog mPageInfoDialog;
- private WebView mPageInfoView;
+ private TabControl.Tab mPageInfoView;
// If the Page-Info dialog is launched from the SSL-certificate-on-error
// dialog, we should not just dismiss it, but should get back to the
// SSL-certificate-on-error dialog. This flag is used to store this state
@@ -4474,7 +4595,7 @@
// as SSLCertificate has different style for landscape / portrait, we
// have to re-open it when configuration changed
private AlertDialog mSSLCertificateDialog;
- private WebView mSSLCertificateView;
+ private TabControl.Tab mSSLCertificateView;
// as HttpAuthentication has different style for landscape / portrait, we
// have to re-open it when configuration changed
@@ -4487,10 +4608,7 @@
ViewGroup.LayoutParams.FILL_PARENT);
// We may provide UI to customize these
// Google search from the browser
- final static String QuickSearch_G =
- "http://www.google.com/m?client=ms-"
- + SystemProperties.get("ro.com.google.clientid", "unknown")
- + "&source=android-chrome&q=%s";
+ static String QuickSearch_G;
// Wikipedia search
final static String QuickSearch_W = "http://en.wikipedia.org/w/index.php?search=%s&go=Go";
// Dictionary search
@@ -4498,7 +4616,20 @@
// Google Mobile Local search
final static String QuickSearch_L = "http://www.google.com/m/search?site=local&q=%s&near=mountain+view";
- private final static String QUERY_PLACE_HOLDER = "%s";
+ final static String QUERY_PLACE_HOLDER = "%s";
+
+ // "source" parameter for Google search through search key
+ final static String GOOGLE_SEARCH_SOURCE_SEARCHKEY = "browser-key";
+ // "source" parameter for Google search through search menu
+ final static String GOOGLE_SEARCH_SOURCE_SEARCHMENU = "browser-menu";
+ // "source" parameter for Google search through goto menu
+ final static String GOOGLE_SEARCH_SOURCE_GOTO = "browser-goto";
+ // "source" parameter for Google search through simplily type
+ final static String GOOGLE_SEARCH_SOURCE_TYPE = "browser-type";
+ // "source" parameter for Google search suggested by the browser
+ final static String GOOGLE_SEARCH_SOURCE_SUGGEST = "browser-suggest";
+ // "source" parameter for Google search from unknown source
+ final static String GOOGLE_SEARCH_SOURCE_UNKNOWN = "unknown";
private final static String LOGTAG = "browser";
@@ -4516,6 +4647,13 @@
// overlap. A count of 0 means no animation where a count of > 0 means
// there are animations in progress.
private int mAnimationCount;
+
+ // As the ids are dynamically created, we can't guarantee that they will
+ // be in sequence, so this static array maps ids to a window number.
+ final static private int[] WINDOW_SHORTCUT_ID_ARRAY =
+ { R.id.window_one_menu_id, R.id.window_two_menu_id, R.id.window_three_menu_id,
+ R.id.window_four_menu_id, R.id.window_five_menu_id, R.id.window_six_menu_id,
+ R.id.window_seven_menu_id, R.id.window_eight_menu_id };
// monitor platform changes
private IntentFilter mNetworkStateChangedFilter;