• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.test.tilebenchmark;
18 
19 import android.content.Context;
20 import android.os.CountDownTimer;
21 import android.util.AttributeSet;
22 import android.util.Log;
23 import android.webkit.WebSettingsClassic;
24 import android.webkit.WebView;
25 import android.webkit.WebViewClassic;
26 
27 import java.util.ArrayList;
28 
29 import com.test.tilebenchmark.ProfileActivity.ProfileCallback;
30 import com.test.tilebenchmark.RunData.TileData;
31 
32 public class ProfiledWebView extends WebView implements WebViewClassic.PageSwapDelegate {
33     private static final String LOGTAG = "ProfiledWebView";
34 
35     private int mSpeed;
36 
37     private boolean mIsTesting = false;
38     private boolean mIsScrolling = false;
39     private ProfileCallback mCallback;
40     private long mContentInvalMillis;
41     private static final int LOAD_STALL_MILLIS = 2000; // nr of millis after load,
42                                                        // before test is forced
43 
44     // ignore anim end events until this many millis after load
45     private static final long ANIM_SAFETY_THRESHOLD = 200;
46     private long mLoadTime;
47     private long mAnimationTime;
48 
ProfiledWebView(Context context)49     public ProfiledWebView(Context context) {
50         super(context);
51     }
52 
ProfiledWebView(Context context, AttributeSet attrs)53     public ProfiledWebView(Context context, AttributeSet attrs) {
54         super(context, attrs);
55     }
56 
ProfiledWebView(Context context, AttributeSet attrs, int defStyle)57     public ProfiledWebView(Context context, AttributeSet attrs, int defStyle) {
58         super(context, attrs, defStyle);
59     }
60 
ProfiledWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing)61     public ProfiledWebView(Context context, AttributeSet attrs, int defStyle,
62             boolean privateBrowsing) {
63         super(context, attrs, defStyle, privateBrowsing);
64     }
65 
66     private class JavaScriptInterface {
67         Context mContext;
68 
69         /** Instantiate the interface and set the context */
JavaScriptInterface(Context c)70         JavaScriptInterface(Context c) {
71             mContext = c;
72         }
73 
animationComplete()74         public void animationComplete() {
75             mAnimationTime = System.currentTimeMillis();
76         }
77     }
78 
init(Context c)79     public void init(Context c) {
80         WebSettingsClassic settings = getWebViewClassic().getSettings();
81         settings.setJavaScriptEnabled(true);
82         settings.setSupportZoom(true);
83         settings.setEnableSmoothTransition(true);
84         settings.setBuiltInZoomControls(true);
85         settings.setLoadWithOverviewMode(true);
86         settings.setProperty("use_minimal_memory", "false"); // prefetch tiles, as browser does
87         addJavascriptInterface(new JavaScriptInterface(c), "Android");
88         mAnimationTime = 0;
89         mLoadTime = 0;
90     }
91 
setUseMinimalMemory(boolean minimal)92     public void setUseMinimalMemory(boolean minimal) {
93         WebSettingsClassic settings = getWebViewClassic().getSettings();
94         settings.setProperty("use_minimal_memory", minimal ? "true" : "false");
95     }
96 
onPageFinished()97     public void onPageFinished() {
98         mLoadTime = System.currentTimeMillis();
99     }
100 
101     @Override
onDraw(android.graphics.Canvas canvas)102     protected void onDraw(android.graphics.Canvas canvas) {
103         if (mIsTesting && mIsScrolling) {
104             if (canScrollVertically(1)) {
105                 scrollBy(0, mSpeed);
106             } else {
107                 stopScrollTest();
108                 mIsScrolling = false;
109             }
110         }
111         super.onDraw(canvas);
112     }
113 
114     /*
115      * Called once the page is loaded to start scrolling for evaluating tiles.
116      * If autoScrolling isn't set, stop must be called manually. Before
117      * scrolling, invalidate all content and redraw it, measuring time taken.
118      */
startScrollTest(ProfileCallback callback, boolean autoScrolling)119     public void startScrollTest(ProfileCallback callback, boolean autoScrolling) {
120         mCallback = callback;
121         mIsTesting = false;
122         mIsScrolling = false;
123         WebSettingsClassic settings = getWebViewClassic().getSettings();
124         settings.setProperty("tree_updates", "0");
125 
126 
127         if (autoScrolling) {
128             // after a while, force it to start even if the pages haven't swapped
129             new CountDownTimer(LOAD_STALL_MILLIS, LOAD_STALL_MILLIS) {
130                 @Override
131                 public void onTick(long millisUntilFinished) {
132                 }
133 
134                 @Override
135                 public void onFinish() {
136                     // invalidate all content, and kick off redraw
137                     Log.d("ProfiledWebView",
138                             "kicking off test with callback registration, and tile discard...");
139                     getWebViewClassic().discardAllTextures();
140                     invalidate();
141                     mIsScrolling = true;
142                     mContentInvalMillis = System.currentTimeMillis();
143                 }
144             }.start();
145         } else {
146             mIsTesting = true;
147             getWebViewClassic().tileProfilingStart();
148         }
149     }
150 
151     /*
152      * Called after the manual contentInvalidateAll, after the tiles have all
153      * been redrawn.
154      * From PageSwapDelegate.
155      */
156     @Override
onPageSwapOccurred(boolean startAnim)157     public void onPageSwapOccurred(boolean startAnim) {
158         if (!mIsTesting && mIsScrolling) {
159             // kick off testing
160             mContentInvalMillis = System.currentTimeMillis() - mContentInvalMillis;
161             Log.d("ProfiledWebView", "REDRAW TOOK " + mContentInvalMillis + "millis");
162             mIsTesting = true;
163             invalidate(); // ensure a redraw so that auto-scrolling can occur
164             getWebViewClassic().tileProfilingStart();
165         }
166     }
167 
animFramerate()168     private double animFramerate() {
169         WebSettingsClassic settings = getWebViewClassic().getSettings();
170         String updatesString = settings.getProperty("tree_updates");
171         int updates = (updatesString == null) ? -1 : Integer.parseInt(updatesString);
172 
173         long animationTime;
174         if (mAnimationTime == 0 || mAnimationTime - mLoadTime < ANIM_SAFETY_THRESHOLD) {
175             animationTime = System.currentTimeMillis() - mLoadTime;
176         } else {
177             animationTime = mAnimationTime - mLoadTime;
178         }
179 
180         return updates * 1000.0 / animationTime;
181     }
182 
setDoubleBuffering(boolean useDoubleBuffering)183     public void setDoubleBuffering(boolean useDoubleBuffering) {
184         WebSettingsClassic settings = getWebViewClassic().getSettings();
185         settings.setProperty("use_double_buffering", useDoubleBuffering ? "true" : "false");
186     }
187 
188     /*
189      * Called once the page has stopped scrolling
190      */
stopScrollTest()191     public void stopScrollTest() {
192         getWebViewClassic().tileProfilingStop();
193         mIsTesting = false;
194 
195         if (mCallback == null) {
196             getWebViewClassic().tileProfilingClear();
197             return;
198         }
199 
200         RunData data = new RunData(getWebViewClassic().tileProfilingNumFrames());
201         // record the time spent (before scrolling) rendering the page
202         data.singleStats.put(getResources().getString(R.string.render_millis),
203                 (double)mContentInvalMillis);
204 
205         // record framerate
206         double framerate = animFramerate();
207         Log.d(LOGTAG, "anim framerate was "+framerate);
208         data.singleStats.put(getResources().getString(R.string.animation_framerate),
209                 framerate);
210 
211         for (int frame = 0; frame < data.frames.length; frame++) {
212             data.frames[frame] = new TileData[
213                     getWebViewClassic().tileProfilingNumTilesInFrame(frame)];
214             for (int tile = 0; tile < data.frames[frame].length; tile++) {
215                 int left = getWebViewClassic().tileProfilingGetInt(frame, tile, "left");
216                 int top = getWebViewClassic().tileProfilingGetInt(frame, tile, "top");
217                 int right = getWebViewClassic().tileProfilingGetInt(frame, tile, "right");
218                 int bottom = getWebViewClassic().tileProfilingGetInt(frame, tile, "bottom");
219 
220                 boolean isReady = getWebViewClassic().tileProfilingGetInt(
221                         frame, tile, "isReady") == 1;
222                 int level = getWebViewClassic().tileProfilingGetInt(frame, tile, "level");
223 
224                 float scale = getWebViewClassic().tileProfilingGetFloat(frame, tile, "scale");
225 
226                 data.frames[frame][tile] = data.new TileData(left, top, right, bottom,
227                         isReady, level, scale);
228             }
229         }
230         getWebViewClassic().tileProfilingClear();
231 
232         mCallback.profileCallback(data);
233     }
234 
235     @Override
loadUrl(String url)236     public void loadUrl(String url) {
237         mAnimationTime = 0;
238         mLoadTime = 0;
239         if (!url.startsWith("http://") && !url.startsWith("file://")) {
240             url = "http://" + url;
241         }
242         super.loadUrl(url);
243     }
244 
setAutoScrollSpeed(int speedInt)245     public void setAutoScrollSpeed(int speedInt) {
246         mSpeed = speedInt;
247     }
248 
getWebViewClassic()249     public WebViewClassic getWebViewClassic() {
250         return WebViewClassic.fromWebView(this);
251     }
252 }
253