Home | History | Annotate | Download | only in dumprendertree
      1 /*
      2  * Copyright (C) 2009 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 android.app.Activity;
     20 import android.app.ActivityThread;
     21 import android.graphics.Bitmap;
     22 import android.net.http.SslError;
     23 import android.os.Bundle;
     24 import android.os.Handler;
     25 import android.os.Message;
     26 import android.util.Log;
     27 import android.view.ViewGroup;
     28 import android.webkit.HttpAuthHandler;
     29 import android.webkit.JsPromptResult;
     30 import android.webkit.JsResult;
     31 import android.webkit.SslErrorHandler;
     32 import android.webkit.WebChromeClient;
     33 import android.webkit.WebView;
     34 import android.webkit.WebViewClient;
     35 import android.webkit.WebSettings.LayoutAlgorithm;
     36 import android.widget.LinearLayout;
     37 import android.widget.LinearLayout.LayoutParams;
     38 
     39 public class ReliabilityTestActivity extends Activity {
     40 
     41     public static final String TEST_URL_ACTION = "com.andrdoid.dumprendertree.TestUrlAction";
     42     public static final String PARAM_URL = "URL";
     43     public static final String PARAM_TIMEOUT = "Timeout";
     44     public static final int RESULT_TIMEOUT = 0xDEAD;
     45     public static final int MSG_TIMEOUT = 0xC001;
     46     public static final int MSG_NAVIGATE = 0xC002;
     47     public static final String MSG_NAV_URL = "url";
     48     public static final String MSG_NAV_LOGTIME = "logtime";
     49 
     50     private static final String LOGTAG = "ReliabilityTestActivity";
     51 
     52     private WebView webView;
     53     private SimpleWebViewClient webViewClient;
     54     private SimpleChromeClient chromeClient;
     55     private Handler handler;
     56     private boolean timeoutFlag;
     57     private boolean logTime;
     58     private boolean pageDone;
     59     private Object pageDoneLock;
     60     private int pageStartCount;
     61     private int manualDelay;
     62     private long startTime;
     63     private long pageLoadTime;
     64     private PageDoneRunner pageDoneRunner = new PageDoneRunner();
     65 
     66     @Override
     67     protected void onCreate(Bundle savedInstanceState) {
     68         super.onCreate(savedInstanceState);
     69 
     70         Log.v(LOGTAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
     71 
     72         LinearLayout contentView = new LinearLayout(this);
     73         contentView.setOrientation(LinearLayout.VERTICAL);
     74         setContentView(contentView);
     75         setTitle("Idle");
     76 
     77         webView = new WebView(this);
     78         webView.getSettings().setJavaScriptEnabled(true);
     79         webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
     80         webView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
     81 
     82         webViewClient = new SimpleWebViewClient();
     83         chromeClient = new SimpleChromeClient();
     84         webView.setWebViewClient(webViewClient);
     85         webView.setWebChromeClient(chromeClient);
     86 
     87         contentView.addView(webView, new LayoutParams(
     88                 ViewGroup.LayoutParams.MATCH_PARENT,
     89                 ViewGroup.LayoutParams.MATCH_PARENT, 0.0f));
     90 
     91         handler = new Handler() {
     92             @Override
     93             public void handleMessage(Message msg) {
     94                 switch (msg.what) {
     95                     case MSG_TIMEOUT:
     96                         handleTimeout();
     97                         return;
     98                     case MSG_NAVIGATE:
     99                         manualDelay = msg.arg2;
    100                         navigate(msg.getData().getString(MSG_NAV_URL), msg.arg1);
    101                         logTime = msg.getData().getBoolean(MSG_NAV_LOGTIME);
    102                         return;
    103                 }
    104             }
    105         };
    106 
    107         pageDoneLock = new Object();
    108     }
    109 
    110     public void reset() {
    111         synchronized (pageDoneLock) {
    112             pageDone = false;
    113         }
    114         timeoutFlag = false;
    115         pageStartCount = 0;
    116         chromeClient.resetJsTimeout();
    117     }
    118 
    119     private void navigate(String url, int timeout) {
    120         if(url == null) {
    121             Log.v(LOGTAG, "URL is null, cancelling...");
    122             finish();
    123         }
    124         webView.stopLoading();
    125         if(logTime) {
    126             webView.clearCache(true);
    127         }
    128         startTime = System.currentTimeMillis();
    129         Log.v(LOGTAG, "Navigating to URL: " + url);
    130         webView.loadUrl(url);
    131 
    132         if(timeout != 0) {
    133             //set a timer with specified timeout (in ms)
    134             handler.sendMessageDelayed(handler.obtainMessage(MSG_TIMEOUT),
    135                     timeout);
    136         }
    137     }
    138 
    139     @Override
    140     protected void onDestroy() {
    141         super.onDestroy();
    142         Log.v(LOGTAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
    143         webView.clearCache(true);
    144         webView.destroy();
    145     }
    146 
    147     private boolean isPageDone() {
    148         synchronized (pageDoneLock) {
    149             return pageDone;
    150         }
    151     }
    152 
    153     private void setPageDone(boolean pageDone) {
    154         synchronized (pageDoneLock) {
    155             this.pageDone = pageDone;
    156             pageDoneLock.notifyAll();
    157         }
    158     }
    159 
    160     private void handleTimeout() {
    161         int progress = webView.getProgress();
    162         webView.stopLoading();
    163         Log.v(LOGTAG, "Page timeout triggered, progress = " + progress);
    164         timeoutFlag = true;
    165         handler.postDelayed(pageDoneRunner, manualDelay);
    166     }
    167 
    168     public boolean waitUntilDone() {
    169         validateNotAppThread();
    170         synchronized (pageDoneLock) {
    171             while(!isPageDone()) {
    172                 try {
    173                     pageDoneLock.wait();
    174                 } catch (InterruptedException ie) {
    175                     //no-op
    176                 }
    177             }
    178         }
    179         return timeoutFlag;
    180     }
    181 
    182     public Handler getHandler() {
    183         return handler;
    184     }
    185 
    186     private final void validateNotAppThread() {
    187         if (ActivityThread.currentActivityThread() != null) {
    188             throw new RuntimeException(
    189                 "This method can not be called from the main application thread");
    190         }
    191     }
    192 
    193     public long getPageLoadTime() {
    194         return pageLoadTime;
    195     }
    196 
    197     class SimpleWebViewClient extends WebViewClient {
    198 
    199         @Override
    200         public void onReceivedError(WebView view, int errorCode, String description,
    201                 String failingUrl) {
    202             Log.v(LOGTAG, "Received WebCore error: code=" + errorCode
    203                     + ", description=" + description
    204                     + ", url=" + failingUrl);
    205         }
    206 
    207         @Override
    208         public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
    209             //ignore certificate error
    210             Log.v(LOGTAG, "Received SSL error: " + error.toString());
    211             handler.proceed();
    212         }
    213 
    214         @Override
    215         public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host,
    216                 String realm) {
    217             // cancel http auth request
    218             handler.cancel();
    219         }
    220 
    221         @Override
    222         public void onPageStarted(WebView view, String url, Bitmap favicon) {
    223             pageStartCount++;
    224             Log.v(LOGTAG, "onPageStarted: " + url);
    225         }
    226 
    227         @Override
    228         public void onPageFinished(WebView view, String url) {
    229             Log.v(LOGTAG, "onPageFinished: " + url);
    230             // let handleTimeout take care of finishing the page
    231             if(!timeoutFlag)
    232                 handler.postDelayed(new WebViewStatusChecker(), 500);
    233         }
    234     }
    235 
    236     class SimpleChromeClient extends WebChromeClient {
    237 
    238         private int timeoutCounter = 0;
    239 
    240         @Override
    241         public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    242             result.confirm();
    243             return true;
    244         }
    245 
    246         @Override
    247         public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) {
    248             result.confirm();
    249             return true;
    250         }
    251 
    252         @Override
    253         public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {
    254             result.confirm();
    255             return true;
    256         }
    257 
    258         @Override
    259         public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
    260                 JsPromptResult result) {
    261             result.confirm();
    262             return true;
    263         }
    264 
    265         @Override
    266         public boolean onJsTimeout() {
    267             timeoutCounter++;
    268             Log.v(LOGTAG, "JavaScript timeout, count=" + timeoutCounter);
    269             return timeoutCounter > 2;
    270         }
    271 
    272         public void resetJsTimeout() {
    273             timeoutCounter = 0;
    274         }
    275 
    276         @Override
    277         public void onReceivedTitle(WebView view, String title) {
    278             ReliabilityTestActivity.this.setTitle(title);
    279         }
    280     }
    281 
    282     class WebViewStatusChecker implements Runnable {
    283 
    284         private int initialStartCount;
    285 
    286         public WebViewStatusChecker() {
    287             initialStartCount = pageStartCount;
    288         }
    289 
    290         public void run() {
    291             if (initialStartCount == pageStartCount && !isPageDone()) {
    292                 handler.removeMessages(MSG_TIMEOUT);
    293                 webView.stopLoading();
    294                 handler.postDelayed(pageDoneRunner, manualDelay);
    295             }
    296         }
    297     }
    298 
    299     class PageDoneRunner implements Runnable {
    300 
    301         public void run() {
    302             Log.v(LOGTAG, "Finishing URL: " + webView.getUrl());
    303             pageLoadTime = System.currentTimeMillis() - startTime;
    304             setPageDone(true);
    305         }
    306     }
    307 }
    308