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.app.Activity; 20 import android.content.Intent; 21 import android.content.Context; 22 import android.graphics.Bitmap; 23 import android.os.AsyncTask; 24 import android.os.Bundle; 25 import android.util.Pair; 26 import android.view.KeyEvent; 27 import android.view.View; 28 import android.view.View.OnClickListener; 29 import android.webkit.WebSettings; 30 import android.webkit.WebView; 31 import android.webkit.WebViewClient; 32 import android.widget.AdapterView; 33 import android.widget.AdapterView.OnItemSelectedListener; 34 import android.widget.ArrayAdapter; 35 import android.widget.Button; 36 import android.widget.EditText; 37 import android.widget.Spinner; 38 import android.widget.TextView; 39 import android.widget.TextView.OnEditorActionListener; 40 import android.widget.ToggleButton; 41 42 import java.io.FileOutputStream; 43 import java.io.IOException; 44 import java.io.ObjectOutputStream; 45 46 /** 47 * Interface for profiling the webview's scrolling, with simple controls on how 48 * to scroll, and what content to load. 49 */ 50 public class ProfileActivity extends Activity { 51 52 public interface ProfileCallback { profileCallback(RunData data)53 public void profileCallback(RunData data); 54 } 55 56 public static final String TEMP_FILENAME = "profile.tiles"; 57 58 Button mInspectButton; 59 ToggleButton mCaptureButton; 60 Spinner mVelocitySpinner; 61 Spinner mMovementSpinner; 62 EditText mUrl; 63 ProfiledWebView mWeb; 64 ProfileCallback mCallback; 65 66 LoggingWebViewClient mLoggingWebViewClient = new LoggingWebViewClient(); 67 AutoLoggingWebViewClient mAutoLoggingWebViewClient = new AutoLoggingWebViewClient(); 68 69 private enum TestingState { 70 NOT_TESTING, 71 PRE_TESTING, 72 START_TESTING, 73 STOP_TESTING, 74 SAVED_TESTING 75 }; 76 77 private class VelocitySelectedListener implements OnItemSelectedListener { 78 @Override onItemSelected(AdapterView<?> parent, View view, int position, long id)79 public void onItemSelected(AdapterView<?> parent, View view, 80 int position, long id) { 81 String speedStr = parent.getItemAtPosition(position).toString(); 82 int speedInt = Integer.parseInt(speedStr); 83 mWeb.setAutoScrollSpeed(speedInt); 84 } 85 86 @Override onNothingSelected(AdapterView<?> parent)87 public void onNothingSelected(AdapterView<?> parent) { 88 } 89 } 90 91 private class MovementSelectedListener implements OnItemSelectedListener { 92 @Override onItemSelected(AdapterView<?> parent, View view, int position, long id)93 public void onItemSelected(AdapterView<?> parent, View view, 94 int position, long id) { 95 String movementStr = parent.getItemAtPosition(position).toString(); 96 if (movementStr == getResources().getString( 97 R.string.movement_auto_scroll) 98 || movementStr == getResources().getString( 99 R.string.movement_auto_fling)) { 100 mWeb.setWebViewClient(mAutoLoggingWebViewClient); 101 mCaptureButton.setEnabled(false); 102 mVelocitySpinner.setEnabled(true); 103 } else if (movementStr == getResources().getString( 104 R.string.movement_manual)) { 105 mWeb.setWebViewClient(mLoggingWebViewClient); 106 mCaptureButton.setEnabled(true); 107 mVelocitySpinner.setEnabled(false); 108 } 109 } 110 111 @Override onNothingSelected(AdapterView<?> parent)112 public void onNothingSelected(AdapterView<?> parent) { 113 } 114 } 115 116 private class LoggingWebViewClient extends WebViewClient { 117 @Override shouldOverrideUrlLoading(WebView view, String url)118 public boolean shouldOverrideUrlLoading(WebView view, String url) { 119 return false; 120 } 121 122 @Override onPageStarted(WebView view, String url, Bitmap favicon)123 public void onPageStarted(WebView view, String url, Bitmap favicon) { 124 super.onPageStarted(view, url, favicon); 125 mUrl.setText(url); 126 } 127 } 128 129 private class AutoLoggingWebViewClient extends LoggingWebViewClient { 130 131 @Override onPageFinished(WebView view, String url)132 public void onPageFinished(WebView view, String url) { 133 super.onPageFinished(view, url); 134 view.requestFocus(); 135 136 startViewProfiling(true); 137 } 138 139 @Override onPageStarted(WebView view, String url, Bitmap favicon)140 public void onPageStarted(WebView view, String url, Bitmap favicon) { 141 super.onPageStarted(view, url, favicon); 142 setTestingState(TestingState.PRE_TESTING); 143 } 144 } 145 146 private class StoreFileTask extends 147 AsyncTask<Pair<String, RunData>, Void, Void> { 148 149 @Override doInBackground(Pair<String, RunData>.... params)150 protected Void doInBackground(Pair<String, RunData>... params) { 151 try { 152 FileOutputStream fos = openFileOutput(params[0].first, 153 Context.MODE_PRIVATE); 154 ObjectOutputStream out = new ObjectOutputStream(fos); 155 out.writeObject(params[0].second); 156 out.close(); 157 } catch (IOException ex) { 158 ex.printStackTrace(); 159 } 160 return null; 161 } 162 163 @Override onPostExecute(Void v)164 protected void onPostExecute(Void v) { 165 setTestingState(TestingState.SAVED_TESTING); 166 } 167 } 168 setTestingState(TestingState state)169 public void setTestingState(TestingState state) { 170 switch (state) { 171 case NOT_TESTING: 172 mUrl.setBackgroundResource(R.color.background_not_testing); 173 mInspectButton.setEnabled(true); 174 mMovementSpinner.setEnabled(true); 175 break; 176 case PRE_TESTING: 177 mInspectButton.setEnabled(false); 178 mMovementSpinner.setEnabled(false); 179 break; 180 case START_TESTING: 181 mUrl.setBackgroundResource(R.color.background_start_testing); 182 mInspectButton.setEnabled(false); 183 mMovementSpinner.setEnabled(false); 184 break; 185 case STOP_TESTING: 186 mUrl.setBackgroundResource(R.color.background_stop_testing); 187 break; 188 case SAVED_TESTING: 189 mInspectButton.setEnabled(true); 190 mMovementSpinner.setEnabled(true); 191 break; 192 } 193 } 194 195 /** auto - automatically scroll. */ startViewProfiling(boolean auto)196 private void startViewProfiling(boolean auto) { 197 // toggle capture button to indicate capture state to user 198 mCaptureButton.setChecked(true); 199 mWeb.startScrollTest(mCallback, auto); 200 setTestingState(TestingState.START_TESTING); 201 } 202 203 /** Called when the activity is first created. */ 204 @Override onCreate(Bundle savedInstanceState)205 public void onCreate(Bundle savedInstanceState) { 206 super.onCreate(savedInstanceState); 207 setContentView(R.layout.main); 208 mInspectButton = (Button) findViewById(R.id.inspect); 209 mCaptureButton = (ToggleButton) findViewById(R.id.capture); 210 mVelocitySpinner = (Spinner) findViewById(R.id.velocity); 211 mMovementSpinner = (Spinner) findViewById(R.id.movement); 212 mUrl = (EditText) findViewById(R.id.url); 213 mWeb = (ProfiledWebView) findViewById(R.id.web); 214 setCallback(new ProfileCallback() { 215 @SuppressWarnings("unchecked") 216 @Override 217 public void profileCallback(RunData data) { 218 new StoreFileTask().execute(new Pair<String, RunData>( 219 TEMP_FILENAME, data)); 220 mCaptureButton.setChecked(false); 221 setTestingState(TestingState.STOP_TESTING); 222 } 223 }); 224 225 // Inspect button (opens PlaybackActivity) 226 mInspectButton.setOnClickListener(new OnClickListener() { 227 @Override 228 public void onClick(View v) { 229 startActivity(new Intent(ProfileActivity.this, 230 PlaybackActivity.class)); 231 } 232 }); 233 234 // Velocity spinner 235 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource( 236 this, R.array.velocity_array, 237 android.R.layout.simple_spinner_item); 238 adapter.setDropDownViewResource( 239 android.R.layout.simple_spinner_dropdown_item); 240 mVelocitySpinner.setAdapter(adapter); 241 mVelocitySpinner.setOnItemSelectedListener( 242 new VelocitySelectedListener()); 243 mVelocitySpinner.setSelection(3); 244 245 // Movement spinner 246 String content[] = { 247 getResources().getString(R.string.movement_auto_scroll), 248 getResources().getString(R.string.movement_auto_fling), 249 getResources().getString(R.string.movement_manual) 250 }; 251 adapter = new ArrayAdapter<CharSequence>(this, 252 android.R.layout.simple_spinner_item, content); 253 adapter.setDropDownViewResource( 254 android.R.layout.simple_spinner_dropdown_item); 255 mMovementSpinner.setAdapter(adapter); 256 mMovementSpinner.setOnItemSelectedListener( 257 new MovementSelectedListener()); 258 mMovementSpinner.setSelection(0); 259 260 // Capture toggle button 261 mCaptureButton.setOnClickListener(new OnClickListener() { 262 @Override 263 public void onClick(View v) { 264 if (mCaptureButton.isChecked()) { 265 startViewProfiling(false); 266 } else { 267 mWeb.stopScrollTest(); 268 } 269 } 270 }); 271 272 // Custom profiling WebView 273 WebSettings settings = mWeb.getSettings(); 274 settings.setJavaScriptEnabled(true); 275 settings.setSupportZoom(true); 276 settings.setEnableSmoothTransition(true); 277 settings.setBuiltInZoomControls(true); 278 settings.setLoadWithOverviewMode(true); 279 mWeb.setWebViewClient(new LoggingWebViewClient()); 280 281 // URL text entry 282 mUrl.setOnEditorActionListener(new OnEditorActionListener() { 283 public boolean onEditorAction(TextView v, int actionId, 284 KeyEvent event) { 285 String url = mUrl.getText().toString(); 286 mWeb.loadUrl(url); 287 mWeb.requestFocus(); 288 return true; 289 } 290 }); 291 292 setTestingState(TestingState.NOT_TESTING); 293 } 294 setCallback(ProfileCallback callback)295 public void setCallback(ProfileCallback callback) { 296 mCallback = callback; 297 } 298 299 @Override onKeyDown(int keyCode, KeyEvent event)300 public boolean onKeyDown(int keyCode, KeyEvent event) { 301 if ((keyCode == KeyEvent.KEYCODE_BACK) && mWeb.canGoBack()) { 302 mWeb.goBack(); 303 return true; 304 } 305 return super.onKeyDown(keyCode, event); 306 } 307 } 308