summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathew Inwood <mathewi@google.com>2011-07-08 17:27:38 +0100
committerMathew Inwood <mathewi@google.com>2011-07-14 11:40:04 +0100
commite1dbb956d762c3f07033f247c05270a9882a79a7 (patch)
tree9d22907dc6193e11628feef9dc56798e738f3a42
parent629b22ce19f44e38ee470687cd2d9218d2066f85 (diff)
downloadpackages_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.java9
-rw-r--r--src/com/android/browser/GoogleAccountLogin.java2
-rw-r--r--src/com/android/browser/InstantSearchEngine.java10
-rw-r--r--src/com/android/browser/PreloadController.java49
-rw-r--r--src/com/android/browser/PreloadedTabControl.java55
-rw-r--r--src/com/android/browser/Preloader.java10
-rw-r--r--src/com/android/browser/WebViewTimersControl.java91
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);
+ }
+
+}