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