1/* 2 * Copyright (C) 2008 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.functional; 18 19import com.android.mediaframeworktest.MediaFrameworkTest; 20import com.android.mediaframeworktest.MediaNames; 21 22import android.content.Context; 23import android.hardware.Camera; 24import android.hardware.Camera.PictureCallback; 25import android.hardware.Camera.PreviewCallback; 26import android.hardware.Camera.ShutterCallback; 27import android.os.ConditionVariable; 28import android.os.Environment; 29import android.os.Looper; 30import android.test.ActivityInstrumentationTestCase; 31import android.test.suitebuilder.annotation.LargeTest; 32import android.util.Log; 33import android.view.SurfaceHolder; 34 35import java.io.*; 36 37/** 38 * Junit / Instrumentation test case for the camera api 39 * 40 * To run only tests in this class: 41 * 42 * adb shell am instrument \ 43 * -e class com.android.mediaframeworktest.functional.CameraTest \ 44 * -w com.android.mediaframeworktest/.MediaFrameworkTestRunner 45 */ 46public class CameraTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> { 47 private String TAG = "CameraTest"; 48 49 private boolean rawPreviewCallbackResult = false; 50 private boolean shutterCallbackResult = false; 51 private boolean rawPictureCallbackResult = false; 52 private boolean jpegPictureCallbackResult = false; 53 54 private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000; // Milliseconds. 55 private static final int CAMERA_ID = 0; 56 57 private RawPreviewCallback mRawPreviewCallback = new RawPreviewCallback(); 58 private TestShutterCallback mShutterCallback = new TestShutterCallback(); 59 private RawPictureCallback mRawPictureCallback = new RawPictureCallback(); 60 private JpegPictureCallback mJpegPictureCallback = new JpegPictureCallback(); 61 62 private boolean mInitialized = false; 63 private Looper mLooper = null; 64 private final ConditionVariable mPreviewDone = new ConditionVariable(); 65 private final ConditionVariable mSnapshotDone = new ConditionVariable(); 66 67 Camera mCamera; 68 Context mContext; 69 70 public CameraTest() { 71 super("com.android.mediaframeworktest", MediaFrameworkTest.class); 72 } 73 74 protected void setUp() throws Exception { 75 super.setUp(); 76 } 77 78 /* 79 * Initializes the message looper so that the Camera object can 80 * receive the callback messages. 81 */ 82 private void initializeMessageLooper() { 83 final ConditionVariable startDone = new ConditionVariable(); 84 Log.v(TAG, "start looper"); 85 new Thread() { 86 @Override 87 public void run() { 88 // Set up a looper to be used by camera. 89 Looper.prepare(); 90 Log.v(TAG, "start loopRun"); 91 // Save the looper so that we can terminate this thread 92 // after we are done with it. 93 mLooper = Looper.myLooper(); 94 mCamera = Camera.open(CAMERA_ID); 95 startDone.open(); 96 Looper.loop(); // Blocks forever until Looper.quit() is called. 97 Log.v(TAG, "initializeMessageLooper: quit."); 98 } 99 }.start(); 100 101 if (!startDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { 102 fail("initializeMessageLooper: start timeout"); 103 } 104 } 105 106 /* 107 * Terminates the message looper thread. 108 */ 109 private void terminateMessageLooper() throws Exception { 110 mLooper.quit(); 111 // Looper.quit() is asynchronous. The looper may still has some 112 // preview callbacks in the queue after quit is called. The preview 113 // callback still uses the camera object (setHasPreviewCallback). 114 // After camera is released, RuntimeException will be thrown from 115 // the method. So we need to join the looper thread here. 116 mLooper.getThread().join(); 117 mCamera.release(); 118 } 119 120 //Implement the previewCallback 121 private final class RawPreviewCallback implements PreviewCallback { 122 public void onPreviewFrame(byte [] rawData, Camera camera) { 123 Log.v(TAG, "Preview callback start"); 124 int rawDataLength = 0; 125 if (rawData != null) { 126 rawDataLength = rawData.length; 127 } 128 if (rawDataLength > 0) { 129 rawPreviewCallbackResult = true; 130 } else { 131 rawPreviewCallbackResult = false; 132 } 133 mPreviewDone.open(); 134 Log.v(TAG, "Preview callback stop"); 135 } 136 }; 137 138 //Implement the shutterCallback 139 private final class TestShutterCallback implements ShutterCallback { 140 public void onShutter() { 141 shutterCallbackResult = true; 142 Log.v(TAG, "onShutter called"); 143 } 144 }; 145 146 //Implement the RawPictureCallback 147 private final class RawPictureCallback implements PictureCallback { 148 public void onPictureTaken(byte [] rawData, Camera camera) { 149 // no support for raw data - success if we get the callback 150 rawPictureCallbackResult = true; 151 Log.v(TAG, "RawPictureCallback callback"); 152 } 153 }; 154 155 //Implement the JpegPictureCallback 156 private final class JpegPictureCallback implements PictureCallback { 157 public void onPictureTaken(byte [] rawData, Camera camera) { 158 try { 159 if (rawData != null) { 160 int rawDataLength = rawData.length; 161 File rawoutput = new File( 162 Environment.getExternalStorageDirectory().toString(), "/test.bmp"); 163 FileOutputStream outstream = new FileOutputStream(rawoutput); 164 outstream.write(rawData); 165 Log.v(TAG, "JpegPictureCallback rawDataLength = " + rawDataLength); 166 jpegPictureCallbackResult = true; 167 } else { 168 jpegPictureCallbackResult = false; 169 } 170 mSnapshotDone.open(); 171 Log.v(TAG, "Jpeg Picture callback"); 172 } catch (Exception e) { 173 Log.v(TAG, e.toString()); 174 } 175 } 176 }; 177 178 private void waitForPreviewDone() { 179 if (!mPreviewDone.block(WAIT_FOR_COMMAND_TO_COMPLETE)) { 180 Log.v(TAG, "waitForPreviewDone: timeout"); 181 } 182 mPreviewDone.close(); 183 } 184 185 private void waitForSnapshotDone() { 186 if (!mSnapshotDone.block(MediaNames.WAIT_SNAPSHOT_TIME)) { 187 // timeout could be expected or unexpected. The caller will decide. 188 Log.v(TAG, "waitForSnapshotDone: timeout"); 189 } 190 mSnapshotDone.close(); 191 } 192 193 194 private void checkTakePicture() { 195 SurfaceHolder mSurfaceHolder; 196 try { 197 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 198 mCamera.setPreviewDisplay(mSurfaceHolder); 199 Log.v(TAG, "Start preview"); 200 mCamera.startPreview(); 201 waitForPreviewDone(); 202 mCamera.setPreviewCallback(null); 203 mCamera.takePicture(mShutterCallback, mRawPictureCallback, mJpegPictureCallback); 204 waitForSnapshotDone(); 205 } catch (Exception e) { 206 Log.v(TAG, e.toString()); 207 } 208 } 209 210 private void checkPreviewCallback() { 211 SurfaceHolder mSurfaceHolder; 212 try { 213 mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder(); 214 mCamera.setPreviewDisplay(mSurfaceHolder); 215 Log.v(TAG, "start preview"); 216 mCamera.startPreview(); 217 waitForPreviewDone(); 218 mCamera.setPreviewCallback(null); 219 } catch (Exception e) { 220 Log.v(TAG, e.toString()); 221 } 222 } 223 224 /* 225 * TODO(yslau): Need to setup the golden rawData and compare the 226 * the new captured rawData with the golden one. 227 * 228 * Test case 1: Take a picture and verify all the callback 229 * functions are called properly. 230 */ 231 @LargeTest 232 public void testTakePicture() throws Exception { 233 initializeMessageLooper(); 234 mCamera.setPreviewCallback(mRawPreviewCallback); 235 checkTakePicture(); 236 terminateMessageLooper(); 237 assertTrue("shutterCallbackResult", shutterCallbackResult); 238 assertTrue("rawPictureCallbackResult", rawPictureCallbackResult); 239 assertTrue("jpegPictureCallbackResult", jpegPictureCallbackResult); 240 } 241 242 /* 243 * Test case 2: Set the preview and 244 * verify the RawPreviewCallback is called 245 */ 246 @LargeTest 247 public void testCheckPreview() throws Exception { 248 initializeMessageLooper(); 249 mCamera.setPreviewCallback(mRawPreviewCallback); 250 checkPreviewCallback(); 251 terminateMessageLooper(); 252 assertTrue("RawPreviewCallbackResult", rawPreviewCallbackResult); 253 } 254 255} 256 257