summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/browser/AutoFillProfileDatabase.java2
-rw-r--r--src/com/android/browser/AutoFillSettingsFragment.java83
-rw-r--r--src/com/android/browser/AutofillHandler.java58
-rw-r--r--src/com/android/browser/BaseUi.java9
-rw-r--r--src/com/android/browser/BrowserActivity.java10
-rw-r--r--src/com/android/browser/BrowserSettings.java137
-rw-r--r--src/com/android/browser/BrowserWebView.java20
-rw-r--r--src/com/android/browser/Controller.java204
-rw-r--r--src/com/android/browser/CrashRecoveryHandler.java89
-rw-r--r--src/com/android/browser/IntentHandler.java10
-rw-r--r--src/com/android/browser/NavigationBarTablet.java8
-rw-r--r--src/com/android/browser/NetworkStateHandler.java8
-rw-r--r--src/com/android/browser/NfcHandler.java11
-rw-r--r--src/com/android/browser/PageDialogsHandler.java9
-rw-r--r--src/com/android/browser/PhoneUi.java13
-rw-r--r--src/com/android/browser/PreferenceKeys.java14
-rw-r--r--src/com/android/browser/PreloadedTabControl.java6
-rw-r--r--src/com/android/browser/SnapshotTab.java5
-rw-r--r--src/com/android/browser/Tab.java47
-rw-r--r--src/com/android/browser/TabBar.java33
-rw-r--r--src/com/android/browser/TabControl.java2
-rw-r--r--src/com/android/browser/XLargeUi.java18
-rw-r--r--src/com/android/browser/homepages/HomeProvider.java26
-rw-r--r--src/com/android/browser/homepages/RequestHandler.java105
-rw-r--r--src/com/android/browser/preferences/BandwidthPreferencesFragment.java17
-rw-r--r--src/com/android/browser/preferences/FontSizePreview.java2
-rw-r--r--src/com/android/browser/preferences/InvertedContrastPreview.java11
-rw-r--r--src/com/android/browser/preferences/WebViewPreview.java6
-rw-r--r--src/com/android/browser/preferences/WebsiteSettingsFragment.java6
-rw-r--r--src/com/android/browser/provider/BrowserProvider2.java4
-rw-r--r--src/com/android/browser/view/BasePieView.java3
-rw-r--r--src/com/android/browser/view/PieListView.java10
-rw-r--r--src/com/android/browser/view/PieMenu.java5
-rw-r--r--src/com/android/browser/view/PieStackView.java7
34 files changed, 695 insertions, 303 deletions
diff --git a/src/com/android/browser/AutoFillProfileDatabase.java b/src/com/android/browser/AutoFillProfileDatabase.java
index 3345e9258..966692680 100644
--- a/src/com/android/browser/AutoFillProfileDatabase.java
+++ b/src/com/android/browser/AutoFillProfileDatabase.java
@@ -22,7 +22,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.util.Log;
-import android.webkit.WebSettings.AutoFillProfile;
+import android.webkit.WebSettingsClassic.AutoFillProfile;
public class AutoFillProfileDatabase {
diff --git a/src/com/android/browser/AutoFillSettingsFragment.java b/src/com/android/browser/AutoFillSettingsFragment.java
index 04f45b5cf..68b325eac 100644
--- a/src/com/android/browser/AutoFillSettingsFragment.java
+++ b/src/com/android/browser/AutoFillSettingsFragment.java
@@ -32,7 +32,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.inputmethod.InputMethodManager;
-import android.webkit.WebSettings.AutoFillProfile;
+import android.webkit.WebSettingsClassic.AutoFillProfile;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
@@ -52,7 +52,9 @@ public class AutoFillSettingsFragment extends Fragment {
private EditText mCountryEdit;
private EditText mPhoneEdit;
- private Button mSaveButton;
+ private MenuItem mSaveMenuItem;
+
+ private boolean mInitialised;
// Used to display toast after DB interactions complete.
private Handler mHandler;
@@ -87,7 +89,7 @@ public class AutoFillSettingsFragment extends Fragment {
mPhoneEdit.setError(null);
}
- updateButtonState();
+ updateSaveMenuItemState();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -99,7 +101,7 @@ public class AutoFillSettingsFragment extends Fragment {
private class FieldChangedListener implements TextWatcher {
public void afterTextChanged(Editable s) {
- updateButtonState();
+ updateSaveMenuItemState();
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -147,11 +149,14 @@ public class AutoFillSettingsFragment extends Fragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.autofill_profile_editor, menu);
+ mSaveMenuItem = menu.findItem(R.id.autofill_profile_editor_save_profile_menu_id);
+ updateSaveMenuItemState();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == R.id.autofill_profile_editor_delete_profile_menu_id) {
+ switch (item.getItemId()) {
+ case R.id.autofill_profile_editor_delete_profile_menu_id:
// Clear the UI.
mFullNameEdit.setText("");
mEmailEdit.setText("");
@@ -168,10 +173,30 @@ public class AutoFillSettingsFragment extends Fragment {
// trigger the current profile to get deleted from the DB.
mSettings.setAutoFillProfile(null,
mHandler.obtainMessage(PROFILE_DELETED_MSG));
- updateButtonState();
+ updateSaveMenuItemState();
+ return true;
+
+ case R.id.autofill_profile_editor_save_profile_menu_id:
+ AutoFillProfile newProfile = new AutoFillProfile(
+ mUniqueId,
+ mFullNameEdit.getText().toString(),
+ mEmailEdit.getText().toString(),
+ mCompanyEdit.getText().toString(),
+ mAddressLine1Edit.getText().toString(),
+ mAddressLine2Edit.getText().toString(),
+ mCityEdit.getText().toString(),
+ mStateEdit.getText().toString(),
+ mZipEdit.getText().toString(),
+ mCountryEdit.getText().toString(),
+ mPhoneEdit.getText().toString());
+
+ mSettings.setAutoFillProfile(newProfile,
+ mHandler.obtainMessage(PROFILE_SAVED_MSG));
return true;
+
+ default:
+ return false;
}
- return false;
}
@Override
@@ -203,27 +228,6 @@ public class AutoFillSettingsFragment extends Fragment {
mCountryEdit.addTextChangedListener(mFieldChangedListener);
mPhoneEdit.addTextChangedListener(new PhoneNumberValidator());
- mSaveButton = (Button)v.findViewById(R.id.autofill_profile_editor_save_button);
- mSaveButton.setOnClickListener(new OnClickListener() {
- public void onClick(View button) {
- AutoFillProfile newProfile = new AutoFillProfile(
- mUniqueId,
- mFullNameEdit.getText().toString(),
- mEmailEdit.getText().toString(),
- mCompanyEdit.getText().toString(),
- mAddressLine1Edit.getText().toString(),
- mAddressLine2Edit.getText().toString(),
- mCityEdit.getText().toString(),
- mStateEdit.getText().toString(),
- mZipEdit.getText().toString(),
- mCountryEdit.getText().toString(),
- mPhoneEdit.getText().toString());
-
- mSettings.setAutoFillProfile(newProfile,
- mHandler.obtainMessage(PROFILE_SAVED_MSG));
- }
- });
-
// Populate the text boxes with any pre existing AutoFill data.
AutoFillProfile activeProfile = mSettings.getAutoFillProfile();
if (activeProfile != null) {
@@ -239,14 +243,25 @@ public class AutoFillSettingsFragment extends Fragment {
mPhoneEdit.setText(activeProfile.getPhoneNumber());
}
- updateButtonState();
+ mInitialised = true;
+
+ updateSaveMenuItemState();
return v;
}
- public void updateButtonState() {
+ private void updateSaveMenuItemState() {
+ if (mSaveMenuItem == null) {
+ return;
+ }
- boolean valid = (mFullNameEdit.getText().toString().length() > 0 ||
+ if (!mInitialised) {
+ mSaveMenuItem.setEnabled(false);
+ return;
+ }
+
+ boolean currentState = mSaveMenuItem.isEnabled();
+ boolean newState = (mFullNameEdit.getText().toString().length() > 0 ||
mEmailEdit.getText().toString().length() > 0 ||
mCompanyEdit.getText().toString().length() > 0 ||
mAddressLine1Edit.getText().toString().length() > 0 ||
@@ -257,9 +272,9 @@ public class AutoFillSettingsFragment extends Fragment {
mCountryEdit.getText().toString().length() > 0) &&
mPhoneEdit.getError() == null;
- // Only enable the save buttons if we have at least one field completed
- // and the phone number (if present is valid).
- mSaveButton.setEnabled(valid);
+ if (currentState != newState) {
+ mSaveMenuItem.setEnabled(newState);
+ }
}
private void closeEditor() {
diff --git a/src/com/android/browser/AutofillHandler.java b/src/com/android/browser/AutofillHandler.java
index c4b14d797..99ee6a0b4 100644
--- a/src/com/android/browser/AutofillHandler.java
+++ b/src/com/android/browser/AutofillHandler.java
@@ -21,10 +21,12 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.Cursor;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Message;
import android.preference.PreferenceManager;
-import android.webkit.WebSettings.AutoFillProfile;
+import android.provider.ContactsContract;
+import android.webkit.WebSettingsClassic.AutoFillProfile;
import java.util.concurrent.CountDownLatch;
@@ -114,8 +116,62 @@ public class AutofillHandler {
c.close();
autoFillDb.close();
+ if (mAutoFillProfile == null) {
+ // We did not load a profile from disk. Try to populate one with the user's
+ // "me" contact.
+ final Uri profileUri = Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.Contacts.Data.CONTENT_DIRECTORY);
+
+ String name = getContactField(profileUri,
+ ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME,
+ ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
+ // Only attempt to read other data and set a profile if we could successfully
+ // get a name.
+ if (name != null) {
+ String email = getContactField(profileUri,
+ ContactsContract.CommonDataKinds.Email.ADDRESS,
+ ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
+ String phone = getContactField(profileUri,
+ ContactsContract.CommonDataKinds.Phone.NUMBER,
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
+ String company = getContactField(profileUri,
+ ContactsContract.CommonDataKinds.Organization.COMPANY,
+ ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
+
+ // Can't easily get structured postal address information (even using
+ // CommonDataKinds.StructuredPostal) so omit prepopulating that for now.
+ // When querying structured postal data, it often all comes back as a string
+ // inside the "street" field.
+
+ mAutoFillProfile = new AutoFillProfile(
+ 1, name, email, company, null, null, null, null,
+ null, null, phone);
+ }
+ }
+
mLoaded.countDown();
}
+
+ private String getContactField(Uri uri, String field, String itemType) {
+ String result = null;
+
+ Cursor c = mContext.getContentResolver().query(uri, new String[] { field },
+ ContactsContract.Data.MIMETYPE + "=?", new String[] { itemType }, null);
+
+ if (c == null) {
+ return null;
+ }
+
+ try {
+ // Just use the first returned value if we get more than one.
+ if (c.moveToFirst()) {
+ result = c.getString(0);
+ }
+ } finally {
+ c.close();
+ }
+ return result;
+ }
}
public void setAutoFillProfile(AutoFillProfile profile, Message msg) {
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 69063eb62..ffb2928cf 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -47,6 +47,7 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
@@ -236,6 +237,7 @@ public abstract class BaseUi implements UI {
@Override
public void setActiveTab(final Tab tab) {
+ if (tab == null) return;
mHandler.removeMessages(MSG_HIDE_TITLEBAR);
if ((tab != mActiveTab) && (mActiveTab != null)) {
removeTabFromContentView(mActiveTab);
@@ -343,7 +345,7 @@ public abstract class BaseUi implements UI {
// Remove the container from the content and then remove the
// WebView from the container. This will trigger a focus change
// needed by WebView.
- mainView.setEmbeddedTitleBar(null);
+ WebViewClassic.fromWebView(mainView).setEmbeddedTitleBar(null);
FrameLayout wrapper =
(FrameLayout) container.findViewById(R.id.webview_wrapper);
wrapper.removeView(mainView);
@@ -394,7 +396,8 @@ public abstract class BaseUi implements UI {
final WebView cancelSubView = subView;
cancel.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
- cancelSubView.getWebChromeClient().onCloseWindow(cancelSubView);
+ WebViewClassic.fromWebView(cancelSubView).getWebChromeClient().onCloseWindow(
+ cancelSubView);
}
});
tab.setSubWebView(subView);
@@ -475,7 +478,7 @@ public abstract class BaseUi implements UI {
protected void setTitleGravity(int gravity) {
WebView web = getWebView();
if (web != null) {
- web.setTitleBarGravity(gravity);
+ WebViewClassic.fromWebView(web).setTitleBarGravity(gravity);
}
}
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 23aeed5e7..77fac4f25 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -62,7 +62,7 @@ public class BrowserActivity extends Activity {
finish();
return;
}
- mController = new Controller(this, icicle == null);
+ mController = new Controller(this);
boolean xlarge = isTablet(this);
if (xlarge) {
mUi = new XLargeUi(this, mController);
@@ -71,12 +71,8 @@ public class BrowserActivity extends Activity {
}
mController.setUi(mUi);
- Bundle state = getIntent().getBundleExtra(EXTRA_STATE);
- if (state != null && icicle == null) {
- icicle = state;
- }
-
- mController.start(icicle, getIntent());
+ Intent intent = (icicle == null) ? getIntent() : null;
+ mController.start(intent);
}
public static boolean isTablet(Context context) {
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 236955493..415e72da9 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -22,6 +22,8 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.Build;
import android.os.Message;
import android.preference.PreferenceManager;
@@ -32,11 +34,12 @@ import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
import android.webkit.WebIconDatabase;
import android.webkit.WebSettings;
-import android.webkit.WebSettings.AutoFillProfile;
import android.webkit.WebSettings.LayoutAlgorithm;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebSettings.TextSize;
import android.webkit.WebSettings.ZoomDensity;
+import android.webkit.WebSettingsClassic;
+import android.webkit.WebSettingsClassic.AutoFillProfile;
import android.webkit.WebStorage;
import android.webkit.WebView;
import android.webkit.WebViewDatabase;
@@ -114,6 +117,9 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
private boolean mNeedsSharedSync = true;
private float mFontSizeMult = 1.0f;
+ // Current state of network-dependent settings
+ private boolean mLinkPrefetchAllowed = true;
+
// Cached values
private int mPageCacheCapacity = 1;
private String mAppCachePath;
@@ -149,16 +155,28 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
}
public void startManagingSettings(WebSettings settings) {
+ WebSettingsClassic settingsClassic = (WebSettingsClassic) settings;
if (mNeedsSharedSync) {
syncSharedSettings();
}
synchronized (mManagedSettings) {
- syncStaticSettings(settings);
- syncSetting(settings);
+ syncStaticSettings(settingsClassic);
+ syncSetting(settingsClassic);
mManagedSettings.add(new WeakReference<WebSettings>(settings));
}
}
+ public void stopManagingSettings(WebSettings settings) {
+ Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator();
+ while (iter.hasNext()) {
+ WeakReference<WebSettings> ref = iter.next();
+ if (ref.get() == settings) {
+ iter.remove();
+ return;
+ }
+ }
+ }
+
private Runnable mSetup = new Runnable() {
@Override
@@ -174,8 +192,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
mWebStorageSizeManager = new WebStorageSizeManager(mContext,
new WebStorageSizeManager.StatFsDiskInfo(getAppCachePath()),
new WebStorageSizeManager.WebKitAppCacheInfo(getAppCachePath()));
- // Workaround b/5253777
- CookieManager.getInstance().acceptCookie();
// Workaround b/5254577
mPrefs.registerOnSharedPreferenceChangeListener(BrowserSettings.this);
if (Build.VERSION.CODENAME.equals("REL")) {
@@ -235,7 +251,7 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
/**
* Syncs all the settings that have a Preference UI
*/
- private void syncSetting(WebSettings settings) {
+ private void syncSetting(WebSettingsClassic settings) {
settings.setGeolocationEnabled(enableGeolocation());
settings.setJavaScriptEnabled(enableJavascript());
settings.setLightTouchEnabled(enableLightTouch());
@@ -279,13 +295,15 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
settings.setProperty(WebViewProperties.gfxEnableCpuUploadPath,
enableCpuUploadPath() ? "true" : "false");
}
+
+ settings.setLinkPrefetchEnabled(mLinkPrefetchAllowed);
}
/**
* Syncs all the settings that have no UI
* These cannot change, so we only need to set them once per WebSettings
*/
- private void syncStaticSettings(WebSettings settings) {
+ private void syncStaticSettings(WebSettingsClassic settings) {
settings.setDefaultFontSize(16);
settings.setDefaultFixedFontSize(13);
settings.setPageCacheCapacity(getPageCacheCapacity());
@@ -334,7 +352,7 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
Iterator<WeakReference<WebSettings>> iter = mManagedSettings.iterator();
while (iter.hasNext()) {
WeakReference<WebSettings> ref = iter.next();
- WebSettings settings = ref.get();
+ WebSettingsClassic settings = (WebSettingsClassic)ref.get();
if (settings == null) {
iter.remove();
continue;
@@ -350,8 +368,7 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
syncManagedSettings();
if (PREF_SEARCH_ENGINE.equals(key)) {
updateSearchEngine(false);
- }
- if (PREF_FULLSCREEN.equals(key)) {
+ } else if (PREF_FULLSCREEN.equals(key)) {
if (mController.getUi() != null) {
mController.getUi().setFullscreen(useFullscreen());
}
@@ -359,6 +376,8 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
if (mController.getUi() != null) {
mController.getUi().setUseQuickControls(sharedPreferences.getBoolean(key, false));
}
+ } else if (PREF_LINK_PREFETCH.equals(key)) {
+ updateConnectionType();
}
}
@@ -565,6 +584,37 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
return mPrefs;
}
+ // update connectivity-dependent options
+ public void updateConnectionType() {
+ ConnectivityManager cm = (ConnectivityManager)
+ mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ String linkPrefetchPreference = getLinkPrefetchEnabled();
+ boolean linkPrefetchAllowed = linkPrefetchPreference.
+ equals(getLinkPrefetchAlwaysPreferenceString(mContext));
+ NetworkInfo ni = cm.getActiveNetworkInfo();
+ if (ni != null) {
+ switch (ni.getType()) {
+ case ConnectivityManager.TYPE_WIFI:
+ case ConnectivityManager.TYPE_ETHERNET:
+ case ConnectivityManager.TYPE_BLUETOOTH:
+ linkPrefetchAllowed |= linkPrefetchPreference.
+ equals(getLinkPrefetchOnWifiOnlyPreferenceString(mContext));
+ break;
+ case ConnectivityManager.TYPE_MOBILE:
+ case ConnectivityManager.TYPE_MOBILE_DUN:
+ case ConnectivityManager.TYPE_MOBILE_MMS:
+ case ConnectivityManager.TYPE_MOBILE_SUPL:
+ case ConnectivityManager.TYPE_WIMAX:
+ default:
+ break;
+ }
+ }
+ if (mLinkPrefetchAllowed != linkPrefetchAllowed) {
+ mLinkPrefetchAllowed = linkPrefetchAllowed;
+ syncManagedSettings();
+ }
+ }
+
// -----------------------------
// getter/setters for accessibility_preferences.xml
// -----------------------------
@@ -847,4 +897,71 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
return mPrefs.getString(PREF_DATA_PRELOAD, getDefaultPreloadSetting());
}
+ public static String getLinkPrefetchOnWifiOnlyPreferenceString(Context context) {
+ return context.getResources().getString(R.string.pref_link_prefetch_value_wifi_only);
+ }
+
+ public static String getLinkPrefetchAlwaysPreferenceString(Context context) {
+ return context.getResources().getString(R.string.pref_link_prefetch_value_always);
+ }
+
+ private static final String DEFAULT_LINK_PREFETCH_SECURE_SETTING_KEY =
+ "browser_default_link_prefetch_setting";
+
+ public String getDefaultLinkPrefetchSetting() {
+ String preload = Settings.Secure.getString(mContext.getContentResolver(),
+ DEFAULT_LINK_PREFETCH_SECURE_SETTING_KEY);
+ if (preload == null) {
+ preload = mContext.getResources().getString(R.string.pref_link_prefetch_default_value);
+ }
+ return preload;
+ }
+
+ public String getLinkPrefetchEnabled() {
+ return mPrefs.getString(PREF_LINK_PREFETCH, getDefaultLinkPrefetchSetting());
+ }
+
+ // -----------------------------
+ // getter/setters for browser recovery
+ // -----------------------------
+ /**
+ * The last time browser was started.
+ * @return The last browser start time as System.currentTimeMillis. This
+ * can be 0 if this is the first time or the last tab was closed.
+ */
+ public long getLastRecovered() {
+ return mPrefs.getLong(KEY_LAST_RECOVERED, 0);
+ }
+
+ /**
+ * Sets the last browser start time.
+ * @param time The last time as System.currentTimeMillis that the browser
+ * was started. This should be set to 0 if the last tab is closed.
+ */
+ public void setLastRecovered(long time) {
+ mPrefs.edit()
+ .putLong(KEY_LAST_RECOVERED, time)
+ .apply();
+ }
+
+ /**
+ * Used to determine whether or not the previous browser run crashed. Once
+ * the previous state has been determined, the value will be set to false
+ * until a pause is received.
+ * @return true if the last browser run was paused or false if it crashed.
+ */
+ public boolean wasLastRunPaused() {
+ return mPrefs.getBoolean(KEY_LAST_RUN_PAUSED, false);
+ }
+
+ /**
+ * Sets whether or not the last run was a pause or crash.
+ * @param isPaused Set to true When a pause is received or false after
+ * resuming.
+ */
+ public void setLastRunPaused(boolean isPaused) {
+ mPrefs.edit()
+ .putBoolean(KEY_LAST_RUN_PAUSED, isPaused)
+ .apply();
+ }
}
diff --git a/src/com/android/browser/BrowserWebView.java b/src/com/android/browser/BrowserWebView.java
index b763cf10e..49d1a2e90 100644
--- a/src/com/android/browser/BrowserWebView.java
+++ b/src/com/android/browser/BrowserWebView.java
@@ -21,13 +21,14 @@ import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import java.util.Map;
/**
* Manage WebView scroll events
*/
-public class BrowserWebView extends WebView {
+public class BrowserWebView extends WebView implements WebViewClassic.TitleBarDelegate {
public interface OnScrollChangedListener {
void onScrollChanged(int l, int t, int oldl, int oldt);
@@ -73,18 +74,15 @@ public class BrowserWebView extends WebView {
super(context);
}
+ // From TitleBarDelegate
@Override
- protected int getTitleHeight() {
+ public int getTitleHeight() {
return (mTitleBar != null) ? mTitleBar.getEmbeddedHeight() : 0;
}
- void hideEmbeddedTitleBar() {
- scrollBy(0, getVisibleTitleHeight());
- }
-
+ // From TitleBarDelegate
@Override
- public void setEmbeddedTitleBar(final View title) {
- super.setEmbeddedTitleBar(title);
+ public void onSetEmbeddedTitleBar(final View title) {
mTitleBar = (TitleBar) title;
}
@@ -126,4 +124,10 @@ public class BrowserWebView extends WebView {
return false;
}
+ @Override
+ public void destroy() {
+ BrowserSettings.getInstance().stopManagingSettings(getSettings());
+ super.destroy();
+ }
+
}
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 8238d7725..986118431 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -76,6 +76,7 @@ import android.webkit.WebChromeClient;
import android.webkit.WebIconDatabase;
import android.webkit.WebSettings;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import android.widget.Toast;
import com.android.browser.IntentHandler.UrlData;
@@ -218,15 +219,13 @@ public class Controller
private boolean mBlockEvents;
- public Controller(Activity browser, boolean preloadCrashState) {
+ public Controller(Activity browser) {
mActivity = browser;
mSettings = BrowserSettings.getInstance();
mTabControl = new TabControl(this);
mSettings.setController(this);
mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this);
- if (preloadCrashState) {
- mCrashRecoveryHandler.preloadCrashState();
- }
+ mCrashRecoveryHandler.preloadCrashState();
mFactory = new BrowserWebViewFactory(browser);
mUrlHandler = new UrlHandler(this);
@@ -256,16 +255,12 @@ public class Controller
openIconDatabase();
}
- void start(final Bundle icicle, final Intent intent) {
- boolean noCrashRecovery = intent.getBooleanExtra(NO_CRASH_RECOVERY, false);
- if (icicle != null || noCrashRecovery) {
- doStart(icicle, intent, false);
- } else {
- mCrashRecoveryHandler.startRecovery(intent);
- }
+ void start(final Intent intent) {
+ // mCrashRecoverHandler has any previously saved state.
+ mCrashRecoveryHandler.startRecovery(intent);
}
- void doStart(final Bundle icicle, final Intent intent, final boolean fromCrash) {
+ void doStart(final Bundle icicle, final Intent intent) {
// Unless the last browser usage was within 24 hours, destroy any
// remaining incognito tabs.
@@ -293,36 +288,42 @@ public class Controller
GoogleAccountLogin.startLoginIfNeeded(mActivity,
new Runnable() {
@Override public void run() {
- onPreloginFinished(icicle, intent, currentTabId, restoreIncognitoTabs,
- fromCrash);
+ onPreloginFinished(icicle, intent, currentTabId,
+ restoreIncognitoTabs);
}
});
}
private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
- boolean restoreIncognitoTabs, boolean fromCrash) {
+ boolean restoreIncognitoTabs) {
if (currentTabId == -1) {
BackgroundHandler.execute(new PruneThumbnails(mActivity, null));
- final Bundle extra = intent.getExtras();
- // Create an initial tab.
- // 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.
- UrlData urlData = IntentHandler.getUrlDataFromIntent(intent);
- Tab t = null;
- if (urlData.isEmpty()) {
- t = openTabToHomePage();
+ if (intent == null) {
+ // This won't happen under common scenarios. The icicle is
+ // not null, but there aren't any tabs to restore.
+ openTabToHomePage();
} else {
- t = openTab(urlData);
- }
- if (t != null) {
- t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
- }
- WebView webView = t.getWebView();
- if (extra != null) {
- int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
- if (scale > 0 && scale <= 1000) {
- webView.setInitialScale(scale);
+ final Bundle extra = intent.getExtras();
+ // Create an initial tab.
+ // 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.
+ UrlData urlData = IntentHandler.getUrlDataFromIntent(intent);
+ Tab t = null;
+ if (urlData.isEmpty()) {
+ t = openTabToHomePage();
+ } else {
+ t = openTab(urlData);
+ }
+ if (t != null) {
+ t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
+ }
+ WebView webView = t.getWebView();
+ if (extra != null) {
+ int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
+ if (scale > 0 && scale <= 1000) {
+ webView.setInitialScale(scale);
+ }
}
}
mUi.updateTabs(mTabControl.getTabs());
@@ -342,18 +343,19 @@ public class Controller
// TabControl.restoreState() will create a new tab even if
// restoring the state fails.
setActiveTab(mTabControl.getCurrentTab());
- // Handle the intent if needed. If icicle != null, we are restoring
- // and the intent will be stale - ignore it.
- if (icicle == null || fromCrash) {
+ // Intent is non-null when framework thinks the browser should be
+ // launching with a new intent (icicle is null).
+ if (intent != null) {
mIntentHandler.onNewIntent(intent);
}
}
// Read JavaScript flags if it exists.
String jsFlags = getSettings().getJsEngineFlags();
if (jsFlags.trim().length() != 0) {
- getCurrentWebView().setJsFlags(jsFlags);
+ WebViewClassic.fromWebView(getCurrentWebView()).setJsFlags(jsFlags);
}
- if (BrowserActivity.ACTION_SHOW_BOOKMARKS.equals(intent.getAction())) {
+ if (intent != null
+ && BrowserActivity.ACTION_SHOW_BOOKMARKS.equals(intent.getAction())) {
bookmarksOrHistoryPicker(ComboViews.Bookmarks);
}
}
@@ -602,6 +604,8 @@ public class Controller
protected void onConfgurationChanged(Configuration config) {
mConfigChanged = true;
+ // update the menu in case of a locale change
+ mActivity.invalidateOptionsMenu();
if (mPageDialogsHandler != null) {
mPageDialogsHandler.onConfigurationChanged(config);
}
@@ -651,18 +655,27 @@ public class Controller
}
void onSaveInstanceState(Bundle outState) {
- // the default implementation requires each view to have an id. As the
- // browser handles the state itself and it doesn't use id for the views,
- // don't call the default implementation. Otherwise it will trigger the
- // warning like this, "couldn't save which view has focus because the
- // focused view XXX has no id".
-
// Save all the tabs
- mTabControl.saveState(outState);
- if (!outState.isEmpty()) {
+ Bundle saveState = createSaveState();
+
+ // crash recovery manages all save & restore state
+ mCrashRecoveryHandler.writeState(saveState);
+ mSettings.setLastRunPaused(true);
+ }
+
+ /**
+ * Save the current state to outState. Does not write the state to
+ * disk.
+ * @return Bundle containing the current state of all tabs.
+ */
+ /* package */ Bundle createSaveState() {
+ Bundle saveState = new Bundle();
+ mTabControl.saveState(saveState);
+ if (!saveState.isEmpty()) {
// Save time so that we know how old incognito tabs (if any) are.
- outState.putSerializable("lastActiveDate", Calendar.getInstance());
+ saveState.putSerializable("lastActiveDate", Calendar.getInstance());
}
+ return saveState;
}
void onResume() {
@@ -670,6 +683,7 @@ public class Controller
Log.e(LOGTAG, "BrowserActivity is already resumed.");
return;
}
+ mSettings.setLastRunPaused(false);
mActivityPaused = false;
Tab current = mTabControl.getCurrentTab();
if (current != null) {
@@ -829,21 +843,6 @@ public class Controller
@Override
public void onPageFinished(Tab tab) {
mUi.onTabDataChanged(tab);
- if (!tab.isPrivateBrowsingEnabled()
- && !TextUtils.isEmpty(tab.getUrl())
- && !tab.isSnapshot()) {
- // Only update the bookmark screenshot if the user did not
- // cancel the load early and there is not already
- // a pending update for the tab.
- if (tab.inForeground() && !didUserStopLoading()
- || !tab.inForeground()) {
- if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
- mHandler.sendMessageDelayed(mHandler.obtainMessage(
- UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
- 500);
- }
- }
- }
// pause the WebView timer and release the wake lock if it is finished
// while BrowserActivity is in pause state.
if (mActivityPaused && pauseWebViewTimers(tab)) {
@@ -875,6 +874,21 @@ public class Controller
if (tab.inPageLoad()) {
updateInLoadMenuItems(mCachedMenu, tab);
}
+ if (!tab.isPrivateBrowsingEnabled()
+ && !TextUtils.isEmpty(tab.getUrl())
+ && !tab.isSnapshot()) {
+ // Only update the bookmark screenshot if the user did not
+ // cancel the load early and there is not already
+ // a pending update for the tab.
+ if (tab.inForeground() && !didUserStopLoading()
+ || !tab.inForeground()) {
+ if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
+ 500);
+ }
+ }
+ }
} else {
if (!tab.inPageLoad()) {
// onPageFinished may have already been called but a subframe is
@@ -1282,6 +1296,7 @@ public class Controller
// Show the correct menu group
final String extra = result.getExtra();
+ if (extra == null) return;
menu.setGroupVisible(R.id.PHONE_MENU,
type == WebView.HitTestResult.PHONE_TYPE);
menu.setGroupVisible(R.id.EMAIL_MENU,
@@ -1388,8 +1403,20 @@ public class Controller
}
// otherwise fall through to handle image part
case WebView.HitTestResult.IMAGE_TYPE:
+ MenuItem shareItem = menu.findItem(R.id.share_link_context_menu_id);
+ shareItem.setVisible(type == WebView.HitTestResult.IMAGE_TYPE);
if (type == WebView.HitTestResult.IMAGE_TYPE) {
menu.setHeaderTitle(extra);
+ shareItem.setOnMenuItemClickListener(
+ new MenuItem.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ sharePage(mActivity, null, extra, null,
+ null);
+ return true;
+ }
+ }
+ );
}
menu.findItem(R.id.view_image_context_menu_id)
.setOnMenuItemClickListener(new OnMenuItemClickListener() {
@@ -1509,9 +1536,6 @@ public class Controller
nav.setEnabled(isNavDump);
boolean showDebugSettings = mSettings.isDebugEnabled();
- final MenuItem counter = menu.findItem(R.id.dump_counters_menu_id);
- counter.setVisible(showDebugSettings);
- counter.setEnabled(showDebugSettings);
final MenuItem uaSwitcher = menu.findItem(R.id.ua_desktop_menu_id);
uaSwitcher.setChecked(isDesktopUa);
menu.setGroupVisible(R.id.LIVE_MENU, isLive);
@@ -1666,10 +1690,6 @@ public class Controller
getCurrentTopWebView().debugDump();
break;
- case R.id.dump_counters_menu_id:
- getCurrentTopWebView().dumpV8Counters();
- break;
-
case R.id.zoom_in_menu_id:
getCurrentTopWebView().zoomIn();
break;
@@ -2006,7 +2026,6 @@ public class Controller
}
final String url = tab.getUrl();
final String originalUrl = view.getOriginalUrl();
-
if (TextUtils.isEmpty(url)) {
return;
}
@@ -2107,7 +2126,7 @@ public class Controller
manager.addCompletedDownload(target.getName(),
mActivity.getTitle().toString(), false,
uri.getMimeType(), target.getAbsolutePath(),
- (long)uri.getData().length, false);
+ (long)uri.getData().length, true);
} catch (IOException e) {
Log.e(LOGTAG, "Could not save data URL");
} finally {
@@ -2143,7 +2162,7 @@ public class Controller
}
private static class SelectText implements OnMenuItemClickListener {
- private WebView mWebView;
+ private WebViewClassic mWebView;
public boolean onMenuItemClick(MenuItem item) {
if (mWebView != null) {
@@ -2153,7 +2172,7 @@ public class Controller
}
public SelectText(WebView webView) {
- mWebView = webView;
+ mWebView = WebViewClassic.fromWebView(webView);
}
}
@@ -2426,7 +2445,8 @@ public class Controller
// In case the user enters nothing.
if (url != null && url.length() != 0 && tab != null && view != null) {
url = UrlUtils.smartUrlFilter(url);
- if (!view.getWebViewClient().shouldOverrideUrlLoading(view, url)) {
+ if (!WebViewClassic.fromWebView(view).getWebViewClient().
+ shouldOverrideUrlLoading(view, url)) {
loadUrl(tab, url);
}
}
@@ -2565,8 +2585,11 @@ public class Controller
* returns the current tab if it can't advance
*/
private Tab getNextTab() {
- return mTabControl.getTab(Math.min(mTabControl.getTabCount() - 1,
- mTabControl.getCurrentPosition() + 1));
+ int pos = mTabControl.getCurrentPosition() + 1;
+ if (pos >= mTabControl.getTabCount()) {
+ pos = 0;
+ }
+ return mTabControl.getTab(pos);
}
/**
@@ -2574,8 +2597,17 @@ public class Controller
* returns the current tab if it can't advance
*/
private Tab getPrevTab() {
- return mTabControl.getTab(Math.max(0,
- mTabControl.getCurrentPosition() - 1));
+ int pos = mTabControl.getCurrentPosition() - 1;
+ if ( pos < 0) {
+ pos = mTabControl.getTabCount() - 1;
+ }
+ return mTabControl.getTab(pos);
+ }
+
+ boolean isMenuOrCtrlKey(int keyCode) {
+ return (KeyEvent.KEYCODE_MENU == keyCode)
+ || (KeyEvent.KEYCODE_CTRL_LEFT == keyCode)
+ || (KeyEvent.KEYCODE_CTRL_RIGHT == keyCode);
}
/**
@@ -2589,10 +2621,7 @@ public class Controller
boolean noModifiers = event.hasNoModifiers();
// Even if MENU is already held down, we need to call to super to open
// the IME on long press.
- if (!noModifiers
- && ((KeyEvent.KEYCODE_MENU == keyCode)
- || (KeyEvent.KEYCODE_CTRL_LEFT == keyCode)
- || (KeyEvent.KEYCODE_CTRL_RIGHT == keyCode))) {
+ if (!noModifiers && isMenuOrCtrlKey(keyCode)) {
mMenuIsDown = true;
return false;
}
@@ -2649,14 +2678,14 @@ public class Controller
break;
case KeyEvent.KEYCODE_A:
if (ctrl) {
- webView.selectAll();
+ WebViewClassic.fromWebView(webView).selectAll();
return true;
}
break;
// case KeyEvent.KEYCODE_B: // menu
case KeyEvent.KEYCODE_C:
if (ctrl) {
- webView.copySelection();
+ WebViewClassic.fromWebView(webView).copySelection();
return true;
}
break;
@@ -2712,9 +2741,10 @@ public class Controller
}
boolean onKeyUp(int keyCode, KeyEvent event) {
- if (KeyEvent.KEYCODE_MENU == keyCode) {
+ if (isMenuOrCtrlKey(keyCode)) {
mMenuIsDown = false;
- if (event.isTracking() && !event.isCanceled()) {
+ if (KeyEvent.KEYCODE_MENU == keyCode
+ && event.isTracking() && !event.isCanceled()) {
return onMenuKey();
}
}
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 3202016ed..822e82a80 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -37,8 +37,6 @@ public class CrashRecoveryHandler {
private static final boolean LOGV_ENABLED = Browser.LOGV_ENABLED;
private static final String LOGTAG = "BrowserCrashRecovery";
private static final String STATE_FILE = "browser_state.parcel";
- private static final String RECOVERY_PREFERENCES = "browser_recovery_prefs";
- private static final String KEY_LAST_RECOVERED = "last_recovered";
private static final int BUFFER_SIZE = 4096;
private static final long BACKUP_DELAY = 500; // 500ms between writes
/* This is the duration for which we will prompt to restore
@@ -85,31 +83,8 @@ public class CrashRecoveryHandler {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_WRITE_STATE:
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Saving crash recovery state");
- }
- Parcel p = Parcel.obtain();
- try {
- Bundle state = (Bundle) msg.obj;
- state.writeToParcel(p, 0);
- File stateJournal = new File(mContext.getCacheDir(),
- STATE_FILE + ".journal");
- FileOutputStream fout = new FileOutputStream(stateJournal);
- fout.write(p.marshall());
- fout.close();
- File stateFile = new File(mContext.getCacheDir(),
- STATE_FILE);
- if (!stateJournal.renameTo(stateFile)) {
- // Failed to rename, try deleting the existing
- // file and try again
- stateFile.delete();
- stateJournal.renameTo(stateFile);
- }
- } catch (Throwable e) {
- Log.i(LOGTAG, "Failed to save persistent state", e);
- } finally {
- p.recycle();
- }
+ Bundle saveState = (Bundle) msg.obj;
+ writeState(saveState);
break;
case MSG_CLEAR_STATE:
if (LOGV_ENABLED) {
@@ -142,8 +117,7 @@ public class CrashRecoveryHandler {
@Override
public void run() {
try {
- final Bundle state = new Bundle();
- mController.onSaveInstanceState(state);
+ final Bundle state = mController.createSaveState();
Message.obtain(mBackgroundHandler, MSG_WRITE_STATE, state)
.sendToTarget();
// Remove any queued up saves
@@ -162,28 +136,24 @@ public class CrashRecoveryHandler {
}
private boolean shouldRestore() {
- SharedPreferences prefs = mContext.getSharedPreferences(
- RECOVERY_PREFERENCES, Context.MODE_PRIVATE);
- long lastRecovered = prefs.getLong(KEY_LAST_RECOVERED, 0);
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ long lastRecovered = browserSettings.getLastRecovered();
long timeSinceLastRecover = System.currentTimeMillis() - lastRecovered;
- if (timeSinceLastRecover > PROMPT_INTERVAL) {
- return true;
- }
- return false;
+ return (timeSinceLastRecover > PROMPT_INTERVAL)
+ || browserSettings.wasLastRunPaused();
}
private void updateLastRecovered(long time) {
- SharedPreferences prefs = mContext.getSharedPreferences(
- RECOVERY_PREFERENCES, Context.MODE_PRIVATE);
- prefs.edit()
- .putLong(KEY_LAST_RECOVERED, time)
- .apply();
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ browserSettings.setLastRecovered(time);
}
- private Bundle loadCrashState() {
+ synchronized private Bundle loadCrashState() {
if (!shouldRestore()) {
return null;
}
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ browserSettings.setLastRunPaused(false);
Bundle state = null;
Parcel parcel = Parcel.obtain();
FileInputStream fin = null;
@@ -231,7 +201,7 @@ public class CrashRecoveryHandler {
}
updateLastRecovered(mRecoveryState != null
? System.currentTimeMillis() : 0);
- mController.doStart(mRecoveryState, intent, true);
+ mController.doStart(mRecoveryState, intent);
mRecoveryState = null;
}
@@ -245,4 +215,35 @@ public class CrashRecoveryHandler {
mBackgroundHandler.sendEmptyMessage(MSG_PRELOAD_STATE);
}
-}
+ /**
+ * Writes the crash recovery state to a file synchronously.
+ * Errors are swallowed, but logged.
+ * @param state The state to write out
+ */
+ synchronized void writeState(Bundle state) {
+ if (LOGV_ENABLED) {
+ Log.v(LOGTAG, "Saving crash recovery state");
+ }
+ Parcel p = Parcel.obtain();
+ try {
+ state.writeToParcel(p, 0);
+ File stateJournal = new File(mContext.getCacheDir(),
+ STATE_FILE + ".journal");
+ FileOutputStream fout = new FileOutputStream(stateJournal);
+ fout.write(p.marshall());
+ fout.close();
+ File stateFile = new File(mContext.getCacheDir(),
+ STATE_FILE);
+ if (!stateJournal.renameTo(stateFile)) {
+ // Failed to rename, try deleting the existing
+ // file and try again
+ stateFile.delete();
+ stateJournal.renameTo(stateFile);
+ }
+ } catch (Throwable e) {
+ Log.i(LOGTAG, "Failed to save persistent state", e);
+ } finally {
+ p.recycle();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index e5ddb4787..ecd454521 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -197,15 +197,15 @@ public class IntentHandler {
if (!urlData.isEmpty()
&& urlData.mUrl.startsWith("about:debug")) {
if ("about:debug.dom".equals(urlData.mUrl)) {
- current.getWebView().dumpDomTree(false);
+ current.getWebViewClassic().dumpDomTree(false);
} else if ("about:debug.dom.file".equals(urlData.mUrl)) {
- current.getWebView().dumpDomTree(true);
+ current.getWebViewClassic().dumpDomTree(true);
} else if ("about:debug.render".equals(urlData.mUrl)) {
- current.getWebView().dumpRenderTree(false);
+ current.getWebViewClassic().dumpRenderTree(false);
} else if ("about:debug.render.file".equals(urlData.mUrl)) {
- current.getWebView().dumpRenderTree(true);
+ current.getWebViewClassic().dumpRenderTree(true);
} else if ("about:debug.display".equals(urlData.mUrl)) {
- current.getWebView().dumpDisplayTree();
+ current.getWebViewClassic().dumpDisplayTree();
} else if ("about:debug.nav".equals(urlData.mUrl)) {
current.getWebView().debugDump();
} else {
diff --git a/src/com/android/browser/NavigationBarTablet.java b/src/com/android/browser/NavigationBarTablet.java
index 04f372a32..3403fd7e6 100644
--- a/src/com/android/browser/NavigationBarTablet.java
+++ b/src/com/android/browser/NavigationBarTablet.java
@@ -165,9 +165,9 @@ public class NavigationBarTablet extends NavigationBarBase {
@Override
public void onClick(View v) {
- if (mBackButton == v) {
+ if ((mBackButton == v) && (mUiController.getCurrentTab() != null)) {
mUiController.getCurrentTab().goBack();
- } else if (mForwardButton == v) {
+ } else if ((mForwardButton == v) && (mUiController.getCurrentTab() != null)) {
mUiController.getCurrentTab().goForward();
} else if (mStar == v) {
Intent intent = mUiController.createBookmarkCurrentPageIntent(true);
@@ -261,7 +261,9 @@ public class NavigationBarTablet extends NavigationBarBase {
if (mTitleBar.isInLoad()) {
mUiController.stopLoading();
} else {
- mUiController.getCurrentTopWebView().reload();
+ if (mUiController.getCurrentTopWebView() != null) {
+ mUiController.getCurrentTopWebView().reload();
+ }
}
}
diff --git a/src/com/android/browser/NetworkStateHandler.java b/src/com/android/browser/NetworkStateHandler.java
index 2fbd035ae..4480664f8 100644
--- a/src/com/android/browser/NetworkStateHandler.java
+++ b/src/com/android/browser/NetworkStateHandler.java
@@ -24,6 +24,9 @@ import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
+
+import com.android.browser.BrowserSettings;
/**
* Handle network state changes
@@ -67,6 +70,7 @@ public class NetworkStateHandler {
String subtypeName = info.getSubtypeName();
sendNetworkType(typeName.toLowerCase(),
(subtypeName != null ? subtypeName.toLowerCase() : ""));
+ BrowserSettings.getInstance().updateConnectionType();
boolean noConnection = intent.getBooleanExtra(
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
@@ -86,6 +90,7 @@ public class NetworkStateHandler {
void onResume() {
mActivity.registerReceiver(mNetworkStateIntentReceiver,
mNetworkStateChangedFilter);
+ BrowserSettings.getInstance().updateConnectionType();
}
/**
@@ -110,8 +115,7 @@ public class NetworkStateHandler {
private void sendNetworkType(String type, String subtype) {
WebView w = mController.getCurrentWebView();
if (w != null) {
- w.setNetworkType(type, subtype);
+ WebViewClassic.fromWebView(w).setNetworkType(type, subtype);
}
}
-
}
diff --git a/src/com/android/browser/NfcHandler.java b/src/com/android/browser/NfcHandler.java
index 1b34df2b9..0dd85769a 100644
--- a/src/com/android/browser/NfcHandler.java
+++ b/src/com/android/browser/NfcHandler.java
@@ -23,6 +23,7 @@ import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.os.Handler;
import android.os.Message;
+import android.util.Log;
import java.util.concurrent.CountDownLatch;
@@ -32,6 +33,7 @@ import java.util.concurrent.CountDownLatch;
* Incognito tabs will not be shared over NFC.
*/
public class NfcHandler implements NfcAdapter.CreateNdefMessageCallback {
+ static final String TAG = "BrowserNfcHandler";
static final int GET_PRIVATE_BROWSING_STATE_MSG = 100;
final Controller mController;
@@ -94,9 +96,12 @@ public class NfcHandler implements NfcAdapter.CreateNdefMessageCallback {
String currentUrl = mCurrentTab.getUrl();
if (currentUrl != null) {
- NdefRecord record = NdefRecord.createUri(currentUrl);
- NdefMessage msg = new NdefMessage(new NdefRecord[] { record });
- return msg;
+ try {
+ return new NdefMessage(NdefRecord.createUri(currentUrl));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "IllegalArgumentException creating URI NdefRecord", e);
+ return null;
+ }
} else {
return null;
}
diff --git a/src/com/android/browser/PageDialogsHandler.java b/src/com/android/browser/PageDialogsHandler.java
index 013eaf1f5..19cbfcdea 100644
--- a/src/com/android/browser/PageDialogsHandler.java
+++ b/src/com/android/browser/PageDialogsHandler.java
@@ -27,6 +27,7 @@ import android.view.View;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -296,8 +297,8 @@ public class PageDialogsHandler {
mSSLCertificateOnErrorHandler = null;
mSSLCertificateOnErrorError = null;
- view.getWebViewClient().onReceivedSslError(
- view, handler, error);
+ WebViewClassic.fromWebView(view).getWebViewClient().
+ onReceivedSslError(view, handler, error);
}
})
.setNeutralButton(R.string.page_info_view,
@@ -324,8 +325,8 @@ public class PageDialogsHandler {
mSSLCertificateOnErrorHandler = null;
mSSLCertificateOnErrorError = null;
- view.getWebViewClient().onReceivedSslError(
- view, handler, error);
+ WebViewClassic.fromWebView(view).getWebViewClient().
+ onReceivedSslError(view, handler, error);
}
})
.show();
diff --git a/src/com/android/browser/PhoneUi.java b/src/com/android/browser/PhoneUi.java
index 4da0668a0..5afb9c447 100644
--- a/src/com/android/browser/PhoneUi.java
+++ b/src/com/android/browser/PhoneUi.java
@@ -38,6 +38,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -169,7 +170,7 @@ public class PhoneUi extends BaseUi {
} else {
// check if title bar is already attached by animation
if (mTitleBar.getParent() == null) {
- view.setEmbeddedTitleBar(mTitleBar);
+ WebViewClassic.fromWebView(view).setEmbeddedTitleBar(mTitleBar);
}
}
if (tab.isInVoiceSearchMode()) {
@@ -287,7 +288,7 @@ public class PhoneUi extends BaseUi {
mPieControl.attachToContainer(mContentView);
WebView web = getWebView();
if (web != null) {
- web.setEmbeddedTitleBar(null);
+ WebViewClassic.fromWebView(web).setEmbeddedTitleBar(null);
}
} else {
if (mPieControl != null) {
@@ -299,7 +300,7 @@ public class PhoneUi extends BaseUi {
if ((mTitleBar != null) && (mTitleBar.getParent() != null)) {
((ViewGroup) mTitleBar.getParent()).removeView(mTitleBar);
}
- web.setEmbeddedTitleBar(mTitleBar);
+ WebViewClassic.fromWebView(web).setEmbeddedTitleBar(mTitleBar);
}
setTitleGravity(Gravity.NO_GRAVITY);
}
@@ -428,13 +429,15 @@ public class PhoneUi extends BaseUi {
mAnimScreen = new AnimScreen(mActivity);
}
mAnimScreen.set(tab.getScreenshot());
- mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
+ if (mAnimScreen.mMain.getParent() == null) {
+ mCustomViewContainer.addView(mAnimScreen.mMain, COVER_SCREEN_PARAMS);
+ }
mAnimScreen.mMain.layout(0, 0, mContentView.getWidth(),
mContentView.getHeight());
mNavScreen.mScroller.finishScroller();
ImageView target = tabview.mImage;
int toLeft = 0;
- int toTop = getTitleBar().getHeight();
+ int toTop = (tab.getWebView() != null) ? tab.getWebView().getVisibleTitleHeight() : 0;
int toRight = mContentView.getWidth();
int width = target.getDrawable().getIntrinsicWidth();
int height = target.getDrawable().getIntrinsicHeight();
diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java
index ecab008a5..ff42aafea 100644
--- a/src/com/android/browser/PreferenceKeys.java
+++ b/src/com/android/browser/PreferenceKeys.java
@@ -102,6 +102,20 @@ public interface PreferenceKeys {
// Keys for bandwidth_preferences.xml
// ----------------------
static final String PREF_DATA_PRELOAD = "preload_when";
+ static final String PREF_LINK_PREFETCH = "link_prefetch_when";
static final String PREF_LOAD_IMAGES = "load_images";
+ // ----------------------
+ // Keys for browser recovery
+ // ----------------------
+ /**
+ * The last time recovery was started as System.currentTimeMillis.
+ * 0 if not set.
+ */
+ static final String KEY_LAST_RECOVERED = "last_recovered";
+
+ /**
+ * Key for whether or not the last run was paused.
+ */
+ static final String KEY_LAST_RUN_PAUSED = "last_paused";
}
diff --git a/src/com/android/browser/PreloadedTabControl.java b/src/com/android/browser/PreloadedTabControl.java
index 4ffe6b47b..0b2956ffb 100644
--- a/src/com/android/browser/PreloadedTabControl.java
+++ b/src/com/android/browser/PreloadedTabControl.java
@@ -62,12 +62,12 @@ public class PreloadedTabControl {
}
public void setQuery(String query) {
- maybeSetQuery(query, mTab.getWebView().getSearchBox());
+ maybeSetQuery(query, mTab.getWebViewClassic().getSearchBox());
}
public boolean searchBoxSubmit(final String query,
final String fallbackUrl, final Map<String, String> fallbackHeaders) {
- final SearchBox sb = mTab.getWebView().getSearchBox();
+ final SearchBox sb = mTab.getWebViewClassic().getSearchBox();
if (sb == null) {
// no searchbox, cannot submit. Fallback to regular tab creation
if (LOGD_ENABLED) Log.d(LOGTAG, "No searchbox, cannot submit query");
@@ -106,7 +106,7 @@ public class PreloadedTabControl {
}
public void searchBoxCancel() {
- SearchBox sb = mTab.getWebView().getSearchBox();
+ SearchBox sb = mTab.getWebViewClassic().getSearchBox();
if (sb != null) {
mLastQuery = null;
sb.oncancel(new SearchBox.SearchBoxListener(){
diff --git a/src/com/android/browser/SnapshotTab.java b/src/com/android/browser/SnapshotTab.java
index d9c71f03f..f58f88b4c 100644
--- a/src/com/android/browser/SnapshotTab.java
+++ b/src/com/android/browser/SnapshotTab.java
@@ -25,6 +25,7 @@ import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import com.android.browser.provider.SnapshotProvider.Snapshots;
@@ -121,7 +122,7 @@ public class SnapshotTab extends Tab {
public void loadUrl(String url, Map<String, String> headers) {
if (!mIsLive) {
mIsLive = true;
- getWebView().clearViewState();
+ getWebViewClassic().clearViewState();
}
super.loadUrl(url, headers);
}
@@ -185,7 +186,7 @@ public class SnapshotTab extends Tab {
mTab.mCurrentState.mFavicon = BitmapFactory
.decodeByteArray(favicon, 0, favicon.length);
}
- WebView web = mTab.getWebView();
+ WebViewClassic web = mTab.getWebViewClassic();
if (web != null) {
byte[] data = result.getBlob(4);
ByteArrayInputStream bis = new ByteArrayInputStream(data);
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 0abc86bdf..acccb3150 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -64,6 +64,7 @@ import android.webkit.WebHistoryItem;
import android.webkit.WebResourceResponse;
import android.webkit.WebStorage;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import android.webkit.WebView.PictureListener;
import android.webkit.WebViewClient;
import android.widget.CheckBox;
@@ -610,11 +611,6 @@ class Tab implements PictureListener {
@Override
public void onPageFinished(WebView view, String url) {
- if (!mInPageLoad) {
- // In page navigation links (www.something.com#footer) will
- // trigger an onPageFinished which we don't care about.
- return;
- }
if (!isPrivateBrowsingEnabled()) {
LogTag.logPageFinishedLoading(
url, SystemClock.uptimeMillis() - mLoadStartTime);
@@ -1506,11 +1502,15 @@ class Tab implements PictureListener {
return mId;
}
+ void setWebView(WebView w) {
+ setWebView(w, true);
+ }
+
/**
* Sets the WebView for this tab, correctly removing the old WebView from
* the container view.
*/
- void setWebView(WebView w) {
+ void setWebView(WebView w, boolean restore) {
if (mMainView == w) {
return;
}
@@ -1542,12 +1542,13 @@ class Tab implements PictureListener {
// does a redirect after a period of time. The user could have
// switched to another tab while waiting for the download to start.
mMainView.setDownloadListener(mDownloadListener);
- mMainView.setWebBackForwardListClient(mWebBackForwardListClient);
+ getWebViewClassic().setWebBackForwardListClient(mWebBackForwardListClient);
TabControl tc = mWebViewController.getTabControl();
if (tc != null && tc.getOnThumbnailUpdatedListener() != null) {
mMainView.setPictureListener(this);
}
- if (mSavedState != null) {
+ if (restore && (mSavedState != null)) {
+ restoreUserAgent();
WebBackForwardList restoredState
= mMainView.restoreState(mSavedState);
if (restoredState == null || restoredState.getSize() == 0) {
@@ -1566,7 +1567,7 @@ class Tab implements PictureListener {
if (mMainView != null) {
dismissSubWindow();
// Make sure the embedded title bar isn't still attached
- mMainView.setEmbeddedTitleBar(null);
+ getWebViewClassic().setEmbeddedTitleBar(null);
// save the WebView to call destroy() after detach it from the tab
WebView webView = mMainView;
setWebView(null);
@@ -1779,6 +1780,15 @@ class Tab implements PictureListener {
return mMainView;
}
+ /**
+ * Return the underlying WebViewClassic implementation. As with getWebView,
+ * this maybe null for background tabs.
+ * @return The main WebView of this tab.
+ */
+ WebViewClassic getWebViewClassic() {
+ return WebViewClassic.fromWebView(mMainView);
+ }
+
void setViewContainer(View container) {
mContainer = container;
}
@@ -2001,10 +2011,7 @@ class Tab implements PictureListener {
mId = b.getLong(ID);
mAppId = b.getString(APPID);
mCloseOnBack = b.getBoolean(CLOSEFLAG);
- if (b.getBoolean(USERAGENT)
- != mSettings.hasDesktopUseragent(getWebView())) {
- mSettings.toggleDesktopUseragent(getWebView());
- }
+ restoreUserAgent();
String url = b.getString(CURRURL);
String title = b.getString(CURRTITLE);
boolean incognito = b.getBoolean(INCOGNITO);
@@ -2017,6 +2024,16 @@ class Tab implements PictureListener {
}
}
+ private void restoreUserAgent() {
+ if (mMainView == null || mSavedState == null) {
+ return;
+ }
+ if (mSavedState.getBoolean(USERAGENT)
+ != mSettings.hasDesktopUseragent(mMainView)) {
+ mSettings.toggleDesktopUseragent(mMainView);
+ }
+ }
+
public void updateBookmarkedStatus() {
mDataController.queryBookmarkStatus(getUrl(), mIsBookmarkCallback);
}
@@ -2047,7 +2064,7 @@ class Tab implements PictureListener {
SnapshotByteArrayOutputStream bos = new SnapshotByteArrayOutputStream();
try {
GZIPOutputStream stream = new GZIPOutputStream(bos);
- if (!mMainView.saveViewState(stream)) {
+ if (!getWebViewClassic().saveViewState(stream)) {
return null;
}
stream.flush();
@@ -2061,7 +2078,7 @@ class Tab implements PictureListener {
values.put(Snapshots.TITLE, mCurrentState.mTitle);
values.put(Snapshots.URL, mCurrentState.mUrl);
values.put(Snapshots.VIEWSTATE, data);
- values.put(Snapshots.BACKGROUND, mMainView.getPageBackgroundColor());
+ values.put(Snapshots.BACKGROUND, getWebViewClassic().getPageBackgroundColor());
values.put(Snapshots.DATE_CREATED, System.currentTimeMillis());
values.put(Snapshots.FAVICON, compressBitmap(getFavicon()));
Bitmap screenshot = Controller.createScreenshot(mMainView,
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index d549ac347..bd17c747e 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -31,10 +31,7 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Shader;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.PaintDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -253,7 +250,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
ImageView mLock;
ImageView mClose;
boolean mSelected;
- boolean mInLoad;
Path mPath;
Path mFocusPath;
int[] mWindowPos;
@@ -281,7 +277,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
mIncognito = mTabContent.findViewById(R.id.incognito);
mSnapshot = mTabContent.findViewById(R.id.snapshot);
mSelected = false;
- mInLoad = false;
// update the status
updateFromTab();
}
@@ -299,7 +294,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
displayTitle = mTab.getUrl();
}
setDisplayTitle(displayTitle);
- setProgress(mTab.getLoadProgress());
if (mTab.getFavicon() != null) {
setFavicon(mUi.getFaviconDrawable(mTab.getFavicon()));
}
@@ -352,16 +346,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
}
}
- void setProgress(int newProgress) {
- if (newProgress >= PROGRESS_MAX) {
- mInLoad = false;
- } else {
- if (!mInLoad && getWindowToken() != null) {
- mInLoad = true;
- }
- }
- }
-
private void closeTab() {
if (mTab == mTabControl.getCurrentTab()) {
mUiController.closeCurrentTab();
@@ -503,10 +487,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
public void onSetActiveTab(Tab tab) {
mTabs.setSelectedTab(mTabControl.getTabPosition(tab));
- TabView tv = mTabMap.get(tab);
- if (tv != null) {
- tv.setProgress(tv.mTab.getLoadProgress());
- }
}
public void onFavicon(Tab tab, Bitmap favicon) {
@@ -521,13 +501,6 @@ public class TabBar extends LinearLayout implements OnClickListener {
animateTabIn(tab, tv);
}
- public void onProgress(Tab tab, int progress) {
- TabView tv = mTabMap.get(tab);
- if (tv != null) {
- tv.setProgress(progress);
- }
- }
-
public void onRemoveTab(Tab tab) {
TabView tv = mTabMap.get(tab);
if (tv != null) {
@@ -550,9 +523,9 @@ public class TabBar extends LinearLayout implements OnClickListener {
}
private boolean isLoading() {
- TabView tv = mTabMap.get(mTabControl.getCurrentTab());
- if (tv != null) {
- return tv.mInLoad;
+ Tab tab = mTabControl.getCurrentTab();
+ if (tab != null) {
+ return tab.inPageLoad();
} else {
return false;
}
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 0668b7445..993cd1138 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -613,7 +613,7 @@ class TabControl {
}
// Create a new WebView. If this tab is the current tab, we need to put
// back all the clients so force it to be the current tab.
- t.setWebView(createNewWebView());
+ t.setWebView(createNewWebView(), false);
if (getCurrentTab() == t) {
setCurrentTab(t, true);
}
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index c828df420..46149aace 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -36,6 +36,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient.CustomViewCallback;
import android.webkit.WebView;
+import android.webkit.WebViewClassic;
import java.util.List;
@@ -93,7 +94,7 @@ public class XLargeUi extends BaseUi {
mPieControl.attachToContainer(mContentView);
WebView web = getWebView();
if (web != null) {
- web.setEmbeddedTitleBar(null);
+ WebViewClassic.fromWebView(web).setEmbeddedTitleBar(null);
}
} else {
@@ -107,7 +108,7 @@ public class XLargeUi extends BaseUi {
ViewGroup p = (ViewGroup) mTitleBar.getParent();
p.removeView(mTitleBar);
}
- web.setEmbeddedTitleBar(mTitleBar);
+ WebViewClassic.fromWebView(web).setEmbeddedTitleBar(mTitleBar);
}
setTitleGravity(Gravity.NO_GRAVITY);
}
@@ -133,6 +134,7 @@ public class XLargeUi extends BaseUi {
public void onResume() {
super.onResume();
mNavBar.clearCompletions();
+ checkTabCount();
}
@Override
@@ -143,7 +145,7 @@ public class XLargeUi extends BaseUi {
void stopWebViewScrolling() {
BrowserWebView web = (BrowserWebView) mUiController.getCurrentWebView();
if (web != null) {
- web.stopScroll();
+ WebViewClassic.fromWebView(web).stopScroll();
}
}
@@ -162,9 +164,15 @@ public class XLargeUi extends BaseUi {
@Override
public void onProgressChanged(Tab tab) {
int progress = tab.getLoadProgress();
- mTabBar.onProgress(tab, progress);
if (tab.inForeground()) {
mTitleBar.setProgress(progress);
+ if (mUseQuickControls) {
+ if (progress == 100) {
+ mTitleBar.setShowProgressOnly(false);
+ } else if (!mTitleBar.isEditingUrl()) {
+ mTitleBar.setShowProgressOnly(true);
+ }
+ }
}
}
@@ -195,7 +203,7 @@ public class XLargeUi extends BaseUi {
} else {
// check if title bar is already attached by animation
if (mTitleBar.getParent() == null) {
- view.setEmbeddedTitleBar(mTitleBar);
+ WebViewClassic.fromWebView(view).setEmbeddedTitleBar(mTitleBar);
}
}
mTabBar.onSetActiveTab(tab);
diff --git a/src/com/android/browser/homepages/HomeProvider.java b/src/com/android/browser/homepages/HomeProvider.java
index 98fcfbef8..49ae6944f 100644
--- a/src/com/android/browser/homepages/HomeProvider.java
+++ b/src/com/android/browser/homepages/HomeProvider.java
@@ -16,8 +16,6 @@
*/
package com.android.browser.homepages;
-import com.android.browser.BrowserSettings;
-
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
@@ -28,8 +26,13 @@ import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.webkit.WebResourceResponse;
+import com.android.browser.BrowserSettings;
+
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
public class HomeProvider extends ContentProvider {
@@ -95,8 +98,27 @@ public class HomeProvider extends ContentProvider {
return new WebResourceResponse("text/html", "utf-8", ins);
}
}
+ boolean listFiles = BrowserSettings.getInstance().isDebugEnabled();
+ if (listFiles && interceptFile(url)) {
+ PipedInputStream ins = new PipedInputStream();
+ PipedOutputStream outs = new PipedOutputStream(ins);
+ new RequestHandler(context, Uri.parse(url), outs).start();
+ return new WebResourceResponse("text/html", "utf-8", ins);
+ }
} catch (Exception e) {}
return null;
}
+ private static boolean interceptFile(String url) {
+ if (!url.startsWith("file:///")) {
+ return false;
+ }
+ String fpath = url.substring(7);
+ File f = new File(fpath);
+ if (!f.isDirectory()) {
+ return false;
+ }
+ return true;
+ }
+
}
diff --git a/src/com/android/browser/homepages/RequestHandler.java b/src/com/android/browser/homepages/RequestHandler.java
index defda612d..b3a03b9d7 100644
--- a/src/com/android/browser/homepages/RequestHandler.java
+++ b/src/com/android/browser/homepages/RequestHandler.java
@@ -20,17 +20,23 @@ import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
+import android.database.MergeCursor;
import android.net.Uri;
-import android.provider.Browser;
+import android.provider.BrowserContract.Bookmarks;
+import android.provider.BrowserContract.History;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.android.browser.R;
+import com.android.browser.homepages.Template.ListEntityIterator;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.text.DateFormat;
+import java.text.DecimalFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -69,6 +75,10 @@ public class RequestHandler extends Thread {
}
void doHandleRequest() throws IOException {
+ if ("file".equals(mUri.getScheme())) {
+ writeFolderIndex();
+ return;
+ }
int match = sUriMatcher.match(mUri);
switch (match) {
case INDEX:
@@ -84,11 +94,33 @@ public class RequestHandler extends Thread {
return TextUtils.htmlEncode(s).getBytes();
}
+ // We can reuse this for both History and Bookmarks queries because the
+ // columns defined actually belong to the CommonColumn and ImageColumn
+ // interfaces that both History and Bookmarks implement
+ private static final String[] PROJECTION = new String[] {
+ History.URL,
+ History.TITLE,
+ History.THUMBNAIL
+ };
+ private static final String SELECTION = History.URL
+ + " NOT LIKE 'content:%' AND " + History.THUMBNAIL + " IS NOT NULL";
void writeTemplatedIndex() throws IOException {
Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);
- Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI,
- new String[] { "DISTINCT url", "title", "thumbnail" },
- "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12");
+ Cursor historyResults = mContext.getContentResolver().query(
+ History.CONTENT_URI, PROJECTION, SELECTION,
+ null, History.VISITS + " DESC LIMIT 12");
+ Cursor cursor = historyResults;
+ if (cursor.getCount() < 12) {
+ Cursor bookmarkResults = mContext.getContentResolver().query(
+ Bookmarks.CONTENT_URI, PROJECTION, SELECTION,
+ null, Bookmarks.DATE_CREATED + " DESC LIMIT 12");
+ cursor = new MergeCursor(new Cursor[] { historyResults, bookmarkResults }) {
+ @Override
+ public int getCount() {
+ return Math.min(12, super.getCount());
+ }
+ };
+ }
t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) {
@Override
@@ -108,6 +140,71 @@ public class RequestHandler extends Thread {
t.write(mOutput);
}
+ void writeFolderIndex() throws IOException {
+ File f = new File(mUri.getPath());
+ final File[] files = f.listFiles();
+ Template t = Template.getCachedTemplate(mContext, R.raw.folder_view);
+ t.assign("path", mUri.getPath());
+ t.assign("parent_url", f.getParent() != null ? f.getParent() : f.getPath());
+ t.assignLoop("files", new ListEntityIterator() {
+ int index = -1;
+
+ @Override
+ public void writeValue(OutputStream stream, String key) throws IOException {
+ File f = files[index];
+ if ("name".equals(key)) {
+ stream.write(f.getName().getBytes());
+ }
+ if ("url".equals(key)) {
+ stream.write(("file://" + f.getAbsolutePath()).getBytes());
+ }
+ if ("type".equals(key)) {
+ stream.write((f.isDirectory() ? "dir" : "file").getBytes());
+ }
+ if ("size".equals(key)) {
+ if (f.isFile()) {
+ stream.write(readableFileSize(f.length()).getBytes());
+ }
+ }
+ if ("last_modified".equals(key)) {
+ String date = DateFormat.getDateTimeInstance(
+ DateFormat.SHORT, DateFormat.SHORT)
+ .format(f.lastModified());
+ stream.write(date.getBytes());
+ }
+ if ("alt".equals(key)) {
+ if (index % 2 == 0) {
+ stream.write("alt".getBytes());
+ }
+ }
+ }
+
+ @Override
+ public ListEntityIterator getListIterator(String key) {
+ return null;
+ }
+
+ @Override
+ public void reset() {
+ index = -1;
+ }
+
+ @Override
+ public boolean moveToNext() {
+ return (++index) < files.length;
+ }
+ });
+ t.write(mOutput);
+ }
+
+ static String readableFileSize(long size) {
+ if(size <= 0) return "0";
+ final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
+ int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
+ return new DecimalFormat("#,##0.#").format(
+ size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
+ }
+
String getUriResourcePath() {
final Pattern pattern = Pattern.compile("/?res/([\\w/]+)");
Matcher m = pattern.matcher(mUri.getPath());
diff --git a/src/com/android/browser/preferences/BandwidthPreferencesFragment.java b/src/com/android/browser/preferences/BandwidthPreferencesFragment.java
index 2c147ccba..0cb064abb 100644
--- a/src/com/android/browser/preferences/BandwidthPreferencesFragment.java
+++ b/src/com/android/browser/preferences/BandwidthPreferencesFragment.java
@@ -16,9 +16,11 @@
package com.android.browser.preferences;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
import com.android.browser.BrowserSettings;
import com.android.browser.PreferenceKeys;
@@ -38,15 +40,24 @@ public class BandwidthPreferencesFragment extends PreferenceFragment {
@Override
public void onResume() {
super.onResume();
- if (!getPreferenceScreen().getSharedPreferences()
- .contains(PreferenceKeys.PREF_DATA_PRELOAD)) {
+ PreferenceScreen prefScreen = getPreferenceScreen();
+ SharedPreferences sharedPrefs = prefScreen.getSharedPreferences();
+ if (!sharedPrefs.contains(PreferenceKeys.PREF_DATA_PRELOAD)) {
// set default value for preload setting
- ListPreference preload = (ListPreference) getPreferenceScreen().findPreference(
+ ListPreference preload = (ListPreference) prefScreen.findPreference(
PreferenceKeys.PREF_DATA_PRELOAD);
if (preload != null) {
preload.setValue(BrowserSettings.getInstance().getDefaultPreloadSetting());
}
}
+ if (!sharedPrefs.contains(PreferenceKeys.PREF_LINK_PREFETCH)) {
+ // set default value for link prefetch setting
+ ListPreference prefetch = (ListPreference) prefScreen.findPreference(
+ PreferenceKeys.PREF_LINK_PREFETCH);
+ if (prefetch != null) {
+ prefetch.setValue(BrowserSettings.getInstance().getDefaultLinkPrefetchSetting());
+ }
+ }
}
}
diff --git a/src/com/android/browser/preferences/FontSizePreview.java b/src/com/android/browser/preferences/FontSizePreview.java
index 91ecb0010..8825f3d85 100644
--- a/src/com/android/browser/preferences/FontSizePreview.java
+++ b/src/com/android/browser/preferences/FontSizePreview.java
@@ -54,7 +54,7 @@ public class FontSizePreview extends WebViewPreview {
}
@Override
- protected void updatePreview() {
+ protected void updatePreview(boolean forceReload) {
if (mWebView == null) return;
WebSettings ws = mWebView.getSettings();
diff --git a/src/com/android/browser/preferences/InvertedContrastPreview.java b/src/com/android/browser/preferences/InvertedContrastPreview.java
index c290daf93..ed6eadf3c 100644
--- a/src/com/android/browser/preferences/InvertedContrastPreview.java
+++ b/src/com/android/browser/preferences/InvertedContrastPreview.java
@@ -19,7 +19,8 @@ package com.android.browser.preferences;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.webkit.WebSettings;
+import android.webkit.WebSettingsClassic;
+import android.webkit.WebViewClassic;
import com.android.browser.BrowserSettings;
import com.android.browser.WebViewProperties;
@@ -73,16 +74,18 @@ public class InvertedContrastPreview extends WebViewPreview {
}
@Override
- protected void updatePreview() {
+ protected void updatePreview(boolean forceReload) {
if (mWebView == null) return;
- WebSettings ws = mWebView.getSettings();
+ WebSettingsClassic ws = WebViewClassic.fromWebView(mWebView).getSettings();
BrowserSettings bs = BrowserSettings.getInstance();
ws.setProperty(WebViewProperties.gfxInvertedScreen,
bs.useInvertedRendering() ? "true" : "false");
ws.setProperty(WebViewProperties.gfxInvertedScreenContrast,
Float.toString(bs.getInvertedContrast()));
- mWebView.loadData(mHtml, "text/html", null);
+ if (forceReload) {
+ mWebView.loadData(mHtml, "text/html", null);
+ }
}
}
diff --git a/src/com/android/browser/preferences/WebViewPreview.java b/src/com/android/browser/preferences/WebViewPreview.java
index a3c19a45f..1f938f051 100644
--- a/src/com/android/browser/preferences/WebViewPreview.java
+++ b/src/com/android/browser/preferences/WebViewPreview.java
@@ -53,7 +53,7 @@ public abstract class WebViewPreview extends Preference
setLayoutResource(R.layout.webview_preview);
}
- protected abstract void updatePreview();
+ protected abstract void updatePreview(boolean forceReload);
protected void setupWebView(WebView view) {}
@@ -77,7 +77,7 @@ public abstract class WebViewPreview extends Preference
protected void onBindView(View view) {
super.onBindView(view);
mWebView = (WebView) view.findViewById(R.id.webview);
- updatePreview();
+ updatePreview(true);
}
@Override
@@ -95,7 +95,7 @@ public abstract class WebViewPreview extends Preference
@Override
public void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
- updatePreview();
+ updatePreview(false);
}
}
diff --git a/src/com/android/browser/preferences/WebsiteSettingsFragment.java b/src/com/android/browser/preferences/WebsiteSettingsFragment.java
index 92cc62f31..da06428f5 100644
--- a/src/com/android/browser/preferences/WebsiteSettingsFragment.java
+++ b/src/com/android/browser/preferences/WebsiteSettingsFragment.java
@@ -75,10 +75,10 @@ public class WebsiteSettingsFragment extends ListFragment implements OnClickList
// They must be consecutive. To add a new feature, add a new FEATURE_XXX
// variable with value equal to the current value of FEATURE_COUNT, then
// increment FEATURE_COUNT.
- private final static int FEATURE_WEB_STORAGE = 0;
- private final static int FEATURE_GEOLOCATION = 1;
+ final static int FEATURE_WEB_STORAGE = 0;
+ final static int FEATURE_GEOLOCATION = 1;
// The number of features available.
- private final static int FEATURE_COUNT = 2;
+ final static int FEATURE_COUNT = 2;
public Site(String origin) {
mOrigin = origin;
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index 06ace20f9..6121abc3a 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -386,6 +386,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
static final int DATABASE_VERSION = 32;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ setWriteAheadLoggingEnabled(true);
}
@Override
@@ -624,7 +625,6 @@ public class BrowserProvider2 extends SQLiteContentProvider {
}
public void onOpen(SQLiteDatabase db) {
- db.enableWriteAheadLogging();
mSyncHelper.onDatabaseOpened(db);
}
@@ -697,6 +697,8 @@ public class BrowserProvider2 extends SQLiteContentProvider {
}
}
} catch (ArrayIndexOutOfBoundsException e) {
+ } finally {
+ preloads.recycle();
}
}
diff --git a/src/com/android/browser/view/BasePieView.java b/src/com/android/browser/view/BasePieView.java
index ec02e3a68..b9178be07 100644
--- a/src/com/android/browser/view/BasePieView.java
+++ b/src/com/android/browser/view/BasePieView.java
@@ -109,7 +109,8 @@ public abstract class BasePieView implements PieMenu.PieView {
* needs to set top, left, width, height
*/
@Override
- public void layout(int anchorX, int anchorY, boolean left, float angle) {
+ public void layout(int anchorX, int anchorY, boolean left, float angle,
+ int parentHeight) {
if (mListener != null) {
mListener.onLayout(anchorX, anchorY, left);
}
diff --git a/src/com/android/browser/view/PieListView.java b/src/com/android/browser/view/PieListView.java
index 04b512b17..1043fc772 100644
--- a/src/com/android/browser/view/PieListView.java
+++ b/src/com/android/browser/view/PieListView.java
@@ -39,13 +39,17 @@ public class PieListView extends BasePieView {
* this will be called before the first draw call
*/
@Override
- public void layout(int anchorX, int anchorY, boolean left, float angle) {
- super.layout(anchorX, anchorY, left, angle);
+ public void layout(int anchorX, int anchorY, boolean left, float angle,
+ int pHeight) {
+ super.layout(anchorX, anchorY, left, angle, pHeight);
buildViews();
mWidth = mChildWidth;
mHeight = mChildHeight * mAdapter.getCount();
mLeft = anchorX + (left ? 0 : - mChildWidth);
- mTop = anchorY - mHeight / 2;
+ mTop = Math.max(anchorY - mHeight / 2, 0);
+ if (mTop + mHeight > pHeight) {
+ mTop = pHeight - mHeight;
+ }
if (mViews != null) {
layoutChildrenLinear();
}
diff --git a/src/com/android/browser/view/PieMenu.java b/src/com/android/browser/view/PieMenu.java
index 536ac92fd..7f8dd6b8d 100644
--- a/src/com/android/browser/view/PieMenu.java
+++ b/src/com/android/browser/view/PieMenu.java
@@ -60,7 +60,8 @@ public class PieMenu extends FrameLayout {
public void setLayoutListener(OnLayoutListener l);
- public void layout(int anchorX, int anchorY, boolean onleft, float angle);
+ public void layout(int anchorX, int anchorY, boolean onleft, float angle,
+ int parentHeight);
public void draw(Canvas c);
@@ -383,7 +384,7 @@ public class PieMenu extends FrameLayout {
}
private void layoutPieView(PieView pv, int x, int y, float angle) {
- pv.layout(x, y, onTheLeft(), angle);
+ pv.layout(x, y, onTheLeft(), angle, getHeight());
}
/**
diff --git a/src/com/android/browser/view/PieStackView.java b/src/com/android/browser/view/PieStackView.java
index ca641f9b4..16d42cbcc 100644
--- a/src/com/android/browser/view/PieStackView.java
+++ b/src/com/android/browser/view/PieStackView.java
@@ -59,8 +59,9 @@ public class PieStackView extends BasePieView {
* this will be called before the first draw call
*/
@Override
- public void layout(int anchorX, int anchorY, boolean left, float angle) {
- super.layout(anchorX, anchorY, left, angle);
+ public void layout(int anchorX, int anchorY, boolean left, float angle,
+ int pHeight) {
+ super.layout(anchorX, anchorY, left, angle, pHeight);
buildViews();
mWidth = mChildWidth;
mHeight = mChildHeight + (mViews.size() - 1) * mMinHeight;
@@ -84,7 +85,7 @@ public class PieStackView extends BasePieView {
@Override
public void draw(Canvas canvas) {
- if (mViews != null) {
+ if ((mViews != null) && (mCurrent > -1)) {
final int n = mViews.size();
for (int i = 0; i < mCurrent; i++) {
drawView(mViews.get(i), canvas);