Home | History | Annotate | Download | only in dumprendertree
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dumprendertree;
     18 
     19 import com.android.dumprendertree.forwarder.ForwardService;
     20 
     21 import android.app.Activity;
     22 import android.app.AlertDialog;
     23 import android.content.Context;
     24 import android.content.DialogInterface;
     25 import android.content.Intent;
     26 import android.content.DialogInterface.OnClickListener;
     27 import android.graphics.Bitmap;
     28 import android.graphics.Canvas;
     29 import android.graphics.Bitmap.CompressFormat;
     30 import android.graphics.Bitmap.Config;
     31 import android.net.http.SslError;
     32 import android.os.Bundle;
     33 import android.os.Handler;
     34 import android.os.Message;
     35 import android.util.Log;
     36 import android.view.ViewGroup;
     37 import android.webkit.GeolocationPermissions;
     38 import android.webkit.HttpAuthHandler;
     39 import android.webkit.JsPromptResult;
     40 import android.webkit.JsResult;
     41 import android.webkit.SslErrorHandler;
     42 import android.webkit.WebChromeClient;
     43 import android.webkit.WebSettings;
     44 import android.webkit.WebStorage;
     45 import android.webkit.WebView;
     46 import android.webkit.WebViewClient;
     47 import android.widget.LinearLayout;
     48 
     49 import java.io.BufferedReader;
     50 import java.io.File;
     51 import java.io.FileOutputStream;
     52 import java.io.FileReader;
     53 import java.io.IOException;
     54 import java.net.MalformedURLException;
     55 import java.net.URL;
     56 import java.util.HashMap;
     57 import java.util.Map;
     58 import java.util.Vector;
     59 
     60 public class TestShellActivity extends Activity implements LayoutTestController {
     61 
     62     static enum DumpDataType {DUMP_AS_TEXT, EXT_REPR, NO_OP}
     63 
     64     // String constants for use with layoutTestController.overridePreferences
     65     private final String WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED = "WebKitOfflineWebApplicationCacheEnabled";
     66 
     67     public class AsyncHandler extends Handler {
     68         @Override
     69         public void handleMessage(Message msg) {
     70             if (msg.what == MSG_TIMEOUT) {
     71                 mTimedOut = true;
     72                 if (mCallback != null)
     73                     mCallback.timedOut(mWebView.getUrl());
     74                 if (!mRequestedWebKitData) {
     75                     requestWebKitData();
     76                 } else {
     77                     // if timed out and webkit data has been dumped before
     78                     // finish directly
     79                     finished();
     80                 }
     81                 return;
     82             } else if (msg.what == MSG_WEBKIT_DATA) {
     83                 TestShellActivity.this.dump(mTimedOut, (String)msg.obj);
     84                 return;
     85             }
     86 
     87             super.handleMessage(msg);
     88         }
     89     }
     90 
     91     public void requestWebKitData() {
     92         Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
     93 
     94         if (mRequestedWebKitData)
     95             throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
     96 
     97         mRequestedWebKitData = true;
     98         Log.v(LOGTAG, "message sent to WebView to dump text.");
     99         switch (mDumpDataType) {
    100             case DUMP_AS_TEXT:
    101                 mWebView.documentAsText(callback);
    102                 break;
    103             case EXT_REPR:
    104                 mWebView.externalRepresentation(callback);
    105                 break;
    106             default:
    107                 finished();
    108                 break;
    109         }
    110     }
    111 
    112     public void clearCache() {
    113       mWebView.freeMemory();
    114     }
    115 
    116     @Override
    117     protected void onCreate(Bundle icicle) {
    118         super.onCreate(icicle);
    119 
    120         LinearLayout contentView = new LinearLayout(this);
    121         contentView.setOrientation(LinearLayout.VERTICAL);
    122         setContentView(contentView);
    123 
    124         mWebView = new WebView(this);
    125         mEventSender = new WebViewEventSender(mWebView);
    126         mCallbackProxy = new CallbackProxy(mEventSender, this);
    127 
    128         mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
    129         mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
    130         setupWebViewForLayoutTests(mWebView, mCallbackProxy);
    131 
    132         contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0.0f));
    133 
    134         mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
    135 
    136         // Expose window.gc function to JavaScript. JSC build exposes
    137         // this function by default, but V8 requires the flag to turn it on.
    138         // WebView::setJsFlags is noop in JSC build.
    139         mWebView.setJsFlags("--expose_gc");
    140 
    141         mHandler = new AsyncHandler();
    142 
    143         Intent intent = getIntent();
    144         if (intent != null) {
    145             executeIntent(intent);
    146         }
    147     }
    148 
    149     @Override
    150     protected void onNewIntent(Intent intent) {
    151         super.onNewIntent(intent);
    152         executeIntent(intent);
    153     }
    154 
    155     private void executeIntent(Intent intent) {
    156         resetTestStatus();
    157         if (!Intent.ACTION_VIEW.equals(intent.getAction())) {
    158             return;
    159         }
    160 
    161         mTestUrl = intent.getStringExtra(TEST_URL);
    162         if (mTestUrl == null) {
    163             mUiAutoTestPath = intent.getStringExtra(UI_AUTO_TEST);
    164             if(mUiAutoTestPath != null) {
    165                 beginUiAutoTest();
    166             }
    167             return;
    168         }
    169 
    170         mResultFile = intent.getStringExtra(RESULT_FILE);
    171         mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 0);
    172         mGetDrawtime = intent.getBooleanExtra(GET_DRAW_TIME, false);
    173         mSaveImagePath = intent.getStringExtra(SAVE_IMAGE);
    174 
    175         Log.v(LOGTAG, "  Loading " + mTestUrl);
    176         mWebView.loadUrl(mTestUrl);
    177 
    178         if (mTimeoutInMillis > 0) {
    179             // Create a timeout timer
    180             Message m = mHandler.obtainMessage(MSG_TIMEOUT);
    181             mHandler.sendMessageDelayed(m, mTimeoutInMillis);
    182         }
    183     }
    184 
    185     private void beginUiAutoTest() {
    186         try {
    187             mTestListReader = new BufferedReader(
    188                     new FileReader(mUiAutoTestPath));
    189         } catch (IOException ioe) {
    190             Log.e(LOGTAG, "Failed to open test list for read.", ioe);
    191             finishUiAutoTest();
    192             return;
    193         }
    194         moveToNextTest();
    195     }
    196 
    197     private void finishUiAutoTest() {
    198         try {
    199             if(mTestListReader != null)
    200                 mTestListReader.close();
    201         } catch (IOException ioe) {
    202             Log.w(LOGTAG, "Failed to close test list file.", ioe);
    203         }
    204         ForwardService.getForwardService().stopForwardService();
    205         finished();
    206     }
    207 
    208     private void moveToNextTest() {
    209         String url = null;
    210         try {
    211             url = mTestListReader.readLine();
    212         } catch (IOException ioe) {
    213             Log.e(LOGTAG, "Failed to read next test.", ioe);
    214             finishUiAutoTest();
    215             return;
    216         }
    217         if (url == null) {
    218             mUiAutoTestPath = null;
    219             finishUiAutoTest();
    220             AlertDialog.Builder builder = new AlertDialog.Builder(this);
    221             builder.setMessage("All tests finished. Exit?")
    222                    .setCancelable(false)
    223                    .setPositiveButton("Yes", new OnClickListener(){
    224                        public void onClick(DialogInterface dialog, int which) {
    225                            TestShellActivity.this.finish();
    226                        }
    227                    })
    228                    .setNegativeButton("No", new OnClickListener(){
    229                        public void onClick(DialogInterface dialog, int which) {
    230                            dialog.cancel();
    231                        }
    232                    });
    233             builder.create().show();
    234             return;
    235         }
    236         Intent intent = new Intent(Intent.ACTION_VIEW);
    237         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
    238         intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
    239         intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
    240         executeIntent(intent);
    241     }
    242 
    243     @Override
    244     protected void onStop() {
    245         super.onStop();
    246         mWebView.stopLoading();
    247     }
    248 
    249     @Override
    250     protected void onDestroy() {
    251         super.onDestroy();
    252         mWebView.destroy();
    253         mWebView = null;
    254     }
    255 
    256     @Override
    257     public void onLowMemory() {
    258         super.onLowMemory();
    259         Log.e(LOGTAG, "Low memory, clearing caches");
    260         mWebView.freeMemory();
    261     }
    262 
    263     // Dump the page
    264     public void dump(boolean timeout, String webkitData) {
    265         mDumpWebKitData = true;
    266         if (mResultFile == null || mResultFile.length() == 0) {
    267             finished();
    268             return;
    269         }
    270 
    271         try {
    272             File parentDir = new File(mResultFile).getParentFile();
    273             if (!parentDir.exists()) {
    274                 parentDir.mkdirs();
    275             }
    276 
    277             FileOutputStream os = new FileOutputStream(mResultFile);
    278             if (timeout) {
    279                 Log.w("Layout test: Timeout", mResultFile);
    280                 os.write(TIMEOUT_STR.getBytes());
    281                 os.write('\n');
    282             }
    283             if (mDumpTitleChanges)
    284                 os.write(mTitleChanges.toString().getBytes());
    285             if (mDialogStrings != null)
    286                 os.write(mDialogStrings.toString().getBytes());
    287             mDialogStrings = null;
    288             if (mDatabaseCallbackStrings != null)
    289                 os.write(mDatabaseCallbackStrings.toString().getBytes());
    290             mDatabaseCallbackStrings = null;
    291             if (mConsoleMessages != null)
    292                 os.write(mConsoleMessages.toString().getBytes());
    293             mConsoleMessages = null;
    294             if (webkitData != null)
    295                 os.write(webkitData.getBytes());
    296             os.flush();
    297             os.close();
    298         } catch (IOException ex) {
    299             Log.e(LOGTAG, "Cannot write to " + mResultFile + ", " + ex.getMessage());
    300         }
    301 
    302         finished();
    303     }
    304 
    305     public void setCallback(TestShellCallback callback) {
    306         mCallback = callback;
    307     }
    308 
    309     public boolean finished() {
    310         if (canMoveToNextTest()) {
    311             mHandler.removeMessages(MSG_TIMEOUT);
    312             if (mUiAutoTestPath != null) {
    313                 //don't really finish here
    314                 moveToNextTest();
    315             } else {
    316                 if (mCallback != null) {
    317                     mCallback.finished();
    318                 }
    319             }
    320             return true;
    321         }
    322         return false;
    323     }
    324 
    325     public void setDefaultDumpDataType(DumpDataType defaultDumpDataType) {
    326         mDefaultDumpDataType = defaultDumpDataType;
    327     }
    328 
    329     // .......................................
    330     // LayoutTestController Functions
    331     public void dumpAsText() {
    332         mDumpDataType = DumpDataType.DUMP_AS_TEXT;
    333         if (mWebView != null) {
    334             String url = mWebView.getUrl();
    335             Log.v(LOGTAG, "dumpAsText called: "+url);
    336         }
    337     }
    338 
    339     public void waitUntilDone() {
    340         mWaitUntilDone = true;
    341         String url = mWebView.getUrl();
    342         Log.v(LOGTAG, "waitUntilDone called: " + url);
    343     }
    344 
    345     public void notifyDone() {
    346         String url = mWebView.getUrl();
    347         Log.v(LOGTAG, "notifyDone called: " + url);
    348         if (mWaitUntilDone) {
    349             mWaitUntilDone = false;
    350             mChromeClient.onProgressChanged(mWebView, 101);
    351         }
    352     }
    353 
    354     public void display() {
    355         mWebView.invalidate();
    356     }
    357 
    358     public void clearBackForwardList() {
    359         mWebView.clearHistory();
    360 
    361     }
    362 
    363     public void dumpBackForwardList() {
    364         //printf("\n============== Back Forward List ==============\n");
    365         // mWebHistory
    366         //printf("===============================================\n");
    367 
    368     }
    369 
    370     public void dumpChildFrameScrollPositions() {
    371         // TODO Auto-generated method stub
    372 
    373     }
    374 
    375     public void dumpEditingCallbacks() {
    376         // TODO Auto-generated method stub
    377 
    378     }
    379 
    380     public void dumpSelectionRect() {
    381         // TODO Auto-generated method stub
    382 
    383     }
    384 
    385     public void dumpTitleChanges() {
    386         if (!mDumpTitleChanges) {
    387             mTitleChanges = new StringBuffer();
    388         }
    389         mDumpTitleChanges = true;
    390     }
    391 
    392     public void keepWebHistory() {
    393         if (!mKeepWebHistory) {
    394             mWebHistory = new Vector();
    395         }
    396         mKeepWebHistory = true;
    397     }
    398 
    399     public void queueBackNavigation(int howfar) {
    400         // TODO Auto-generated method stub
    401 
    402     }
    403 
    404     public void queueForwardNavigation(int howfar) {
    405         // TODO Auto-generated method stub
    406 
    407     }
    408 
    409     public void queueLoad(String Url, String frameTarget) {
    410         // TODO Auto-generated method stub
    411 
    412     }
    413 
    414     public void queueReload() {
    415         mWebView.reload();
    416     }
    417 
    418     public void queueScript(String scriptToRunInCurrentContext) {
    419         mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
    420     }
    421 
    422     public void repaintSweepHorizontally() {
    423         // TODO Auto-generated method stub
    424 
    425     }
    426 
    427     public void setAcceptsEditing(boolean b) {
    428         // TODO Auto-generated method stub
    429 
    430     }
    431 
    432     public void setMainFrameIsFirstResponder(boolean b) {
    433         // TODO Auto-generated method stub
    434 
    435     }
    436 
    437     public void setWindowIsKey(boolean b) {
    438         // This is meant to show/hide the window. The best I can find
    439         // is setEnabled()
    440         mWebView.setEnabled(b);
    441     }
    442 
    443     public void testRepaint() {
    444         mWebView.invalidate();
    445     }
    446 
    447     public void dumpDatabaseCallbacks() {
    448         Log.v(LOGTAG, "dumpDatabaseCallbacks called.");
    449         mDumpDatabaseCallbacks = true;
    450     }
    451 
    452     public void setCanOpenWindows() {
    453         Log.v(LOGTAG, "setCanOpenWindows called.");
    454         mCanOpenWindows = true;
    455     }
    456 
    457     /**
    458      * Sets the Geolocation permission state to be used for all future requests.
    459      */
    460     public void setGeolocationPermission(boolean allow) {
    461         mGeolocationPermissionSet = true;
    462         mGeolocationPermission = allow;
    463     }
    464 
    465     public void overridePreference(String key, boolean value) {
    466         // TODO: We should look up the correct WebView for the frame which
    467         // called the layoutTestController method. Currently, we just use the
    468         // WebView for the main frame. EventSender suffers from the same
    469         // problem.
    470         if (key.equals(WEBKIT_OFFLINE_WEB_APPLICATION_CACHE_ENABLED)) {
    471             mWebView.getSettings().setAppCacheEnabled(value);
    472         }
    473     }
    474 
    475     private final WebViewClient mViewClient = new WebViewClient(){
    476         @Override
    477         public void onPageFinished(WebView view, String url) {
    478             Log.v(LOGTAG, "onPageFinished, url=" + url);
    479             mPageFinished = true;
    480             // get page draw time
    481             if (FsUtils.isTestPageUrl(url)) {
    482                 if (mGetDrawtime) {
    483                     long[] times = new long[DRAW_RUNS];
    484                     times = getDrawWebViewTime(mWebView, DRAW_RUNS);
    485                     FsUtils.writeDrawTime(DRAW_TIME_LOG, url, times);
    486                 }
    487                 if (mSaveImagePath != null) {
    488                     String name = FsUtils.getLastSegmentInPath(url);
    489                     drawPageToFile(mSaveImagePath + "/" + name + ".png", mWebView);
    490                 }
    491             }
    492             // Calling finished() will check if we've met all the conditions for completing
    493             // this test and move to the next one if we are ready.
    494             if (finished()) {
    495                 return;
    496             }
    497             super.onPageFinished(view, url);
    498         }
    499 
    500         @Override
    501         public void onPageStarted(WebView view, String url, Bitmap favicon) {
    502             Log.v(LOGTAG, "onPageStarted, url=" + url);
    503             mPageFinished = false;
    504             super.onPageStarted(view, url, favicon);
    505         }
    506 
    507         @Override
    508         public void onReceivedError(WebView view, int errorCode, String description,
    509                 String failingUrl) {
    510             Log.v(LOGTAG, "onReceivedError, errorCode=" + errorCode
    511                     + ", desc=" + description + ", url=" + failingUrl);
    512             super.onReceivedError(view, errorCode, description, failingUrl);
    513         }
    514 
    515         @Override
    516         public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler,
    517                 String host, String realm) {
    518             if (handler.useHttpAuthUsernamePassword() && view != null) {
    519                 String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
    520                 if (credentials != null && credentials.length == 2) {
    521                     handler.proceed(credentials[0], credentials[1]);
    522                     return;
    523                 }
    524             }
    525             handler.cancel();
    526         }
    527 
    528         @Override
    529         public void onReceivedSslError(WebView view, SslErrorHandler handler,
    530                 SslError error) {
    531             handler.proceed();
    532         }
    533     };
    534 
    535 
    536     private final WebChromeClient mChromeClient = new WebChromeClient() {
    537         @Override
    538         public void onProgressChanged(WebView view, int newProgress) {
    539 
    540             // notifyDone calls this with 101%. We only want to update this flag if this
    541             // is the real call from WebCore.
    542             if (newProgress == 100) {
    543                 mOneHundredPercentComplete = true;
    544             }
    545 
    546             // With the flag updated, we can now proceed as normal whether the progress update came from
    547             // WebCore or notifyDone.
    548             if (newProgress >= 100) {
    549                 // finished() will check if we are ready to move to the next test and do so if we are.
    550                 if (finished()) {
    551                     return;
    552                 }
    553 
    554                 if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
    555                     String url = mWebView.getUrl();
    556                     Log.v(LOGTAG, "Finished: "+ url);
    557                     requestWebKitData();
    558                 } else {
    559                     String url = mWebView.getUrl();
    560                     if (mTimedOut) {
    561                         Log.v(LOGTAG, "Timed out before finishing: " + url);
    562                     } else if (mWaitUntilDone) {
    563                         Log.v(LOGTAG, "Waiting for notifyDone: " + url);
    564                     } else if (mRequestedWebKitData) {
    565                         Log.v(LOGTAG, "Requested webkit data ready: " + url);
    566                     }
    567                 }
    568             }
    569         }
    570 
    571         @Override
    572         public void onReceivedTitle(WebView view, String title) {
    573             if (title.length() > 30)
    574                 title = "..."+title.substring(title.length()-30);
    575             setTitle(title);
    576             if (mDumpTitleChanges) {
    577                 mTitleChanges.append("TITLE CHANGED: ");
    578                 mTitleChanges.append(title);
    579                 mTitleChanges.append("\n");
    580             }
    581         }
    582 
    583         @Override
    584         public boolean onJsAlert(WebView view, String url, String message,
    585                 JsResult result) {
    586             if (mDialogStrings == null) {
    587                 mDialogStrings = new StringBuffer();
    588             }
    589             mDialogStrings.append("ALERT: ");
    590             mDialogStrings.append(message);
    591             mDialogStrings.append('\n');
    592             result.confirm();
    593             return true;
    594         }
    595 
    596         @Override
    597         public boolean onJsConfirm(WebView view, String url, String message,
    598                 JsResult result) {
    599             if (mDialogStrings == null) {
    600                 mDialogStrings = new StringBuffer();
    601             }
    602             mDialogStrings.append("CONFIRM: ");
    603             mDialogStrings.append(message);
    604             mDialogStrings.append('\n');
    605             result.confirm();
    606             return true;
    607         }
    608 
    609         @Override
    610         public boolean onJsPrompt(WebView view, String url, String message,
    611                 String defaultValue, JsPromptResult result) {
    612             if (mDialogStrings == null) {
    613                 mDialogStrings = new StringBuffer();
    614             }
    615             mDialogStrings.append("PROMPT: ");
    616             mDialogStrings.append(message);
    617             mDialogStrings.append(", default text: ");
    618             mDialogStrings.append(defaultValue);
    619             mDialogStrings.append('\n');
    620             result.confirm();
    621             return true;
    622         }
    623 
    624         @Override
    625         public boolean onJsTimeout() {
    626             Log.v(LOGTAG, "JavaScript timeout");
    627             return false;
    628         }
    629 
    630         @Override
    631         public void onExceededDatabaseQuota(String url_str,
    632                 String databaseIdentifier, long currentQuota,
    633                 long estimatedSize, long totalUsedQuota,
    634                 WebStorage.QuotaUpdater callback) {
    635             if (mDumpDatabaseCallbacks) {
    636                 if (mDatabaseCallbackStrings == null) {
    637                     mDatabaseCallbackStrings = new StringBuffer();
    638                 }
    639 
    640                 String protocol = "";
    641                 String host = "";
    642                 int port = 0;
    643 
    644                 try {
    645                     URL url = new URL(url_str);
    646                     protocol = url.getProtocol();
    647                     host = url.getHost();
    648                     if (url.getPort() > -1) {
    649                         port = url.getPort();
    650                     }
    651                 } catch (MalformedURLException e) {}
    652 
    653                 String databaseCallbackString =
    654                         "UI DELEGATE DATABASE CALLBACK: " +
    655                         "exceededDatabaseQuotaForSecurityOrigin:{" + protocol +
    656                         ", " + host + ", " + port + "} database:" +
    657                         databaseIdentifier + "\n";
    658                 Log.v(LOGTAG, "LOG: "+databaseCallbackString);
    659                 mDatabaseCallbackStrings.append(databaseCallbackString);
    660             }
    661             // Give 5MB more quota.
    662             callback.updateQuota(currentQuota + 1024 * 1024 * 5);
    663         }
    664 
    665         /**
    666          * Instructs the client to show a prompt to ask the user to set the
    667          * Geolocation permission state for the specified origin.
    668          */
    669         @Override
    670         public void onGeolocationPermissionsShowPrompt(String origin,
    671                 GeolocationPermissions.Callback callback) {
    672             if (mGeolocationPermissionSet) {
    673                 callback.invoke(origin, mGeolocationPermission, false);
    674             }
    675         }
    676 
    677         @Override
    678         public void onConsoleMessage(String message, int lineNumber,
    679                 String sourceID) {
    680             if (mConsoleMessages == null) {
    681                 mConsoleMessages = new StringBuffer();
    682             }
    683             String consoleMessage = "CONSOLE MESSAGE: line "
    684                     + lineNumber +": "+ message +"\n";
    685             mConsoleMessages.append(consoleMessage);
    686             Log.v(LOGTAG, "LOG: "+consoleMessage);
    687         }
    688 
    689         @Override
    690         public boolean onCreateWindow(WebView view, boolean dialog,
    691                 boolean userGesture, Message resultMsg) {
    692             if (!mCanOpenWindows) {
    693                 // We can't open windows, so just send null back.
    694                 WebView.WebViewTransport transport =
    695                         (WebView.WebViewTransport) resultMsg.obj;
    696                 transport.setWebView(null);
    697                 resultMsg.sendToTarget();
    698                 return true;
    699             }
    700 
    701             // We never display the new window, just create the view and
    702             // allow it's content to execute and be recorded by the test
    703             // runner.
    704 
    705             HashMap<String, Object> jsIfaces = new HashMap<String, Object>();
    706             jsIfaces.put("layoutTestController", mCallbackProxy);
    707             jsIfaces.put("eventSender", mCallbackProxy);
    708             WebView newWindowView = new NewWindowWebView(TestShellActivity.this, jsIfaces);
    709             setupWebViewForLayoutTests(newWindowView, mCallbackProxy);
    710             WebView.WebViewTransport transport =
    711                     (WebView.WebViewTransport) resultMsg.obj;
    712             transport.setWebView(newWindowView);
    713             resultMsg.sendToTarget();
    714             return true;
    715         }
    716 
    717         @Override
    718         public void onCloseWindow(WebView view) {
    719             view.destroy();
    720         }
    721     };
    722 
    723     private static class NewWindowWebView extends WebView {
    724         public NewWindowWebView(Context context, Map<String, Object> jsIfaces) {
    725             super(context, null, 0, jsIfaces);
    726         }
    727     }
    728 
    729     private void resetTestStatus() {
    730         mWaitUntilDone = false;
    731         mDumpDataType = mDefaultDumpDataType;
    732         mTimedOut = false;
    733         mDumpTitleChanges = false;
    734         mRequestedWebKitData = false;
    735         mDumpDatabaseCallbacks = false;
    736         mCanOpenWindows = false;
    737         mEventSender.resetMouse();
    738         mEventSender.clearTouchPoints();
    739         mEventSender.clearTouchMetaState();
    740         mPageFinished = false;
    741         mOneHundredPercentComplete = false;
    742         mDumpWebKitData = false;
    743         mGetDrawtime = false;
    744         mSaveImagePath = null;
    745     }
    746 
    747     private long[] getDrawWebViewTime(WebView view, int count) {
    748         if (count == 0)
    749             return null;
    750         long[] ret = new long[count];
    751         long start;
    752         Canvas canvas = new Canvas();
    753         Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Config.ARGB_8888);
    754         canvas.setBitmap(bitmap);
    755         for (int i = 0; i < count; i++) {
    756             start = System.currentTimeMillis();
    757             view.draw(canvas);
    758             ret[i] = System.currentTimeMillis() - start;
    759         }
    760         return ret;
    761     }
    762 
    763     private void drawPageToFile(String fileName, WebView view) {
    764         Canvas canvas = new Canvas();
    765         Bitmap bitmap = Bitmap.createBitmap(view.getContentWidth(), view.getContentHeight(),
    766                 Config.ARGB_8888);
    767         canvas.setBitmap(bitmap);
    768         view.drawPage(canvas);
    769         try {
    770             FileOutputStream fos = new FileOutputStream(fileName);
    771             if(!bitmap.compress(CompressFormat.PNG, 90, fos)) {
    772                 Log.w(LOGTAG, "Failed to compress and save image.");
    773             }
    774         } catch (IOException ioe) {
    775             Log.e(LOGTAG, "", ioe);
    776         }
    777         bitmap.recycle();
    778     }
    779 
    780     private boolean canMoveToNextTest() {
    781         return (mDumpWebKitData && mOneHundredPercentComplete && mPageFinished && !mWaitUntilDone) || mTimedOut;
    782     }
    783 
    784     private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
    785         if (webview == null) {
    786             return;
    787         }
    788 
    789         WebSettings settings = webview.getSettings();
    790         settings.setAppCacheEnabled(true);
    791         settings.setAppCachePath(getApplicationContext().getCacheDir().getPath());
    792         settings.setAppCacheMaxSize(Long.MAX_VALUE);
    793         settings.setJavaScriptEnabled(true);
    794         settings.setJavaScriptCanOpenWindowsAutomatically(true);
    795         settings.setSupportMultipleWindows(true);
    796         settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
    797         settings.setDatabaseEnabled(true);
    798         settings.setDatabasePath(getDir("databases",0).getAbsolutePath());
    799         settings.setDomStorageEnabled(true);
    800         settings.setWorkersEnabled(false);
    801 
    802         webview.setWebChromeClient(mChromeClient);
    803         webview.setWebViewClient(mViewClient);
    804         // Setting a touch interval of -1 effectively disables the optimisation in WebView
    805         // that stops repeated touch events flooding WebCore. The Event Sender only sends a
    806         // single event rather than a stream of events (like what would generally happen in
    807         // a real use of touch events in a WebView)  and so if the WebView drops the event,
    808         // the test will fail as the test expects one callback for every touch it synthesizes.
    809         webview.setTouchInterval(-1);
    810     }
    811 
    812     private WebView mWebView;
    813     private WebViewEventSender mEventSender;
    814     private AsyncHandler mHandler;
    815     private TestShellCallback mCallback;
    816 
    817     private CallbackProxy mCallbackProxy;
    818 
    819     private String mTestUrl;
    820     private String mResultFile;
    821     private int mTimeoutInMillis;
    822     private String mUiAutoTestPath;
    823     private String mSaveImagePath;
    824     private BufferedReader mTestListReader;
    825     private boolean mGetDrawtime;
    826 
    827     // States
    828     private boolean mTimedOut;
    829     private boolean mRequestedWebKitData;
    830     private boolean mFinishedRunning;
    831 
    832     // Layout test controller variables.
    833     private DumpDataType mDumpDataType;
    834     private DumpDataType mDefaultDumpDataType = DumpDataType.EXT_REPR;
    835     private boolean mWaitUntilDone;
    836     private boolean mDumpTitleChanges;
    837     private StringBuffer mTitleChanges;
    838     private StringBuffer mDialogStrings;
    839     private boolean mKeepWebHistory;
    840     private Vector mWebHistory;
    841     private boolean mDumpDatabaseCallbacks;
    842     private StringBuffer mDatabaseCallbackStrings;
    843     private StringBuffer mConsoleMessages;
    844     private boolean mCanOpenWindows;
    845 
    846     private boolean mPageFinished = false;
    847     private boolean mDumpWebKitData = false;
    848     private boolean mOneHundredPercentComplete = false;
    849 
    850     static final String TIMEOUT_STR = "**Test timeout";
    851 
    852     static final int MSG_TIMEOUT = 0;
    853     static final int MSG_WEBKIT_DATA = 1;
    854 
    855     static final String LOGTAG="TestShell";
    856 
    857     static final String TEST_URL = "TestUrl";
    858     static final String RESULT_FILE = "ResultFile";
    859     static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
    860     static final String UI_AUTO_TEST = "UiAutoTest";
    861     static final String GET_DRAW_TIME = "GetDrawTime";
    862     static final String SAVE_IMAGE = "SaveImage";
    863 
    864     static final int DRAW_RUNS = 5;
    865     static final String DRAW_TIME_LOG = "/sdcard/android/page_draw_time.txt";
    866 
    867     private boolean mGeolocationPermissionSet;
    868     private boolean mGeolocationPermission;
    869 }
    870