VideoChatTestActivity.java revision 202e88cbb3a52a78d6c4ccf55fa9ed9248f43ecd
1/*
2 * Copyright (C) 2010 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.example.android.videochatcameratest;
18
19import android.app.Activity;
20import android.graphics.ImageFormat;
21import android.hardware.Camera;
22import android.hardware.Camera.Size;
23import android.os.AsyncTask;
24import android.os.Bundle;
25import android.util.Log;
26import android.view.View;
27import android.view.View.OnClickListener;
28import android.widget.Button;
29import android.widget.CheckBox;
30import android.widget.TextView;
31
32import java.io.IOException;
33import java.lang.UnsupportedOperationException;
34import java.util.ArrayList;
35import java.util.List;
36
37/**
38 * This class provides a basic demonstration of how to write an Android
39 * activity. Inside of its window, it places a single view: an EditText that
40 * displays and edits some internal text.
41 */
42public class VideoChatTestActivity extends Activity {
43
44    static final private int NUM_CAMERA_PREVIEW_BUFFERS = 2;
45
46    static final private String TAG = "VideoChatTest";
47    TextView mTextStatusHistory;
48    public VideoChatTestActivity() {
49    }
50
51    /** Called with the activity is first created. */
52    @Override
53    public void onCreate(Bundle savedInstanceState) {
54        super.onCreate(savedInstanceState);
55
56        // Inflate our UI from its XML layout description.
57        setContentView(R.layout.videochatcameratest_activity);
58
59        ((Button) findViewById(R.id.gobutton)).setOnClickListener(mGoListener);
60
61        ((TextView)findViewById(R.id.statushistory)).setVerticalScrollBarEnabled(true);
62        mTextStatusHistory = (TextView) findViewById(R.id.statushistory);
63
64        for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
65            dumpCameraCaps(i);
66        }
67    }
68
69    private void logMessage(String message) {
70        Log.v(TAG, message);
71        mTextStatusHistory.append(message + "\r\n");
72    }
73
74    public int getCameraOrientation(int id) {
75        Camera.CameraInfo info =
76            new Camera.CameraInfo();
77        Camera.getCameraInfo(id, info);
78        return info.orientation;
79    }
80
81    private void dumpCameraCaps(int id) {
82        Camera cam = Camera.open(id);
83        Camera.Parameters params = cam.getParameters();
84        List<Integer> formats = params.getSupportedPreviewFormats();
85        List<int[]> frameRates = params.getSupportedPreviewFpsRange();
86        List<Camera.Size> sizes = params.getSupportedPreviewSizes();
87        logMessage("Camera " + id);
88        logMessage("Orientation " + getCameraOrientation(id));
89        logMessage("Sizes");
90        for (Size size : sizes) {
91            logMessage(size.width + "x" + size.height);
92        }
93        logMessage("frameRates");
94        for (int[] rates : frameRates) {
95            logMessage(rates[0] + "-" + rates[1]);
96        }
97        logMessage("formats");
98        for (Integer format : formats) {
99            logMessage(format.toString());
100        }
101        cam.release();
102    }
103    /**
104     * Called when the activity is about to start interacting with the user.
105     */
106    @Override
107    protected void onResume() {
108        super.onResume();
109    }
110
111    /**
112     * A call-back for when the user presses the back button.
113     */
114    OnClickListener mGoListener = new OnClickListener() {
115
116        public void onClick(View v) {
117            new CameraTestRunner().execute();
118        }
119    };
120
121    private class CameraTestRunner extends AsyncTask<Void, String, Void> {
122
123        TextView mTextStatus;
124        TextView mTextStatusHistory;
125
126        @Override
127        protected Void doInBackground(Void... params) {
128            mTextStatus = (TextView) findViewById(R.id.status);
129            mTextStatusHistory = (TextView) findViewById(R.id.statushistory);
130            boolean testFrontCamera =
131                    ((CheckBox) findViewById(R.id.frontcameracheckbox)).isChecked();
132            boolean testBackCamera = ((CheckBox) findViewById(R.id.backcameracheckbox)).isChecked();
133            boolean testQVGA = ((CheckBox) findViewById(R.id.qvgacheckbox)).isChecked();
134            boolean testVGA = ((CheckBox) findViewById(R.id.vgacheckbox)).isChecked();
135            boolean test15fps = ((CheckBox) findViewById(R.id.fps15checkbox)).isChecked();
136            boolean test30fps = ((CheckBox) findViewById(R.id.fps30checkbox)).isChecked();
137            boolean testRotate0 = ((CheckBox) findViewById(R.id.rotate0checkbox)).isChecked();
138            boolean testRotate90 = ((CheckBox) findViewById(R.id.rotate90checkbox)).isChecked();
139            boolean testRotate180 = ((CheckBox) findViewById(R.id.rotate180checkbox)).isChecked();
140            boolean testRotate270 = ((CheckBox) findViewById(R.id.rotate270checkbox)).isChecked();
141
142            ArrayList<Integer> setDisplayOrentationAngles = new ArrayList<Integer>();
143
144            if (testRotate0) {
145                setDisplayOrentationAngles.add(0);
146            }
147            if (testRotate90) {
148                setDisplayOrentationAngles.add(90);
149            }
150            if (testRotate180) {
151                setDisplayOrentationAngles.add(180);
152            }
153            if (testRotate270) {
154                setDisplayOrentationAngles.add(270);
155            }
156
157            final int widths[] = new int[] {320, 640};
158            final int heights[] = new int[] {240, 480};
159
160            final int framerates[] = new int[] {15, 30};
161
162            do {
163                for (int whichCamera = 0; whichCamera < 2; whichCamera++) {
164                    if (whichCamera == 0 && !testBackCamera) {
165                        continue;
166                    }
167
168
169                    if (whichCamera == 1 && !testFrontCamera) {
170                        continue;
171                    }
172
173                    for (int whichResolution = 0; whichResolution < 2; whichResolution++) {
174                        if (whichResolution == 0 && !testQVGA) {
175                            continue;
176                        }
177                        if (whichResolution == 1 && !testVGA) {
178                            continue;
179                        }
180
181                        for (int whichFramerate = 0; whichFramerate < 2; whichFramerate++) {
182                            if (whichFramerate == 0 && !test15fps) {
183                                continue;
184                            }
185                            if (whichFramerate == 1 && !test30fps) {
186                                continue;
187                            }
188
189                            TestCamera(whichCamera, widths[whichResolution],
190                                    heights[whichResolution], framerates[whichFramerate],
191                                    setDisplayOrentationAngles);
192                        }
193                    }
194                }
195            } while (((CheckBox) findViewById(R.id.repeatcheckbox)).isChecked());
196            // start tests
197
198            return null;
199        }
200
201        @Override
202        protected void onPostExecute(Void result) {
203            final String allDoneString = "Test complete";
204            Log.v(TAG, allDoneString);
205            mTextStatus.setText(allDoneString);
206            mTextStatusHistory.append(allDoneString + "\r\n");
207        }
208
209
210        private class FrameCatcher implements Camera.PreviewCallback {
211            public int mFrames = 0;
212            private final int mExpectedSize;
213            public FrameCatcher(int width, int height) {
214                mExpectedSize = width * height * 3 / 2;
215            }
216
217            @Override
218            public void onPreviewFrame(byte[] data, Camera camera) {
219                if (mExpectedSize != data.length) {
220                    throw new UnsupportedOperationException("bad size, got " + data.length + " expected " + mExpectedSize);
221                }
222                mFrames++;
223                camera.addCallbackBuffer(data);
224            }
225
226        }
227
228        private void setupCallback(Camera camera, FrameCatcher catcher, int bufferSize) {
229            camera.setPreviewCallbackWithBuffer(null);
230            camera.setPreviewCallbackWithBuffer(catcher);
231            for (int i = 0; i < NUM_CAMERA_PREVIEW_BUFFERS; i++) {
232                byte [] cameraBuffer = new byte[bufferSize];
233                camera.addCallbackBuffer(cameraBuffer);
234            }
235        }
236        protected void TestCamera(int whichCamera,
237                int width, int height,
238                int frameRate,
239                List<Integer> setDisplayOrentationAngles) {
240            String baseStatus = "Camera id " + whichCamera + " " +
241                width + "x" + height + " " +
242                frameRate + "fps";
243            publishProgress("Initializing " + baseStatus);
244            String status = "";
245            boolean succeeded = true;
246            Log.v(TAG, "Start test -- id " + whichCamera + " " + width + "x" + height +
247                    " " + frameRate + "fps");
248            Camera camera;
249            CameraPreviewView previewView = (CameraPreviewView)findViewById(R.id.previewrender);
250
251            camera = Camera.open(whichCamera);
252            publishProgress("Opened " + baseStatus);
253            try {
254                try {
255                    camera.setPreviewDisplay(previewView.mHolder);
256                } catch (IOException exception) {
257                    succeeded = false;
258                    status = exception.toString();
259                    return;
260                }
261                camera.startPreview();
262
263                camera.setPreviewCallbackWithBuffer(null);
264                Camera.Parameters parameters = camera.getParameters();
265
266                publishProgress("Changing preview parameters " + width + "x" + height + baseStatus);
267
268                parameters.setPreviewSize(width, height);
269                parameters.setPreviewFormat(ImageFormat.NV21);
270
271                parameters.setPreviewFrameRate(frameRate);
272                camera.stopPreview();
273                camera.setParameters(parameters);
274                camera.startPreview();
275
276                publishProgress("Validating preview parameters " + baseStatus);
277
278                parameters = camera.getParameters();
279                Size setSize = parameters.getPreviewSize();
280                if (setSize.width != width || setSize.height != height) {
281                    status += "Bad reported size, wanted " + width + "x" + height + ", got " +
282                    setSize.width + "x" + setSize.height;
283                    succeeded = false;
284                }
285
286                if (parameters.getPreviewFrameRate() != frameRate) {
287                    status += "Bad reported frame rate, wanted " + frameRate
288                    + ", got " + parameters.getPreviewFrameRate();
289                    succeeded = false;
290                }
291
292                publishProgress("Initializing callback buffers " + baseStatus);
293                int imageFormat = parameters.getPreviewFormat();
294                if (imageFormat != ImageFormat.NV21) {
295                    status = "Bad reported image format, wanted NV21 (" + ImageFormat.NV21 +
296                            ") got " + imageFormat;
297                    succeeded = false;
298                    throw new UnsupportedOperationException(status);
299                }
300                int bufferSize;
301                bufferSize = setSize.width * setSize.height
302                                * ImageFormat.getBitsPerPixel(imageFormat) / 8;
303                int sizeWeShouldHave = (width * height * 3 / 2);
304                if (bufferSize != sizeWeShouldHave) {
305                    status = "Bad calculate size. Should have been " + (width * height * 3 / 2) +
306                            " but got " + imageFormat;
307                    succeeded = false;
308                    throw new UnsupportedOperationException(status);
309                }
310                camera.stopPreview();
311
312                FrameCatcher catcher = new FrameCatcher(setSize.width, setSize.height);
313
314                if (succeeded) {
315                    publishProgress("Starting " + baseStatus);
316                } else {
317                    publishProgress("Starting " + baseStatus + " -- but " + status);
318                }
319
320                int numPasses;
321                boolean doSetDisplayOrientation;
322                if (setDisplayOrentationAngles == null || setDisplayOrentationAngles.size() == 0) {
323                    numPasses = 1;
324                    doSetDisplayOrientation = false;
325                } else {
326                    numPasses = setDisplayOrentationAngles.size();
327                    doSetDisplayOrientation = true;
328                }
329
330                for (int i = 0; i < numPasses; i++) {
331                    if (doSetDisplayOrientation) {
332                        int rotation = setDisplayOrentationAngles.get(i);
333                        publishProgress("setDisplayOrientation to " + rotation);
334                        try {
335                            camera.setDisplayOrientation(rotation);
336                        } catch (RuntimeException exception) {
337                            succeeded = false;
338                            status = exception.toString();
339                            return;
340                        }
341                    }
342                    setupCallback(camera, catcher, bufferSize);
343                    camera.startPreview();
344                    try {
345                        Thread.sleep(5000);
346                    } catch (InterruptedException exception) {
347                        succeeded = false;
348                        status = exception.toString();
349                        return;
350                    }
351                    camera.setPreviewCallbackWithBuffer(null);
352                    camera.stopPreview();
353                }
354
355                if (catcher.mFrames == 0) {
356                    succeeded = false;
357                    publishProgress("Preview callback received no frames from " + baseStatus);
358                } else {
359                    publishProgress("Preview callback got " + catcher.mFrames + " frames (~" +
360                            Math.round(((double)catcher.mFrames)/(5.0 * numPasses)) + "fps) " +
361                            baseStatus);
362                }
363                try {
364                    camera.setPreviewDisplay(null);
365                } catch (IOException exception) {
366                    succeeded = false;
367                    status = exception.toString();
368                    return;
369                }
370            } finally {
371                Log.v(TAG, "Releasing camera");
372
373                if (succeeded) {
374                    publishProgress("Success " + baseStatus);
375                } else {
376                    publishProgress("Finished " + baseStatus + " -- but " + status);
377                }
378
379                camera.release();
380            }
381        }
382
383        @Override
384        protected void onProgressUpdate(String... message) {
385            Log.v(TAG, message[0]);
386            mTextStatus.setText(message[0]);
387            mTextStatusHistory.append(message[0] + "\r\n");
388        }
389    }
390}
391