diff options
author | Michael Kolb <kolby@google.com> | 2011-07-01 09:00:37 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-07-01 09:00:37 -0700 |
commit | 36afb9b00d7c1e91331bacbd67724a593b26ac0b (patch) | |
tree | c8ceb7ebcba02f6b2ab07877b1ca475412ca784f /src | |
parent | 61b138b21da1549a967ee398e42de2f20511d897 (diff) | |
parent | 1461244018a225006a8d4c203f9dfe294ffe94fa (diff) | |
download | packages_apps_Browser-36afb9b00d7c1e91331bacbd67724a593b26ac0b.zip packages_apps_Browser-36afb9b00d7c1e91331bacbd67724a593b26ac0b.tar.gz packages_apps_Browser-36afb9b00d7c1e91331bacbd67724a593b26ac0b.tar.bz2 |
Merge "Preloading support in browser"
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/browser/BaseUi.java | 37 | ||||
-rw-r--r-- | src/com/android/browser/Browser.java | 1 | ||||
-rw-r--r-- | src/com/android/browser/BrowserActivity.java | 1 | ||||
-rw-r--r-- | src/com/android/browser/BrowserSettings.java | 7 | ||||
-rw-r--r-- | src/com/android/browser/BrowserWebViewFactory.java | 69 | ||||
-rw-r--r-- | src/com/android/browser/Controller.java | 31 | ||||
-rw-r--r-- | src/com/android/browser/IntentHandler.java | 34 | ||||
-rw-r--r-- | src/com/android/browser/PreferenceKeys.java | 5 | ||||
-rw-r--r-- | src/com/android/browser/PreloadController.java | 224 | ||||
-rw-r--r-- | src/com/android/browser/PreloadRequestReceiver.java | 82 | ||||
-rw-r--r-- | src/com/android/browser/Preloader.java | 137 | ||||
-rw-r--r-- | src/com/android/browser/SnapshotTab.java | 2 | ||||
-rw-r--r-- | src/com/android/browser/Tab.java | 71 | ||||
-rw-r--r-- | src/com/android/browser/TabControl.java | 8 | ||||
-rw-r--r-- | src/com/android/browser/WebViewController.java | 5 | ||||
-rw-r--r-- | src/com/android/browser/XLargeUi.java | 23 | ||||
-rw-r--r-- | src/com/android/browser/preferences/BandwidthPreferencesFragment.java | 39 |
17 files changed, 678 insertions, 98 deletions
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java index 3ab0098..e577b1b 100644 --- a/src/com/android/browser/BaseUi.java +++ b/src/com/android/browser/BaseUi.java @@ -60,7 +60,7 @@ import java.util.List; /** * UI interface definitions */ -public abstract class BaseUi implements UI, WebViewFactory, OnTouchListener { +public abstract class BaseUi implements UI, OnTouchListener { private static final String LOGTAG = "BaseUi"; @@ -143,41 +143,6 @@ public abstract class BaseUi implements UI, WebViewFactory, OnTouchListener { config.getScaledTouchSlop()); } - @Override - public WebView createWebView(boolean privateBrowsing) { - // Create a new WebView - BrowserWebView w = new BrowserWebView(mActivity, null, - android.R.attr.webViewStyle, privateBrowsing); - initWebViewSettings(w); - return w; - } - - @Override - public WebView createSubWebView(boolean privateBrowsing) { - return createWebView(privateBrowsing); - } - - /** - * common webview initialization - * @param w the webview to initialize - */ - protected void initWebViewSettings(WebView w) { - w.setScrollbarFadingEnabled(true); - w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); - w.setMapTrackballToArrowKeys(false); // use trackball directly - // Enable the built-in zoom - w.getSettings().setBuiltInZoomControls(true); - boolean supportsMultiTouch = mActivity.getPackageManager() - .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH); - w.getSettings().setDisplayZoomControls(!supportsMultiTouch); - w.setExpandedTileBounds(true); // smoother scrolling - - // Add this WebView to the settings observer list and update the - // settings - final BrowserSettings s = BrowserSettings.getInstance(); - s.startManagingSettings(w.getSettings()); - } - private void cancelStopToast() { if (mStopToast != null) { mStopToast.cancel(); diff --git a/src/com/android/browser/Browser.java b/src/com/android/browser/Browser.java index 6fceaff..c4412e2 100644 --- a/src/com/android/browser/Browser.java +++ b/src/com/android/browser/Browser.java @@ -61,6 +61,7 @@ public class Browser extends Application { // create CookieSyncManager with current Context CookieSyncManager.createInstance(this); BrowserSettings.initialize(getApplicationContext()); + Preloader.initialize(getApplicationContext()); } static Intent createBrowserViewIntent() { diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java index dbcae2e..13b8b06 100644 --- a/src/com/android/browser/BrowserActivity.java +++ b/src/com/android/browser/BrowserActivity.java @@ -92,7 +92,6 @@ public class BrowserActivity extends Activity { mUi = new PhoneUi(this, mController); } mController.setUi(mUi); - mController.setWebViewFactory((BaseUi) mUi); Bundle state = getIntent().getBundleExtra(EXTRA_STATE); if (state != null && icicle == null) { diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java index 4928e61..3a6349a 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -689,4 +689,11 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, return mPrefs.getBoolean(PREF_REMEMBER_PASSWORDS, true); } + // ----------------------------- + // getter/setters for bandwidth_preferences.xml + // ----------------------------- + + public boolean isPreloadEnabled() { + return mPrefs.getBoolean(PREF_DATA_PRELOAD, false); + } } diff --git a/src/com/android/browser/BrowserWebViewFactory.java b/src/com/android/browser/BrowserWebViewFactory.java new file mode 100644 index 0000000..fbd26a9 --- /dev/null +++ b/src/com/android/browser/BrowserWebViewFactory.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.util.AttributeSet; +import android.view.View; +import android.webkit.WebView; + +/** + * Web view factory class for creating {@link BrowserWebView}'s. + */ +public class BrowserWebViewFactory implements WebViewFactory { + + private final Context mContext; + + public BrowserWebViewFactory(Context context) { + mContext = context; + } + + protected WebView instantiateWebView(AttributeSet attrs, int defStyle, + boolean privateBrowsing) { + return new BrowserWebView(mContext, attrs, defStyle, privateBrowsing); + } + + @Override + public WebView createSubWebView(boolean privateBrowsing) { + return createWebView(privateBrowsing); + } + + @Override + public WebView createWebView(boolean privateBrowsing) { + WebView w = instantiateWebView(null, android.R.attr.webViewStyle, privateBrowsing); + initWebViewSettings(w); + return w; + } + + protected void initWebViewSettings(WebView w) { + w.setScrollbarFadingEnabled(true); + w.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); + w.setMapTrackballToArrowKeys(false); // use trackball directly + // Enable the built-in zoom + w.getSettings().setBuiltInZoomControls(true); + boolean supportsMultiTouch = mContext.getPackageManager() + .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH); + w.getSettings().setDisplayZoomControls(!supportsMultiTouch); + w.setExpandedTileBounds(true); // smoother scrolling + + // Add this WebView to the settings observer list and update the + // settings + final BrowserSettings s = BrowserSettings.getInstance(); + s.startManagingSettings(w.getSettings()); + } + +} diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java index 447e61b..9046745 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -229,6 +229,7 @@ public class Controller mTabControl = new TabControl(this); mSettings.setController(this); mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this); + mFactory = new BrowserWebViewFactory(browser); mUrlHandler = new UrlHandler(this); mIntentHandler = new IntentHandler(mActivity, this); @@ -312,7 +313,7 @@ public class Controller // 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 = mIntentHandler.getUrlDataFromIntent(intent); + UrlData urlData = IntentHandler.getUrlDataFromIntent(intent); Tab t = null; if (urlData.isEmpty()) { t = openTabToHomePage(); @@ -356,10 +357,6 @@ public class Controller } } - void setWebViewFactory(WebViewFactory factory) { - mFactory = factory; - } - @Override public WebViewFactory getWebViewFactory() { return mFactory; @@ -381,6 +378,11 @@ public class Controller } @Override + public Context getContext() { + return mActivity; + } + + @Override public Activity getActivity() { return mActivity; } @@ -1637,6 +1639,7 @@ public class Controller return id; } + @Override protected void onPostExecute(Long id) { if (id > 0) { createNewSnapshotTab(id, true); @@ -2247,11 +2250,19 @@ public class Controller // open a non inconito tab with the given url data // and set as active tab public Tab openTab(UrlData urlData) { - Tab tab = createNewTab(false, true, true); - if ((tab != null) && !urlData.isEmpty()) { - loadUrlDataIn(tab, urlData); + if (urlData.isPreloaded()) { + Tab tab = urlData.getPreloadedTab(); + tab.getWebView().clearHistory(); + mTabControl.addPreloadedTab(tab); + setActiveTab(tab); + return tab; + } else { + Tab tab = createNewTab(false, true, true); + if ((tab != null) && !urlData.isEmpty()) { + loadUrlDataIn(tab, urlData); + } + return tab; } - return tab; } @Override @@ -2417,6 +2428,8 @@ public class Controller if (data != null) { if (data.mVoiceIntent != null) { t.activateVoiceSearchMode(data.mVoiceIntent); + } else if (data.isPreloaded()) { + // this isn't called for preloaded tabs } else { loadUrl(t, data.mUrl, data.mHeaders); } diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java index 088a788..a99164a 100644 --- a/src/com/android/browser/IntentHandler.java +++ b/src/com/android/browser/IntentHandler.java @@ -135,8 +135,14 @@ public class IntentHandler { urlData = new UrlData(mSettings.getHomePage()); } - if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false)) { - mController.openTab(urlData); + if (intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false) + || urlData.isPreloaded()) { + Tab t = mController.openTab(urlData); + if (t == null && urlData.isPreloaded()) { + Tab pre = urlData.getPreloadedTab(); + // TODO: check if we need to stop loading + pre.destroy(); + } return; } /* @@ -220,9 +226,10 @@ public class IntentHandler { } } - protected UrlData getUrlDataFromIntent(Intent intent) { + protected static UrlData getUrlDataFromIntent(Intent intent) { String url = ""; Map<String, String> headers = null; + Tab preloaded = null; if (intent != null && (intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) == 0) { final String action = intent.getAction(); @@ -241,6 +248,10 @@ public class IntentHandler { } } } + if (intent.hasExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID)) { + String id = intent.getStringExtra(PreloadRequestReceiver.EXTRA_PRELOAD_ID); + preloaded = Preloader.getInstance().getPreloadedTab(id); + } } else if (Intent.ACTION_SEARCH.equals(action) || MediaStore.INTENT_ACTION_MEDIA_SEARCH.equals(action) || Intent.ACTION_WEB_SEARCH.equals(action)) { @@ -265,7 +276,7 @@ public class IntentHandler { } } } - return new UrlData(url, headers, intent); + return new UrlData(url, headers, intent, preloaded); } /** @@ -348,14 +359,20 @@ public class IntentHandler { final String mUrl; final Map<String, String> mHeaders; final Intent mVoiceIntent; + final Tab mPreloadedTab; UrlData(String url) { this.mUrl = url; this.mHeaders = null; this.mVoiceIntent = null; + this.mPreloadedTab = null; } UrlData(String url, Map<String, String> headers, Intent intent) { + this(url, headers, intent, null); + } + + UrlData(String url, Map<String, String> headers, Intent intent, Tab preloaded) { this.mUrl = url; this.mHeaders = headers; if (RecognizerResultsIntent.ACTION_VOICE_SEARCH_RESULTS @@ -364,11 +381,20 @@ public class IntentHandler { } else { this.mVoiceIntent = null; } + mPreloadedTab = preloaded; } boolean isEmpty() { return mVoiceIntent == null && (mUrl == null || mUrl.length() == 0); } + + boolean isPreloaded() { + return mPreloadedTab != null; + } + + Tab getPreloadedTab() { + return mPreloadedTab; + } } } diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java index bc8d38f..144d505 100644 --- a/src/com/android/browser/PreferenceKeys.java +++ b/src/com/android/browser/PreferenceKeys.java @@ -94,4 +94,9 @@ public interface PreferenceKeys { static final String PREF_SAVE_FORMDATA = "save_formdata"; static final String PREF_SHOW_SECURITY_WARNINGS = "show_security_warnings"; + // ---------------------- + // Keys for bandwidth_preferences.xml + // ---------------------- + static final String PREF_DATA_PRELOAD = "preload_enabled"; + } diff --git a/src/com/android/browser/PreloadController.java b/src/com/android/browser/PreloadController.java new file mode 100644 index 0000000..6528410 --- /dev/null +++ b/src/com/android/browser/PreloadController.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.browser; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.net.http.SslError; +import android.os.Message; +import android.view.KeyEvent; +import android.view.View; +import android.webkit.HttpAuthHandler; +import android.webkit.SslErrorHandler; +import android.webkit.ValueCallback; +import android.webkit.WebChromeClient.CustomViewCallback; +import android.webkit.WebView; + +import java.util.List; + +public class PreloadController implements WebViewController { + + private Context mContext; + + public PreloadController(Context ctx) { + mContext = ctx; + + } + + @Override + public Context getContext() { + return mContext; + } + + @Override + public Activity getActivity() { + return null; + } + + @Override + public TabControl getTabControl() { + return null; + } + + @Override + public WebViewFactory getWebViewFactory() { + return null; + } + + @Override + public void onSetWebView(Tab tab, WebView view) { + } + + @Override + public void createSubWindow(Tab tab) { + } + + @Override + public void onPageStarted(Tab tab, WebView view, Bitmap favicon) { + } + + @Override + public void onPageFinished(Tab tab) { + } + + @Override + public void onProgressChanged(Tab tab) { + } + + @Override + public void onReceivedTitle(Tab tab, String title) { + } + + @Override + public void onFavicon(Tab tab, WebView view, Bitmap icon) { + } + + @Override + public boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) { + return false; + } + + @Override + public boolean shouldOverrideKeyEvent(KeyEvent event) { + return false; + } + + @Override + public void onUnhandledKeyEvent(KeyEvent event) { + } + + @Override + public void doUpdateVisitedHistory(Tab tab, boolean isReload) { + } + + @Override + public void getVisitedHistory(ValueCallback<String[]> callback) { + } + + @Override + public void onReceivedHttpAuthRequest(Tab tab, WebView view, + HttpAuthHandler handler, String host, + String realm) { + } + + @Override + public void onDownloadStart(Tab tab, String url, String useragent, + String contentDisposition, String mimeType, + long contentLength) { + } + + @Override + public void showCustomView(Tab tab, View view, int requestedOrientation, + CustomViewCallback callback) { + } + + @Override + public void hideCustomView() { + } + + @Override + public Bitmap getDefaultVideoPoster() { + return null; + } + + @Override + public View getVideoLoadingProgressView() { + return null; + } + + @Override + public void showSslCertificateOnError(WebView view, + SslErrorHandler handler, SslError error) { + } + + @Override + public void onUserCanceledSsl(Tab tab) { + } + + @Override + public void activateVoiceSearchMode(String title, List<String> results) { + } + + @Override + public void revertVoiceSearchMode(Tab tab) { + } + + @Override + public boolean shouldShowErrorConsole() { + return false; + } + + @Override + public void onUpdatedLockIcon(Tab tab) { + } + + @Override + public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { + } + + @Override + public void endActionMode() { + } + + @Override + public void attachSubWindow(Tab tab) { + } + + @Override + public void dismissSubWindow(Tab tab) { + } + + @Override + public Tab openTab(String url, boolean incognito, boolean setActive, + boolean useCurrent) { + return null; + } + + @Override + public Tab openTab(String url, Tab parent, boolean setActive, + boolean useCurrent) { + return null; + } + + @Override + public boolean switchToTab(Tab tab) { + return false; + } + + @Override + public void closeTab(Tab tab) { + } + + @Override + public void setupAutoFill(Message message) { + } + + @Override + public void bookmarkedStatusHasChanged(Tab tab) { + } + + @Override + public void showAutoLogin(Tab tab) { + } + + @Override + public void hideAutoLogin(Tab tab) { + } + +} diff --git a/src/com/android/browser/PreloadRequestReceiver.java b/src/com/android/browser/PreloadRequestReceiver.java new file mode 100644 index 0000000..c86d660 --- /dev/null +++ b/src/com/android/browser/PreloadRequestReceiver.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.Browser; +import android.util.Log; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Broadcast receiver for receiving browser preload requests + */ +public class PreloadRequestReceiver extends BroadcastReceiver { + + private final static String LOGTAG = "browser.preloader"; + private final static boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED; + + private static final String ACTION_PRELOAD = "android.intent.action.PRELOAD"; + static final String EXTRA_PRELOAD_ID = "preload_id"; + static final String EXTRA_PRELOAD_DISCARD = "preload_discard"; + + @Override + public void onReceive(Context context, Intent intent) { + if (LOGD_ENABLED) Log.d(LOGTAG, "received intent " + intent); + if (BrowserSettings.getInstance().isPreloadEnabled() + && intent.getAction().equals(ACTION_PRELOAD)) { + handlePreload(context, intent); + } + } + + private void handlePreload(Context context, Intent i) { + String url = UrlUtils.smartUrlFilter(i.getData()); + String id = i.getStringExtra(EXTRA_PRELOAD_ID); + Map<String, String> headers = null; + if (id == null) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Preload request has no " + EXTRA_PRELOAD_ID); + return; + } + if (i.getBooleanExtra(EXTRA_PRELOAD_DISCARD, false)) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Got " + id + " preload discard request"); + Preloader.getInstance().discardPreload(id); + } else { + if (LOGD_ENABLED) Log.d(LOGTAG, "Got " + id + " preload request for " + url); + if (url != null && url.startsWith("http")) { + final Bundle pairs = i.getBundleExtra(Browser.EXTRA_HEADERS); + if (pairs != null && !pairs.isEmpty()) { + Iterator<String> iter = pairs.keySet().iterator(); + headers = new HashMap<String, String>(); + while (iter.hasNext()) { + String key = iter.next(); + headers.put(key, pairs.getString(key)); + } + } + } + if (url != null) { + Preloader.getInstance().handlePreloadRequest(id, url, headers); + } + } + } + +} diff --git a/src/com/android/browser/Preloader.java b/src/com/android/browser/Preloader.java new file mode 100644 index 0000000..5a5f687 --- /dev/null +++ b/src/com/android/browser/Preloader.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.browser; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.AttributeSet; +import android.util.Log; +import android.webkit.WebView; + +import java.util.HashMap; +import java.util.Map; + +/** + * Singleton class for handling preload requests. + */ +public class Preloader { + + private final static String LOGTAG = "browser.preloader"; + private final static boolean LOGD_ENABLED = true;//com.android.browser.Browser.LOGD_ENABLED; + + private static final int PRERENDER_TIMEOUT_MILLIS = 30 * 1000; // 30s + + private static Preloader sInstance; + + private final Context mContext; + private final Handler mHandler; + private final BrowserWebViewFactory mFactory; + private final HashMap<String, PreloaderSession> mSessions; + + public static void initialize(Context context) { + sInstance = new Preloader(context); + } + + public static Preloader getInstance() { + return sInstance; + } + + private Preloader(Context context) { + mContext = context; + mHandler = new Handler(Looper.getMainLooper()); + mSessions = new HashMap<String, PreloaderSession>(); + mFactory = new BrowserWebViewFactory(context); + + } + + private PreloaderSession getSession(String id) { + PreloaderSession s = mSessions.get(id); + if (s == null) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Create new preload session " + id); + s = new PreloaderSession(id); + mSessions.put(id, s); + } + return s; + } + + private PreloaderSession takeSession(String id) { + PreloaderSession s = mSessions.remove(id); + if (s != null) { + s.cancelTimeout(); + } + return s; + } + + public void handlePreloadRequest(String id, String url, Map<String, String> headers) { + PreloaderSession s = getSession(id); + s.touch(); // reset timer + if (LOGD_ENABLED) Log.d(LOGTAG, "Preloading " + url); + s.getTab().loadUrl(url, headers); + } + + public void discardPreload(String id) { + PreloaderSession s = takeSession(id); + if (s != null) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Discard preload session " + id); + Tab t = s.getTab(); + t.destroy(); + } + } + + /** + * Return a preloaded tab, and remove it from the preloader. This is used when the + * view is about to be displayed. + */ + public Tab getPreloadedTab(String id) { + PreloaderSession s = takeSession(id); + if (LOGD_ENABLED) Log.d(LOGTAG, "Showing preload session " + id + "=" + s); + return s == null ? null : s.getTab(); + } + + private class PreloaderSession { + private final String mId; + private final Tab mTab; + + private final Runnable mTimeoutTask = new Runnable(){ + @Override + public void run() { + if (LOGD_ENABLED) Log.d(LOGTAG, "Preload session timeout " + mId); + discardPreload(mId); + }}; + + public PreloaderSession(String id) { + mId = id; + mTab = new Tab(new PreloadController(mContext), mFactory.createWebView(false)); + touch(); + } + + public void cancelTimeout() { + mHandler.removeCallbacks(mTimeoutTask); + } + + public void touch() { + cancelTimeout(); + mHandler.postDelayed(mTimeoutTask, PRERENDER_TIMEOUT_MILLIS); + } + + public Tab getTab() { + return mTab; + } + + } + +} diff --git a/src/com/android/browser/SnapshotTab.java b/src/com/android/browser/SnapshotTab.java index 52a5c5f..adccdf3 100644 --- a/src/com/android/browser/SnapshotTab.java +++ b/src/com/android/browser/SnapshotTab.java @@ -76,7 +76,7 @@ public class SnapshotTab extends Tab { void loadData() { if (mLoadTask == null) { - mLoadTask = new LoadData(this, mActivity.getContentResolver()); + mLoadTask = new LoadData(this, mContext.getContentResolver()); mLoadTask.execute(); } } diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java index a705c07..334bd9d 100644 --- a/src/com/android/browser/Tab.java +++ b/src/com/android/browser/Tab.java @@ -92,7 +92,7 @@ class Tab { LOCK_ICON_MIXED, } - Activity mActivity; + Context mContext; protected WebViewController mWebViewController; // The tab ID @@ -304,7 +304,7 @@ class Tab { logIntent.putExtra( LoggingEvents.VoiceSearch.EXTRA_N_BEST_CHOOSE_INDEX, index); - mActivity.sendBroadcast(logIntent); + mContext.sendBroadcast(logIntent); } if (mVoiceSearchData.mVoiceSearchIntent != null) { // Copy the Intent, so that each history item will have its own @@ -487,7 +487,7 @@ class Tab { private void showError(ErrorDialog errDialog) { if (mInForeground) { - AlertDialog d = new AlertDialog.Builder(mActivity) + AlertDialog d = new AlertDialog.Builder(mContext) .setTitle(errDialog.mTitle) .setMessage(errDialog.mDescription) .setPositiveButton(R.string.ok, null) @@ -508,7 +508,7 @@ class Tab { public void onPageStarted(WebView view, String url, Bitmap favicon) { mInPageLoad = true; mPageLoadProgress = 0; - mCurrentState = new PageState(mActivity, + mCurrentState = new PageState(mContext, view.isPrivateBrowsingEnabled(), url, favicon); mLoadStartTime = SystemClock.uptimeMillis(); if (mVoiceSearchData != null @@ -516,7 +516,7 @@ class Tab { if (mVoiceSearchData.mSourceIsGoogle) { Intent i = new Intent(LoggingEvents.ACTION_LOG_EVENT); i.putExtra(LoggingEvents.EXTRA_FLUSH, true); - mActivity.sendBroadcast(i); + mContext.sendBroadcast(i); } revertVoiceSearchMode(); } @@ -587,7 +587,7 @@ class Tab { Intent logIntent = new Intent(LoggingEvents.ACTION_LOG_EVENT); logIntent.putExtra(LoggingEvents.EXTRA_EVENT, LoggingEvents.VoiceSearch.RESULT_CLICKED); - mActivity.sendBroadcast(logIntent); + mContext.sendBroadcast(logIntent); } if (mInForeground) { return mWebViewController.shouldOverrideUrlLoading(Tab.this, @@ -659,7 +659,7 @@ class Tab { } mDontResend = dontResend; mResend = resend; - new AlertDialog.Builder(mActivity).setTitle( + new AlertDialog.Builder(mContext).setTitle( R.string.browserFrameFormResubmitLabel).setMessage( R.string.browserFrameFormResubmitMessage) .setPositiveButton(R.string.ok, @@ -718,7 +718,7 @@ class Tab { } if (mSettings.showSecurityWarnings()) { final LayoutInflater factory = - LayoutInflater.from(mActivity); + LayoutInflater.from(mContext); final View warningsView = factory.inflate(R.layout.ssl_warnings, null); final LinearLayout placeholder = @@ -756,7 +756,7 @@ class Tab { placeholder.addView(ll); } - new AlertDialog.Builder(mActivity).setTitle( + new AlertDialog.Builder(mContext).setTitle( R.string.security_warning).setIcon( android.R.drawable.ic_dialog_alert).setView( warningsView).setPositiveButton(R.string.ssl_continue, @@ -817,13 +817,14 @@ class Tab { port = -1; } } - KeyChain.choosePrivateKeyAlias(mActivity, new KeyChainAliasCallback() { + KeyChain.choosePrivateKeyAlias( + mWebViewController.getActivity(), new KeyChainAliasCallback() { @Override public void alias(String alias) { if (alias == null) { handler.cancel(); return; } - new KeyChainLookup(mActivity, handler, alias).execute(); + new KeyChainLookup(mContext, handler, alias).execute(); } }, null, null, host, port, null); } @@ -846,7 +847,7 @@ class Tab { public WebResourceResponse shouldInterceptRequest(WebView view, String url) { WebResourceResponse res = HomeProvider.shouldInterceptRequest( - mActivity, url); + mContext, url); return res; } @@ -869,7 +870,7 @@ class Tab { @Override public void onReceivedLoginRequest(WebView view, String realm, String account, String args) { - new DeviceAccountLogin(mActivity, view, Tab.this, mWebViewController) + new DeviceAccountLogin(mWebViewController.getActivity(), view, Tab.this, mWebViewController) .handleLogin(realm, account, args); } @@ -916,7 +917,7 @@ class Tab { } // Short-circuit if we can't create any more tabs or sub windows. if (dialog && mSubView != null) { - new AlertDialog.Builder(mActivity) + new AlertDialog.Builder(mContext) .setTitle(R.string.too_many_subwindows_dialog_title) .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.too_many_subwindows_dialog_message) @@ -924,7 +925,7 @@ class Tab { .show(); return false; } else if (!mWebViewController.getTabControl().canCreateNewTab()) { - new AlertDialog.Builder(mActivity) + new AlertDialog.Builder(mContext) .setTitle(R.string.too_many_windows_dialog_title) .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.too_many_windows_dialog_message) @@ -958,7 +959,7 @@ class Tab { // Build a confirmation dialog to display to the user. final AlertDialog d = - new AlertDialog.Builder(mActivity) + new AlertDialog.Builder(mContext) .setTitle(R.string.attention) .setIcon(android.R.drawable.ic_dialog_alert) .setMessage(R.string.popup_window_attempt) @@ -1011,7 +1012,7 @@ class Tab { @Override public void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed) { - final ContentResolver cr = mActivity.getContentResolver(); + final ContentResolver cr = mContext.getContentResolver(); // Let precomposed icons take precedence over non-composed // icons. if (precomposed && mTouchIconLoader != null) { @@ -1021,7 +1022,7 @@ class Tab { // Have only one async task at a time. if (mTouchIconLoader == null) { mTouchIconLoader = new DownloadTouchIcon(Tab.this, - mActivity, cr, view); + mContext, cr, view); mTouchIconLoader.execute(url); } } @@ -1029,7 +1030,10 @@ class Tab { @Override public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) { - onShowCustomView(view, mActivity.getRequestedOrientation(), callback); + Activity activity = mWebViewController.getActivity(); + if (activity != null) { + onShowCustomView(view, activity.getRequestedOrientation(), callback); + } } @Override @@ -1202,8 +1206,8 @@ class Tab { public void setupAutoFill(Message message) { // Prompt the user to set up their profile. final Message msg = message; - AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService( + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( Context.LAYOUT_INFLATER_SERVICE); final View layout = inflater.inflate(R.layout.setup_autofill_dialog, null); @@ -1217,7 +1221,7 @@ class Tab { if (disableAutoFill.isChecked()) { // Disable autofill and show a toast with how to turn it on again. mSettings.setAutofillEnabled(false); - Toast.makeText(mActivity, + Toast.makeText(mContext, R.string.autofill_setup_dialog_negative_toast, Toast.LENGTH_LONG).show(); } else { @@ -1338,10 +1342,10 @@ class Tab { // Construct a new tab Tab(WebViewController wvcontroller, WebView w) { mWebViewController = wvcontroller; - mActivity = mWebViewController.getActivity(); + mContext = mWebViewController.getContext(); mSettings = BrowserSettings.getInstance(); - mDataController = DataController.getInstance(mActivity); - mCurrentState = new PageState(mActivity, w != null + mDataController = DataController.getInstance(mContext); + mCurrentState = new PageState(mContext, w != null ? w.isPrivateBrowsingEnabled() : false); mInPageLoad = false; mInForeground = false; @@ -1373,6 +1377,10 @@ class Tab { setWebView(w); } + public void setController(WebViewController ctl) { + mWebViewController = ctl; + } + public void setId(long id) { mId = id; } @@ -1468,7 +1476,7 @@ class Tab { } } }); - mSubView.setOnCreateContextMenuListener(mActivity); + mSubView.setOnCreateContextMenuListener(mWebViewController.getActivity()); return true; } return false; @@ -1558,9 +1566,10 @@ class Tab { void putInForeground() { mInForeground = true; resume(); - mMainView.setOnCreateContextMenuListener(mActivity); + Activity activity = mWebViewController.getActivity(); + mMainView.setOnCreateContextMenuListener(activity); if (mSubView != null) { - mSubView.setOnCreateContextMenuListener(mActivity); + mSubView.setOnCreateContextMenuListener(activity); } // Show the pending error dialog if the queue is not empty if (mQueuedErrors != null && mQueuedErrors.size() > 0) { @@ -1689,7 +1698,7 @@ class Tab { */ String getTitle() { if (mCurrentState.mTitle == null && mInPageLoad) { - return mActivity.getString(R.string.title_bar_loading); + return mContext.getString(R.string.title_bar_loading); } return mCurrentState.mTitle; } @@ -1715,7 +1724,7 @@ class Tab { */ ErrorConsoleView getErrorConsole(boolean createIfNecessary) { if (createIfNecessary && mErrorConsole == null) { - mErrorConsole = new ErrorConsoleView(mActivity); + mErrorConsole = new ErrorConsoleView(mContext); mErrorConsole.setWebView(mMainView); } return mErrorConsole; @@ -1881,7 +1890,7 @@ class Tab { public void loadUrl(String url, Map<String, String> headers) { if (mMainView != null) { - mCurrentState = new PageState(mActivity, false, url, null); + mCurrentState = new PageState(mContext, false, url, null); mWebViewController.onPageStarted(this, mMainView, null); mMainView.loadUrl(url, headers); } diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java index 2eb24e9..1110bda 100644 --- a/src/com/android/browser/TabControl.java +++ b/src/com/android/browser/TabControl.java @@ -176,6 +176,14 @@ class TabControl { return false; } + void addPreloadedTab(Tab tab) { + tab.setId(getNextId()); + mTabs.add(tab); + tab.setController(mController); + mController.onSetWebView(tab, tab.getWebView()); + tab.putInBackground(); + } + /** * Create a new tab. * @return The newly createTab or null if we have reached the maximum diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java index 018af99..175cbf8 100644 --- a/src/com/android/browser/WebViewController.java +++ b/src/com/android/browser/WebViewController.java @@ -17,6 +17,7 @@ package com.android.browser; import android.app.Activity; +import android.content.Context; import android.graphics.Bitmap; import android.net.Uri; import android.net.http.SslError; @@ -36,6 +37,8 @@ import java.util.List; */ public interface WebViewController { + Context getContext(); + Activity getActivity(); TabControl getTabControl(); @@ -72,7 +75,7 @@ public interface WebViewController { void onDownloadStart(Tab tab, String url, String useragent, String contentDisposition, String mimeType, long contentLength); - void showCustomView(Tab tab, View view, int requestedOrientation, + void showCustomView(Tab tab, View view, int requestedOrientation, WebChromeClient.CustomViewCallback callback); void hideCustomView(); diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java index 8b43a74..8455e74 100644 --- a/src/com/android/browser/XLargeUi.java +++ b/src/com/android/browser/XLargeUi.java @@ -70,6 +70,14 @@ public class XLargeUi extends BaseUi implements ScrollListener { } @Override + public void onSetWebView(Tab tab, WebView v) { + super.onSetWebView(tab, v); + if (v != null) { + ((BrowserWebView) v).setScrollListener(this); + } + } + + @Override public void showComboView(boolean startWithHistory, Bundle extras) { super.showComboView(startWithHistory, extras); if (mUseQuickControls) { @@ -135,21 +143,6 @@ public class XLargeUi extends BaseUi implements ScrollListener { hideTitleBar(); } - // webview factory - - @Override - public WebView createWebView(boolean privateBrowsing) { - // Create a new WebView - BrowserWebView w = (BrowserWebView) super.createWebView(privateBrowsing); - w.setScrollListener(this); - return w; - } - - @Override - public WebView createSubWebView(boolean privateBrowsing) { - return super.createWebView(privateBrowsing); - } - @Override public void onScroll(int visibleTitleHeight, boolean userInitiated) { mTabBar.onScroll(visibleTitleHeight, userInitiated); diff --git a/src/com/android/browser/preferences/BandwidthPreferencesFragment.java b/src/com/android/browser/preferences/BandwidthPreferencesFragment.java new file mode 100644 index 0000000..18b9fa4 --- /dev/null +++ b/src/com/android/browser/preferences/BandwidthPreferencesFragment.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.browser.preferences; + +import android.content.res.Resources; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceFragment; +import android.util.Log; + +import com.android.browser.PreferenceKeys; +import com.android.browser.R; + +public class BandwidthPreferencesFragment extends PreferenceFragment { + + static final String TAG = "BandwidthPreferencesFragment"; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // Load the XML preferences file + addPreferencesFromResource(R.xml.bandwidth_preferences); + } + +} |