/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mediaframeworktest.stress; import com.android.mediaframeworktest.MediaFrameworkTest; import java.io.BufferedWriter; import java.io.File; import java.io.FilenameFilter; import java.io.FileWriter; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.Writer; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.ShutterCallback; import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.view.SurfaceHolder; import com.android.mediaframeworktest.CameraStressTestRunner; import junit.framework.Assert; /** * Junit / Instrumentation test case for the camera zoom api * * adb shell am instrument * -e class com.android.mediaframeworktest.stress.CameraStressTest * -w com.android.mediaframeworktest/.CameraStressTestRunner */ public class CameraStressTest extends ActivityInstrumentationTestCase2 { private String TAG = "CameraStressTest"; private Camera mCamera; private static final int NUMBER_OF_ZOOM_LOOPS = 100; private static final long WAIT_GENERIC = 3 * 1000; // 3 seconds private static final long WAIT_TIMEOUT = 10 * 1000; // 10 seconds private static final long WAIT_ZOOM_ANIMATION = 5 * 1000; // 5 seconds private static final String CAMERA_STRESS_OUTPUT = "/sdcard/cameraStressOutput.txt"; private static final int CAMERA_ID = 0; private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback(); private Thread mLooperThread; private Handler mHandler; public CameraStressTest() { super("com.android.mediaframeworktest", MediaFrameworkTest.class); } protected void setUp() throws Exception { final Semaphore sem = new Semaphore(0); mLooperThread = new Thread() { @Override public void run() { Log.v(TAG, "starting looper"); Looper.prepare(); mHandler = new Handler(); sem.release(); Looper.loop(); Log.v(TAG, "quit looper"); } }; mLooperThread.start(); if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { fail("Failed to start the looper."); } getActivity(); super.setUp(); } @Override protected void tearDown() throws Exception { if (mHandler != null) { mHandler.getLooper().quit(); mHandler = null; } if (mLooperThread != null) { mLooperThread.join(WAIT_TIMEOUT); if (mLooperThread.isAlive()) { fail("Failed to stop the looper."); } mLooperThread = null; } super.tearDown(); } private void runOnLooper(final Runnable command) throws InterruptedException { final Semaphore sem = new Semaphore(0); mHandler.post(new Runnable() { @Override public void run() { try { command.run(); } finally { sem.release(); } } }); if (!sem.tryAcquire(WAIT_TIMEOUT, TimeUnit.MILLISECONDS)) { fail("Failed to run the command on the looper."); } } private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback { public void onError(int error, android.hardware.Camera camera) { if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) { assertTrue("Camera test mediaserver died", false); } } } private ShutterCallback shutterCallback = new ShutterCallback() { @Override public void onShutter() { Log.v(TAG, "Shutter"); } }; private PictureCallback rawCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { Log.v(TAG, "Raw picture taken"); } }; private PictureCallback jpegCallback = new PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { FileOutputStream fos = null; try { Log.v(TAG, "JPEG picture taken"); fos = new FileOutputStream(String.format("%s/zoom-test-%d.jpg", Environment.getExternalStorageDirectory(), System.currentTimeMillis())); fos.write(data); } catch (FileNotFoundException e) { Log.v(TAG, "File not found: " + e.toString()); } catch (IOException e) { Log.v(TAG, "Error accessing file: " + e.toString()); } finally { try { if (fos != null) { fos.close(); } } catch (IOException e) { Log.v(TAG, "Error closing file: " + e.toString()); } } } }; // Helper method for cleaning up pics taken during testStressCameraZoom private void cleanupZoomImages() { try { File sdcard = Environment.getExternalStorageDirectory(); File[] zoomImages = null; FilenameFilter filter = new FilenameFilter() { public boolean accept(File dir, String name) { return name.startsWith("zoom-test-"); } }; zoomImages = sdcard.listFiles(filter); for (File f : zoomImages) { f.delete(); } } catch (SecurityException e) { Log.v(TAG, "Security manager access violation: " + e.toString()); } } // Test case for stressing the camera zoom in/out feature @LargeTest public void testStressCameraZoom() throws Exception { SurfaceHolder mSurfaceHolder; mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); File stressOutFile = new File(CAMERA_STRESS_OUTPUT); Writer output = new BufferedWriter(new FileWriter(stressOutFile, true)); output.write("Camera zoom stress:\n"); output.write("Total number of loops: " + NUMBER_OF_ZOOM_LOOPS + "\n"); try { Log.v(TAG, "Start preview"); output.write("No of loop: "); mCamera = Camera.open(CAMERA_ID); Camera.Parameters params = mCamera.getParameters(); mCamera.release(); if (!params.isSmoothZoomSupported() && !params.isZoomSupported()) { Log.v(TAG, "Device camera does not support zoom"); assertTrue("Camera zoom stress test", false); } else { Log.v(TAG, "Device camera does support zoom"); int nextZoomLevel = 0; for (int i = 0; i < NUMBER_OF_ZOOM_LOOPS; i++) { runOnLooper(new Runnable() { @Override public void run() { mCamera = Camera.open(CAMERA_ID); } }); mCamera.setErrorCallback(mCameraErrorCallback); mCamera.setPreviewDisplay(mSurfaceHolder); mCamera.startPreview(); Thread.sleep(WAIT_GENERIC); params = mCamera.getParameters(); int currentZoomLevel = params.getZoom(); if (nextZoomLevel >= params.getMaxZoom()) { nextZoomLevel = 0; } ++nextZoomLevel; if (params.isSmoothZoomSupported()) { mCamera.startSmoothZoom(nextZoomLevel); } else { params.setZoom(nextZoomLevel); mCamera.setParameters(params); } Log.v(TAG, "Zooming from " + currentZoomLevel + " to " + nextZoomLevel); // sleep allows for zoom animation to finish Thread.sleep(WAIT_ZOOM_ANIMATION); // take picture mCamera.takePicture(shutterCallback, rawCallback, jpegCallback); Thread.sleep(WAIT_GENERIC); mCamera.stopPreview(); mCamera.release(); output.write(" ," + i); } } cleanupZoomImages(); } catch (Exception e) { assertTrue("Camera zoom stress test Exception", false); Log.v(TAG, e.toString()); } output.write("\n\n"); output.close(); } }