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
17package com.test.tilebenchmark;
18
19import android.app.Activity;
20import android.content.Intent;
21import android.content.Context;
22import android.graphics.Bitmap;
23import android.os.AsyncTask;
24import android.os.Bundle;
25import android.util.Pair;
26import android.view.KeyEvent;
27import android.view.View;
28import android.view.View.OnClickListener;
29import android.webkit.WebSettings;
30import android.webkit.WebView;
31import android.webkit.WebViewClient;
32import android.widget.AdapterView;
33import android.widget.AdapterView.OnItemSelectedListener;
34import android.widget.ArrayAdapter;
35import android.widget.Button;
36import android.widget.EditText;
37import android.widget.Spinner;
38import android.widget.TextView;
39import android.widget.TextView.OnEditorActionListener;
40import android.widget.ToggleButton;
41
42import java.io.FileOutputStream;
43import java.io.IOException;
44import 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 */
50public class ProfileActivity extends Activity {
51
52    public interface ProfileCallback {
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
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
87        public void onNothingSelected(AdapterView<?> parent) {
88        }
89    }
90
91    private class MovementSelectedListener implements OnItemSelectedListener {
92        @Override
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
112        public void onNothingSelected(AdapterView<?> parent) {
113        }
114    }
115
116    private class LoggingWebViewClient extends WebViewClient {
117        @Override
118        public boolean shouldOverrideUrlLoading(WebView view, String url) {
119            return false;
120        }
121
122        @Override
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
132        public void onPageFinished(WebView view, String url) {
133            super.onPageFinished(view, url);
134            view.requestFocus();
135
136            startViewProfiling(true);
137        }
138
139        @Override
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
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
164        protected void onPostExecute(Void v) {
165            setTestingState(TestingState.SAVED_TESTING);
166        }
167    }
168
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. */
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
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
295    public void setCallback(ProfileCallback callback) {
296        mCallback = callback;
297    }
298
299    @Override
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