diff options
author | Mathew Inwood <mathewi@google.com> | 2011-07-08 17:27:38 +0100 |
---|---|---|
committer | Mathew Inwood <mathewi@google.com> | 2011-07-14 11:40:04 +0100 |
commit | e1dbb956d762c3f07033f247c05270a9882a79a7 (patch) | |
tree | 9d22907dc6193e11628feef9dc56798e738f3a42 | |
parent | 629b22ce19f44e38ee470687cd2d9218d2066f85 (diff) | |
download | packages_apps_browser-e1dbb956d762c3f07033f247c05270a9882a79a7.zip packages_apps_browser-e1dbb956d762c3f07033f247c05270a9882a79a7.tar.gz packages_apps_browser-e1dbb956d762c3f07033f247c05270a9882a79a7.tar.bz2 |
SearchBox preloading fixes.
It now seems to work pretty reliably. Nice. Requires changes to SearchBox
API in frameworks/base:
Depends on change: If283ecdfa62aecb1fa697b1a2cd43b771b908d72
Change-Id: I5af94c8df8f24dfafb02c4052381aa547c72684c
-rw-r--r-- | src/com/android/browser/Controller.java | 9 | ||||
-rw-r--r-- | src/com/android/browser/GoogleAccountLogin.java | 2 | ||||
-rw-r--r-- | src/com/android/browser/InstantSearchEngine.java | 10 | ||||
-rw-r--r-- | src/com/android/browser/PreloadController.java | 49 | ||||
-rw-r--r-- | src/com/android/browser/PreloadedTabControl.java | 55 | ||||
-rw-r--r-- | src/com/android/browser/Preloader.java | 10 | ||||
-rw-r--r-- | src/com/android/browser/WebViewTimersControl.java | 91 |
7 files changed, 189 insertions, 37 deletions
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java index 5b00179..b495cc0 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -679,9 +679,7 @@ public class Controller if ((!mActivityPaused && !inLoad) || (mActivityPaused && inLoad)) { CookieSyncManager.getInstance().startSync(); WebView w = tab.getWebView(); - if (w != null) { - w.resumeTimers(); - } + WebViewTimersControl.getInstance().onBrowserActivityResume(w); } } @@ -695,10 +693,7 @@ public class Controller return true; } else if (!tab.inPageLoad()) { CookieSyncManager.getInstance().stopSync(); - WebView w = getCurrentWebView(); - if (w != null) { - w.pauseTimers(); - } + WebViewTimersControl.getInstance().onBrowserActivityPause(getCurrentWebView()); return true; } return false; diff --git a/src/com/android/browser/GoogleAccountLogin.java b/src/com/android/browser/GoogleAccountLogin.java index c7d1924..3b4f2aa 100644 --- a/src/com/android/browser/GoogleAccountLogin.java +++ b/src/com/android/browser/GoogleAccountLogin.java @@ -84,7 +84,7 @@ public class GoogleAccountLogin implements Runnable, // resumeWebViewTimers. So to avoid problems with timers not running, we // duplicate the work here using the off-screen WebView. CookieSyncManager.getInstance().startSync(); - mWebView.resumeTimers(); + WebViewTimersControl.getInstance().onBrowserActivityResume(mWebView); mWebView.setWebViewClient(new WebViewClient() { @Override diff --git a/src/com/android/browser/InstantSearchEngine.java b/src/com/android/browser/InstantSearchEngine.java index e2e9c8a..c913494 100644 --- a/src/com/android/browser/InstantSearchEngine.java +++ b/src/com/android/browser/InstantSearchEngine.java @@ -85,10 +85,10 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener mSearchBox.setQuery(query); mSearchBox.setVerbatim(true); - mSearchBox.onsubmit(); + mSearchBox.onsubmit(null); } - private final class BrowserSearchboxListener implements SearchBox.SearchBoxListener { + private final class BrowserSearchboxListener extends SearchBox.SearchBoxListener { /* * The maximum number of out of order suggestions we accept * before giving up the wait. @@ -253,7 +253,7 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener } mSearchBox.setDimensions(0, 0, 0, mHeight); - mSearchBox.onresize(); + mSearchBox.onresize(null); if (TextUtils.isEmpty(query)) { // To force the SRP to render an empty (no results) page. @@ -262,7 +262,7 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener mSearchBox.setVerbatim(false); } mSearchBox.setQuery(query); - mSearchBox.onchange(); + mSearchBox.onchange(null); // Don't bother waiting for suggestions for an empty query. We still // set the query so that the SRP clears itself. @@ -327,7 +327,7 @@ public class InstantSearchEngine implements SearchEngine, DropdownChangeListener mHeight = rescaledHeight; if (mSearchBox != null) { mSearchBox.setDimensions(0, 0, 0, rescaledHeight); - mSearchBox.onresize(); + mSearchBox.onresize(null); } } } diff --git a/src/com/android/browser/PreloadController.java b/src/com/android/browser/PreloadController.java index 6528410..11586ea 100644 --- a/src/com/android/browser/PreloadController.java +++ b/src/com/android/browser/PreloadController.java @@ -22,6 +22,7 @@ import android.graphics.Bitmap; import android.net.Uri; import android.net.http.SslError; import android.os.Message; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.webkit.HttpAuthHandler; @@ -34,6 +35,9 @@ import java.util.List; public class PreloadController implements WebViewController { + private static final boolean LOGD_ENABLED = false; + private static final String LOGTAG = "PreloadController"; + private Context mContext; public PreloadController(Context ctx) { @@ -48,177 +52,214 @@ public class PreloadController implements WebViewController { @Override public Activity getActivity() { + if (LOGD_ENABLED) Log.d(LOGTAG, "getActivity()"); return null; } @Override public TabControl getTabControl() { + if (LOGD_ENABLED) Log.d(LOGTAG, "getTabControl()"); return null; } @Override public WebViewFactory getWebViewFactory() { + if (LOGD_ENABLED) Log.d(LOGTAG, "getWebViewFactory()"); return null; } @Override public void onSetWebView(Tab tab, WebView view) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onSetWebView()"); } @Override public void createSubWindow(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "createSubWindow()"); } @Override public void onPageStarted(Tab tab, WebView view, Bitmap favicon) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onPageStarted()"); } @Override public void onPageFinished(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onPageFinished()"); } @Override public void onProgressChanged(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onProgressChanged()"); } @Override public void onReceivedTitle(Tab tab, String title) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onReceivedTitle()"); } @Override public void onFavicon(Tab tab, WebView view, Bitmap icon) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onFavicon()"); } @Override public boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) { + if (LOGD_ENABLED) Log.d(LOGTAG, "shouldOverrideUrlLoading()"); return false; } @Override public boolean shouldOverrideKeyEvent(KeyEvent event) { + if (LOGD_ENABLED) Log.d(LOGTAG, "shouldOverrideKeyEvent()"); return false; } @Override public void onUnhandledKeyEvent(KeyEvent event) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onUnhandledKeyEvent()"); } @Override public void doUpdateVisitedHistory(Tab tab, boolean isReload) { + if (LOGD_ENABLED) Log.d(LOGTAG, "doUpdateVisitedHistory()"); } @Override public void getVisitedHistory(ValueCallback<String[]> callback) { + if (LOGD_ENABLED) Log.d(LOGTAG, "getVisitedHistory()"); } @Override public void onReceivedHttpAuthRequest(Tab tab, WebView view, HttpAuthHandler handler, String host, String realm) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onReceivedHttpAuthRequest()"); } @Override public void onDownloadStart(Tab tab, String url, String useragent, String contentDisposition, String mimeType, long contentLength) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onDownloadStart()"); } @Override public void showCustomView(Tab tab, View view, int requestedOrientation, CustomViewCallback callback) { + if (LOGD_ENABLED) Log.d(LOGTAG, "showCustomView()"); } @Override public void hideCustomView() { + if (LOGD_ENABLED) Log.d(LOGTAG, "hideCustomView()"); } @Override public Bitmap getDefaultVideoPoster() { + if (LOGD_ENABLED) Log.d(LOGTAG, "getDefaultVideoPoster()"); return null; } @Override public View getVideoLoadingProgressView() { + if (LOGD_ENABLED) Log.d(LOGTAG, "getVideoLoadingProgressView()"); return null; } @Override public void showSslCertificateOnError(WebView view, SslErrorHandler handler, SslError error) { + if (LOGD_ENABLED) Log.d(LOGTAG, "showSslCertificateOnError()"); } @Override public void onUserCanceledSsl(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onUserCanceledSsl()"); } @Override public void activateVoiceSearchMode(String title, List<String> results) { + if (LOGD_ENABLED) Log.d(LOGTAG, "activateVoiceSearchMode()"); } @Override public void revertVoiceSearchMode(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "revertVoiceSearchMode()"); } @Override public boolean shouldShowErrorConsole() { + if (LOGD_ENABLED) Log.d(LOGTAG, "shouldShowErrorConsole()"); return false; } @Override public void onUpdatedLockIcon(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onUpdatedLockIcon()"); } @Override public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) { + if (LOGD_ENABLED) Log.d(LOGTAG, "openFileChooser()"); } @Override public void endActionMode() { + if (LOGD_ENABLED) Log.d(LOGTAG, "endActionMode()"); } @Override public void attachSubWindow(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "attachSubWindow()"); } @Override public void dismissSubWindow(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "dismissSubWindow()"); } @Override - public Tab openTab(String url, boolean incognito, boolean setActive, - boolean useCurrent) { + public Tab openTab(String url, boolean incognito, boolean setActive, boolean useCurrent) { + if (LOGD_ENABLED) Log.d(LOGTAG, "openTab()"); return null; } @Override - public Tab openTab(String url, Tab parent, boolean setActive, - boolean useCurrent) { + public Tab openTab(String url, Tab parent, boolean setActive, boolean useCurrent) { + if (LOGD_ENABLED) Log.d(LOGTAG, "openTab()"); return null; } @Override public boolean switchToTab(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "switchToTab()"); return false; } @Override public void closeTab(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "closeTab()"); } @Override public void setupAutoFill(Message message) { + if (LOGD_ENABLED) Log.d(LOGTAG, "setupAutoFill()"); } @Override public void bookmarkedStatusHasChanged(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "bookmarkedStatusHasChanged()"); } @Override public void showAutoLogin(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "showAutoLogin()"); } @Override public void hideAutoLogin(Tab tab) { + if (LOGD_ENABLED) Log.d(LOGTAG, "hideAutoLogin()"); } } diff --git a/src/com/android/browser/PreloadedTabControl.java b/src/com/android/browser/PreloadedTabControl.java index 99592fb..d2482a4 100644 --- a/src/com/android/browser/PreloadedTabControl.java +++ b/src/com/android/browser/PreloadedTabControl.java @@ -15,6 +15,7 @@ */ package com.android.browser; +import android.net.Uri; import android.text.TextUtils; import android.util.Log; import android.webkit.SearchBox; @@ -25,7 +26,7 @@ import java.util.Map; * Class to manage the controlling of preloaded tab. */ public class PreloadedTabControl { - private static final boolean LOGD_ENABLED = true;//com.android.browser.Browser.LOGD_ENABLED; + private static final boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED; private static final String LOGTAG = "PreloadedTabControl"; final Tab mTab; @@ -33,17 +34,26 @@ public class PreloadedTabControl { private boolean mDestroyed; public PreloadedTabControl(Tab t) { + if (LOGD_ENABLED) Log.d(LOGTAG, "PreloadedTabControl.<init>"); mTab = t; } - private void maybeSetQuery(String query, SearchBox sb) { + private void maybeSetQuery(final String query, SearchBox sb) { if (!TextUtils.equals(mLastQuery, query)) { if (sb != null) { if (LOGD_ENABLED) Log.d(LOGTAG, "Changing searchbox query to " + query); sb.setVerbatim(true); sb.setQuery(query); - sb.onchange(); - mLastQuery = query; + sb.onchange(new SearchBox.SearchBoxListener() { + @Override + public void onChangeComplete(boolean called) { + if (mDestroyed) return; + if (LOGD_ENABLED) Log.d(LOGTAG, "Changed searchbox query: " + called); + if (called) { + mLastQuery = query; + } + } + }); } else { if (LOGD_ENABLED) Log.d(LOGTAG, "Cannot set query: no searchbox interface"); } @@ -62,30 +72,34 @@ public class PreloadedTabControl { if (LOGD_ENABLED) Log.d(LOGTAG, "No searchbox, cannot submit query"); return false; } - sb.isSupported(new SearchBox.IsSupportedCallback() { + maybeSetQuery(query, sb); + if (LOGD_ENABLED) Log.d(LOGTAG, "Submitting query " + query); + sb.onsubmit(new SearchBox.SearchBoxListener() { @Override - public void searchBoxIsSupported(boolean supported) { - if (LOGD_ENABLED) Log.d(LOGTAG, "SearchBox supported: " + supported); - if (mDestroyed) { - if (LOGD_ENABLED) Log.d(LOGTAG, "tab has been destroyed"); - return; - } - if (supported) { - maybeSetQuery(query, sb); - if (LOGD_ENABLED) Log.d(LOGTAG, "Submitting query " + query); - sb.onsubmit(); - } else { - if (LOGD_ENABLED) Log.d(LOGTAG, "SearchBox not supported; falling back"); + public void onSubmitComplete(boolean called) { + if (mDestroyed) return; + if (LOGD_ENABLED) Log.d(LOGTAG, "Query submitted: " + called); + if (!called) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Query not submitted; falling back"); loadUrl(fallbackUrl, fallbackHeaders); } mTab.getWebView().clearHistory(); - } - }); + }}); return true; } public void loadUrlIfChanged(String url, Map<String, String> headers) { - if (!TextUtils.equals(url, mTab.getUrl())) { + String currentUrl = mTab.getUrl(); + if (!TextUtils.isEmpty(currentUrl)) { + try { + // remove fragment: + currentUrl = Uri.parse(currentUrl).buildUpon().fragment(null).build().toString(); + } catch (UnsupportedOperationException e) { + // carry on + } + } + if (LOGD_ENABLED) Log.d(LOGTAG, "loadUrlIfChanged\nnew: " + url + "\nold: " +currentUrl); + if (!TextUtils.equals(url, currentUrl)) { loadUrl(url, headers); } } @@ -96,6 +110,7 @@ public class PreloadedTabControl { } public void destroy() { + if (LOGD_ENABLED) Log.d(LOGTAG, "PreloadedTabControl.destroy"); mDestroyed = true; mTab.destroy(); } diff --git a/src/com/android/browser/Preloader.java b/src/com/android/browser/Preloader.java index 336b77a..bc84523 100644 --- a/src/com/android/browser/Preloader.java +++ b/src/com/android/browser/Preloader.java @@ -19,6 +19,7 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; import android.util.Log; +import android.webkit.WebView; import java.util.HashMap; import java.util.Map; @@ -62,6 +63,7 @@ public class Preloader { if (LOGD_ENABLED) Log.d(LOGTAG, "Create new preload session " + id); s = new PreloaderSession(id); mSessions.put(id, s); + WebViewTimersControl.getInstance().onPrerenderStart(s.getWebView()); } return s; } @@ -71,6 +73,9 @@ public class Preloader { if (s != null) { s.cancelTimeout(); } + if (mSessions.size() == 0) { + WebViewTimersControl.getInstance().onPrerenderDone(s == null ? null : s.getWebView()); + } return s; } @@ -139,6 +144,11 @@ public class Preloader { return mTabControl; } + public WebView getWebView() { + Tab t = mTabControl.getTab(); + return t == null? null : t.getWebView(); + } + } } diff --git a/src/com/android/browser/WebViewTimersControl.java b/src/com/android/browser/WebViewTimersControl.java new file mode 100644 index 0000000..d6d1726 --- /dev/null +++ b/src/com/android/browser/WebViewTimersControl.java @@ -0,0 +1,91 @@ +/* + * 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.os.Looper; +import android.util.Log; +import android.webkit.WebView; + +/** + * Centralised point for controlling WebView timers pausing and resuming. + * + * All methods on this class should only be called from the UI thread. + */ +public class WebViewTimersControl { + + private static final boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED; + private static final String LOGTAG = "WebViewTimersControl"; + + private static WebViewTimersControl sInstance; + + private boolean mBrowserActive; + private boolean mPrerenderActive; + + /** + * Get the static instance. Must be called from UI thread. + */ + public static WebViewTimersControl getInstance() { + if (Looper.myLooper() != Looper.getMainLooper()) { + throw new IllegalStateException("WebViewTimersControl.get() called on wrong thread"); + } + if (sInstance == null) { + sInstance = new WebViewTimersControl(); + } + return sInstance; + } + + private WebViewTimersControl() { + } + + private void resumeTimers(WebView wv) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Resuming webview timers, view=" + wv); + if (wv != null) { + wv.resumeTimers(); + } + } + + private void maybePauseTimers(WebView wv) { + if (!mBrowserActive && !mPrerenderActive && wv != null) { + if (LOGD_ENABLED) Log.d(LOGTAG, "Pausing webview timers, view=" + wv); + wv.pauseTimers(); + } + } + + public void onBrowserActivityResume(WebView wv) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onBrowserActivityResume"); + mBrowserActive = true; + resumeTimers(wv); + } + + public void onBrowserActivityPause(WebView wv) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onBrowserActivityPause"); + mBrowserActive = false; + maybePauseTimers(wv); + } + + public void onPrerenderStart(WebView wv) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onPrerenderStart"); + mPrerenderActive = true; + resumeTimers(wv); + } + + public void onPrerenderDone(WebView wv) { + if (LOGD_ENABLED) Log.d(LOGTAG, "onPrerenderDone"); + mPrerenderActive = false; + maybePauseTimers(wv); + } + +} |