CameraStressTest.java revision bac8666893ee6d0074db7fa7f995de04598013b1
1/*
2 * Copyright (C) 2012 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.android.mediaframeworktest.stress;
18
19import com.android.mediaframeworktest.MediaFrameworkTest;
20
21import java.io.BufferedWriter;
22import java.io.File;
23import java.io.FilenameFilter;
24import java.io.FileWriter;
25import java.io.FileNotFoundException;
26import java.io.FileOutputStream;
27import java.io.IOException;
28import java.io.Writer;
29import java.util.concurrent.Semaphore;
30import java.util.concurrent.TimeUnit;
31import java.util.List;
32
33import android.hardware.Camera;
34import android.hardware.Camera.PictureCallback;
35import android.hardware.Camera.ShutterCallback;
36import android.os.Environment;
37import android.os.Handler;
38import android.os.Looper;
39import android.test.ActivityInstrumentationTestCase2;
40import android.test.suitebuilder.annotation.LargeTest;
41import android.util.Log;
42import android.view.SurfaceHolder;
43import com.android.mediaframeworktest.CameraStressTestRunner;
44
45import junit.framework.Assert;
46
47/**
48 * Junit / Instrumentation test case for the camera zoom and scene mode APIs
49 *
50 * adb shell am instrument
51 *  -e class com.android.mediaframeworktest.stress.CameraStressTest
52 *  -w com.android.mediaframeworktest/.CameraStressTestRunner
53 */
54public class CameraStressTest extends ActivityInstrumentationTestCase2<MediaFrameworkTest> {
55    private String TAG = "CameraStressTest";
56    private Camera mCamera;
57
58    private static final int CAMERA_ID = 0;
59    private static final int NUMBER_OF_ZOOM_LOOPS = 100;
60    private static final int NUMBER_OF_SCENE_MODE_LOOPS = 10;
61    private static final long WAIT_GENERIC = 3 * 1000; // 3 seconds
62    private static final long WAIT_TIMEOUT = 10 * 1000; // 10 seconds
63    private static final long WAIT_ZOOM_ANIMATION = 5 * 1000; // 5 seconds
64    private static final String CAMERA_STRESS_IMAGES_DIRECTORY = "cameraStressImages";
65    private static final String CAMERA_STRESS_IMAGES_PREFIX = "camera-stress-test";
66    private static final String CAMERA_STRESS_OUTPUT = "cameraStressOutput.txt";
67    private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
68
69    private Thread mLooperThread;
70    private Handler mHandler;
71
72    private Writer mOutput;
73
74    public CameraStressTest() {
75        super("com.android.mediaframeworktest", MediaFrameworkTest.class);
76    }
77
78    protected void setUp() throws Exception {
79        final Semaphore sem = new Semaphore(0);
80        mLooperThread = new Thread() {
81            @Override
82            public void run() {
83                Log.v(TAG, "starting looper");
84                Looper.prepare();
85                mHandler = new Handler();
86                sem.release();
87                Looper.loop();
88                Log.v(TAG, "quit looper");
89            }
90        };
91        mLooperThread.start();
92        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
93            fail("Failed to start the looper.");
94        }
95        getActivity();
96        super.setUp();
97
98        File sdcard = Environment.getExternalStorageDirectory();
99
100        // Create the test images directory if it doesn't exist
101        File stressImagesDirectory = new File(String.format("%s/%s", sdcard,
102                CAMERA_STRESS_IMAGES_DIRECTORY));
103        if (!stressImagesDirectory.exists()) {
104            stressImagesDirectory.mkdir();
105        }
106
107        // Start writing output file
108        File stressOutFile = new File(String.format("%s/%s",sdcard, CAMERA_STRESS_OUTPUT));
109        mOutput = new BufferedWriter(new FileWriter(stressOutFile, true));
110        mOutput.write(this.getName() + ":\n");
111    }
112
113    @Override
114    protected void tearDown() throws Exception {
115        if (mHandler != null) {
116            mHandler.getLooper().quit();
117            mHandler = null;
118        }
119        if (mLooperThread != null) {
120            mLooperThread.join(WAIT_TIMEOUT);
121            if (mLooperThread.isAlive()) {
122                fail("Failed to stop the looper.");
123            }
124            mLooperThread = null;
125        }
126
127        mOutput.write("\n\n");
128        mOutput.close();
129
130        super.tearDown();
131    }
132
133    private void runOnLooper(final Runnable command) throws InterruptedException {
134        final Semaphore sem = new Semaphore(0);
135        mHandler.post(new Runnable() {
136            @Override
137            public void run() {
138                try {
139                    command.run();
140                } finally {
141                    sem.release();
142                }
143            }
144        });
145        if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) {
146            fail("Failed to run the command on the looper.");
147        }
148    }
149
150    private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback {
151        public void onError(int error, android.hardware.Camera camera) {
152            fail(String.format("Camera error, code: %d", error));
153        }
154    }
155
156    private ShutterCallback shutterCallback = new ShutterCallback() {
157        @Override
158        public void onShutter() {
159            Log.v(TAG, "Shutter");
160        }
161    };
162
163    private PictureCallback rawCallback = new PictureCallback() {
164        @Override
165        public void onPictureTaken(byte[] data, Camera camera) {
166            Log.v(TAG, "Raw picture taken");
167        }
168    };
169
170    private PictureCallback jpegCallback = new PictureCallback() {
171        @Override
172        public void onPictureTaken(byte[] data, Camera camera) {
173            FileOutputStream fos = null;
174
175            try {
176                Log.v(TAG, "JPEG picture taken");
177                fos = new FileOutputStream(String.format("%s/%s/%s-%d.jpg",
178                        Environment.getExternalStorageDirectory(), CAMERA_STRESS_IMAGES_DIRECTORY,
179                        CAMERA_STRESS_IMAGES_PREFIX, System.currentTimeMillis()));
180                fos.write(data);
181            } catch (FileNotFoundException e) {
182                Log.e(TAG, "File not found: " + e.toString());
183            } catch (IOException e) {
184                Log.e(TAG, "Error accessing file: " + e.toString());
185            } finally {
186                try {
187                    if (fos != null) {
188                        fos.close();
189                    }
190                } catch (IOException e) {
191                    Log.e(TAG, "Error closing file: " + e.toString());
192                }
193            }
194        }
195    };
196
197    // Helper method for cleaning up pics taken during testStressCameraZoom
198    private void cleanupStressTestImages() {
199        try {
200            File stressImagesDirectory = new File(String.format("%s/%s",
201                    Environment.getExternalStorageDirectory(), CAMERA_STRESS_IMAGES_DIRECTORY));
202            File[] zoomImages = null;
203
204            FilenameFilter filter = new FilenameFilter() {
205                public boolean accept(File dir, String name) {
206                    return name.startsWith(CAMERA_STRESS_IMAGES_PREFIX);
207                }
208            };
209
210            zoomImages = stressImagesDirectory.listFiles(filter);
211
212            for (File f : zoomImages) {
213                f.delete();
214            }
215        } catch (SecurityException e) {
216            Log.e(TAG, "Security manager access violation: " + e.toString());
217        }
218    }
219
220    // Helper method for starting up the camera preview
221    private void startCameraPreview(SurfaceHolder surfaceHolder) {
222        try {
223            mCamera.setErrorCallback(mCameraErrorCallback);
224            mCamera.setPreviewDisplay(surfaceHolder);
225            mCamera.startPreview();
226            Thread.sleep(WAIT_GENERIC);
227        } catch (IOException e) {
228            Log.e(TAG, "Error setting preview display: " + e.toString());
229        } catch (InterruptedException e) {
230            Log.e(TAG, "Error waiting for preview to come up: " + e.toString());
231        } catch (Exception e) {
232            Log.e(TAG, "Error starting up camera preview: " + e.toString());
233        }
234    }
235
236    // Helper method for taking a photo
237    private void capturePhoto() {
238        try {
239            mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
240            Thread.sleep(WAIT_GENERIC);
241            mCamera.stopPreview();
242            mCamera.release();
243        } catch (InterruptedException e) {
244            Log.e(TAG, "Error waiting for photo to be taken: " + e.toString());
245        } catch (Exception e) {
246            Log.e(TAG, "Error capturing photo: " + e.toString());
247        }
248    }
249
250    // Test case for stressing the camera zoom in/out feature
251    @LargeTest
252    public void testStressCameraZoom() throws Exception {
253        SurfaceHolder mSurfaceHolder;
254        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
255        mOutput.write("Total number of loops: " + NUMBER_OF_ZOOM_LOOPS + "\n");
256
257        try {
258            Log.v(TAG, "Start preview");
259            mOutput.write("No of loop: ");
260
261            mCamera = Camera.open(CAMERA_ID);
262            Camera.Parameters params = mCamera.getParameters();
263            mCamera.release();
264
265            if (!params.isSmoothZoomSupported() && !params.isZoomSupported()) {
266                Log.v(TAG, "Device camera does not support zoom");
267                fail("Camera zoom stress test failed");
268            } else {
269                Log.v(TAG, "Device camera does support zoom");
270
271                int nextZoomLevel = 0;
272
273                for (int i = 0; i < NUMBER_OF_ZOOM_LOOPS; i++) {
274                    runOnLooper(new Runnable() {
275                        @Override
276                        public void run() {
277                            mCamera = Camera.open(CAMERA_ID);
278                        }
279                    });
280
281                    startCameraPreview(mSurfaceHolder);
282                    params = mCamera.getParameters();
283                    int currentZoomLevel = params.getZoom();
284
285                    if (nextZoomLevel >= params.getMaxZoom()) {
286                        nextZoomLevel = 0;
287                    }
288                    ++nextZoomLevel;
289
290                    if (params.isSmoothZoomSupported()) {
291                        mCamera.startSmoothZoom(nextZoomLevel);
292                    } else {
293                        params.setZoom(nextZoomLevel);
294                        mCamera.setParameters(params);
295                    }
296                    Log.v(TAG, "Zooming from " + currentZoomLevel + " to " + nextZoomLevel);
297
298                    // sleep allows for zoom animation to finish
299                    Thread.sleep(WAIT_ZOOM_ANIMATION);
300                    capturePhoto();
301
302                    if (i == 0) {
303                        mOutput.write(Integer.toString(i));
304                    } else {
305                        mOutput.write(", " + i);
306                    }
307                }
308            }
309            cleanupStressTestImages();
310        } catch (Exception e) {
311            Log.e(TAG, e.toString());
312            fail("Camera zoom stress test Exception");
313        }
314    }
315
316    // Test case for stressing the camera scene mode feature
317    @LargeTest
318    public void testStressCameraSceneModes() throws Exception {
319        SurfaceHolder mSurfaceHolder;
320        mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
321
322        try {
323            mCamera = Camera.open(CAMERA_ID);
324            Camera.Parameters params = mCamera.getParameters();
325            mCamera.release();
326            List<String> supportedSceneModes = params.getSupportedSceneModes();
327            assertNotNull("No scene modes supported", supportedSceneModes);
328
329            mOutput.write("Total number of loops: " +
330                    (NUMBER_OF_SCENE_MODE_LOOPS * supportedSceneModes.size()) + "\n");
331            Log.v(TAG, "Start preview");
332            mOutput.write("No of loop: ");
333
334            for (int i = 0; i < supportedSceneModes.size(); i++) {
335                for (int j = 0; j < NUMBER_OF_SCENE_MODE_LOOPS; j++) {
336                    runOnLooper(new Runnable() {
337                        @Override
338                        public void run() {
339                            mCamera = Camera.open(CAMERA_ID);
340                        }
341                    });
342
343                    startCameraPreview(mSurfaceHolder);
344                    Log.v(TAG, "Setting mode to " + supportedSceneModes.get(i));
345                    params.setSceneMode(supportedSceneModes.get(i));
346                    mCamera.setParameters(params);
347                    capturePhoto();
348
349                    if ((i == 0) && (j == 0)) {
350                        mOutput.write(Integer.toString(j + i * NUMBER_OF_SCENE_MODE_LOOPS));
351                    } else {
352                        mOutput.write(", " + (j + i * NUMBER_OF_SCENE_MODE_LOOPS));
353                    }
354                }
355            }
356            cleanupStressTestImages();
357        } catch (Exception e) {
358            Log.e(TAG, e.toString());
359            fail("Camera scene mode test Exception");
360        }
361    }
362}
363