Merge "Remove unused strings."
diff --git a/Android.mk b/Android.mk
index 537ad60..6e20ab8 100644
--- a/Android.mk
+++ b/Android.mk
@@ -4,11 +4,10 @@
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-common \
- gsf-client
+ android-common
LOCAL_SRC_FILES := \
- $(call all-subdir-java-files) \
+ $(call all-java-files-under, src) \
src/com/android/browser/EventLogTags.logtags
LOCAL_PACKAGE_NAME := Browser
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark.png b/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark.png
index f861650..7b2c680 100644
--- a/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark.png
+++ b/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark_icon.png b/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark_icon.png
new file mode 100644
index 0000000..57fc915
--- /dev/null
+++ b/res/drawable-hdpi/ic_launcher_shortcut_browser_bookmark_icon.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_launcher_shortcut_browser_bookmark_icon.png b/res/drawable-mdpi/ic_launcher_shortcut_browser_bookmark_icon.png
new file mode 100644
index 0000000..ba82911
--- /dev/null
+++ b/res/drawable-mdpi/ic_launcher_shortcut_browser_bookmark_icon.png
Binary files differ
diff --git a/res/layout/title_bar.xml b/res/layout/title_bar.xml
index d619d6b..f5c6d6d 100644
--- a/res/layout/title_bar.xml
+++ b/res/layout/title_bar.xml
@@ -76,9 +76,11 @@
android:id="@+id/rt_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
- android:layout_marginLeft="6dip"
+ android:layout_marginLeft="-2dip"
+ android:layout_marginTop="-6.5dip"
+ android:layout_marginBottom="-2dip"
+ android:layout_marginRight="-5dip"
android:scaleType="center"
- android:layout_marginBottom="4dip"
android:background="@drawable/btn_bookmark"
android:src="@drawable/ic_btn_bookmarks"
/>
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index fc337f9..f860b1f 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -73,6 +73,7 @@
import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Patterns;
import android.view.ContextMenu;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -110,12 +111,9 @@
import android.accounts.OperationCanceledException;
import android.accounts.AccountManagerCallback;
-import com.android.common.Patterns;
import com.android.common.Search;
import com.android.common.speech.LoggingEvents;
-import com.google.android.gsf.GoogleLoginServiceConstants;
-
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
@@ -157,13 +155,20 @@
private Account[] mAccountsGoogle;
private Account[] mAccountsPreferHosted;
+ // XXX: These constants should be exposed through some public api. Hardcode
+ // the values for now until some solution for gsf can be worked out.
+ // http://b/issue?id=2425179
+ private static final String ACCOUNT_TYPE = "com.google";
+ private static final String FEATURE_LEGACY_GOOGLE = "legacy_google";
+ private static final String FEATURE_LEGACY_HOSTED_OR_GOOGLE =
+ "legacy_hosted_or_google";
+
private void startReadOfGoogleAccounts() {
mAccountsGoogle = null;
mAccountsPreferHosted = null;
AccountManager.get(this).getAccountsByTypeAndFeatures(
- GoogleLoginServiceConstants.ACCOUNT_TYPE,
- new String[]{GoogleLoginServiceConstants.FEATURE_LEGACY_HOSTED_OR_GOOGLE},
+ ACCOUNT_TYPE, new String[]{ FEATURE_LEGACY_HOSTED_OR_GOOGLE },
this, null);
}
@@ -174,8 +179,7 @@
mAccountsGoogle = accountManagerFuture.getResult();
AccountManager.get(this).getAccountsByTypeAndFeatures(
- GoogleLoginServiceConstants.ACCOUNT_TYPE,
- new String[]{GoogleLoginServiceConstants.FEATURE_LEGACY_GOOGLE},
+ ACCOUNT_TYPE, new String[]{ FEATURE_LEGACY_GOOGLE },
this, null);
} else {
mAccountsPreferHosted = accountManagerFuture.getResult();
@@ -2149,7 +2153,7 @@
resetTitleIconAndProgress();
}
- private void goBackOnePageOrQuit() {
+ /* package */ void goBackOnePageOrQuit() {
Tab current = mTabControl.getCurrentTab();
if (current == null) {
/*
@@ -2461,7 +2465,7 @@
* an {@link Intent} to launch the Activity chooser.
* @param c Context used to launch a new Activity.
* @param title Title of the page. Stored in the Intent with
- * {@link Browser#EXTRA_SHARE_TITLE}
+ * {@link Intent#EXTRA_SUBJECT}
* @param url URL of the page. Stored in the Intent with
* {@link Intent#EXTRA_TEXT}
* @param favicon Bitmap of the favicon for the page. Stored in the Intent
@@ -2474,7 +2478,7 @@
Intent send = new Intent(Intent.ACTION_SEND);
send.setType("text/plain");
send.putExtra(Intent.EXTRA_TEXT, url);
- send.putExtra(Browser.EXTRA_SHARE_TITLE, title);
+ send.putExtra(Intent.EXTRA_SUBJECT, title);
send.putExtra(Browser.EXTRA_SHARE_FAVICON, favicon);
send.putExtra(Browser.EXTRA_SHARE_SCREENSHOT, screenshot);
try {
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index d835f84..1183b70 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -30,6 +30,7 @@
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.net.Uri;
import android.os.Bundle;
@@ -445,7 +446,7 @@
R.drawable.ic_launcher_shortcut_browser_bookmark));
} else {
Bitmap icon = BitmapFactory.decodeResource(getResources(),
- R.drawable.ic_launcher_shortcut_browser_bookmark);
+ R.drawable.ic_launcher_shortcut_browser_bookmark_icon);
// Make a copy of the regular icon so we can modify the pixels.
Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
@@ -458,13 +459,22 @@
p.setStyle(Paint.Style.FILL_AND_STROKE);
p.setColor(Color.WHITE);
- float density = getResources().getDisplayMetrics().density;
+ final float density =
+ getResources().getDisplayMetrics().density;
// Create a rectangle that is slightly wider than the favicon
final float iconSize = 16 * density; // 16x16 favicon
- final float padding = 2; // white padding around icon
+ final float padding = 2 * density; // white padding around icon
final float rectSize = iconSize + 2 * padding;
- final float y = icon.getHeight() - rectSize;
- RectF r = new RectF(0, y, rectSize, y + rectSize);
+
+ final Rect iconBounds =
+ new Rect(0, 0, icon.getWidth(), icon.getHeight());
+ final float x = iconBounds.exactCenterX() - (rectSize / 2);
+ // Note: Subtract 2 dip from the y position since the box is
+ // slightly higher than center. Use padding since it is already
+ // 2 * density.
+ final float y = iconBounds.exactCenterY() - (rectSize / 2)
+ - padding;
+ RectF r = new RectF(x, y, x + rectSize, y + rectSize);
// Draw a white rounded rectangle behind the favicon
canvas.drawRoundRect(r, 2, 2, p);
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index dda5765..94d7eca 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -46,12 +46,10 @@
import android.speech.RecognizerResultsIntent;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Patterns;
import android.util.TypedValue;
import android.webkit.GeolocationPermissions;
-import com.android.common.Patterns;
-
-import com.google.android.gsf.GoogleSettingsContract.Partner;
import java.io.File;
import java.io.FilenameFilter;
@@ -181,13 +179,32 @@
public BrowserProvider() {
}
+ // XXX: This is a major hack to remove our dependency on gsf constants and
+ // its content provider. http://b/issue?id=2425179
+ static String getClientId(ContentResolver cr) {
+ String ret = "android-google";
+ Cursor c = null;
+ try {
+ c = cr.query(Uri.parse("content://com.google.settings/partner"),
+ new String[] { "value" }, "name='client_id'", null, null);
+ if (c != null && c.moveToNext()) {
+ ret = c.getString(0);
+ }
+ } catch (RuntimeException ex) {
+ // fall through to return the default
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return ret;
+ }
private static CharSequence replaceSystemPropertyInString(Context context, CharSequence srcString) {
StringBuffer sb = new StringBuffer();
int lastCharLoc = 0;
- final String client_id = Partner.getString(context.getContentResolver(),
- Partner.CLIENT_ID, "android-google");
+ final String client_id = getClientId(context.getContentResolver());
for (int i = 0; i < srcString.length(); ++i) {
char c = srcString.charAt(i);
@@ -1056,18 +1073,14 @@
throw new IllegalArgumentException("Unknown URL");
}
- String id = null;
- boolean isBookmarkTable = (match == URI_MATCH_BOOKMARKS_ID);
- boolean changingBookmarks = false;
-
- if (isBookmarkTable || match == URI_MATCH_SEARCHES_ID) {
+ if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_SEARCHES_ID) {
StringBuilder sb = new StringBuilder();
if (where != null && where.length() > 0) {
sb.append("( ");
sb.append(where);
sb.append(" ) AND ");
}
- id = url.getPathSegments().get(1);
+ String id = url.getPathSegments().get(1);
sb.append("_id = ");
sb.append(id);
where = sb.toString();
@@ -1078,23 +1091,23 @@
// Not all bookmark-table updates should be backed up. Look to see
// whether we changed the title, url, or "is a bookmark" state, and
// request a backup if so.
- if (isBookmarkTable) {
+ if (match == URI_MATCH_BOOKMARKS_ID || match == URI_MATCH_BOOKMARKS) {
+ boolean changingBookmarks = false;
// Alterations to the bookmark field inherently change the bookmark
// set, so we don't need to query the record; we know a priori that
// we will need to back up this change.
if (values.containsKey(BookmarkColumns.BOOKMARK)) {
changingBookmarks = true;
- }
- // changing the title or URL of a bookmark record requires a backup,
- // but we don't know wether such an update is on a bookmark without
- // querying the record
- if (!changingBookmarks &&
- (values.containsKey(BookmarkColumns.TITLE)
- || values.containsKey(BookmarkColumns.URL))) {
- // when isBookmarkTable is true, the 'id' var was assigned above
+ } else if ((values.containsKey(BookmarkColumns.TITLE)
+ || values.containsKey(BookmarkColumns.URL))
+ && values.containsKey(BookmarkColumns._ID)) {
+ // If a title or URL has been changed, check to see if it is to
+ // a bookmark. The ID should have been included in the update,
+ // so use it.
Cursor cursor = cr.query(Browser.BOOKMARKS_URI,
new String[] { BookmarkColumns.BOOKMARK },
- "_id = " + id, null, null);
+ BookmarkColumns._ID + " = "
+ + values.getAsString(BookmarkColumns._ID), null, null);
if (cursor.moveToNext()) {
changingBookmarks = (cursor.getInt(0) != 0);
}
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 1e282c6..fbff0fa 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -17,8 +17,6 @@
package com.android.browser;
-import com.google.android.gsf.GoogleSettingsContract.Partner;
-
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -578,8 +576,8 @@
private String getFactoryResetHomeUrl(Context context) {
String url = context.getResources().getString(R.string.homepage_base);
if (url.indexOf("{CID}") != -1) {
- url = url.replace("{CID}", Partner.getString(context
- .getContentResolver(), Partner.CLIENT_ID, "android-google"));
+ url = url.replace("{CID}",
+ BrowserProvider.getClientId(context.getContentResolver()));
}
return url;
}
diff --git a/src/com/android/browser/DownloadTouchIcon.java b/src/com/android/browser/DownloadTouchIcon.java
index 22ed73c..e2d4594 100644
--- a/src/com/android/browser/DownloadTouchIcon.java
+++ b/src/com/android/browser/DownloadTouchIcon.java
@@ -22,11 +22,11 @@
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.provider.Browser;
import android.webkit.WebView;
-import com.android.common.AndroidHttpClient;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
diff --git a/src/com/android/browser/FetchUrlMimeType.java b/src/com/android/browser/FetchUrlMimeType.java
index 9e34736..1e4debf 100644
--- a/src/com/android/browser/FetchUrlMimeType.java
+++ b/src/com/android/browser/FetchUrlMimeType.java
@@ -18,7 +18,7 @@
import android.content.ContentValues;
import android.net.Uri;
-import com.android.common.AndroidHttpClient;
+import android.net.http.AndroidHttpClient;
import org.apache.http.HttpResponse;
import org.apache.http.Header;
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index afd9b09..512f2b7 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -48,6 +48,7 @@
import android.view.View.OnClickListener;
import android.webkit.ConsoleMessage;
import android.webkit.CookieSyncManager;
+import android.webkit.DownloadListener;
import android.webkit.GeolocationPermissions;
import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
@@ -123,6 +124,9 @@
private final LayoutInflater mInflateService;
// The BrowserActivity which owners the Tab
private final BrowserActivity mActivity;
+ // The listener that gets invoked when a download is started from the
+ // mMainView
+ private final DownloadListener mDownloadListener;
// AsyncTask for downloading touch icons
DownloadTouchIcon mTouchIconLoader;
@@ -1224,6 +1228,27 @@
(GeolocationPermissionsPrompt) mContainer.findViewById(
R.id.geolocation_permissions_prompt);
+ mDownloadListener = new DownloadListener() {
+ public void onDownloadStart(String url, String userAgent,
+ String contentDisposition, String mimetype,
+ long contentLength) {
+ mActivity.onDownloadStart(url, userAgent, contentDisposition,
+ mimetype, contentLength);
+ if (mMainView.copyBackForwardList().getSize() == 0) {
+ // This Tab was opened for the sole purpose of downloading a
+ // file. Remove it.
+ if (mActivity.getTabControl().getCurrentWebView()
+ == mMainView) {
+ // In this case, the Tab is still on top.
+ mActivity.goBackOnePageOrQuit();
+ } else {
+ // In this case, it is not.
+ mActivity.closeTab(Tab.this);
+ }
+ }
+ }
+ };
+
setWebView(w);
}
@@ -1246,10 +1271,15 @@
// set the new one
mMainView = w;
- // attached the WebViewClient and WebChromeClient
+ // attach the WebViewClient, WebChromeClient and DownloadListener
if (mMainView != null) {
mMainView.setWebViewClient(mWebViewClient);
mMainView.setWebChromeClient(mWebChromeClient);
+ // Attach DownloadManager so that downloads can start in an active
+ // or a non-active window. This can happen when going to a site that
+ // 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);
}
}
@@ -1297,7 +1327,21 @@
mSubView.setWebViewClient(new SubWindowClient(mWebViewClient));
mSubView.setWebChromeClient(new SubWindowChromeClient(
mWebChromeClient));
- mSubView.setDownloadListener(mActivity);
+ // Set a different DownloadListener for the mSubView, since it will
+ // just need to dismiss the mSubView, rather than close the Tab
+ mSubView.setDownloadListener(new DownloadListener() {
+ public void onDownloadStart(String url, String userAgent,
+ String contentDisposition, String mimetype,
+ long contentLength) {
+ mActivity.onDownloadStart(url, userAgent,
+ contentDisposition, mimetype, contentLength);
+ if (mSubView.copyBackForwardList().getSize() == 0) {
+ // This subwindow was opened for the sole purpose of
+ // downloading a file. Remove it.
+ dismissSubWindow();
+ }
+ }
+ });
mSubView.setOnCreateContextMenuListener(mActivity);
final BrowserSettings s = BrowserSettings.getInstance();
s.addObserver(mSubView.getSettings()).update(s, null);
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 1790098..e64f3fb 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -533,18 +533,13 @@
w.setMapTrackballToArrowKeys(false); // use trackball directly
// Enable the built-in zoom
w.getSettings().setBuiltInZoomControls(true);
- // Attach DownloadManager so that downloads can start in an active or
- // a non-active window. This can happen when going to a site that does
- // a redirect after a period of time. The user could have switched to
- // another tab while waiting for the download to start.
- w.setDownloadListener(mActivity);
// Add this WebView to the settings observer list and update the
// settings
final BrowserSettings s = BrowserSettings.getInstance();
s.addObserver(w.getSettings()).update(s, null);
// pick a default
- if (true) {
+ if (false) {
MeshTracker mt = new MeshTracker(2);
Paint paint = new Paint();
Bitmap bm = BitmapFactory.decodeResource(mActivity.getResources(),
diff --git a/tests/Android.mk b/tests/Android.mk
index f86942d..ce9acbd 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -31,7 +31,4 @@
LOCAL_INSTRUMENTATION_FOR := Browser
-LOCAL_SDK_VERSION := current
-
include $(BUILD_PACKAGE)
-
diff --git a/tests/src/com/android/browser/PopularUrlsTest.java b/tests/src/com/android/browser/PopularUrlsTest.java
new file mode 100644
index 0000000..4ae69c7
--- /dev/null
+++ b/tests/src/com/android/browser/PopularUrlsTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2010 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 java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.util.concurrent.CountDownLatch;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.net.Uri;
+import android.net.http.SslError;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebView;
+
+/**
+ *
+ * Iterates over a list of URLs from a file and outputs the time to load each.
+ */
+public class PopularUrlsTest extends ActivityInstrumentationTestCase2<BrowserActivity> {
+
+ private final static String TAG = "PopularUrlsTest";
+ private final static String newLine = System.getProperty("line.separator");
+ private final static String sInputFile = "popular_urls.txt";
+ private final static String sOutputFile = "test_output.txt";
+ private final static File sExternalStorage = Environment.getExternalStorageDirectory();
+ private BrowserActivity mActivity = null;
+ private Instrumentation mInst = null;
+ private CountDownLatch mLatch = new CountDownLatch(1);
+
+ public PopularUrlsTest() {
+ super("com.android.browser", BrowserActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInst = getInstrumentation();
+ mInst.waitForIdleSync();
+ }
+
+ static BufferedReader getInputStream() throws FileNotFoundException {
+ String path = sExternalStorage + File.separator + sInputFile;
+ FileReader fileReader = new FileReader(path);
+ BufferedReader bufferedReader = new BufferedReader(fileReader);
+
+ return bufferedReader;
+ }
+
+ static OutputStreamWriter getOutputStream() throws IOException {
+ String path = sExternalStorage + File.separator + sOutputFile;
+
+ File file = new File(path);
+ if (file.exists()) {
+ file.delete();
+ }
+
+ return new FileWriter(file);
+ }
+
+ /**
+ * Gets the browser ready for testing by starting the application
+ * and wrapping the WebView's helper clients.
+ */
+ void setUpBrowser() {
+ Tab tab = mActivity.getTabControl().getCurrentTab();
+ WebView webView = tab.getWebView();
+
+ webView.setWebChromeClient(new TestWebChromeClient(webView.getWebChromeClient()) {
+
+ /**
+ * Reset the latch whenever page progress reaches 100%.
+ */
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ super.onProgressChanged(view, newProgress);
+ if (newProgress >= 100) {
+ resetLatch();
+ }
+ }
+
+ /**
+ * Dismisses and logs Javascript alerts.
+ */
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ String logMsg = String.format("JS Alert '%s' received from %s", message, url);
+ Log.w(TAG, logMsg);
+ result.confirm();
+
+ return true;
+ }
+
+ /**
+ * Confirms and logs Javascript alerts.
+ */
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ String logMsg = String.format("JS Confirmation '%s' received from %s",
+ message, url);
+ Log.w(TAG, logMsg);
+ result.confirm();
+
+ return true;
+ }
+
+ /**
+ * Confirms and logs Javascript alerts, providing the default value.
+ */
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ String logMsg = String.format("JS Prompt '%s' received from %s; " +
+ "Giving default value '%s'", message, url, defaultValue);
+ Log.w(TAG, logMsg);
+ result.confirm(defaultValue);
+
+ return true;
+ }
+ });
+
+ webView.setWebViewClient(new TestWebViewClient(webView.getWebViewClient()) {
+
+ /**
+ * Bypasses and logs errors.
+ */
+ @Override
+ public void onReceivedError(WebView view, int errorCode,
+ String description, String failingUrl) {
+ String message = String.format("Error '%s' (%d) loading url: %s",
+ description, errorCode, failingUrl);
+ Log.w(TAG, message);
+ }
+
+ /**
+ * Ignores and logs SSL errors.
+ */
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ Log.w(TAG, "SSL error: " + error);
+ handler.proceed();
+ }
+
+ });
+ }
+
+ void resetLatch() {
+ CountDownLatch temp = mLatch;
+ mLatch = new CountDownLatch(1);
+ if (temp != null) {
+ // Notify existing latch that it's done.
+ while (temp.getCount() > 0) {
+ temp.countDown();
+ }
+ }
+ }
+
+ void waitForLoad() throws InterruptedException {
+ mLatch.await();
+ }
+
+ /**
+ * Loops over a list of URLs, points the browser to each one, and records the time elapsed.
+ *
+ * @param input the reader from which to get the URLs.
+ * @param writer the writer to which to output the results.
+ * @throws IOException unable to read from input or write to writer.
+ * @throws InterruptedException the thread was interrupted waiting for the page to load.
+ */
+ void loopUrls(BufferedReader input, OutputStreamWriter writer)
+ throws IOException, InterruptedException {
+ Tab tab = mActivity.getTabControl().getCurrentTab();
+ WebView webView = tab.getWebView();
+ String page;
+
+ while (null != (page = input.readLine())) {
+ Uri uri = Uri.parse(page);
+ webView.clearCache(true);
+ final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+ writer.write(uri.toString());
+
+ long startTime = System.nanoTime();
+ mInst.runOnMainSync(new Runnable() {
+
+ public void run() {
+ mActivity.onNewIntent(intent);
+ }
+
+ });
+ waitForLoad();
+ long stopTime = System.nanoTime();
+
+ String url = webView.getUrl();
+ Log.i(TAG, "Loaded url: " + url);
+ writer.write("|" + (stopTime - startTime) + newLine);
+ }
+ }
+
+ public void testLoadPerformance() throws IOException, InterruptedException {
+ setUpBrowser();
+
+ OutputStreamWriter writer = getOutputStream();
+ try {
+ BufferedReader bufferedReader = getInputStream();
+ try {
+ loopUrls(bufferedReader, writer);
+ } finally {
+ if (bufferedReader != null) {
+ bufferedReader.close();
+ }
+ }
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+}
+
diff --git a/tests/src/com/android/browser/TestWebChromeClient.java b/tests/src/com/android/browser/TestWebChromeClient.java
new file mode 100644
index 0000000..d78eaed
--- /dev/null
+++ b/tests/src/com/android/browser/TestWebChromeClient.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2010 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.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Message;
+import android.view.View;
+import android.webkit.ConsoleMessage;
+import android.webkit.GeolocationPermissions;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+
+/**
+ *
+ * WebChromeClient for browser tests.
+ * Wraps around existing client so that specific methods can be overridden if needed.
+ *
+ */
+abstract class TestWebChromeClient extends WebChromeClient {
+
+ private WebChromeClient mWrappedClient;
+
+ protected TestWebChromeClient(WebChromeClient wrappedClient) {
+ mWrappedClient = wrappedClient;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ mWrappedClient.onProgressChanged(view, newProgress);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ mWrappedClient.onReceivedTitle(view, title);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ mWrappedClient.onReceivedIcon(view, icon);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedTouchIconUrl(WebView view, String url,
+ boolean precomposed) {
+ mWrappedClient.onReceivedTouchIconUrl(view, url, precomposed);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onShowCustomView(View view, CustomViewCallback callback) {
+ mWrappedClient.onShowCustomView(view, callback);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onHideCustomView() {
+ mWrappedClient.onHideCustomView();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onCreateWindow(WebView view, boolean dialog,
+ boolean userGesture, Message resultMsg) {
+ return mWrappedClient.onCreateWindow(view, dialog, userGesture, resultMsg);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onRequestFocus(WebView view) {
+ mWrappedClient.onRequestFocus(view);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onCloseWindow(WebView window) {
+ mWrappedClient.onCloseWindow(window);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ return mWrappedClient.onJsAlert(view, url, message, result);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ return mWrappedClient.onJsConfirm(view, url, message, result);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ return mWrappedClient.onJsPrompt(view, url, message, defaultValue, result);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onJsBeforeUnload(WebView view, String url, String message,
+ JsResult result) {
+ return mWrappedClient.onJsBeforeUnload(view, url, message, result);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onExceededDatabaseQuota(String url, String databaseIdentifier,
+ long currentQuota, long estimatedSize, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ mWrappedClient.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota,
+ estimatedSize, totalUsedQuota, quotaUpdater);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ mWrappedClient.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota, quotaUpdater);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ mWrappedClient.onGeolocationPermissionsShowPrompt(origin, callback);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onGeolocationPermissionsHidePrompt() {
+ mWrappedClient.onGeolocationPermissionsHidePrompt();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onJsTimeout() {
+ return mWrappedClient.onJsTimeout();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Deprecated
+ public void onConsoleMessage(String message, int lineNumber, String sourceID) {
+ mWrappedClient.onConsoleMessage(message, lineNumber, sourceID);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+ return mWrappedClient.onConsoleMessage(consoleMessage);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public Bitmap getDefaultVideoPoster() {
+ return mWrappedClient.getDefaultVideoPoster();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public View getVideoLoadingProgressView() {
+ return mWrappedClient.getVideoLoadingProgressView();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void getVisitedHistory(ValueCallback<String[]> callback) {
+ mWrappedClient.getVisitedHistory(callback);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void openFileChooser(ValueCallback<Uri> uploadFile) {
+ mWrappedClient.openFileChooser(uploadFile);
+ }
+}
diff --git a/tests/src/com/android/browser/TestWebViewClient.java b/tests/src/com/android/browser/TestWebViewClient.java
new file mode 100644
index 0000000..7159a7e
--- /dev/null
+++ b/tests/src/com/android/browser/TestWebViewClient.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 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.graphics.Bitmap;
+import android.net.http.SslError;
+import android.os.Message;
+import android.view.KeyEvent;
+import android.webkit.HttpAuthHandler;
+import android.webkit.SslErrorHandler;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+/**
+ *
+ *
+ * WebViewClient for browser tests.
+ * Wraps around existing client so that specific methods can be overridden if needed.
+ *
+ */
+abstract class TestWebViewClient extends WebViewClient {
+
+ private WebViewClient mWrappedClient;
+
+ protected TestWebViewClient(WebViewClient wrappedClient) {
+ mWrappedClient = wrappedClient;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean shouldOverrideUrlLoading(WebView view, String url) {
+ return mWrappedClient.shouldOverrideUrlLoading(view, url);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onPageStarted(WebView view, String url, Bitmap favicon) {
+ mWrappedClient.onPageStarted(view, url, favicon);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ mWrappedClient.onPageFinished(view, url);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onLoadResource(WebView view, String url) {
+ mWrappedClient.onLoadResource(view, url);
+ }
+
+ /** {@inheritDoc} */
+ @Deprecated
+ @Override
+ public void onTooManyRedirects(WebView view, Message cancelMsg,
+ Message continueMsg) {
+ mWrappedClient.onTooManyRedirects(view, cancelMsg, continueMsg);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedError(WebView view, int errorCode,
+ String description, String failingUrl) {
+ mWrappedClient.onReceivedError(view, errorCode, description, failingUrl);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onFormResubmission(WebView view, Message dontResend,
+ Message resend) {
+ mWrappedClient.onFormResubmission(view, dontResend, resend);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void doUpdateVisitedHistory(WebView view, String url,
+ boolean isReload) {
+ mWrappedClient.doUpdateVisitedHistory(view, url, isReload);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedSslError(WebView view, SslErrorHandler handler,
+ SslError error) {
+ mWrappedClient.onReceivedSslError(view, handler, error);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onReceivedHttpAuthRequest(WebView view,
+ HttpAuthHandler handler, String host, String realm) {
+ mWrappedClient.onReceivedHttpAuthRequest(view, handler, host, realm);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
+ return mWrappedClient.shouldOverrideKeyEvent(view, event);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onUnhandledKeyEvent(WebView view, KeyEvent event) {
+ mWrappedClient.onUnhandledKeyEvent(view, event);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onScaleChanged(WebView view, float oldScale, float newScale) {
+ mWrappedClient.onScaleChanged(view, oldScale, newScale);
+ }
+}