diff options
Diffstat (limited to 'tests_camera')
10 files changed, 1139 insertions, 0 deletions
diff --git a/tests_camera/src/com/android/camera/CameraLaunchPerformance.java b/tests_camera/src/com/android/camera/CameraLaunchPerformance.java new file mode 100644 index 000000000..fe2b7761a --- /dev/null +++ b/tests_camera/src/com/android/camera/CameraLaunchPerformance.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2007 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.camera; + +import android.app.Activity; +import android.os.Bundle; +import android.test.LaunchPerformanceBase; + +/** + * Instrumentation class for Camera launch performance testing. + */ +public class CameraLaunchPerformance extends LaunchPerformanceBase { + @SuppressWarnings("unused") + private static final String TAG = "CameraLaunchPerformance"; + + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + mIntent.setClassName(getTargetContext(), + "com.android.camera.CameraActivity"); + start(); + } + + /** + * Calls LaunchApp and finish. + */ + @Override + public void onStart() { + super.onStart(); + LaunchApp(); + finish(Activity.RESULT_OK, mResults); + } +} diff --git a/tests_camera/src/com/android/camera/CameraTestRunner.java b/tests_camera/src/com/android/camera/CameraTestRunner.java new file mode 100755 index 000000000..96c48a4c8 --- /dev/null +++ b/tests_camera/src/com/android/camera/CameraTestRunner.java @@ -0,0 +1,48 @@ +/* + * 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.camera; + +import android.test.InstrumentationTestRunner; +import android.test.InstrumentationTestSuite; + +import com.android.camera.activity.CameraActivityTest; +import com.android.camera.functional.CameraTest; +import com.android.camera.functional.ImageCaptureIntentTest; +import com.android.camera.functional.VideoCaptureIntentTest; +import com.android.camera.unittest.CameraUnitTest; + +import junit.framework.TestSuite; + + +public class CameraTestRunner extends InstrumentationTestRunner { + + @Override + public TestSuite getAllTests() { + TestSuite suite = new InstrumentationTestSuite(this); + suite.addTestSuite(CameraActivityTest.class); + suite.addTestSuite(CameraTest.class); + suite.addTestSuite(ImageCaptureIntentTest.class); + suite.addTestSuite(VideoCaptureIntentTest.class); + suite.addTestSuite(CameraUnitTest.class); + return suite; + } + + @Override + public ClassLoader getLoader() { + return CameraTestRunner.class.getClassLoader(); + } +} diff --git a/tests_camera/src/com/android/camera/UnitTests.java b/tests_camera/src/com/android/camera/UnitTests.java new file mode 100644 index 000000000..e56a907f0 --- /dev/null +++ b/tests_camera/src/com/android/camera/UnitTests.java @@ -0,0 +1,35 @@ +/* + * 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.camera; + +import android.test.suitebuilder.UnitTestSuiteBuilder; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * TestSuite for all Camera unit tests. + */ +public class UnitTests extends TestSuite { + + public static Test suite() { + return new UnitTestSuiteBuilder(UnitTests.class) + .includePackages("com.android.camera.unittest") + .named("Camera Unit Tests") + .build(); + } +} diff --git a/tests_camera/src/com/android/camera/activity/CameraActivityTest.java b/tests_camera/src/com/android/camera/activity/CameraActivityTest.java new file mode 100644 index 000000000..eb027e9d3 --- /dev/null +++ b/tests_camera/src/com/android/camera/activity/CameraActivityTest.java @@ -0,0 +1,53 @@ +/* + * 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.camera.activity; + +import android.hardware.Camera.Parameters; +import android.test.suitebuilder.annotation.LargeTest; + +import com.android.camera.CameraActivity; +import com.android.camera.CameraHolder; +import com.android.gallery3d.R; + +import static com.google.testing.littlemock.LittleMock.doReturn; + +public class CameraActivityTest extends CameraTestCase <CameraActivity> { + public CameraActivityTest() { + super(CameraActivity.class); + } + + @LargeTest + public void testFailToConnect() throws Exception { + super.internalTestFailToConnect(); + } + + @LargeTest + public void testTakePicture() throws Exception { + CameraHolder.injectMockCamera(mCameraInfo, mOneMockCamera); + + getActivity(); + getInstrumentation().waitForIdleSync(); + + // Press shutter button to take a picture. + performClick(R.id.shutter_button); + getInstrumentation().waitForIdleSync(); + + // Force the activity to finish. + getActivity().finish(); + getInstrumentation().waitForIdleSync(); + } +} diff --git a/tests_camera/src/com/android/camera/activity/CameraTestCase.java b/tests_camera/src/com/android/camera/activity/CameraTestCase.java new file mode 100644 index 000000000..27be3c7d3 --- /dev/null +++ b/tests_camera/src/com/android/camera/activity/CameraTestCase.java @@ -0,0 +1,246 @@ +/* + * 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.camera.activity; + +import android.app.Activity; +import android.app.Instrumentation; +import android.hardware.Camera; +import android.hardware.Camera.AutoFocusCallback; +import android.hardware.Camera.CameraInfo; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.PictureCallback; +import android.hardware.Camera.ShutterCallback; +import android.test.ActivityInstrumentationTestCase2; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; + +import com.android.camera.CameraHolder; +import com.android.camera.CameraManager.CameraProxy; +import com.android.camera.Util; +import com.android.gallery3d.R; + +import static com.google.testing.littlemock.LittleMock.mock; +import static com.google.testing.littlemock.LittleMock.doAnswer; +import static com.google.testing.littlemock.LittleMock.doReturn; +import static com.google.testing.littlemock.LittleMock.anyObject; +import com.google.testing.littlemock.AppDataDirGuesser; +import com.google.testing.littlemock.ArgumentCaptor; +import com.google.testing.littlemock.Captor; +import com.google.testing.littlemock.LittleMock; +import com.google.testing.littlemock.Mock; + +import java.io.File; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.concurrent.Callable; + + +public class CameraTestCase<T extends Activity> extends ActivityInstrumentationTestCase2<T> { + protected CameraInfo mCameraInfo[]; + protected CameraProxy mMockCamera[]; + protected CameraInfo mOneCameraInfo[]; + protected CameraProxy mOneMockCamera[]; + private static Parameters mParameters; + private byte[] mBlankJpeg; + @Mock private CameraProxy mMockBackCamera; + @Mock private CameraProxy mMockFrontCamera; + @Captor private ArgumentCaptor<ShutterCallback> mShutterCallback; + @Captor private ArgumentCaptor<PictureCallback> mRawPictureCallback; + @Captor private ArgumentCaptor<PictureCallback> mJpegPictureCallback; + @Captor private ArgumentCaptor<AutoFocusCallback> mAutoFocusCallback; + Callable<Object> mAutoFocusCallable = new AutoFocusCallable(); + Callable<Object> mTakePictureCallable = new TakePictureCallable(); + + private class TakePictureCallable implements Callable<Object> { + @Override + public Object call() throws Exception { + Runnable runnable = new Runnable() { + @Override + public void run() { + readBlankJpeg(); + Camera camera = mOneMockCamera[0].getCamera(); + mShutterCallback.getValue().onShutter(); + mRawPictureCallback.getValue().onPictureTaken(null, camera); + mJpegPictureCallback.getValue().onPictureTaken(mBlankJpeg, camera); + } + }; + // Probably need some delay. Make sure shutter callback is called + // after onShutterButtonFocus(false). + getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50); + return null; + } + } + + private class AutoFocusCallable implements Callable<Object> { + @Override + public Object call() throws Exception { + Runnable runnable = new Runnable() { + @Override + public void run() { + Camera camera = mOneMockCamera[0].getCamera(); + mAutoFocusCallback.getValue().onAutoFocus(true, camera); + } + }; + // Need some delay. Otherwise, focus callback will be run before + // onShutterButtonClick + getActivity().findViewById(R.id.gl_root_view).postDelayed(runnable, 50); + return null; + } + } + + public CameraTestCase(Class<T> activityClass) { + super(activityClass); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + AppDataDirGuesser.setInstance(new AppDataDirGuesser() { + @Override + public File guessSuitableDirectoryForGeneratedClasses() { + return getInstrumentation().getTargetContext().getCacheDir(); + } + }); + AppDataDirGuesser.getsInstance().guessSuitableDirectoryForGeneratedClasses(); + LittleMock.initMocks(this); + mCameraInfo = new CameraInfo[2]; + mCameraInfo[0] = new CameraInfo(); + mCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK; + mCameraInfo[1] = new CameraInfo(); + mCameraInfo[1].facing = CameraInfo.CAMERA_FACING_FRONT; + mMockCamera = new CameraProxy[2]; + mMockCamera[0] = mMockBackCamera; + mMockCamera[1] = mMockFrontCamera; + doReturn(getParameters()).when(mMockCamera[0]).getParameters(); + doReturn(getParameters()).when(mMockCamera[1]).getParameters(); + + mOneCameraInfo = new CameraInfo[1]; + mOneCameraInfo[0] = new CameraInfo(); + mOneCameraInfo[0].facing = CameraInfo.CAMERA_FACING_BACK; + mOneMockCamera = new CameraProxy[1]; + mOneMockCamera[0] = mMockBackCamera; + doReturn(getParameters()).when(mOneMockCamera[0]).getParameters(); + + // Mock takePicture call. + doAnswer(mTakePictureCallable).when(mMockBackCamera).takePicture( + mShutterCallback.capture(), mRawPictureCallback.capture(), + (PictureCallback) anyObject(), mJpegPictureCallback.capture()); + + // Mock autoFocus call. + doAnswer(mAutoFocusCallable).when(mMockBackCamera).autoFocus( + mAutoFocusCallback.capture()); + } + + private void readBlankJpeg() { + InputStream ins = getActivity().getResources().openRawResource(R.raw.blank); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + int size = 0; + + // Read the entire resource into a local byte buffer. + byte[] buffer = new byte[1024]; + try { + while((size = ins.read(buffer, 0, 1024)) >= 0){ + outputStream.write(buffer, 0, size); + } + } catch (IOException e) { + // ignore + } finally { + Util.closeSilently(ins); + } + mBlankJpeg = outputStream.toByteArray(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + CameraHolder.injectMockCamera(null, null); + } + + protected void internalTestFailToConnect() throws Exception { + CameraHolder.injectMockCamera(mCameraInfo, null); + + getActivity(); + Instrumentation inst = getInstrumentation(); + inst.waitForIdleSync(); + inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); // close dialog + } + + protected void performClick(final int id) { + Activity activity = getActivity(); + getInstrumentation().waitForIdleSync(); + assertNotNull(activity.findViewById(id)); + Instrumentation inst = getInstrumentation(); + inst.runOnMainSync(new Runnable() { + @Override + public void run() { + View v = getActivity().findViewById(id); + float x = (v.getLeft() + v.getRight()) / 2; + float y = (v.getTop() + v.getBottom()) / 2; + MotionEvent down = MotionEvent.obtain(0, 0, + MotionEvent.ACTION_DOWN, x, y, 0, 0, 0, 0, 0, 0, 0); + MotionEvent up = MotionEvent.obtain(0, 0, + MotionEvent.ACTION_UP, x, y, 0, 0, 0, 0, 0, 0, 0); + View parent = (View) v.getParent(); + parent.dispatchTouchEvent(down); + parent.dispatchTouchEvent(up); + } + }); + inst.waitForIdleSync(); + } + + protected void assertViewNotExist(int id) { + Activity activity = getActivity(); + getInstrumentation().waitForIdleSync(); + assertNull(activity.findViewById(id)); + } + + protected void assertViewNotVisible(int id) { + Activity activity = getActivity(); + getInstrumentation().waitForIdleSync(); + View view = activity.findViewById(id); + assertTrue(view.getVisibility() != View.VISIBLE); + } + + protected static Parameters getParameters() { + synchronized (CameraTestCase.class) { + if (mParameters == null) { + mParameters = android.hardware.Camera.getEmptyParameters(); + mParameters.unflatten("preview-format-values=yuv420sp,yuv420p,yuv422i-yuyv,yuv420p;" + + "preview-format=yuv420sp;" + + "preview-size-values=800x480;preview-size=800x480;" + + "picture-size-values=320x240;picture-size=320x240;" + + "jpeg-thumbnail-size-values=320x240,0x0;jpeg-thumbnail-width=320;jpeg-thumbnail-height=240;" + + "jpeg-thumbnail-quality=60;jpeg-quality=95;" + + "preview-frame-rate-values=30,15;preview-frame-rate=30;" + + "focus-mode-values=continuous-video,auto,macro,infinity,continuous-picture;focus-mode=auto;" + + "preview-fps-range-values=(15000,30000);preview-fps-range=15000,30000;" + + "scene-mode-values=auto,action,night;scene-mode=auto;" + + "flash-mode-values=off,on,auto,torch;flash-mode=off;" + + "whitebalance-values=auto,daylight,fluorescent,incandescent;whitebalance=auto;" + + "effect-values=none,mono,sepia;effect=none;" + + "zoom-supported=true;zoom-ratios=100,200,400;max-zoom=2;" + + "picture-format-values=jpeg;picture-format=jpeg;" + + "min-exposure-compensation=-30;max-exposure-compensation=30;" + + "exposure-compensation=0;exposure-compensation-step=0.1;" + + "horizontal-view-angle=40;vertical-view-angle=40;"); + } + } + return mParameters; + } +} diff --git a/tests_camera/src/com/android/camera/functional/CameraTest.java b/tests_camera/src/com/android/camera/functional/CameraTest.java new file mode 100644 index 000000000..3fdebc030 --- /dev/null +++ b/tests_camera/src/com/android/camera/functional/CameraTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2010 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.camera.functional; + +import com.android.camera.CameraActivity; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Environment; +import android.os.Process; +import android.provider.MediaStore; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +public class CameraTest extends InstrumentationTestCase { + @LargeTest + public void testVideoCaptureIntentFdLeak() throws Exception { + Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://" + + Environment.getExternalStorageDirectory().toString() + + "test_fd_leak.3gp")); + getInstrumentation().startActivitySync(intent).finish(); + // Test if the fd is closed. + for (File f: new File("/proc/" + Process.myPid() + "/fd").listFiles()) { + assertEquals(-1, f.getCanonicalPath().indexOf("test_fd_leak.3gp")); + } + } + + @LargeTest + public void testActivityLeak() throws Exception { + checkActivityLeak(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); + checkActivityLeak(MediaStore.INTENT_ACTION_VIDEO_CAMERA); + } + + private void checkActivityLeak(String action) throws Exception { + final int TEST_COUNT = 5; + Intent intent = new Intent(action); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.setClass(getInstrumentation().getTargetContext(), + CameraActivity.class); + ArrayList<WeakReference<Activity>> refs = + new ArrayList<WeakReference<Activity>>(); + for (int i = 0; i < TEST_COUNT; i++) { + Activity activity = getInstrumentation().startActivitySync(intent); + refs.add(new WeakReference<Activity>(activity)); + activity.finish(); + getInstrumentation().waitForIdleSync(); + activity = null; + } + Runtime.getRuntime().gc(); + Runtime.getRuntime().runFinalization(); + Runtime.getRuntime().gc(); + int refCount = 0; + for (WeakReference<Activity> c: refs) { + if (c.get() != null) refCount++; + } + // If applications are leaking activity, every reference is reachable. + assertTrue(refCount != TEST_COUNT); + } +} diff --git a/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java b/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java new file mode 100644 index 000000000..54ac1b497 --- /dev/null +++ b/tests_camera/src/com/android/camera/functional/ImageCaptureIntentTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2011 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.camera.functional; + +import com.android.camera.CameraActivity; +import com.android.gallery3d.R; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.KeyEvent; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; + +public class ImageCaptureIntentTest extends ActivityInstrumentationTestCase2 <CameraActivity> { + private Intent mIntent; + + public ImageCaptureIntentTest() { + super(CameraActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + } + + @LargeTest + public void testNoExtraOutput() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + takePicture(); + pressDone(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_OK, getActivity().getResultCode()); + Intent resultData = getActivity().getResultData(); + Bitmap bitmap = (Bitmap) resultData.getParcelableExtra("data"); + assertNotNull(bitmap); + assertTrue(bitmap.getWidth() > 0); + assertTrue(bitmap.getHeight() > 0); + } + + @LargeTest + public void testExtraOutput() throws Exception { + File file = new File(Environment.getExternalStorageDirectory(), + "test.jpg"); + BufferedInputStream stream = null; + byte[] jpegData; + + try { + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file)); + setActivityIntent(mIntent); + getActivity(); + + takePicture(); + pressDone(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_OK, getActivity().getResultCode()); + + // Verify the jpeg file + int fileLength = (int) file.length(); + assertTrue(fileLength > 0); + jpegData = new byte[fileLength]; + stream = new BufferedInputStream(new FileInputStream(file)); + stream.read(jpegData); + } finally { + if (stream != null) stream.close(); + file.delete(); + } + + Bitmap b = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length); + assertTrue(b.getWidth() > 0); + assertTrue(b.getHeight() > 0); + } + + @LargeTest + public void testCancel() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + pressCancel(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode()); + } + + @LargeTest + public void testSnapshotCancel() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + takePicture(); + pressCancel(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode()); + } + + private void takePicture() throws Exception { + getInstrumentation().sendKeySync( + new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS)); + getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_CAMERA); + Thread.sleep(4000); + } + + private void pressDone() { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + getActivity().findViewById(R.id.btn_done).performClick(); + } + }); + } + + private void pressCancel() { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + getActivity().findViewById(R.id.btn_cancel).performClick(); + } + }); + } +} diff --git a/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java b/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java new file mode 100644 index 000000000..43e91ca84 --- /dev/null +++ b/tests_camera/src/com/android/camera/functional/VideoCaptureIntentTest.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2011 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.camera.functional; + +import com.android.camera.CameraActivity; +import com.android.gallery3d.R; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Intent; +import android.database.Cursor; +import android.media.MediaMetadataRetriever; +import android.net.Uri; +import android.os.Environment; +import android.provider.MediaStore; +import android.provider.MediaStore.Video.VideoColumns; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.view.KeyEvent; + +import java.io.File; + +public class VideoCaptureIntentTest extends ActivityInstrumentationTestCase2 <CameraActivity> { + private static final String TAG = "VideoCaptureIntentTest"; + private Intent mIntent; + private Uri mVideoUri; + private File mFile, mFile2; + + public VideoCaptureIntentTest() { + super(CameraActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); + } + + @Override + protected void tearDown() throws Exception { + if (mVideoUri != null) { + ContentResolver resolver = getActivity().getContentResolver(); + Uri query = mVideoUri.buildUpon().build(); + String[] projection = new String[] {VideoColumns.DATA}; + + Cursor cursor = null; + try { + cursor = resolver.query(query, projection, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + new File(cursor.getString(0)).delete(); + } + } finally { + if (cursor != null) cursor.close(); + } + + resolver.delete(mVideoUri, null, null); + } + if (mFile != null) mFile.delete(); + if (mFile2 != null) mFile2.delete(); + super.tearDown(); + } + + @LargeTest + public void testNoExtraOutput() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + recordVideo(); + pressDone(); + + Intent resultData = getActivity().getResultData(); + mVideoUri = resultData.getData(); + assertNotNull(mVideoUri); + verify(getActivity(), mVideoUri); + } + + @LargeTest + public void testExtraOutput() throws Exception { + mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp"); + + Uri uri = Uri.fromFile(mFile); + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + setActivityIntent(mIntent); + getActivity(); + + recordVideo(); + pressDone(); + + verify(getActivity(), uri); + } + + @LargeTest + public void testCancel() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + pressCancel(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode()); + } + + @LargeTest + public void testRecordCancel() throws Exception { + setActivityIntent(mIntent); + getActivity(); + + recordVideo(); + pressCancel(); + + assertTrue(getActivity().isFinishing()); + assertEquals(Activity.RESULT_CANCELED, getActivity().getResultCode()); + } + + @LargeTest + public void testExtraSizeLimit() throws Exception { + mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp"); + final long sizeLimit = 500000; // bytes + + Uri uri = Uri.fromFile(mFile); + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mIntent.putExtra(MediaStore.EXTRA_SIZE_LIMIT, sizeLimit); + mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // use low quality to speed up + setActivityIntent(mIntent); + getActivity(); + + recordVideo(5000); + pressDone(); + + verify(getActivity(), uri); + long length = mFile.length(); + Log.v(TAG, "Video size is " + length + " bytes."); + assertTrue(length > 0); + assertTrue("Actual size=" + length, length <= sizeLimit); + } + + @LargeTest + public void testExtraDurationLimit() throws Exception { + mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp"); + final int durationLimit = 2; // seconds + + Uri uri = Uri.fromFile(mFile); + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mIntent.putExtra(MediaStore.EXTRA_DURATION_LIMIT, durationLimit); + setActivityIntent(mIntent); + getActivity(); + + recordVideo(5000); + pressDone(); + + int duration = verify(getActivity(), uri); + // The duraion should be close to to the limit. The last video duration + // also has duration, so the total duration may exceeds the limit a + // little bit. + Log.v(TAG, "Video length is " + duration + " ms."); + assertTrue(duration < (durationLimit + 1) * 1000); + } + + @LargeTest + public void testExtraVideoQuality() throws Exception { + mFile = new File(Environment.getExternalStorageDirectory(), "video.tmp"); + mFile2 = new File(Environment.getExternalStorageDirectory(), "video2.tmp"); + + Uri uri = Uri.fromFile(mFile); + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); // low quality + setActivityIntent(mIntent); + getActivity(); + + recordVideo(); + pressDone(); + + verify(getActivity(), uri); + setActivity(null); + + uri = Uri.fromFile(mFile2); + mIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); + mIntent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY, 1); // high quality + setActivityIntent(mIntent); + getActivity(); + + recordVideo(); + pressDone(); + + verify(getActivity(), uri); + assertTrue(mFile.length() <= mFile2.length()); + } + + // Verify result code, result data, and the duration. + private int verify(CameraActivity activity, Uri uri) throws Exception { + assertTrue(activity.isFinishing()); + assertEquals(Activity.RESULT_OK, activity.getResultCode()); + + // Verify the video file + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + retriever.setDataSource(activity, uri); + String duration = retriever.extractMetadata( + MediaMetadataRetriever.METADATA_KEY_DURATION); + assertNotNull(duration); + int durationValue = Integer.parseInt(duration); + Log.v(TAG, "Video duration is " + durationValue); + assertTrue(durationValue > 0); + return durationValue; + } + + private void recordVideo(int ms) throws Exception { + getInstrumentation().sendCharacterSync(KeyEvent.KEYCODE_CAMERA); + Thread.sleep(ms); + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + // If recording is in progress, stop it. Run these atomically in + // UI thread. + CameraActivity activity = getActivity(); + if (activity.isRecording()) { + activity.findViewById(R.id.shutter_button).performClick(); + } + } + }); + } + + private void recordVideo() throws Exception { + recordVideo(2000); + } + + private void pressDone() { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + getActivity().findViewById(R.id.btn_done).performClick(); + } + }); + } + + private void pressCancel() { + getInstrumentation().runOnMainSync(new Runnable() { + @Override + public void run() { + getActivity().findViewById(R.id.btn_cancel).performClick(); + } + }); + } +} diff --git a/tests_camera/src/com/android/camera/power/ImageAndVideoCapture.java b/tests_camera/src/com/android/camera/power/ImageAndVideoCapture.java new file mode 100755 index 000000000..b89b764c3 --- /dev/null +++ b/tests_camera/src/com/android/camera/power/ImageAndVideoCapture.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2009 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.camera.power; + +import com.android.camera.CameraActivity; + +import android.app.Instrumentation; +import android.provider.MediaStore; +import android.test.ActivityInstrumentationTestCase2; +import android.test.suitebuilder.annotation.LargeTest; +import android.util.Log; +import android.view.KeyEvent; +import android.content.Intent; +/** + * Junit / Instrumentation test case for camera power measurement + * + * Running the test suite: + * + * adb shell am instrument \ + * -e com.android.camera.power.ImageAndVideoCapture \ + * -w com.android.camera.tests/android.test.InstrumentationTestRunner + * + */ + +public class ImageAndVideoCapture extends ActivityInstrumentationTestCase2 <CameraActivity> { + private String TAG = "ImageAndVideoCapture"; + private static final int TOTAL_NUMBER_OF_IMAGECAPTURE = 5; + private static final int TOTAL_NUMBER_OF_VIDEOCAPTURE = 5; + private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 1500; //1.5 sedconds + private static final long WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN = 10000; //10 seconds + private static final long WAIT_FOR_PREVIEW = 1500; //1.5 seconds + private static final long WAIT_FOR_STABLE_STATE = 2000; //2 seconds + + public ImageAndVideoCapture() { + super(CameraActivity.class); + } + + @Override + protected void setUp() throws Exception { + getActivity(); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + super.tearDown(); + } + + @LargeTest + public void testLaunchCamera() { + // This test case capture the baseline for the image preview. + try { + Thread.sleep(WAIT_FOR_STABLE_STATE); + } catch (Exception e) { + Log.v(TAG, "Got exception", e); + assertTrue("testImageCaptureDoNothing", false); + } + } + + @LargeTest + public void testCapture5Image() { + // This test case will use the default camera setting + Instrumentation inst = getInstrumentation(); + try { + for (int i = 0; i < TOTAL_NUMBER_OF_IMAGECAPTURE; i++) { + Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN); + inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_UP); + inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); + Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN); + } + Thread.sleep(WAIT_FOR_STABLE_STATE); + } catch (Exception e) { + Log.v(TAG, "Got exception", e); + assertTrue("testImageCapture", false); + } + } + + @LargeTest + public void testCapture5Videos() { + // This test case will use the default camera setting + Instrumentation inst = getInstrumentation(); + try { + // Switch to the video mode + Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA); + intent.setClass(getInstrumentation().getTargetContext(), + CameraActivity.class); + getActivity().startActivity(intent); + for (int i = 0; i < TOTAL_NUMBER_OF_VIDEOCAPTURE; i++) { + Thread.sleep(WAIT_FOR_PREVIEW); + // record a video + inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); + Thread.sleep(WAIT_FOR_VIDEO_CAPTURE_TO_BE_TAKEN); + inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER); + Thread.sleep(WAIT_FOR_PREVIEW); + } + Thread.sleep(WAIT_FOR_STABLE_STATE); + } catch (Exception e) { + Log.v(TAG, "Got exception", e); + assertTrue("testVideoCapture", false); + } + } +} diff --git a/tests_camera/src/com/android/camera/unittest/CameraUnitTest.java b/tests_camera/src/com/android/camera/unittest/CameraUnitTest.java new file mode 100644 index 000000000..0b4fc80f6 --- /dev/null +++ b/tests_camera/src/com/android/camera/unittest/CameraUnitTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 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.camera.unittest; + +import com.android.camera.Util; + +import android.graphics.Matrix; +import android.test.suitebuilder.annotation.SmallTest; + +import junit.framework.TestCase; + +@SmallTest +public class CameraUnitTest extends TestCase { + public void testRoundOrientation() { + int h = Util.ORIENTATION_HYSTERESIS; + assertEquals(0, Util.roundOrientation(0, 0)); + assertEquals(0, Util.roundOrientation(359, 0)); + assertEquals(0, Util.roundOrientation(0 + 44 + h, 0)); + assertEquals(90, Util.roundOrientation(0 + 45 + h, 0)); + assertEquals(0, Util.roundOrientation(360 - 44 - h, 0)); + assertEquals(270, Util.roundOrientation(360 - 45 - h, 0)); + + assertEquals(90, Util.roundOrientation(90, 90)); + assertEquals(90, Util.roundOrientation(90 + 44 + h, 90)); + assertEquals(180, Util.roundOrientation(90 + 45 + h, 90)); + assertEquals(90, Util.roundOrientation(90 - 44 - h, 90)); + assertEquals(0, Util.roundOrientation(90 - 45 - h, 90)); + + assertEquals(180, Util.roundOrientation(180, 180)); + assertEquals(180, Util.roundOrientation(180 + 44 + h, 180)); + assertEquals(270, Util.roundOrientation(180 + 45 + h, 180)); + assertEquals(180, Util.roundOrientation(180 - 44 - h, 180)); + assertEquals(90, Util.roundOrientation(180 - 45 - h, 180)); + + assertEquals(270, Util.roundOrientation(270, 270)); + assertEquals(270, Util.roundOrientation(270 + 44 + h, 270)); + assertEquals(0, Util.roundOrientation(270 + 45 + h, 270)); + assertEquals(270, Util.roundOrientation(270 - 44 - h, 270)); + assertEquals(180, Util.roundOrientation(270 - 45 - h, 270)); + + assertEquals(90, Util.roundOrientation(90, 0)); + assertEquals(180, Util.roundOrientation(180, 0)); + assertEquals(270, Util.roundOrientation(270, 0)); + + assertEquals(0, Util.roundOrientation(0, 90)); + assertEquals(180, Util.roundOrientation(180, 90)); + assertEquals(270, Util.roundOrientation(270, 90)); + + assertEquals(0, Util.roundOrientation(0, 180)); + assertEquals(90, Util.roundOrientation(90, 180)); + assertEquals(270, Util.roundOrientation(270, 180)); + + assertEquals(0, Util.roundOrientation(0, 270)); + assertEquals(90, Util.roundOrientation(90, 270)); + assertEquals(180, Util.roundOrientation(180, 270)); + } + + public void testPrepareMatrix() { + Matrix matrix = new Matrix(); + float[] points; + int[] expected; + + Util.prepareMatrix(matrix, false, 0, 800, 480); + points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250}; + expected = new int[] {0, 0, 400, 240, 800, 480, 400, 480, 100, 300}; + matrix.mapPoints(points); + assertEquals(expected, points); + + Util.prepareMatrix(matrix, false, 90, 800, 480); + points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250}; + expected = new int[] {800, 0, 400, 240, 0, 480, 0, 240, 300, 60}; + matrix.mapPoints(points); + assertEquals(expected, points); + + Util.prepareMatrix(matrix, false, 180, 800, 480); + points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250}; + expected = new int[] {800, 480, 400, 240, 0, 0, 400, 0, 700, 180}; + matrix.mapPoints(points); + assertEquals(expected, points); + + Util.prepareMatrix(matrix, true, 180, 800, 480); + points = new float[] {-1000, -1000, 0, 0, 1000, 1000, 0, 1000, -750, 250}; + expected = new int[] {0, 480, 400, 240, 800, 0, 400, 0, 100, 180}; + matrix.mapPoints(points); + assertEquals(expected, points); + } + + private void assertEquals(int expected[], float[] actual) { + for (int i = 0; i < expected.length; i++) { + assertEquals("Array index " + i + " mismatch", expected[i], Math.round(actual[i])); + } + } +} |