This fixes a bug in commit https://android-git.corp.google.com/g/#change,52518. Updated index to be zero based when passed around and off by one error on resume. Note that previous commit changes how DumpRenderTree dumps titles. This might affect the results of layout tests. Change-Id: I3d6989d71c336f90168e38c994dd36743bda365c
894 lines
30 KiB
Java
894 lines
30 KiB
Java
/*
|
|
* Copyright (C) 2007 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.dumprendertree;
|
|
|
|
import com.android.dumprendertree.forwarder.ForwardService;
|
|
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.DialogInterface.OnClickListener;
|
|
import android.graphics.Bitmap;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Bitmap.CompressFormat;
|
|
import android.graphics.Bitmap.Config;
|
|
import android.net.http.SslError;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Message;
|
|
import android.util.Log;
|
|
import android.view.ViewGroup;
|
|
import android.webkit.ConsoleMessage;
|
|
import android.webkit.GeolocationPermissions;
|
|
import android.webkit.HttpAuthHandler;
|
|
import android.webkit.JsPromptResult;
|
|
import android.webkit.JsResult;
|
|
import android.webkit.SslErrorHandler;
|
|
import android.webkit.WebChromeClient;
|
|
import android.webkit.WebSettings;
|
|
import android.webkit.WebStorage;
|
|
import android.webkit.WebView;
|
|
import android.webkit.WebViewClient;
|
|
import android.widget.LinearLayout;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileOutputStream;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
import java.util.Vector;
|
|
|
|
public class TestShellActivity extends Activity implements LayoutTestController {
|
|
|
|
static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
|
|
|
|
// String constants for use with layoutTestController.overridePreferences
|
|
private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = "WebKitOfflineWebApplicationCacheEnabled";
|
|
|
|
public class AsyncHandler extends Handler {
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
if (msg.what == MSG_TIMEOUT) {
|
|
mTimedOut = true;
|
|
if (mCallback != null)
|
|
mCallback.timedOut(mWebView.getUrl());
|
|
if (!mRequestedWebKitData) {
|
|
requestWebKitData();
|
|
} else {
|
|
// if timed out and webkit data has been dumped before
|
|
// finish directly
|
|
finished();
|
|
}
|
|
return;
|
|
} else if (msg.what == MSG_WEBKIT_DATA) {
|
|
TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
|
|
return;
|
|
}
|
|
|
|
super.handleMessage(msg);
|
|
}
|
|
}
|
|
|
|
public void requestWebKitData() {
|
|
Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
|
|
|
|
if (mRequestedWebKitData)
|
|
throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
|
|
|
|
mRequestedWebKitData = true;
|
|
Log.v(LOGTAG, "message sent to WebView to dump text.");
|
|
switch (mDumpDataType) {
|
|
case DUMP_AS_TEXT:
|
|
mWebView.documentAsText(callback);
|
|
break;
|
|
case EXT_REPR:
|
|
mWebView.externalRepresentation(callback);
|
|
break;
|
|
default:
|
|
finished();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public void clearCache() {
|
|
mWebView.freeMemory();
|
|
}
|
|
|
|
@Override
|
|
protected void onCreate(Bundle icicle) {
|
|
super.onCreate(icicle);
|
|
|
|
LinearLayout contentView = new LinearLayout(this);
|
|
contentView.setOrientation(LinearLayout.VERTICAL);
|
|
setContentView(contentView);
|
|
|
|
mWebView = new WebView(this);
|
|
mEventSender = new WebViewEventSender(mWebView);
|
|
mCallbackProxy = new CallbackProxy(mEventSender, this);
|
|
|
|
mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
|
|
mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
|
|
setupWebViewForLayoutTests(mWebView, mCallbackProxy);
|
|
|
|
contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f));
|
|
|
|
mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
|
|
|
|
// Expose window.gc function to JavaScript. JSC build exposes
|
|
// this function by default, but V8 requires the flag to turn it on.
|
|
// WebView::setJsFlags is noop in JSC build.
|
|
mWebView.setJsFlags("--expose_gc");
|
|
|
|
mHandler = new AsyncHandler();
|
|
|
|
Intent intent = getIntent();
|
|
if (intent != null) {
|
|
executeIntent(intent);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void onNewIntent(Intent intent) {
|
|
super.onNewIntent(intent);
|
|
executeIntent(intent);
|
|
}
|
|
|
|
private void executeIntent(Intent intent) {
|
|
resetTestStatus();
|
|
if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
|
|
return;
|
|
}
|
|
|
|
mTestUrl = intent.getStringExtra(TEST_URL);
|
|
if (mTestUrl == null) {
|
|
mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST);
|
|
if(mUiAutoTestPath != null) {
|
|
beginUiAutoTest();
|
|
}
|
|
return;
|
|
}
|
|
|
|
mResultFile = intent.getStringExtra(RESULT_FILE);
|
|
mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
|
|
mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false);
|
|
mSaveImagePath = intent.getStringExtra(SAVE_IMAGE);
|
|
mTestCount = intent.getIntExtra(TEST_COUNT, 0);
|
|
mTestIndex = intent.getIntExtra(TEST_INDEX, 0);
|
|
setTitle("Test " + (mTestIndex + 1) + " of " + mTestCount);
|
|
|
|
Log.v(LOGTAG, " Loading " + mTestUrl);
|
|
mWebView.loadUrl(mTestUrl);
|
|
|
|
if (mTimeoutInMillis > 0) {
|
|
// Create a timeout timer
|
|
Message m = mHandler.obtainMessage(MSG_TIMEOUT);
|
|
mHandler.sendMessageDelayed(m, mTimeoutInMillis);
|
|
}
|
|
}
|
|
|
|
private void beginUiAutoTest() {
|
|
try {
|
|
mTestListReader = new BufferedReader(
|
|
new FileReader(mUiAutoTestPath));
|
|
} catch (IOException ioe) {
|
|
Log.e(LOGTAG, "Failed to open test list for read.", ioe);
|
|
finishUiAutoTest();
|
|
return;
|
|
}
|
|
moveToNextTest();
|
|
}
|
|
|
|
private void finishUiAutoTest() {
|
|
try {
|
|
if(mTestListReader != null)
|
|
mTestListReader.close();
|
|
} catch (IOException ioe) {
|
|
Log.w(LOGTAG, "Failed to close test list file.", ioe);
|
|
}
|
|
ForwardService.getForwardService().stopForwardService();
|
|
finished();
|
|
}
|
|
|
|
private void moveToNextTest() {
|
|
String url = null;
|
|
try {
|
|
url = mTestListReader.readLine();
|
|
} catch (IOException ioe) {
|
|
Log.e(LOGTAG, "Failed to read next test.", ioe);
|
|
finishUiAutoTest();
|
|
return;
|
|
}
|
|
if (url == null) {
|
|
mUiAutoTestPath = null;
|
|
finishUiAutoTest();
|
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
|
builder.setMessage("All tests finished. Exit?")
|
|
.setCancelable(false)
|
|
.setPositiveButton("Yes", new OnClickListener(){
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
TestShellActivity.this.finish();
|
|
}
|
|
})
|
|
.setNegativeButton("No", new OnClickListener(){
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
dialog.cancel();
|
|
}
|
|
});
|
|
builder.create().show();
|
|
return;
|
|
}
|
|
Intent intent = new Intent(Intent.ACTION_VIEW);
|
|
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
|
intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
|
|
intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
|
|
executeIntent(intent);
|
|
}
|
|
|
|
@Override
|
|
protected void onStop() {
|
|
super.onStop();
|
|
mWebView.stopLoading();
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
mWebView.destroy();
|
|
mWebView = null;
|
|
}
|
|
|
|
@Override
|
|
public void onLowMemory() {
|
|
super.onLowMemory();
|
|
Log.e(LOGTAG, "Low memory, clearing caches");
|
|
mWebView.freeMemory();
|
|
}
|
|
|
|
// Dump the page
|
|
public void dump(boolean timeout, String webkitData) {
|
|
mDumpWebKitData = true;
|
|
if (mResultFile == null || mResultFile.length() == 0) {
|
|
finished();
|
|
return;
|
|
}
|
|
|
|
try {
|
|
File parentDir = new File(mResultFile).getParentFile();
|
|
if (!parentDir.exists()) {
|
|
parentDir.mkdirs();
|
|
}
|
|
|
|
FileOutputStream os = new FileOutputStream(mResultFile);
|
|
if (timeout) {
|
|
Log.w("Layout test: Timeout", mResultFile);
|
|
os.write(TIMEOUT_STR.getBytes());
|
|
os.write('\n');
|
|
}
|
|
if (mDumpTitleChanges)
|
|
os.write(mTitleChanges.toString().getBytes());
|
|
if (mDialogStrings != null)
|
|
os.write(mDialogStrings.toString().getBytes());
|
|
mDialogStrings = null;
|
|
if (mDatabaseCallbackStrings != null)
|
|
os.write(mDatabaseCallbackStrings.toString().getBytes());
|
|
mDatabaseCallbackStrings = null;
|
|
if (mConsoleMessages != null)
|
|
os.write(mConsoleMessages.toString().getBytes());
|
|
mConsoleMessages = null;
|
|
if (webkitData != null)
|
|
os.write(webkitData.getBytes());
|
|
os.flush();
|
|
os.close();
|
|
} catch (IOException ex) {
|
|
Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage());
|
|
}
|
|
|
|
finished();
|
|
}
|
|
|
|
public void setCallback(TestShellCallback callback) {
|
|
mCallback = callback;
|
|
}
|
|
|
|
public boolean finished() {
|
|
if (canMoveToNextTest()) {
|
|
mHandler.removeMessages(MSG_TIMEOUT);
|
|
if (mUiAutoTestPath != null) {
|
|
//don't really finish here
|
|
moveToNextTest();
|
|
} else {
|
|
if (mCallback != null) {
|
|
mCallback.finished();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) {
|
|
mDefaultDumpDataType = defaultDumpDataType;
|
|
}
|
|
|
|
// .......................................
|
|
// LayoutTestController Functions
|
|
public void dumpAsText() {
|
|
mDumpDataType = DumpDataType.DUMP_AS_TEXT;
|
|
if (mWebView != null) {
|
|
String url = mWebView.getUrl();
|
|
Log.v(LOGTAG, "dumpAsText called: "+url);
|
|
}
|
|
}
|
|
|
|
public void waitUntilDone() {
|
|
mWaitUntilDone = true;
|
|
String url = mWebView.getUrl();
|
|
Log.v(LOGTAG, "waitUntilDone called: " + url);
|
|
}
|
|
|
|
public void notifyDone() {
|
|
String url = mWebView.getUrl();
|
|
Log.v(LOGTAG, "notifyDone called: " + url);
|
|
if (mWaitUntilDone) {
|
|
mWaitUntilDone = false;
|
|
mChromeClient.onProgressChanged(mWebView, 101);
|
|
}
|
|
}
|
|
|
|
public void display() {
|
|
mWebView.invalidate();
|
|
}
|
|
|
|
public void clearBackForwardList() {
|
|
mWebView.clearHistory();
|
|
|
|
}
|
|
|
|
public void dumpBackForwardList() {
|
|
//printf("\n============== Back Forward List ==============\n");
|
|
// mWebHistory
|
|
//printf("===============================================\n");
|
|
|
|
}
|
|
|
|
public void dumpChildFrameScrollPositions() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void dumpEditingCallbacks() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void dumpSelectionRect() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void dumpTitleChanges() {
|
|
if (!mDumpTitleChanges) {
|
|
mTitleChanges = new StringBuffer();
|
|
}
|
|
mDumpTitleChanges = true;
|
|
}
|
|
|
|
public void keepWebHistory() {
|
|
if (!mKeepWebHistory) {
|
|
mWebHistory = new Vector();
|
|
}
|
|
mKeepWebHistory = true;
|
|
}
|
|
|
|
public void queueBackNavigation(int howfar) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void queueForwardNavigation(int howfar) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void queueLoad(String Url, String frameTarget) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void queueReload() {
|
|
mWebView.reload();
|
|
}
|
|
|
|
public void queueScript(String scriptToRunInCurrentContext) {
|
|
mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
|
|
}
|
|
|
|
public void repaintSweepHorizontally() {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void setAcceptsEditing(boolean b) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void setMainFrameIsFirstResponder(boolean b) {
|
|
// TODO Auto-generated method stub
|
|
|
|
}
|
|
|
|
public void setWindowIsKey(boolean b) {
|
|
// This is meant to show/hide the window. The best I can find
|
|
// is setEnabled()
|
|
mWebView.setEnabled(b);
|
|
}
|
|
|
|
public void testRepaint() {
|
|
mWebView.invalidate();
|
|
}
|
|
|
|
public void dumpDatabaseCallbacks() {
|
|
Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
|
|
mDumpDatabaseCallbacks = true;
|
|
}
|
|
|
|
public void setCanOpenWindows() {
|
|
Log.v(LOGTAG, "setCanOpenWindows called.");
|
|
mCanOpenWindows = true;
|
|
}
|
|
|
|
/**
|
|
* Sets the Geolocation permission state to be used for all future requests.
|
|
*/
|
|
public void setGeolocationPermission(boolean allow) {
|
|
mGeolocationPermissionSet = true;
|
|
mGeolocationPermission = allow;
|
|
}
|
|
|
|
public void overridePreference(String key, boolean value) {
|
|
// TODO: We should look up the correct WebView for the frame which
|
|
// called the layoutTestController method. Currently, we just use the
|
|
// WebView for the main frame. EventSender suffers from the same
|
|
// problem.
|
|
if (key.equals(WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) {
|
|
mWebView.getSettings().setAppCacheEnabled(value);
|
|
}
|
|
}
|
|
|
|
private final WebViewClient mViewClient = new WebViewClient(){
|
|
@Override
|
|
public void onPageFinished(WebView view, String url) {
|
|
Log.v(LOGTAG, "onPageFinished, url=" + url);
|
|
mPageFinished = true;
|
|
// get page draw time
|
|
if (FsUtils.isTestPageUrl(url)) {
|
|
if (mGetDrawtime) {
|
|
long[] times = new long[DRAW_RUNS];
|
|
times = getDrawWebViewTime(mWebView, DRAW_RUNS);
|
|
FsUtils.writeDrawTime(DRAW_TIME_LOG, url, times);
|
|
}
|
|
if (mSaveImagePath != null) {
|
|
String name = FsUtils.getLastSegmentInPath(url);
|
|
drawPageToFile(mSaveImagePath + "/" + name + ".png", mWebView);
|
|
}
|
|
}
|
|
// Calling finished() will check if we've met all the conditions for completing
|
|
// this test and move to the next one if we are ready.
|
|
if (finished()) {
|
|
return;
|
|
}
|
|
super.onPageFinished(view, url);
|
|
}
|
|
|
|
@Override
|
|
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
|
Log.v(LOGTAG, "onPageStarted, url=" + url);
|
|
mPageFinished = false;
|
|
super.onPageStarted(view, url, favicon);
|
|
}
|
|
|
|
@Override
|
|
public void onReceivedError(WebView view, int errorCode, String description,
|
|
String failingUrl) {
|
|
Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
|
|
+ ", desc=" + description + ", url=" + failingUrl);
|
|
super.onReceivedError(view, errorCode, description, failingUrl);
|
|
}
|
|
|
|
@Override
|
|
public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
|
|
String host, String realm) {
|
|
if (handler.useHttpAuthUsernamePassword() && view != null) {
|
|
String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
|
|
if (credentials != null && credentials.length == 2) {
|
|
handler.proceed(credentials[0], credentials[1]);
|
|
return;
|
|
}
|
|
}
|
|
handler.cancel();
|
|
}
|
|
|
|
@Override
|
|
public void onReceivedSslError(WebView view, SslErrorHandler handler,
|
|
SslError error) {
|
|
handler.proceed();
|
|
}
|
|
};
|
|
|
|
|
|
private final WebChromeClient mChromeClient = new WebChromeClient() {
|
|
@Override
|
|
public void onProgressChanged(WebView view, int newProgress) {
|
|
|
|
// notifyDone calls this with 101%. We only want to update this flag if this
|
|
// is the real call from WebCore.
|
|
if (newProgress == 100) {
|
|
mOneHundredPercentComplete = true;
|
|
}
|
|
|
|
// With the flag updated, we can now proceed as normal whether the progress update came from
|
|
// WebCore or notifyDone.
|
|
if (newProgress >= 100) {
|
|
// finished() will check if we are ready to move to the next test and do so if we are.
|
|
if (finished()) {
|
|
return;
|
|
}
|
|
|
|
if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
|
|
String url = mWebView.getUrl();
|
|
Log.v(LOGTAG, "Finished: "+ url);
|
|
requestWebKitData();
|
|
} else {
|
|
String url = mWebView.getUrl();
|
|
if (mTimedOut) {
|
|
Log.v(LOGTAG, "Timed out before finishing: " + url);
|
|
} else if (mWaitUntilDone) {
|
|
Log.v(LOGTAG, "Waiting for notifyDone: " + url);
|
|
} else if (mRequestedWebKitData) {
|
|
Log.v(LOGTAG, "Requested webkit data ready: " + url);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onReceivedTitle(WebView view, String title) {
|
|
setTitle("Test " + (mTestIndex + 1) + " of " + mTestCount + ": "+ title);
|
|
if (mDumpTitleChanges) {
|
|
mTitleChanges.append("TITLE CHANGED: ");
|
|
mTitleChanges.append(title);
|
|
mTitleChanges.append("\n");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onJsAlert(WebView view, String url, String message,
|
|
JsResult result) {
|
|
if (mDialogStrings == null) {
|
|
mDialogStrings = new StringBuffer();
|
|
}
|
|
mDialogStrings.append("ALERT: ");
|
|
mDialogStrings.append(message);
|
|
mDialogStrings.append('\n');
|
|
result.confirm();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onJsConfirm(WebView view, String url, String message,
|
|
JsResult result) {
|
|
if (mDialogStrings == null) {
|
|
mDialogStrings = new StringBuffer();
|
|
}
|
|
mDialogStrings.append("CONFIRM: ");
|
|
mDialogStrings.append(message);
|
|
mDialogStrings.append('\n');
|
|
result.confirm();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onJsPrompt(WebView view, String url, String message,
|
|
String defaultValue, JsPromptResult result) {
|
|
if (mDialogStrings == null) {
|
|
mDialogStrings = new StringBuffer();
|
|
}
|
|
mDialogStrings.append("PROMPT: ");
|
|
mDialogStrings.append(message);
|
|
mDialogStrings.append(", default text: ");
|
|
mDialogStrings.append(defaultValue);
|
|
mDialogStrings.append('\n');
|
|
result.confirm();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onJsTimeout() {
|
|
Log.v(LOGTAG, "JavaScript timeout");
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void onExceededDatabaseQuota(String url_str,
|
|
String databaseIdentifier, long currentQuota,
|
|
long estimatedSize, long totalUsedQuota,
|
|
WebStorage.QuotaUpdater callback) {
|
|
if (mDumpDatabaseCallbacks) {
|
|
if (mDatabaseCallbackStrings == null) {
|
|
mDatabaseCallbackStrings = new StringBuffer();
|
|
}
|
|
|
|
String protocol = "";
|
|
String host = "";
|
|
int port = 0;
|
|
|
|
try {
|
|
URL url = new URL(url_str);
|
|
protocol = url.getProtocol();
|
|
host = url.getHost();
|
|
if (url.getPort() > -1) {
|
|
port = url.getPort();
|
|
}
|
|
} catch (MalformedURLException e) {}
|
|
|
|
String databaseCallbackString =
|
|
"UI DELEGATE DATABASE CALLBACK: " +
|
|
"exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
|
|
", " + host + ", " + port + "} database:" +
|
|
databaseIdentifier + "\n";
|
|
Log.v(LOGTAG, "LOG: "+databaseCallbackString);
|
|
mDatabaseCallbackStrings.append(databaseCallbackString);
|
|
}
|
|
// Give 5MB more quota.
|
|
callback.updateQuota(currentQuota + 1024 * 1024 * 5);
|
|
}
|
|
|
|
/**
|
|
* Instructs the client to show a prompt to ask the user to set the
|
|
* Geolocation permission state for the specified origin.
|
|
*/
|
|
@Override
|
|
public void onGeolocationPermissionsShowPrompt(String origin,
|
|
GeolocationPermissions.Callback callback) {
|
|
if (mGeolocationPermissionSet) {
|
|
callback.invoke(origin, mGeolocationPermission, false);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
|
|
String msg = "CONSOLE MESSAGE: line " + consoleMessage.lineNumber() + ": "
|
|
+ consoleMessage.message() + "\n";
|
|
if (mConsoleMessages == null) {
|
|
mConsoleMessages = new StringBuffer();
|
|
}
|
|
mConsoleMessages.append(msg);
|
|
Log.v(LOGTAG, "LOG: " + msg);
|
|
// the rationale here is that if there's an error of either type, and the test was
|
|
// waiting for "notifyDone" signal to finish, then there's no point in waiting
|
|
// anymore because the JS execution is already terminated at this point and a
|
|
// "notifyDone" will never come out so it's just wasting time till timeout kicks in
|
|
if (msg.contains("Uncaught ReferenceError:") || msg.contains("Uncaught TypeError:")
|
|
&& mWaitUntilDone) {
|
|
Log.w(LOGTAG, "Terminating test case on uncaught ReferenceError or TypeError.");
|
|
mHandler.postDelayed(new Runnable() {
|
|
public void run() {
|
|
notifyDone();
|
|
}
|
|
}, 500);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateWindow(WebView view, boolean dialog,
|
|
boolean userGesture, Message resultMsg) {
|
|
if (!mCanOpenWindows) {
|
|
// We can't open windows, so just send null back.
|
|
WebView.WebViewTransport transport =
|
|
(WebView.WebViewTransport) resultMsg.obj;
|
|
transport.setWebView(null);
|
|
resultMsg.sendToTarget();
|
|
return true;
|
|
}
|
|
|
|
// We never display the new window, just create the view and
|
|
// allow it's content to execute and be recorded by the test
|
|
// runner.
|
|
|
|
HashMap<String, Object> jsIfaces = new HashMap<String, Object>();
|
|
jsIfaces.put("layoutTestController", mCallbackProxy);
|
|
jsIfaces.put("eventSender", mCallbackProxy);
|
|
WebView newWindowView = new NewWindowWebView(TestShellActivity.this, jsIfaces);
|
|
setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
|
|
WebView.WebViewTransport transport =
|
|
(WebView.WebViewTransport) resultMsg.obj;
|
|
transport.setWebView(newWindowView);
|
|
resultMsg.sendToTarget();
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public void onCloseWindow(WebView view) {
|
|
view.destroy();
|
|
}
|
|
};
|
|
|
|
private static class NewWindowWebView extends WebView {
|
|
public NewWindowWebView(Context context, Map<String, Object> jsIfaces) {
|
|
super(context, null, 0, jsIfaces);
|
|
}
|
|
}
|
|
|
|
private void resetTestStatus() {
|
|
mWaitUntilDone = false;
|
|
mDumpDataType = mDefaultDumpDataType;
|
|
mTimedOut = false;
|
|
mDumpTitleChanges = false;
|
|
mRequestedWebKitData = false;
|
|
mDumpDatabaseCallbacks = false;
|
|
mCanOpenWindows = false;
|
|
mEventSender.resetMouse();
|
|
mEventSender.clearTouchPoints();
|
|
mEventSender.clearTouchMetaState();
|
|
mPageFinished = false;
|
|
mOneHundredPercentComplete = false;
|
|
mDumpWebKitData = false;
|
|
mGetDrawtime = false;
|
|
mSaveImagePath = null;
|
|
setDefaultWebSettings(mWebView);
|
|
}
|
|
|
|
private long[] getDrawWebViewTime(WebView view, int count) {
|
|
if (count == 0)
|
|
return null;
|
|
long[] ret = new long[count];
|
|
long start;
|
|
Canvas canvas = new Canvas();
|
|
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888);
|
|
canvas.setBitmap(bitmap);
|
|
for (int i = 0; i < count; i++) {
|
|
start = System.currentTimeMillis();
|
|
view.draw(canvas);
|
|
ret[i] = System.currentTimeMillis() - start;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
private void drawPageToFile(String fileName, WebView view) {
|
|
Canvas canvas = new Canvas();
|
|
Bitmap bitmap = Bitmap.createBitmap(view.getContentWidth(), view.getContentHeight(),
|
|
Config.ARGB_8888);
|
|
canvas.setBitmap(bitmap);
|
|
view.drawPage(canvas);
|
|
try {
|
|
FileOutputStream fos = new FileOutputStream(fileName);
|
|
if(!bitmap.compress(CompressFormat.PNG, 90, fos)) {
|
|
Log.w(LOGTAG, "Failed to compress and save image.");
|
|
}
|
|
} catch (IOException ioe) {
|
|
Log.e(LOGTAG, "", ioe);
|
|
}
|
|
bitmap.recycle();
|
|
}
|
|
|
|
private boolean canMoveToNextTest() {
|
|
return (mDumpWebKitData && mOneHundredPercentComplete && mPageFinished && !mWaitUntilDone) || mTimedOut;
|
|
}
|
|
|
|
private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
|
|
if (webview == null) {
|
|
return;
|
|
}
|
|
|
|
setDefaultWebSettings(webview);
|
|
|
|
webview.setWebChromeClient(mChromeClient);
|
|
webview.setWebViewClient(mViewClient);
|
|
// Setting a touch interval of -1 effectively disables the optimisation in WebView
|
|
// that stops repeated touch events flooding WebCore. The Event Sender only sends a
|
|
// single event rather than a stream of events (like what would generally happen in
|
|
// a real use of touch events in a WebView) and so if the WebView drops the event,
|
|
// the test will fail as the test expects one callback for every touch it synthesizes.
|
|
webview.setTouchInterval(-1);
|
|
}
|
|
|
|
public void setDefaultWebSettings(WebView webview) {
|
|
WebSettings settings = webview.getSettings();
|
|
settings.setAppCacheEnabled(true);
|
|
settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
|
|
settings.setAppCacheMaxSize(Long.MAX_VALUE);
|
|
settings.setJavaScriptEnabled(true);
|
|
settings.setJavaScriptCanOpenWindowsAutomatically(true);
|
|
settings.setSupportMultipleWindows(true);
|
|
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
|
|
settings.setDatabaseEnabled(true);
|
|
settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
|
|
settings.setDomStorageEnabled(true);
|
|
settings.setWorkersEnabled(false);
|
|
}
|
|
|
|
private WebView mWebView;
|
|
private WebViewEventSender mEventSender;
|
|
private AsyncHandler mHandler;
|
|
private TestShellCallback mCallback;
|
|
|
|
private CallbackProxy mCallbackProxy;
|
|
|
|
private String mTestUrl;
|
|
private String mResultFile;
|
|
private int mTimeoutInMillis;
|
|
private String mUiAutoTestPath;
|
|
private String mSaveImagePath;
|
|
private BufferedReader mTestListReader;
|
|
private boolean mGetDrawtime;
|
|
private int mTestCount;
|
|
private int mTestIndex;
|
|
|
|
// States
|
|
private boolean mTimedOut;
|
|
private boolean mRequestedWebKitData;
|
|
private boolean mFinishedRunning;
|
|
|
|
// Layout test controller variables.
|
|
private DumpDataType mDumpDataType;
|
|
private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR;
|
|
private boolean mWaitUntilDone;
|
|
private boolean mDumpTitleChanges;
|
|
private StringBuffer mTitleChanges;
|
|
private StringBuffer mDialogStrings;
|
|
private boolean mKeepWebHistory;
|
|
private Vector mWebHistory;
|
|
private boolean mDumpDatabaseCallbacks;
|
|
private StringBuffer mDatabaseCallbackStrings;
|
|
private StringBuffer mConsoleMessages;
|
|
private boolean mCanOpenWindows;
|
|
|
|
private boolean mPageFinished = false;
|
|
private boolean mDumpWebKitData = false;
|
|
private boolean mOneHundredPercentComplete = false;
|
|
|
|
static final String TIMEOUT_STR = "**Test timeout";
|
|
|
|
static final int MSG_TIMEOUT = 0;
|
|
static final int MSG_WEBKIT_DATA = 1;
|
|
|
|
static final String LOGTAG="TestShell";
|
|
|
|
static final String TEST_URL = "TestUrl";
|
|
static final String RESULT_FILE = "ResultFile";
|
|
static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
|
|
static final String UI_AUTO_TEST = "UiAutoTest";
|
|
static final String GET_DRAW_TIME = "GetDrawTime";
|
|
static final String SAVE_IMAGE = "SaveImage";
|
|
static final String TEST_COUNT = "TestCount";
|
|
static final String TEST_INDEX = "TestIndex";
|
|
|
|
static final int DRAW_RUNS = 5;
|
|
static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
|
|
|
|
private boolean mGeolocationPermissionSet;
|
|
private boolean mGeolocationPermission;
|
|
}
|