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