diff options
Diffstat (limited to 'src')
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); |
