OSDN Git Service

Add camera-related tests back.
authorSascha Haeberling <haeberling@google.com>
Fri, 9 Aug 2013 21:43:07 +0000 (14:43 -0700)
committerSascha Haeberling <haeberling@google.com>
Fri, 9 Aug 2013 23:02:43 +0000 (16:02 -0700)
Change-Id: I2213618fe3b2d4ba776c5f1f94aca330a785df1a

21 files changed:
tests/Android.mk [new file with mode: 0644]
tests/AndroidManifest.xml [new file with mode: 0644]
tests/exiftool_parser/parser.py [new file with mode: 0755]
tests/res/raw/android_lawn.mp4 [new file with mode: 0644]
tests/res/raw/galaxy_nexus.jpg [new file with mode: 0755]
tests/res/raw/jpeg_control.jpg [new file with mode: 0644]
tests/res/xml/galaxy_nexus.xml [new file with mode: 0644]
tests/src/com/android/gallery3d/CameraTestRunner.java [new file with mode: 0755]
tests/src/com/android/gallery3d/StressTests.java [new file with mode: 0755]
tests/src/com/android/gallery3d/functional/CameraTest.java [new file with mode: 0644]
tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java [new file with mode: 0644]
tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java [new file with mode: 0644]
tests/src/com/android/gallery3d/stress/CameraLatency.java [new file with mode: 0755]
tests/src/com/android/gallery3d/stress/CameraStartUp.java [new file with mode: 0644]
tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java [new file with mode: 0755]
tests/src/com/android/gallery3d/stress/ImageCapture.java [new file with mode: 0755]
tests/src/com/android/gallery3d/stress/ShotToShotLatency.java [new file with mode: 0644]
tests/src/com/android/gallery3d/stress/SwitchPreview.java [new file with mode: 0755]
tests/src/com/android/gallery3d/stress/TestUtil.java [new file with mode: 0644]
tests/src/com/android/gallery3d/stress/VideoCapture.java [new file with mode: 0755]
tests/src/com/android/gallery3d/unittest/CameraUnitTest.java [new file with mode: 0644]

diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644 (file)
index 0000000..9f33322
--- /dev/null
@@ -0,0 +1,18 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SDK_VERSION := 16
+
+LOCAL_STATIC_JAVA_LIBRARIES := littlemock dexmaker
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := Camera2Tests
+
+LOCAL_INSTRUMENTATION_FOR := Camera2
+
+include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..f44156e
--- /dev/null
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.gallery3d.tests">
+
+    <application
+        android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+             android:targetPackage="com.android.gallery3d"
+             android:label="Tests for GalleryNew3D application."/>
+
+    <instrumentation android:name="com.android.gallery3d.CameraTestRunner"
+            android:targetPackage="com.android.gallery3d"
+            android:label="Camera continuous test runner"/>
+
+    <instrumentation android:name="com.android.gallery3d.exif.ExifTestRunner"
+            android:targetPackage="com.android.gallery3d"
+            android:label="Tests for ExifParser."/>
+
+    <instrumentation android:name="com.android.gallery3d.jpegstream.JpegStreamTestRunner"
+            android:targetPackage="com.android.gallery3d"
+            android:label="Tests for JpegStream classes."/>
+
+    <instrumentation android:name="com.android.gallery3d.stress.CameraStressTestRunner"
+            android:targetPackage="com.android.gallery3d"
+            android:label="Camera stress test runner"/>
+
+    <instrumentation android:name="com.android.photos.data.DataTestRunner"
+            android:targetPackage="com.android.gallery3d"
+            android:label="Tests for android photo DataProviders."/>
+</manifest>
diff --git a/tests/exiftool_parser/parser.py b/tests/exiftool_parser/parser.py
new file mode 100755 (executable)
index 0000000..7df23f1
--- /dev/null
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# This parser parses the output from Phil Harvey's exiftool (version 9.02)
+# and convert it to xml format. It reads exiftool's output from stdin and
+# write the xml format to stdout.
+#
+# In order to get the raw infomation from exiftool, we need to enable the verbose
+# flag (-v2) of exiftool.
+#
+# Usage:
+#      exiftool -v2 img.jpg | ./parser.py >> output.xml
+#
+#
+
+import os
+import sys
+import re
+
+text = sys.stdin.read()
+
+print """<?xml version="1.0" encoding="utf-8"?>"""
+print "<exif>"
+
+# find the following two groups of string:
+#
+# 1. tag:
+#
+# | | | x) name = value
+# | | |     - Tag 0x1234
+#
+# 2. IFD indicator:
+#
+# | | | + [xxx directory with xx entries]
+#
+p = re.compile(
+        "(((?:\| )+)[0-9]*\)(?:(?:.*? = .*?)|(?:.*? \(SubDirectory\) -->))\n.*?- Tag 0x[0-9a-f]{4})" + "|"
+        + "(((?:\| )*)\+ \[.*? directory with [0-9]+ entries]$)"
+        , re.M)
+tags = p.findall(text)
+
+layer = 0
+ifds = []
+
+for s in tags:
+    # IFD indicator
+    if s[2]:
+        l = len(s[3])
+        ifd = s[2][l + 3:].split()[0]
+        new_layer = l / 2 + 1
+        if new_layer > layer:
+            ifds.append(ifd)
+        else:
+            for i in range(layer - new_layer):
+                ifds.pop()
+            ifds[-1] = ifd
+        layer = new_layer
+    else:
+        l = len(s[1])
+        s = s[0]
+        new_layer = l / 2
+        if new_layer < layer:
+            for i in range(layer - new_layer):
+                ifds.pop()
+        layer = new_layer
+
+        # find the ID
+        _id = re.search("0x[0-9a-f]{4}", s)
+        _id = _id.group(0)
+
+        # find the name
+        name = re.search("[0-9]*?\).*?(?:(?: = )|(?: \(SubDirectory\) -->))", s)
+        name = name.group(0).split()[1]
+
+        # find the raw value in the parenthesis
+        value = re.search("\(SubDirectory\) -->", s)
+        if value:
+            value = "NO_VALUE"
+        else:
+            value = re.search("\(.*\)\n", s)
+            if (name != 'Model' and value):
+                value = value.group(0)[1:-2]
+            else:
+                value = re.search("=.*\n", s)
+                value = value.group(0)[2:-1]
+                if "[snip]" in value:
+                    value = "NO_VALUE"
+
+        print ('    <tag ifd="' + ifds[-1] + '" id="'
+            + _id + '" name="' + name +'">' + value + "</tag>")
+print "</exif>"
diff --git a/tests/res/raw/android_lawn.mp4 b/tests/res/raw/android_lawn.mp4
new file mode 100644 (file)
index 0000000..bdeffbe
Binary files /dev/null and b/tests/res/raw/android_lawn.mp4 differ
diff --git a/tests/res/raw/galaxy_nexus.jpg b/tests/res/raw/galaxy_nexus.jpg
new file mode 100755 (executable)
index 0000000..de91df6
Binary files /dev/null and b/tests/res/raw/galaxy_nexus.jpg differ
diff --git a/tests/res/raw/jpeg_control.jpg b/tests/res/raw/jpeg_control.jpg
new file mode 100644 (file)
index 0000000..bb468a7
Binary files /dev/null and b/tests/res/raw/jpeg_control.jpg differ
diff --git a/tests/res/xml/galaxy_nexus.xml b/tests/res/xml/galaxy_nexus.xml
new file mode 100644 (file)
index 0000000..55dd524
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<exif>
+    <tag ifd="IFD0" id="0x0100" name="ImageWidth">2560</tag>
+    <tag ifd="IFD0" id="0x0101" name="ImageHeight">1920</tag>
+    <tag ifd="IFD0" id="0x010f" name="Make">google</tag>
+    <tag ifd="IFD0" id="0x0110" name="Model">Nexus S</tag>
+    <tag ifd="IFD0" id="0x0112" name="Orientation">1</tag>
+    <tag ifd="IFD0" id="0x0131" name="Software">MASTER</tag>
+    <tag ifd="IFD0" id="0x0132" name="ModifyDate">2012:07:30 16:28:42</tag>
+    <tag ifd="IFD0" id="0x0213" name="YCbCrPositioning">1</tag>
+    <tag ifd="IFD0" id="0x8769" name="ExifOffset">NO_VALUE</tag>
+    <tag ifd="ExifIFD" id="0x829a" name="ExposureTime">1/40</tag>
+    <tag ifd="ExifIFD" id="0x829d" name="FNumber">26/10</tag>
+    <tag ifd="ExifIFD" id="0x8822" name="ExposureProgram">3</tag>
+    <tag ifd="ExifIFD" id="0x8827" name="ISO">100</tag>
+    <tag ifd="ExifIFD" id="0x9000" name="ExifVersion">0220</tag>
+    <tag ifd="ExifIFD" id="0x9003" name="DateTimeOriginal">2012:07:30 16:28:42</tag>
+    <tag ifd="ExifIFD" id="0x9004" name="CreateDate">2012:07:30 16:28:42</tag>
+    <tag ifd="ExifIFD" id="0x9201" name="ShutterSpeedValue">50/10</tag>
+    <tag ifd="ExifIFD" id="0x9202" name="ApertureValue">30/10</tag>
+    <tag ifd="ExifIFD" id="0x9203" name="BrightnessValue">30/10</tag>
+    <tag ifd="ExifIFD" id="0x9204" name="ExposureCompensation">0/0</tag>
+    <tag ifd="ExifIFD" id="0x9205" name="MaxApertureValue">30/10</tag>
+    <tag ifd="ExifIFD" id="0x9207" name="MeteringMode">2</tag>
+    <tag ifd="ExifIFD" id="0x9209" name="Flash">0</tag>
+    <tag ifd="ExifIFD" id="0x920a" name="FocalLength">343/100</tag>
+    <tag ifd="ExifIFD" id="0x9286" name="UserComment">IICSAUser comments</tag>
+    <tag ifd="ExifIFD" id="0xa001" name="ColorSpace">1</tag>
+    <tag ifd="ExifIFD" id="0xa002" name="ExifImageWidth">2560</tag>
+    <tag ifd="ExifIFD" id="0xa003" name="ExifImageHeight">1920</tag>
+    <tag ifd="ExifIFD" id="0xa402" name="ExposureMode">0</tag>
+    <tag ifd="ExifIFD" id="0xa403" name="WhiteBalance">0</tag>
+    <tag ifd="ExifIFD" id="0xa406" name="SceneCaptureType">0</tag>
+    <tag ifd="IFD1" id="0x0100" name="ImageWidth">320</tag>
+    <tag ifd="IFD1" id="0x0101" name="ImageHeight">240</tag>
+    <tag ifd="IFD1" id="0x0103" name="Compression">6</tag>
+    <tag ifd="IFD1" id="0x0112" name="Orientation">1</tag>
+    <tag ifd="IFD1" id="0x011a" name="XResolution">72/1</tag>
+    <tag ifd="IFD1" id="0x011b" name="YResolution">72/1</tag>
+    <tag ifd="IFD1" id="0x0128" name="ResolutionUnit">2</tag>
+    <tag ifd="IFD1" id="0x0201" name="ThumbnailOffset">690</tag>
+    <tag ifd="IFD1" id="0x0202" name="ThumbnailLength">10447</tag>
+</exif>
diff --git a/tests/src/com/android/gallery3d/CameraTestRunner.java b/tests/src/com/android/gallery3d/CameraTestRunner.java
new file mode 100755 (executable)
index 0000000..5032336
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.gallery3d;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+import com.android.gallery3d.functional.CameraTest;
+import com.android.gallery3d.functional.ImageCaptureIntentTest;
+import com.android.gallery3d.functional.VideoCaptureIntentTest;
+import com.android.gallery3d.unittest.CameraUnitTest;
+
+import junit.framework.TestSuite;
+
+
+public class CameraTestRunner extends InstrumentationTestRunner {
+
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        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/src/com/android/gallery3d/StressTests.java b/tests/src/com/android/gallery3d/StressTests.java
new file mode 100755 (executable)
index 0000000..b991e9e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.gallery3d;
+
+import com.android.gallery3d.stress.CameraLatency;
+import com.android.gallery3d.stress.CameraStartUp;
+import com.android.gallery3d.stress.ImageCapture;
+import com.android.gallery3d.stress.SwitchPreview;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+
+/**
+ * Instrumentation Test Runner for all Camera tests.
+ *
+ * Running all tests:
+ *
+ * adb shell am instrument \
+ *    -e class com.android.gallery3d.StressTests \
+ *    -w com.google.android.gallery3d.tests/com.android.gallery3d.stress.CameraStressTestRunner
+ */
+
+public class StressTests extends TestSuite {
+    public static Test suite() {
+        TestSuite result = new TestSuite();
+        result.addTestSuite(CameraLatency.class);
+        result.addTestSuite(CameraStartUp.class);
+        result.addTestSuite(ImageCapture.class);
+//      result.addTestSuite(SwitchPreview.class);
+        return result;
+    }
+}
diff --git a/tests/src/com/android/gallery3d/functional/CameraTest.java b/tests/src/com/android/gallery3d/functional/CameraTest.java
new file mode 100644 (file)
index 0000000..c293c0d
--- /dev/null
@@ -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.gallery3d.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/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java b/tests/src/com/android/gallery3d/functional/ImageCaptureIntentTest.java
new file mode 100644 (file)
index 0000000..9ea9128
--- /dev/null
@@ -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.gallery3d.functional;
+
+import com.android.camera.CameraActivity;
+import com.android.camera2.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/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java b/tests/src/com/android/gallery3d/functional/VideoCaptureIntentTest.java
new file mode 100644 (file)
index 0000000..3493989
--- /dev/null
@@ -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.gallery3d.functional;
+
+import com.android.camera.CameraActivity;
+import com.android.camera2.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/src/com/android/gallery3d/stress/CameraLatency.java b/tests/src/com/android/gallery3d/stress/CameraLatency.java
new file mode 100755 (executable)
index 0000000..2cdc2f1
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Instrumentation;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ */
+
+public class CameraLatency extends ActivityInstrumentationTestCase2 <CameraActivity> {
+    private String TAG = "CameraLatency";
+    private static final int TOTAL_NUMBER_OF_IMAGECAPTURE = 20;
+    private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 4000;
+    private static final String CAMERA_TEST_OUTPUT_FILE =
+            Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+
+    private long mTotalAutoFocusTime;
+    private long mTotalShutterLag;
+    private long mTotalShutterToPictureDisplayedTime;
+    private long mTotalPictureDisplayedToJpegCallbackTime;
+    private long mTotalJpegCallbackFinishTime;
+    private long mAvgAutoFocusTime;
+    private long mAvgShutterLag = mTotalShutterLag;
+    private long mAvgShutterToPictureDisplayedTime;
+    private long mAvgPictureDisplayedToJpegCallbackTime;
+    private long mAvgJpegCallbackFinishTime;
+
+    public CameraLatency() {
+        super(CameraActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        getActivity();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testImageCapture() {
+        Log.v(TAG, "start testImageCapture test");
+        Instrumentation inst = getInstrumentation();
+        inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_DOWN);
+        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_CENTER);
+                Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+                //skip the first measurement
+                if (i != 0) {
+                    CameraActivity c = getActivity();
+
+                    // if any of the latency var accessor methods return -1 then the
+                    // camera is set to a different module other than PhotoModule so
+                    // skip the shot and try again
+                    if (c.getAutoFocusTime() != -1) {
+                        mTotalAutoFocusTime += c.getAutoFocusTime();
+                        mTotalShutterLag += c.getShutterLag();
+                        mTotalShutterToPictureDisplayedTime +=
+                                c.getShutterToPictureDisplayedTime();
+                        mTotalPictureDisplayedToJpegCallbackTime +=
+                                c.getPictureDisplayedToJpegCallbackTime();
+                        mTotalJpegCallbackFinishTime += c.getJpegCallbackFinishTime();
+                    }
+                    else {
+                        i--;
+                        continue;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            Log.v(TAG, "Got exception", e);
+        }
+        //ToDO: yslau
+        //1) Need to get the baseline from the cupcake so that we can add the
+        //failure condition of the camera latency.
+        //2) Only count those number with succesful capture. Set the timer to invalid
+        //before capture and ignore them if the value is invalid
+        int numberofRun = TOTAL_NUMBER_OF_IMAGECAPTURE - 1;
+        mAvgAutoFocusTime = mTotalAutoFocusTime / numberofRun;
+        mAvgShutterLag = mTotalShutterLag / numberofRun;
+        mAvgShutterToPictureDisplayedTime =
+                mTotalShutterToPictureDisplayedTime / numberofRun;
+        mAvgPictureDisplayedToJpegCallbackTime =
+                mTotalPictureDisplayedToJpegCallbackTime / numberofRun;
+        mAvgJpegCallbackFinishTime =
+                mTotalJpegCallbackFinishTime / numberofRun;
+
+        try {
+            FileWriter fstream = null;
+            fstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+            BufferedWriter out = new BufferedWriter(fstream);
+            out.write("Camera Latency : \n");
+            out.write("Number of loop: " + TOTAL_NUMBER_OF_IMAGECAPTURE + "\n");
+            out.write("Avg AutoFocus = " + mAvgAutoFocusTime + "\n");
+            out.write("Avg mShutterLag = " + mAvgShutterLag + "\n");
+            out.write("Avg mShutterToPictureDisplayedTime = "
+                    + mAvgShutterToPictureDisplayedTime + "\n");
+            out.write("Avg mPictureDisplayedToJpegCallbackTime = "
+                    + mAvgPictureDisplayedToJpegCallbackTime + "\n");
+            out.write("Avg mJpegCallbackFinishTime = " +
+                    mAvgJpegCallbackFinishTime + "\n");
+            out.close();
+            fstream.close();
+        } catch (Exception e) {
+            fail("Camera Latency write output to file");
+        }
+        Log.v(TAG, "The Image capture wait time = " +
+            WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+        Log.v(TAG, "Avg AutoFocus = " + mAvgAutoFocusTime);
+        Log.v(TAG, "Avg mShutterLag = " + mAvgShutterLag);
+        Log.v(TAG, "Avg mShutterToPictureDisplayedTime = "
+                + mAvgShutterToPictureDisplayedTime);
+        Log.v(TAG, "Avg mPictureDisplayedToJpegCallbackTime = "
+                + mAvgPictureDisplayedToJpegCallbackTime);
+        Log.v(TAG, "Avg mJpegCallbackFinishTime = " + mAvgJpegCallbackFinishTime);
+    }
+}
+
diff --git a/tests/src/com/android/gallery3d/stress/CameraStartUp.java b/tests/src/com/android/gallery3d/stress/CameraStartUp.java
new file mode 100644 (file)
index 0000000..3ca1632
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Environment;
+import android.provider.MediaStore;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
+/**
+ * Test cases to measure the camera and video recorder startup time.
+ */
+public class CameraStartUp extends InstrumentationTestCase {
+
+    private static final int TOTAL_NUMBER_OF_STARTUP = 20;
+
+    private String TAG = "CameraStartUp";
+    private static final String CAMERA_TEST_OUTPUT_FILE =
+            Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+    private static int WAIT_TIME_FOR_PREVIEW = 1500; //1.5 second
+
+    private long launchCamera() {
+        long startupTime = 0;
+        try {
+            Intent intent = new Intent(Intent.ACTION_MAIN);
+            intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            long beforeStart = System.currentTimeMillis();
+            Instrumentation inst = getInstrumentation();
+            Activity cameraActivity = inst.startActivitySync(intent);
+            long cameraStarted = System.currentTimeMillis();
+            Thread.sleep(WAIT_TIME_FOR_PREVIEW);
+            cameraActivity.finish();
+            startupTime = cameraStarted - beforeStart;
+            Thread.sleep(1000);
+            Log.v(TAG, "camera startup time: " + startupTime);
+        } catch (Exception e) {
+            Log.v(TAG, "Got exception", e);
+            fail("Fails to get the output file");
+        }
+        return startupTime;
+    }
+
+    private long launchVideo() {
+        long startupTime = 0;
+
+        try {
+            Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+            intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            long beforeStart = System.currentTimeMillis();
+            Instrumentation inst = getInstrumentation();
+            Activity recorderActivity = inst.startActivitySync(intent);
+            long cameraStarted = System.currentTimeMillis();
+            recorderActivity.finish();
+            startupTime = cameraStarted - beforeStart;
+            Log.v(TAG, "Video Startup Time = " + startupTime);
+            // wait for 1s to make sure it reach a clean stage
+            Thread.sleep(WAIT_TIME_FOR_PREVIEW);
+            Log.v(TAG, "video startup time: " + startupTime);
+        } catch (Exception e) {
+            Log.v(TAG, "Got exception", e);
+            fail("Fails to launch video output file");
+        }
+        return startupTime;
+    }
+
+    private void writeToOutputFile(long totalStartupTime,
+            String individualStartupTime, boolean firstStartUp, String Type) throws Exception {
+        // TODO (yslau) : Need to integrate the output data with central
+        // dashboard
+        try {
+            FileWriter fstream = null;
+            fstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+            BufferedWriter out = new BufferedWriter(fstream);
+            if (firstStartUp) {
+                out.write("First " + Type + " Startup: " + totalStartupTime + "\n");
+            } else {
+                long averageStartupTime = totalStartupTime / (TOTAL_NUMBER_OF_STARTUP -1);
+                out.write(Type + "startup time: " + "\n");
+                out.write("Number of loop: " + (TOTAL_NUMBER_OF_STARTUP -1)  + "\n");
+                out.write(individualStartupTime + "\n\n");
+                out.write(Type + " average startup time: " + averageStartupTime + " ms\n\n");
+            }
+            out.close();
+            fstream.close();
+        } catch (Exception e) {
+            fail("Camera write output to file");
+        }
+    }
+
+    public void testLaunchVideo() throws Exception {
+        String individualStartupTime;
+        individualStartupTime = "Individual Video Startup Time = ";
+        long totalStartupTime = 0;
+        long startupTime = 0;
+        for (int i = 0; i < TOTAL_NUMBER_OF_STARTUP; i++) {
+            if (i == 0) {
+                // Capture the first startup time individually
+                long firstStartUpTime = launchVideo();
+                writeToOutputFile(firstStartUpTime, "na", true, "Video");
+            } else {
+                startupTime = launchVideo();
+                totalStartupTime += startupTime;
+                individualStartupTime += startupTime + " ,";
+            }
+        }
+        Log.v(TAG, "totalStartupTime =" + totalStartupTime);
+        writeToOutputFile(totalStartupTime, individualStartupTime, false, "Video");
+    }
+
+    public void testLaunchCamera() throws Exception {
+        String individualStartupTime;
+        individualStartupTime = "Individual Camera Startup Time = ";
+        long totalStartupTime = 0;
+        long startupTime = 0;
+        for (int i = 0; i < TOTAL_NUMBER_OF_STARTUP; i++) {
+            if (i == 0) {
+                // Capture the first startup time individually
+                long firstStartUpTime = launchCamera();
+                writeToOutputFile(firstStartUpTime, "na", true, "Camera");
+            } else {
+                startupTime = launchCamera();
+                totalStartupTime += startupTime;
+                individualStartupTime += startupTime + " ,";
+            }
+        }
+        Log.v(TAG, "totalStartupTime =" + totalStartupTime);
+        writeToOutputFile(totalStartupTime,
+                individualStartupTime, false, "Camera");
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java b/tests/src/com/android/gallery3d/stress/CameraStressTestRunner.java
new file mode 100755 (executable)
index 0000000..d3fb10d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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.gallery3d.stress;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import junit.framework.TestSuite;
+
+public class CameraStressTestRunner extends InstrumentationTestRunner {
+
+    // Default recorder settings
+    public static int mVideoDuration = 20000; // set default to 20 seconds
+    public static int mVideoIterations = 1; // set default to 1 video
+    public static int mImageIterations = 10; // set default to 10 images
+
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(ImageCapture.class);
+        suite.addTestSuite(VideoCapture.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return CameraStressTestRunner.class.getClassLoader();
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        String video_iterations = (String) icicle.get("video_iterations");
+        String image_iterations = (String) icicle.get("image_iterations");
+        String video_duration = (String) icicle.get("video_duration");
+
+        if ( video_iterations != null ) {
+            mVideoIterations = Integer.parseInt(video_iterations);
+        }
+        if ( image_iterations != null) {
+            mImageIterations = Integer.parseInt(image_iterations);
+        }
+        if ( video_duration != null) {
+            mVideoDuration = Integer.parseInt(video_duration);
+        }
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/ImageCapture.java b/tests/src/com/android/gallery3d/stress/ImageCapture.java
new file mode 100755 (executable)
index 0000000..5a9ee6a
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.stress.CameraStressTestRunner;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.app.Activity;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ *    -e class com.android.camera.stress.ImageCapture \
+ *    -w com.google.android.camera.tests/android.test.InstrumentationTestRunner
+ *
+ */
+
+public class ImageCapture extends ActivityInstrumentationTestCase2 <CameraActivity> {
+    private String TAG = "ImageCapture";
+    private static final long WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN = 1500;   //1.5 sedconds
+    private static final long WAIT_FOR_SWITCH_CAMERA = 3000; //3 seconds
+
+    private TestUtil testUtil = new TestUtil();
+
+    // Private intent extras.
+    private final static String EXTRAS_CAMERA_FACING =
+        "android.intent.extras.CAMERA_FACING";
+
+    public ImageCapture() {
+        super(CameraActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        testUtil.prepareOutputFile();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        testUtil.closeOutputFile();
+        super.tearDown();
+    }
+
+    public void captureImages(String reportTag, Instrumentation inst) {
+        int total_num_of_images = CameraStressTestRunner.mImageIterations;
+        Log.v(TAG, "no of images = " + total_num_of_images);
+
+        //TODO(yslau): Need to integrate the outoput with the central dashboard,
+        //write to a txt file as a temp solution
+        boolean memoryResult = false;
+        KeyEvent focusEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_FOCUS);
+
+        try {
+            testUtil.writeReportHeader(reportTag, total_num_of_images);
+            for (int i = 0; i < total_num_of_images; i++) {
+                Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+                inst.sendKeySync(focusEvent);
+                inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+                Thread.sleep(WAIT_FOR_IMAGE_CAPTURE_TO_BE_TAKEN);
+                testUtil.writeResult(i);
+            }
+        } catch (Exception e) {
+            Log.v(TAG, "Got exception: " + e.toString());
+            assertTrue("testImageCapture", false);
+        }
+    }
+
+    public void testBackImageCapture() throws Exception {
+        Instrumentation inst = getInstrumentation();
+        Intent intent = new Intent();
+
+        intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRAS_CAMERA_FACING,
+                android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
+        Activity act = inst.startActivitySync(intent);
+        Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+        captureImages("Back Camera Image Capture\n", inst);
+        act.finish();
+    }
+
+    public void testFrontImageCapture() throws Exception {
+        Instrumentation inst = getInstrumentation();
+        Intent intent = new Intent();
+
+        intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRAS_CAMERA_FACING,
+                android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
+        Activity act = inst.startActivitySync(intent);
+        Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+        captureImages("Front Camera Image Capture\n", inst);
+        act.finish();
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/ShotToShotLatency.java b/tests/src/com/android/gallery3d/stress/ShotToShotLatency.java
new file mode 100644 (file)
index 0000000..0d5749e
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.gallery3d.stress;
+
+import android.app.Instrumentation;
+import android.os.Environment;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+import com.android.camera.CameraActivity;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * Junit / Instrumentation test case for measuring camera shot to shot latency
+ */
+public class ShotToShotLatency extends ActivityInstrumentationTestCase2<CameraActivity> {
+    private String TAG = "ShotToShotLatency";
+    private static final int TOTAL_NUMBER_OF_SNAPSHOTS = 250;
+    private static final long SNAPSHOT_WAIT = 1000;
+    private static final String CAMERA_TEST_OUTPUT_FILE =
+            Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+    private static final String CAMERA_IMAGE_DIRECTORY =
+            Environment.getExternalStorageDirectory().toString() + "/DCIM/Camera/";
+
+    public ShotToShotLatency() {
+        super(CameraActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        getActivity();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    private void cleanupLatencyImages() {
+        try {
+            File sdcard = new File(CAMERA_IMAGE_DIRECTORY);
+            File[] pics = null;
+            FilenameFilter filter = new FilenameFilter() {
+                public boolean accept(File dir, String name) {
+                    return name.endsWith(".jpg");
+                }
+            };
+            pics = sdcard.listFiles(filter);
+            for (File f : pics) {
+                f.delete();
+            }
+        } catch (SecurityException e) {
+            Log.e(TAG, "Security manager access violation: " + e.toString());
+        }
+    }
+
+    private void sleep(long time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Sleep InterruptedException " + e.toString());
+        }
+    }
+
+    public void testShotToShotLatency() {
+        long sigmaOfDiffFromMeanSquared = 0;
+        double mean = 0;
+        double standardDeviation = 0;
+        ArrayList<Long> captureTimes = new ArrayList<Long>();
+        ArrayList<Long> latencyTimes = new ArrayList<Long>();
+
+        Log.v(TAG, "start testShotToShotLatency test");
+        Instrumentation inst = getInstrumentation();
+
+        // Generate data points
+        for (int i = 0; i < TOTAL_NUMBER_OF_SNAPSHOTS; i++) {
+            inst.sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
+            sleep(SNAPSHOT_WAIT);
+            CameraActivity c = getActivity();
+            if (c.getCaptureStartTime() > 0) {
+                captureTimes.add(c.getCaptureStartTime());
+            }
+        }
+
+        // Calculate latencies
+        for (int j = 1; j < captureTimes.size(); j++) {
+            latencyTimes.add(captureTimes.get(j) - captureTimes.get(j - 1));
+        }
+
+        // Crunch numbers
+        for (long dataPoint : latencyTimes) {
+            mean += (double) dataPoint;
+        }
+        mean /= latencyTimes.size();
+
+        for (long dataPoint : latencyTimes) {
+            sigmaOfDiffFromMeanSquared += (dataPoint - mean) * (dataPoint - mean);
+        }
+        standardDeviation = Math.sqrt(sigmaOfDiffFromMeanSquared / latencyTimes.size());
+
+        // Report statistics
+        File outFile = new File(CAMERA_TEST_OUTPUT_FILE);
+        BufferedWriter output = null;
+        try {
+            output = new BufferedWriter(new FileWriter(outFile, true));
+            output.write("Shot to shot latency - mean: " + mean + "\n");
+            output.write("Shot to shot latency - standard deviation: " + standardDeviation + "\n");
+            cleanupLatencyImages();
+        } catch (IOException e) {
+            Log.e(TAG, "testShotToShotLatency IOException writing to log " + e.toString());
+        } finally {
+            try {
+                if (output != null) {
+                    output.close();
+                }
+            } catch (IOException e) {
+                Log.e(TAG, "Error closing file: " + e.toString());
+            }
+        }
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/SwitchPreview.java b/tests/src/com/android/gallery3d/stress/SwitchPreview.java
new file mode 100755 (executable)
index 0000000..3545f3b
--- /dev/null
@@ -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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ *    -e class com.android.camera.stress.SwitchPreview \
+ *    -w com.android.camera.tests/com.android.camera.stress.CameraStressTestRunner
+ *
+ */
+public class SwitchPreview extends ActivityInstrumentationTestCase2 <CameraActivity>{
+    private String TAG = "SwitchPreview";
+    private static final int TOTAL_NUMBER_OF_SWITCHING = 200;
+    private static final long WAIT_FOR_PREVIEW = 4000;
+
+    private static final String CAMERA_TEST_OUTPUT_FILE =
+            Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+    private BufferedWriter mOut;
+    private FileWriter mfstream;
+
+    public SwitchPreview() {
+        super(CameraActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        getActivity();
+        prepareOutputFile();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getActivity().finish();
+        closeOutputFile();
+        super.tearDown();
+    }
+
+    private void prepareOutputFile(){
+        try{
+            mfstream = new FileWriter(CAMERA_TEST_OUTPUT_FILE, true);
+            mOut = new BufferedWriter(mfstream);
+        } catch (Exception e){
+            assertTrue("Camera Switch Mode", false);
+        }
+    }
+
+    private void closeOutputFile() {
+        try {
+            mOut.write("\n");
+            mOut.close();
+            mfstream.close();
+        } catch (Exception e) {
+            assertTrue("CameraSwitchMode close output", false);
+        }
+    }
+
+    public void testSwitchMode() {
+        //Switching the video and the video recorder mode
+        Instrumentation inst = getInstrumentation();
+        try{
+            mOut.write("Camera Switch Mode:\n");
+            mOut.write("No of loops :" + TOTAL_NUMBER_OF_SWITCHING + "\n");
+            mOut.write("loop: ");
+            for (int i=0; i< TOTAL_NUMBER_OF_SWITCHING; i++) {
+                Thread.sleep(WAIT_FOR_PREVIEW);
+                Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                intent.setClass(getInstrumentation().getTargetContext(),
+                        CameraActivity.class);
+                getActivity().startActivity(intent);
+                Thread.sleep(WAIT_FOR_PREVIEW);
+                intent = new Intent();
+                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                intent.setClass(getInstrumentation().getTargetContext(),
+                        CameraActivity.class);
+                getActivity().startActivity(intent);
+                mOut.write(" ," + i);
+                mOut.flush();
+            }
+        } catch (Exception e){
+            Log.v(TAG, "Got exception", e);
+        }
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/TestUtil.java b/tests/src/com/android/gallery3d/stress/TestUtil.java
new file mode 100644 (file)
index 0000000..56ab715
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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.gallery3d.stress;
+
+import android.os.Environment;
+import java.io.FileWriter;
+import java.io.BufferedWriter;
+
+
+/**
+ * Collection of utility functions used for the test.
+ */
+public class TestUtil {
+    public BufferedWriter mOut;
+    public FileWriter mfstream;
+
+    public TestUtil() {
+    }
+
+    public void prepareOutputFile() throws Exception {
+        String camera_test_output_file =
+                Environment.getExternalStorageDirectory().toString() + "/mediaStressOut.txt";
+        mfstream = new FileWriter(camera_test_output_file, true);
+        mOut = new BufferedWriter(mfstream);
+    }
+
+    public void closeOutputFile() throws Exception {
+        mOut.write("\n");
+        mOut.close();
+        mfstream.close();
+    }
+
+    public void writeReportHeader(String reportTag, int iteration) throws Exception {
+        mOut.write(reportTag);
+        mOut.write("No of loops :" + iteration + "\n");
+        mOut.write("loop: ");
+    }
+
+    public void writeResult(int iteration) throws Exception {
+        mOut.write(" ," + iteration);
+        mOut.flush();
+    }
+}
diff --git a/tests/src/com/android/gallery3d/stress/VideoCapture.java b/tests/src/com/android/gallery3d/stress/VideoCapture.java
new file mode 100755 (executable)
index 0000000..8211bad
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.gallery3d.stress;
+
+import com.android.camera.CameraActivity;
+import com.android.gallery3d.stress.TestUtil;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+
+import com.android.gallery3d.stress.CameraStressTestRunner;
+
+/**
+ * Junit / Instrumentation test case for camera test
+ *
+ * Running the test suite:
+ *
+ * adb shell am instrument \
+ *    -e class com.android.camera.stress.VideoCapture \
+ *    -w com.google.android.camera.tests/android.test.InstrumentationTestRunner
+ *
+ */
+
+public class VideoCapture extends ActivityInstrumentationTestCase2 <CameraActivity> {
+    private static final long WAIT_FOR_PREVIEW = 1500; //1.5 seconds
+    private static final long WAIT_FOR_SWITCH_CAMERA = 3000; //2 seconds
+
+    // Private intent extras which control the camera facing.
+    private final static String EXTRAS_CAMERA_FACING =
+        "android.intent.extras.CAMERA_FACING";
+
+    private TestUtil testUtil = new TestUtil();
+
+    public VideoCapture() {
+        super(CameraActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        testUtil.prepareOutputFile();
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        testUtil.closeOutputFile();
+        super.tearDown();
+    }
+
+    public void captureVideos(String reportTag, Instrumentation inst) throws Exception{
+        boolean memoryResult = false;
+        int total_num_of_videos = CameraStressTestRunner.mVideoIterations;
+        int video_duration = CameraStressTestRunner.mVideoDuration;
+        testUtil.writeReportHeader(reportTag, total_num_of_videos);
+
+        for (int i = 0; i < total_num_of_videos; i++) {
+            Thread.sleep(WAIT_FOR_PREVIEW);
+            // record a video
+            inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+            Thread.sleep(video_duration);
+            inst.sendCharacterSync(KeyEvent.KEYCODE_CAMERA);
+            testUtil.writeResult(i);
+        }
+    }
+
+    public void testBackVideoCapture() throws Exception {
+        Instrumentation inst = getInstrumentation();
+        Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+
+        intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRAS_CAMERA_FACING,
+                android.hardware.Camera.CameraInfo.CAMERA_FACING_BACK);
+        Activity act = inst.startActivitySync(intent);
+        Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+        captureVideos("Back Camera Video Capture\n", inst);
+        act.finish();
+    }
+
+    public void testFrontVideoCapture() throws Exception {
+        Instrumentation inst = getInstrumentation();
+        Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
+
+        intent.setClass(getInstrumentation().getTargetContext(), CameraActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(EXTRAS_CAMERA_FACING,
+                android.hardware.Camera.CameraInfo.CAMERA_FACING_FRONT);
+        Activity act = inst.startActivitySync(intent);
+        Thread.sleep(WAIT_FOR_SWITCH_CAMERA);
+        captureVideos("Front Camera Video Capture\n", inst);
+        act.finish();
+    }
+}
diff --git a/tests/src/com/android/gallery3d/unittest/CameraUnitTest.java b/tests/src/com/android/gallery3d/unittest/CameraUnitTest.java
new file mode 100644 (file)
index 0000000..b8fb05f
--- /dev/null
@@ -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.gallery3d.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]));
+        }
+    }
+}