/* * Copyright (C) 2008 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.functional; import com.android.mediaframeworktest.MediaFrameworkTest; import com.android.mediaframeworktest.MediaNames; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.PictureCallback; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.ShutterCallback; import android.os.ConditionVariable; import android.os.Environment; import android.os.Looper; import android.test.ActivityInstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.view.SurfaceHolder; import java.io.*; /** * Junit / Instrumentation test case for the camera api * * To run only tests in this class: * * adb shell am instrument \ * -e class com.android.mediaframeworktest.functional.CameraTest \ * -w com.android.mediaframeworktest/.MediaFrameworkTestRunner */ public class CameraTest extends ActivityInstrumentationTestCase { private String TAG = "CameraTest"; private boolean rawPreviewCallbackResult = false; private boolean shutterCallbackResult = false; private boolean rawPictureCallbackResult = false; private boolean jpegPictureCallbackResult = false; private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. private static final int CAMERA_ID = 0; private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); private TestShutterCallback mShutterCallback = new TestShutterCallback(); private RawPictureCallback mRawPictureCallback = new RawPictureCallback(); private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback(); private boolean mInitialized = false; private Looper mLooper = null; private final ConditionVariable mPreviewDone = new ConditionVariable(); private final ConditionVariable mSnapshotDone = new ConditionVariable(); Camera mCamera; Context mContext; public CameraTest() { super("com.android.mediaframeworktest", MediaFrameworkTest.class); } protected void setUp() throws Exception { super.setUp(); } /* * Initializes the message looper so that the Camera object can * receive the callback messages. */ private void initializeMessageLooper() { final ConditionVariable startDone = new ConditionVariable(); Log.v(TAG, "start looper"); new Thread() { @Override public void run() { // Set up a looper to be used by camera. Looper.prepare(); Log.v(TAG, "start loopRun"); // Save the looper so that we can terminate this thread // after we are done with it. mLooper = Looper.myLooper(); mCamera = Camera.open(CAMERA_ID); startDone.open(); Looper.loop(); // Blocks forever until Looper.quit() is called. Log.v(TAG, "initializeMessageLooper: quit."); } }.start(); if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { fail("initializeMessageLooper: start timeout"); } } /* * Terminates the message looper thread. */ private void terminateMessageLooper() throws Exception { mLooper.quit(); // Looper.quit() is asynchronous. The looper may still has some // preview callbacks in the queue after quit is called. The preview // callback still uses the camera object (setHasPreviewCallback). // After camera is released, RuntimeException will be thrown from // the method. So we need to join the looper thread here. mLooper.getThread().join(); mCamera.release(); } //Implement the previewCallback private final class RawPreviewCallback implements PreviewCallback { public void onPreviewFrame(byte [] rawData, Camera camera) { Log.v(TAG, "Preview callback start"); int rawDataLength = 0; if (rawData != null) { rawDataLength = rawData.length; } if (rawDataLength > 0) { rawPreviewCallbackResult = true; } else { rawPreviewCallbackResult = false; } mPreviewDone.open(); Log.v(TAG, "Preview callback stop"); } }; //Implement the shutterCallback private final class TestShutterCallback implements ShutterCallback { public void onShutter() { shutterCallbackResult = true; Log.v(TAG, "onShutter called"); } }; //Implement the RawPictureCallback private final class RawPictureCallback implements PictureCallback { public void onPictureTaken(byte [] rawData, Camera camera) { // no support for raw data - success if we get the callback rawPictureCallbackResult = true; Log.v(TAG, "RawPictureCallback callback"); } }; //Implement the JpegPictureCallback private final class JpegPictureCallback implements PictureCallback { public void onPictureTaken(byte [] rawData, Camera camera) { try { if (rawData != null) { int rawDataLength = rawData.length; File rawoutput = new File( Environment.getExternalStorageDirectory().toString(), "/test.bmp"); FileOutputStream outstream = new FileOutputStream(rawoutput); outstream.write(rawData); Log.v(TAG, "JpegPictureCallback rawDataLength = " + rawDataLength); jpegPictureCallbackResult = true; } else { jpegPictureCallbackResult = false; } mSnapshotDone.open(); Log.v(TAG, "Jpeg Picture callback"); } catch (Exception e) { Log.v(TAG, e.toString()); } } }; private void waitForPreviewDone() { if (!mPreviewDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { Log.v(TAG, "waitForPreviewDone: timeout"); } mPreviewDone.close(); } private void waitForSnapshotDone() { if (!mSnapshotDone.block(MediaNames.WAIT_SNAPSHOT_TIME)) { // timeout could be expected or unexpected. The caller will decide. Log.v(TAG, "waitForSnapshotDone: timeout"); } mSnapshotDone.close(); } private void checkTakePicture() { SurfaceHolder mSurfaceHolder; try { mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); mCamera.setPreviewDisplay(mSurfaceHolder); Log.v(TAG, "Start preview"); mCamera.startPreview(); waitForPreviewDone(); mCamera.setPreviewCallback(null); mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); waitForSnapshotDone(); } catch (Exception e) { Log.v(TAG, e.toString()); } } private void checkPreviewCallback() { SurfaceHolder mSurfaceHolder; try { mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); mCamera.setPreviewDisplay(mSurfaceHolder); Log.v(TAG, "start preview"); mCamera.startPreview(); waitForPreviewDone(); mCamera.setPreviewCallback(null); } catch (Exception e) { Log.v(TAG, e.toString()); } } /* * TODO(yslau): Need to setup the golden rawData and compare the * the new captured rawData with the golden one. * * Test case 1: Take a picture and verify all the callback * functions are called properly. */ @LargeTest public void testTakePicture() throws Exception { initializeMessageLooper(); mCamera.setPreviewCallback(mRawPreviewCallback); checkTakePicture(); terminateMessageLooper(); assertTrue("shutterCallbackResult", shutterCallbackResult); assertTrue("rawPictureCallbackResult", rawPictureCallbackResult); assertTrue("jpegPictureCallbackResult", jpegPictureCallbackResult); } /* * Test case 2: Set the preview and * verify the RawPreviewCallback is called */ @LargeTest public void testCheckPreview() throws Exception { initializeMessageLooper(); mCamera.setPreviewCallback(mRawPreviewCallback); checkPreviewCallback(); terminateMessageLooper(); assertTrue("RawPreviewCallbackResult", rawPreviewCallbackResult); } }