am c43a64fc: am 25fe5fc0: am eae51678: temp fix for bug 5572325, increase polling interval to 400ms

* commit 'c43a64fca4ec436d8f5d9cb4ad952f7c105ec70b':
  temp fix for bug 5572325, increase polling interval to 400ms
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index e5c52fb..bcf3dd9 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -5,9 +5,9 @@
      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.
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
       android:versionCode="1"
-      android:versionName="4.0_r1">
+      android:versionName="1337">
 
     <!-- Using 10 for more complete NFC support... -->
     <uses-sdk android:minSdkVersion="10"></uses-sdk>
@@ -28,17 +28,25 @@
     <uses-permission android:name="android.permission.CAMERA" />
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.NFC" />
+    <uses-feature android:name="android.hardware.camera.front"
+                  android:required="false" />
+    <uses-feature android:name="android.hardware.camera.autofocus"
+                  android:required="false" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
-    
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-feature android:name="android.hardware.usb.accessory" />
+    <uses-sdk android:minSdkVersion="10" />
+
     <!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
-    <application android:label="@string/app_name" 
+    <application android:label="@string/app_name"
             android:icon="@drawable/icon"
-            android:backupAgent="VerifierBackupAgent" 
+            android:backupAgent="VerifierBackupAgent"
             android:debuggable="true">
-            
+
+        <uses-library android:name="com.android.future.usb.accessory" />
         <meta-data android:name="com.google.android.backup.api_key"
                 android:value="AEdPqrEAAAAIbK6ldcOzoeRtQ1u1dFVJ1A7KetRhit-a1Xa82Q" />
 
@@ -64,13 +72,9 @@
                     android:resource="@xml/accessory_filter" />
         </activity>
 
-        <activity android:name=".ReportViewerActivity"
-                android:configChanges="keyboardHidden|orientation"
-                android:label="@string/report_viewer" />
-
-        <provider android:name=".TestResultsProvider" 
+        <provider android:name=".TestResultsProvider"
                 android:authorities="com.android.cts.verifier.testresultsprovider" />
-                
+
         <activity android:name=".admin.PolicySerializationTestActivity"
                 android:label="@string/da_policy_serialization_test"
                 android:configChanges="keyboardHidden|orientation">
@@ -117,7 +121,7 @@
             <meta-data android:name="test_category" android:value="@string/test_category_networking" />
             <meta-data android:name="test_required_features" android:value="android.hardware.bluetooth" />
         </activity>
-        
+
         <activity android:name=".bluetooth.BluetoothToggleActivity"
                 android:label="@string/bt_toggle_bluetooth"
                 android:configChanges="keyboardHidden|orientation">
@@ -139,7 +143,7 @@
             <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
         </activity>
-        
+
         <activity android:name=".bluetooth.InsecureServerActivity"
                 android:label="@string/bt_insecure_server"
                 android:configChanges="keyboardHidden|orientation">
@@ -161,7 +165,7 @@
             <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
         </activity>
-        
+
         <activity android:name=".bluetooth.InsecureClientActivity"
                 android:label="@string/bt_insecure_client"
                 android:configChanges="keyboardHidden|orientation">
@@ -173,11 +177,33 @@
             <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
         </activity>
 
+        <activity android:name=".bluetooth.ConnectionAccessServerActivity"
+                android:label="@string/bt_connection_access_server"
+                android:configChanges="keyboardHidden|orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
+        <activity android:name=".bluetooth.ConnectionAccessClientActivity"
+                android:label="@string/bt_connection_access_client"
+                android:configChanges="keyboardHidden|orientation">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/bt_device_communication" />
+            <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
+        </activity>
+
         <activity android:name=".bluetooth.DevicePickerActivity"
                 android:label="@string/bt_device_picker"
                 android:configChanges="keyboardHidden|orientation" />
 
-        <activity android:name=".suid.SuidFilesActivity" 
+        <activity android:name=".suid.SuidFilesActivity"
                 android:label="@string/suid_files"
                 android:configChanges="keyboardHidden|orientation">
             <intent-filter>
@@ -272,7 +298,19 @@
         <service android:name=".audioquality.ExperimentService" />
 
         <activity android:name=".camera.analyzer.CameraAnalyzerActivity"
-                android:label="@string/camera_analyzer">
+                 android:label="@string/camera_analyzer"
+                 android:screenOrientation="landscape">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_camera" />
+
+            <intent-filter>
+                <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+            </intent-filter>
+            <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+                android:resource="@xml/accessory_filter_adk" />
         </activity>
 
         <activity android:name=".usb.UsbAccessoryTestActivity"
@@ -288,4 +326,4 @@
 
    </application>
 
-</manifest> 
+</manifest>
diff --git a/apps/CtsVerifier/include/colorchecker/autolocktest.h b/apps/CtsVerifier/include/colorchecker/autolocktest.h
new file mode 100644
index 0000000..0d30bd7
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/autolocktest.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef AUTOLOCKTEST_H
+#define AUTOLOCKTEST_H
+
+#include <vector>
+
+#include "imagetesthandler.h"
+
+class AutoLockTest : public ImageTestHandler {
+  public:
+    AutoLockTest() : ImageTestHandler() {}
+    AutoLockTest(int debugHeight, int debugWidth) :
+        ImageTestHandler(debugHeight, debugWidth) {}
+    ~AutoLockTest() {}
+
+    void addDataToList(const std::vector<Vec3f>* checkerColors) {
+      mCheckerColors.push_back(*checkerColors);
+      delete checkerColors;
+    }
+
+    void processData();
+
+    void clearData();
+
+    const std::vector<bool>* getComparisonResults() const {
+      return (&mComparisonResults);
+    }
+
+  private:
+    bool IsBrighterThan(const std::vector<Vec3f>* colorCheckers1,
+                        const std::vector<Vec3f>* colorCheckers2) const;
+    bool IsEquivalentTo(const std::vector<Vec3f>* colorCheckers1,
+                        const std::vector<Vec3f>* colorCheckers2) const;
+
+    std::vector<std::vector<Vec3f> > mCheckerColors;
+    std::vector<bool> mComparisonResults;
+    int mNumPatches;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/colorchecker.h b/apps/CtsVerifier/include/colorchecker/colorchecker.h
deleted file mode 100644
index 5409b04..0000000
--- a/apps/CtsVerifier/include/colorchecker/colorchecker.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef COLORCHECKER_H
-#define COLORCHECKER_H
-
-/** Detects the 6x4 Xrite ColorChecker Classic pattern in the input image,
- *   and calculates the average color value per patch.
- *
- *  All squares in the colorchecker pattern have to be fully visible,
- *  and the whole pattern should fill at least 1/3 of the image
- *  width. The pattern cannot be facing away from the camera at a very
- *  large angle (>45 degrees). If multiple 6x4 grids can be found, the
- *  one that is most front-facing will be returned.
- *
- *  The average color is returned as a floating-point value per
- *  channel, linearized by an inverse gamma transform and normalized
- *  to 0-1 (255 = 1). The linearization is only approximate.
- *
- *  @param inputImage Source image to detect the pattern in. Assumed
- *                    to be a 3-channel interleaved image. Row-major
- *  @param width Width of input image
- *  @param height Height of input image
- *  @param patchColors Output 6x4 3-channel image of average patch
- *                     values.  Allocated by caller. Pass in NULL if
- *                     the average values aren't needed.
- *  @param outputImage Resized inputImage with overlaid grid detection
- *                     diagnostics. Image width is approximately 160
- *                     pixels. Pass in NULL if the diagnostic image
- *                     isn't needed.
- *  @param outputWidth Actual width of outputImage.
- *  @param outputHeight Actual height of outputImage.
- *
- *  @return true if a grid was found, false otherwise. If false, the
- *          input variables are unchanged.
- */
-bool findColorChecker(const unsigned char *image,
-                      int width,
-                      int rowSpan,
-                      int height,
-                      float *patchColors,
-                      unsigned char **outputImage,
-                      int *outputWidth,
-                      int *outputHeight);
-
-
-#endif
diff --git a/apps/CtsVerifier/include/colorchecker/colorcheckertest.h b/apps/CtsVerifier/include/colorchecker/colorcheckertest.h
new file mode 100644
index 0000000..f733b32
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/colorcheckertest.h
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#ifndef COLORCHECKERTEST_H
+#define COLORCHECKERTEST_H
+
+#include <vector>
+#include <string>
+
+#include "testingimage.h"
+#include "imagetesthandler.h"
+
+class ColorCheckerTest : public ImageTestHandler {
+public:
+    ColorCheckerTest() : ImageTestHandler() {
+        mImage = NULL;
+        mSuccess = false;
+    }
+    ColorCheckerTest(int debugHeight, int inputWidth) :
+            ImageTestHandler(debugHeight, inputWidth) {
+        mImage = NULL;
+        mSuccess = false;
+    }
+    ~ColorCheckerTest();
+
+    void addTestingImage(TestingImage* inputImage);
+    void processData();
+
+    const std::vector<std::vector<Vec2f> >* getCheckerCenterAdd() const {
+        std::vector<std::vector<Vec2f> >* returnPositions =
+                new std::vector<std::vector<Vec2f> >(
+                        4, std::vector<Vec2f>(6, Vec2f(0.f, 0.f)));
+
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 6; ++j) {
+                (*returnPositions)[i][j] = (*mMatchPositions[i][j]);
+            }
+        }
+        return (returnPositions);
+    }
+
+    const std::vector<std::vector<float> >* getCheckerRadiusAdd() const {
+        std::vector<std::vector<float> >* returnRadius=
+              new std::vector<std::vector<float> >(
+                      4, std::vector<float>(6, 0.f));
+
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 6; ++j) {
+                (*returnRadius)[i][j] = mMatchRadius[i][j];
+            }
+        }
+        return (returnRadius);
+    }
+
+    bool getSuccess() const {
+        return mSuccess;
+    }
+
+private:
+    void initializeRefColor();
+
+    void edgeDetection();
+    void computeGradient(unsigned char* layer, float* gradientMap);
+    void houghLineDetection(bool* edgeMap, float* gradientAbsolute,
+                            float* gradientDirection);
+
+    void findCheckerBoards(std::vector<std::vector<int> > linesDir1,
+                           std::vector<std::vector<int> > linesDir2);
+    Vec2f findCrossing(std::vector<int> line1, std::vector<int> line2);
+    void findBestMatch(int i1, int i2, int j1, int j2);
+
+    bool verifyPointPair(Vec2f pointUpperLeft, Vec2f pointBottomRight,
+                         Vec2f* pointCenter, Vec3i* color);
+    void verifyColorGrid();
+
+    void fillRefColorGrid();
+
+    TestingImage* mImage;
+
+    std::vector<std::vector< Vec3i* > > mCandidateColors;
+    std::vector<std::vector< Vec2f* > > mCandidatePositions;
+
+    std::vector<std::vector< Vec3i* > > mReferenceColors;
+    std::vector<std::vector< Vec2f* > > mMatchPositions;
+    std::vector<std::vector< Vec3f* > > mMatchColors;
+    std::vector<std::vector< float > > mMatchRadius;
+
+    bool mSuccess;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h b/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h
new file mode 100644
index 0000000..866b25e
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/exposurecompensationtest.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef EXPOSURECOMPENSATIONTEST_H
+#define EXPOSURECOMPENSATIONTEST_H
+
+#include <vector>
+
+#include "imagetesthandler.h"
+
+class ExposureCompensationTest : public ImageTestHandler {
+  public:
+    ExposureCompensationTest() : ImageTestHandler() {
+      initializeReferenceColors();
+    }
+    ExposureCompensationTest(int debugHeight, int debugWidth) :
+        ImageTestHandler(debugHeight, debugWidth) {
+      initializeReferenceColors();
+    }
+    ~ExposureCompensationTest() {}
+
+    void addDataToList(const float exposureValue,
+                  const std::vector<Vec3f>* checkerColors) {
+      mExposureValues.push_back(exposureValue);
+      mCheckerColors.push_back(*checkerColors);
+      delete checkerColors;
+    }
+
+    void processData();
+
+  private:
+    void initializeReferenceColors();
+
+    std::vector<std::vector<Vec3f> > mCheckerColors;
+    std::vector<Vec3i> mReferenceColors;
+    std::vector<float> mExposureValues;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/imagetesthandler.h b/apps/CtsVerifier/include/colorchecker/imagetesthandler.h
new file mode 100644
index 0000000..d66a1d2
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/imagetesthandler.h
@@ -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.
+ */
+
+#ifndef IMAGETESTHANDLER_H
+#define IMAGETESTHANDLER_H
+
+#include "vec2.h"
+#include "vec3.h"
+
+class ImageTestHandler{
+  public:
+    ImageTestHandler() {
+        initDebugImage();
+    }
+    ImageTestHandler(int debugHeight, int debugWidth) {
+        initDebugImage(debugHeight, debugWidth);
+    }
+    virtual ~ImageTestHandler() { delete[] mDebugOutput; }
+
+    virtual void processData() {}
+
+    int getDebugWidth() const { return mDebugWidth; }
+    int getDebugHeight() const { return mDebugHeight; }
+    const unsigned char* debug_output() const { return mDebugOutput; }
+    void copyDebugImage(int inputHeight, int inputWidth,
+                        const unsigned char* inputImage);
+
+    void drawPoint(const Vec2i &point, const Vec3i &color);
+    void drawPoint(int row, int column, const Vec3i &color);
+    void drawLine(int angle, int radius, const Vec3i &color);
+
+  protected:
+    void clearDebugImage();
+
+  private:
+    void initDebugImage();
+    void initDebugImage(int debugHeight, int debugWidth);
+
+    unsigned char* mDebugOutput;
+    int mDebugWidth;
+    int mDebugHeight;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/meteringtest.h b/apps/CtsVerifier/include/colorchecker/meteringtest.h
new file mode 100644
index 0000000..3115d93
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/meteringtest.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef METERINGTEST_H
+#define METERINGTEST_H
+
+#include <vector>
+
+#include "imagetesthandler.h"
+
+// Constructs a test handler for the metering test. The instance holds the pixel
+// values of the gray checkers on the color checker under different metering
+// settins. It can also compare two arrays of pixel values to tell whether one
+// is brighter or equivalent or darker than the other one.
+class MeteringTest : public ImageTestHandler {
+  public:
+    MeteringTest() : ImageTestHandler() {}
+    MeteringTest(const int debugHeight, const int debugWidth) :
+            ImageTestHandler(debugHeight, debugWidth) {}
+    ~MeteringTest() {}
+
+    void addDataToList(const std::vector<Vec3f>* checkerColors) {
+        mCheckerColors.push_back(*checkerColors);
+        delete checkerColors;
+    }
+
+    void processData();
+
+    void clearData();
+
+    const std::vector<bool>* getComparisonResults() const {
+        return (&mComparisonResults);
+    }
+
+  private:
+    bool isDarkerThan(const std::vector<Vec3f>* checkerColors1,
+                      const std::vector<Vec3f>* checkerColors2) const;
+    bool isEquivalentTo(const std::vector<Vec3f>* checkerColors1,
+                        const std::vector<Vec3f>* checkerColors2) const;
+
+    std::vector<std::vector<Vec3f> > mCheckerColors;
+    std::vector<bool> mComparisonResults;
+    int mNumPatches;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/testingimage.h b/apps/CtsVerifier/include/colorchecker/testingimage.h
new file mode 100644
index 0000000..f9649d5
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/testingimage.h
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#ifndef TESTINGIMAGE_H
+#define TESTINGIMAGE_H
+
+#include <vector>
+#include "vec3.h"
+#include "vec2.h"
+
+// Implements a class for image representation.
+class TestingImage {
+  public:
+    // Constructs a new instance with the inputImage's row and column counts.
+    // No change in size.
+    TestingImage(const unsigned char* inputImage,
+                 int inputWidth, int inputHeight,
+                 int inputChannels, int inputRowSpan);
+    // Constructs a new instance with an inputImage but resize it to a given
+    // new size.
+    TestingImage(const unsigned char* inputImage,
+                 int inputHeight, int inputWidth,
+                 int inputChannel, int inputRowSpan,
+                 int newHeight, int newWidth);
+    virtual ~TestingImage();
+
+    // Reads the pixel value of a given location.
+    int getPixelValue(int row, int column, int channel) const;
+    Vec3i getPixelValue(int row, int column) const;
+    Vec3i getPixelValue(const Vec2i &pixelPosition) const;
+    Vec3i getPixelValue(const Vec2f &pixelPosition) const;
+
+    inline const unsigned char* getImage() const { return mImage; }
+    inline int getWidth() const { return mWidth; }
+    inline int getHeight() const { return mHeight; }
+    inline int getChannels() const { return mChannels; }
+    inline int getRowSpan() const { return mRowSpan; }
+
+    // Reads the colors of a color checker in the image with the given checker
+    // coordinates including centers and radius.
+    const std::vector<Vec3f>* getColorChecker(
+            int rowStart, int rowEnd, int columnStart, int columnEnd,
+            const std::vector<std::vector< Vec2f > >* centerAddress,
+            const std::vector<std::vector< float > >* radiusAddress) const;
+
+    // Computes the luminance value of a color image.
+    bool rgbToGrayScale(unsigned char* grayLayer) const;
+
+  private:
+    unsigned char* mImage;
+    int mWidth;
+    int mHeight;
+    int mRowSpan;
+    int mChannels;
+};
+
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/vec2.h b/apps/CtsVerifier/include/colorchecker/vec2.h
new file mode 100644
index 0000000..9de614c
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/vec2.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef VEC2_H
+#define VEC2_H
+
+#include <assert.h>
+#include <cmath>
+
+// Implements a class to represent the location of a pixel.
+template <class T>
+class Vec2{
+  public:
+    Vec2(T inputX, T inputY) {
+        mX = inputX;
+        mY = inputY;
+    }
+
+    Vec2() {}
+
+    inline Vec2<T> operator+ (const Vec2<T> &param) const {
+        Vec2<T> temp(mX + param.x(), mY + param.y());
+        return temp;
+    }
+
+    inline Vec2<T> operator- (const Vec2<T> &param) const {
+        Vec2<T> temp(mX - param.x(), mY - param.y());
+        return temp;
+    }
+
+    inline Vec2<float> operator/ (const int param) const {
+        Vec2<float> temp();
+        assert(param != 0);
+        temp.set(static_cast<float>(mX) / static_cast<float>(param),
+                 static_cast<float>(mY) / static_cast<float>(param));
+
+        return temp;
+    }
+
+    template <class U>
+    float squareDistance(const Vec2<U> &param) const {
+        int difference = 0.f;
+        difference = (static_cast<float>(mX) - static_cast<float>(param.x())) *
+              (static_cast<float>(mX) - static_cast<float>(param.x())) +
+              (static_cast<float>(mY) - static_cast<float>(param.y())) *
+              (static_cast<float>(mY) - static_cast<float>(param.y()));
+        return difference;
+    }
+
+    inline T x() const { return mX; }
+    inline T y() const { return mY; }
+
+    inline void set(const T inputX, const T inputY) {
+        mX = inputX;
+        mY = inputY;
+    }
+
+  private:
+    T mX;
+    T mY;
+};
+
+typedef Vec2<int> Vec2i;
+typedef Vec2<float> Vec2f;
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/vec3.h b/apps/CtsVerifier/include/colorchecker/vec3.h
new file mode 100644
index 0000000..1d48188
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/vec3.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+#ifndef VEC3_H
+#define VEC3_H
+
+#include <assert.h>
+#include <cmath>
+
+// Implementes a class to represent the pixel value in a 3-dimensional color
+// space. The colors are all represented by int as it is mostly used as RGB.
+template <class T>
+class Vec3{
+  public:
+    Vec3(T inputRed, T inputGreen, T inputBlue) {
+        mRed = inputRed;
+        mGreen = inputGreen;
+        mBlue = inputBlue;
+    }
+
+    Vec3() {}
+
+    template <class U>
+    inline Vec3<T> operator+ (const Vec3<U> &param) const {
+        Vec3<T> temp(mRed + param.r(), mGreen + param.g(), mBlue + param.b());
+        return temp;
+    }
+
+    inline Vec3<T> operator- (const Vec3<T> &param) const {
+        Vec3<T> temp(mRed - param.r(), mGreen - param.g(), mBlue - param.b());
+        return temp;
+    }
+
+    inline Vec3<T> operator* (const int param) const {
+        Vec3<T> temp(mRed * param, mGreen * param, mBlue * param);
+        return temp;
+    }
+
+    template <class U>
+    inline Vec3<float> operator* (const Vec3<U> &param) const {
+        Vec3<float> temp(mRed * static_cast<U>(param.r()),
+                         mGreen * static_cast<U>(param.g()),
+                         mBlue * static_cast<U>(param.b()));
+        return temp;
+    }
+
+
+    inline Vec3<float> operator/ (const int param) const {
+        Vec3<float> temp;
+        assert(param != 0);
+        temp.set(static_cast<float>(mRed) / static_cast<float>(param),
+                 static_cast<float>(mGreen) / static_cast<float>(param),
+                 static_cast<float>(mBlue) / static_cast<float>(param));
+        return temp;
+    }
+
+    template <class U>
+    inline Vec3<float> operator/ (const Vec3<U> &param) const {
+        Vec3<float> temp;
+        assert((param.r() != 0.f) && (param.g() != 0.f) && (param.b() != 0.f));
+        temp.set(static_cast<float>(mRed) / static_cast<float>(param.r()),
+                 static_cast<float>(mGreen) / static_cast<float>(param.g()),
+                 static_cast<float>(mBlue) / static_cast<float>(param.b()));
+        return temp;
+    }
+
+    template <class U>
+    float squareDistance(const Vec3<U> &param) const {
+        float difference = 0.f;
+        difference = static_cast<float>(mRed - param.r()) *
+                static_cast<float>(mRed - param.r()) +
+                static_cast<float>(mGreen - param.g()) *
+                static_cast<float>(mGreen - param.g()) +
+                static_cast<float>(mBlue - param.b()) *
+                static_cast<float>(mBlue - param.b());
+        return difference;
+    }
+
+    // Assumes conversion from sRGB to luminance.
+    float convertToLuminance() const {
+        return (0.299 * static_cast<float>(mRed) +
+                0.587 * static_cast<float>(mGreen) +
+                0.114 * static_cast<float>(mBlue));
+    }
+
+    inline T r() const { return mRed; }
+    inline T g() const { return mGreen; }
+    inline T b() const { return mBlue; }
+
+    inline void set(const T inputRed, const T inputGreen, const T inputBlue){
+        mRed = inputRed;
+        mGreen = inputGreen;
+        mBlue = inputBlue;
+    }
+
+  private:
+    T mRed;
+    T mGreen;
+    T mBlue;
+};
+
+typedef Vec3<int> Vec3i;
+typedef Vec3<float> Vec3f;
+#endif
diff --git a/apps/CtsVerifier/include/colorchecker/whitebalancetest.h b/apps/CtsVerifier/include/colorchecker/whitebalancetest.h
new file mode 100644
index 0000000..a347ff0
--- /dev/null
+++ b/apps/CtsVerifier/include/colorchecker/whitebalancetest.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef WHITEBALANCETEST_H
+#define WHITEBALANCETEST_H
+
+#include <vector>
+#include <string>
+
+#include "imagetesthandler.h"
+
+class WhiteBalanceTest : public ImageTestHandler {
+  public:
+    WhiteBalanceTest() : ImageTestHandler() {}
+    WhiteBalanceTest(int debugHeight, int debugWidth) :
+            ImageTestHandler(debugHeight, debugWidth) {}
+    ~WhiteBalanceTest() {}
+
+    void addDataToList(const std::string &mode,
+                       const std::vector<Vec3f>* checkerColors) {
+        mMode = mode;
+        mCheckerColors = *checkerColors;
+        delete checkerColors;
+    }
+
+    void processData();
+
+    int getCorrelatedColorTemp() const {
+        return mCorrelatedColorTemp;
+    }
+
+    int getAutoTemp();
+
+  private:
+    int findCorrelatedColorTemp(const Vec3f &whitePoint);
+    Vec3f initializeFromRGB(const Vec3f &rgb);
+    float convertToLinear(float color);
+
+    std::string mMode;
+    std::vector<Vec3f> mCheckerColors;
+    std::vector<Vec3f> mCheckerXyzColors;
+    std::vector<Vec3f> mXyzColorsDaylight;
+    int mCorrelatedColorTemp;
+};
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk b/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
index ccc0998..2859074 100644
--- a/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
+++ b/apps/CtsVerifier/jni/cameraanalyzer/Android.mk
@@ -16,12 +16,18 @@
 LOCAL_PATH := $(call my-dir)
 
 include $(CLEAR_VARS)
+include external/stlport/libstlport.mk
 
 LOCAL_MODULE := libcameraanalyzer
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := com_android_cts_verifier_camera_analyzer_ColorChecker.cpp
+LOCAL_SRC_FILES := com_android_cts_verifier_camera_analyzer_CameraTests.cpp \
+                com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp \
+                com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp \
+                com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp \
+                com_android_cts_verifier_camera_analyzer_MeteringTest.cpp \
+                com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
 
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker $(JNI_H_INCLUDE)
 
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp
new file mode 100644
index 0000000..fac39e1
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "AutoLockJNI"
+#include <utils/Log.h>
+#include "com_android_cts_verifier_camera_analyzer_AutoLockTest.h"
+
+#include <vector>
+#include <string>
+#include <string.h>
+
+#include "testingimage.h"
+#include "autolocktest.h"
+#include "vec2.h"
+#include "android/bitmap.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockTest(
+        JNIEnv*      env,
+        jobject      thiz) {
+
+    AutoLockTest* testHandler = new AutoLockTest();
+    long handlerAddress = (long)testHandler;
+    return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress,
+        jlong        checkercenterAddress,
+        jlong        checkerradiusAddress) {
+
+    ALOGV("JNI createAutoLockClass starts!");
+    long imageAddress = (long)inputImageAddress;
+    long handlerAddress = (long)inputHandlerAddress;
+
+    TestingImage *image = (TestingImage*) imageAddress;
+    AutoLockTest *testHandler = (AutoLockTest*) handlerAddress;
+
+    std::vector<std::vector< Vec2f > >* checkerCenter =
+            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
+    std::vector<std::vector< float > >* checkerRadius =
+            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
+    ALOGV("Classes recovered");
+
+    // Uses only the gray patches on the color checker for comparison.
+    testHandler->addDataToList(image->getColorChecker(3, 4, 0, 6,
+                                                      checkerCenter,
+                                                      checkerRadius));
+
+    delete image;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_processAutoLockTest(
+        JNIEnv*          env,
+        jobject          thiz,
+        jlong            inputHandlerAddress,
+        jbooleanArray    tempArray) {
+
+    ALOGV("Processing Auto Lock data!");
+
+    long handlerAddress = (long) inputHandlerAddress;
+    AutoLockTest *testHandler = (AutoLockTest*) handlerAddress;
+
+    testHandler->processData();
+
+    // Converts the native boolean array into a java boolean array.
+    const std::vector<bool>* nativeComparisonResults =
+            testHandler->getComparisonResults();
+    jboolean comparisonResults[nativeComparisonResults->size()];
+
+    for (int i = 0; i < nativeComparisonResults->size(); ++i) {
+        comparisonResults[i] = (jboolean) (*nativeComparisonResults)[i];
+    }
+
+    env->SetBooleanArrayRegion(tempArray,
+                               0, nativeComparisonResults->size(),
+                               comparisonResults);
+    testHandler->clearData();
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h
new file mode 100644
index 0000000..dc40bc2
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_AutoLockTest.h
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_AUTOLOCKTEST_H
+#define JNI_CAMERAANALYZER_AUTOLOCKTEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockTest(
+        JNIEnv*      env,
+        jobject      thiz);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_createAutoLockClass(
+        JNIEnv *env,
+        jobject thiz,
+        jlong inputImageAddress,
+        jlong inputHandlerAddress,
+        jlong checkercenterAddress,
+        jlong checkerradiusAddress);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_AutoLockTest_processAutoLockTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress,
+        jbooleanArray    tempArray);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp
new file mode 100644
index 0000000..51fd0c5
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "CameraTestsJNI"
+#include <utils/Log.h>
+#include "com_android_cts_verifier_camera_analyzer_CameraTests.h"
+#include "android/bitmap.h"
+#include "testingimage.h"
+#include "imagetesthandler.h"
+
+#include <string.h>
+
+jlong Java_com_android_cts_verifier_camera_analyzer_CameraTests_findNative(
+        JNIEnv*      env,
+        jobject      thiz,
+        jobject      inputBitmap) {
+
+    ALOGV("JNI findNative starts!");
+
+    // Verify that we can handle the input bitmap
+    AndroidBitmapInfo inputInfo;
+    AndroidBitmap_getInfo(env, inputBitmap, &inputInfo);
+    if (inputInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
+        inputInfo.format != ANDROID_BITMAP_FORMAT_RGB_565) {
+        LOGE("Only RGBA_8888 and RGB_565 bitmaps are supported, type was %d.",
+             inputInfo.format);
+    }
+
+    // Get some references to the fields and class type of ColorChecker
+    jclass thizCls = env->GetObjectClass(thiz);
+    ALOGV("ColorChecker field and classes reference finished!");
+
+    // Get raw inputs and outputs ready
+    uint8_t *inputBuffer = NULL;
+    int result = AndroidBitmap_lockPixels(
+            env,
+            inputBitmap,
+            reinterpret_cast<void**>(&inputBuffer));
+
+    if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
+        LOGE("Unable to lock input bitmap");
+    }
+
+    uint8_t *outputImage = NULL;
+    int outputWidth, outputHeight;
+
+    ALOGV("Input and output images created!");
+
+    // Find the color checker
+    bool success;
+    uint8_t *inputBufferRGBA = NULL;
+    int inputStride;
+    bool freeInputRGBA = false;
+    switch (inputInfo.format) {
+        case ANDROID_BITMAP_FORMAT_RGB_565: {
+            // First convert to RGBA_8888
+            inputBufferRGBA = new uint8_t[inputInfo.width *
+                                          inputInfo.height *
+                                          4];
+            inputStride = inputInfo.width * 4;
+            uint8_t *outP = inputBufferRGBA;
+            for (int y = 0; y < inputInfo.height; y++ ) {
+                uint16_t *inP = (uint16_t*)(&inputBuffer[y * inputInfo.stride]);
+                for (int x = 0; x < inputInfo.width; x++) {
+                    *(outP++) = ( ((*inP) >> 0) & 0x001F) << 3;
+                    *(outP++) = ( ((*inP) >> 5) & 0x003F) << 2;
+                    *(outP++) = ( ((*inP) >> 11) & 0x001F) << 3;
+                    outP++;
+                    inP++;
+                }
+            }
+            freeInputRGBA = true;
+
+            ALOGV("RGB_565 Format with width, height and stride as %d, %d, %d",
+                 inputInfo.width, inputInfo.height, inputStride);
+            break;
+        }
+        case ANDROID_BITMAP_FORMAT_RGBA_8888: {
+            // Already in RGBA
+            inputBufferRGBA = inputBuffer;
+            inputStride = inputInfo.stride;
+            ALOGV("RGB_8888 Format with width, height and stride as %d, %d, %d",
+                 inputInfo.width, inputInfo.height, inputStride);
+            break;
+        }
+    }
+
+    TestingImage *input_testing_image =
+            new TestingImage(inputBufferRGBA, inputInfo.height, inputInfo.width,
+                             4, inputStride, 120, 160);
+
+    long lp = (long)input_testing_image;
+
+    result = AndroidBitmap_unlockPixels(env, inputBitmap);
+    if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
+        LOGE("Unable to unlock input bitmap");
+    }
+
+    if (freeInputRGBA) {
+        ALOGV("Deleteing inputbufferRGBA");
+        delete[] inputBufferRGBA;
+    }
+
+    return lp;
+    ALOGV("Input format switched!");
+}
+
+jlong Java_com_android_cts_verifier_camera_analyzer_CameraTests_createImageTestHandler(
+        JNIEnv*      env,
+        jobject      thiz,
+        jint         debugHeight,
+        jint         debugWidth) {
+
+    ImageTestHandler* testHandler =
+            new ImageTestHandler(debugHeight, debugWidth);
+    long handlerAddress = (long)testHandler;
+    return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_CameraTests_cleanUpHandler(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    ImageTestHandler* testHandler = (ImageTestHandler*) (long) inputHandlerAddress;
+    delete testHandler;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_CameraTests_displayHandlerDebugOutput(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    jclass thizCls = env->GetObjectClass(thiz);
+    jfieldID outputId = env->GetFieldID(thizCls, "mDebugOutput",
+                                        "Landroid/graphics/Bitmap;");
+
+    ImageTestHandler* testHandler = (ImageTestHandler*) (long) inputHandlerAddress;
+    uint8_t *outputImage =  new uint8_t[testHandler->getDebugHeight() *
+                                        testHandler->getDebugWidth() * 4];
+
+    const unsigned char *debugoutput = testHandler->debug_output();
+    memcpy(outputImage, debugoutput, testHandler->getDebugHeight() *
+            testHandler->getDebugWidth() * 4);
+
+    int outputWidth = testHandler->getDebugWidth();
+    int outputHeight = testHandler->getDebugHeight();
+    bool success = false;
+
+    if (outputImage == NULL) {
+        ALOGV("output Image is null!");
+    } else {
+        ALOGV("output Image is ready!");
+    }
+
+    // Create debug bitmap from output image data
+    if (outputImage != NULL) {
+        // Get method handles, create inputs to createBitmap
+        jclass bitmapClass =
+                env->FindClass("android/graphics/Bitmap");
+        jclass bitmapConfigClass =
+                env->FindClass("android/graphics/Bitmap$Config");
+
+        jmethodID createBitmap = env->GetStaticMethodID(
+            bitmapClass, "createBitmap",
+            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
+
+        jmethodID getConfig = env->GetStaticMethodID(
+            bitmapConfigClass, "valueOf",
+            "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
+
+        // Create bitmap config and bitmap
+        jstring bitmapConfigValue = env->NewStringUTF("ARGB_8888");
+        jobject rgbaConfig = env->CallStaticObjectMethod(bitmapConfigClass,
+                                                         getConfig,
+                                                         bitmapConfigValue);
+        jobject outputBitmap = env->CallStaticObjectMethod(bitmapClass,
+                                                           createBitmap,
+                                                           outputWidth,
+                                                           outputHeight,
+                                                           rgbaConfig);
+        // Copy output image into it
+        uint8_t *outputBuffer;
+        int result = AndroidBitmap_lockPixels(
+                env,
+                outputBitmap,
+                reinterpret_cast<void**>(&outputBuffer) );
+
+        if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
+            LOGE("Unable to lock output bitmap");
+        }
+
+        memcpy(outputBuffer, outputImage, outputWidth * outputHeight * 4);
+
+        result = AndroidBitmap_unlockPixels(env, outputBitmap);
+        if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
+            LOGE("Unable to unlock output bitmap");
+        }
+
+        // Write new Bitmap reference into mDebugOutput class member
+        env->SetObjectField(thiz, outputId, outputBitmap);
+        ALOGV("Copied to outputBitmap");
+        delete [] outputImage;
+        env->DeleteLocalRef(outputBitmap);
+        env->DeleteLocalRef(rgbaConfig);
+        env->DeleteLocalRef(bitmapClass);
+        env->DeleteLocalRef(bitmapConfigClass);
+    }
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h
new file mode 100644
index 0000000..e071dc1
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_CameraTests.h
@@ -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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_CAMERATESTS_H
+#define JNI_CAMERAANALYZER_CAMERATESTS_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_CameraTests_findNative(
+        JNIEnv *env,
+        jobject thiz,
+        jobject inputBitmap);
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_CameraTests_createImageTestHandler(
+        JNIEnv*      env,
+        jobject      thiz,
+        jint         debugHeight,
+        jint         debugWidth);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_CameraTests_cleanUpHandler(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_CameraTests_displayHandlerDebugOutput(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.cpp
deleted file mode 100644
index 4d247ab..0000000
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.
- */
-
-#include "com_android_cts_verifier_camera_analyzer_ColorChecker.h"
-
-#include "utils/Log.h"
-#include "android/bitmap.h"
-#include "colorchecker.h"
-
-jboolean Java_com_android_cts_verifier_camera_analyzer_ColorChecker_findNative(
-    JNIEnv*      env,
-    jobject      thiz,
-    jobject      inputBitmap) {
-
-    // Verify that we can handle the input bitmap
-    AndroidBitmapInfo inputInfo;
-    AndroidBitmap_getInfo(env, inputBitmap, &inputInfo);
-    if (inputInfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888 &&
-        inputInfo.format != ANDROID_BITMAP_FORMAT_RGB_565) {
-        LOGE("Only RGBA_8888 and RGB_565 bitmaps are supported, was given type %d.", inputInfo.format);
-        return JNI_FALSE;
-    }
-
-    // Get some references to the fields and class type of ColorChecker
-    jclass thizCls = env->GetObjectClass(thiz);
-    jfieldID patchId = env->GetFieldID(thizCls, "mPatchValues", "[F");
-    jfieldID outputId = env->GetFieldID(thizCls, "mDebugOutput", "Landroid/graphics/Bitmap;");
-    jfloatArray patchValues = (jfloatArray)env->GetObjectField(thiz, patchId);
-
-    // Get raw inputs and outputs ready
-
-    uint8_t *inputBuffer;
-    int result = AndroidBitmap_lockPixels(
-        env,
-        inputBitmap,
-        reinterpret_cast<void**>(&inputBuffer) );
-
-    if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-        LOGE("Unable to lock input bitmap");
-        return JNI_FALSE;
-    }
-
-    float *patchRawArray = env->GetFloatArrayElements(patchValues,
-                                                      NULL);
-
-    uint8_t *outputImage = NULL;
-    int outputWidth, outputHeight;
-
-    // Find the color checker
-    bool success;
-    uint8_t *inputBufferRGBA = NULL;
-    int inputStride;
-    bool freeInputRGBA = false;
-    switch (inputInfo.format) {
-        case ANDROID_BITMAP_FORMAT_RGB_565: {
-            // First convert to RGBA_8888
-            inputBufferRGBA = new uint8_t[inputInfo.width *
-                                          inputInfo.height *
-                                          4];
-            inputStride = inputInfo.width * 4;
-            uint8_t *outP = inputBufferRGBA;
-            for (int y = 0; y < inputInfo.height; y++ ) {
-                uint16_t *inP = (uint16_t*)(&inputBuffer[y * inputInfo.stride]);
-                for (int x = 0; x < inputInfo.width; x++) {
-                    *(outP++) = ( ((*inP) >> 0) & 0x001F) << 3;
-                    *(outP++) = ( ((*inP) >> 5) & 0x003F) << 2;
-                    *(outP++) = ( ((*inP) >> 11) & 0x001F) << 3;
-                    outP++;
-                    inP++;
-                }
-            }
-            freeInputRGBA = true;
-            break;
-        }
-        case ANDROID_BITMAP_FORMAT_RGBA_8888:
-            // Already in RGBA
-            inputBufferRGBA = inputBuffer;
-            inputStride = inputInfo.stride;
-            break;
-    }
-
-    success = findColorChecker(inputBufferRGBA,
-                               inputInfo.width,
-                               inputStride,
-                               inputInfo.height,
-                               patchRawArray,
-                               &outputImage,
-                               &outputWidth,
-                               &outputHeight);
-
-    // Clean up raw inputs/outputs
-    env->ReleaseFloatArrayElements(patchValues, patchRawArray, 0);
-    result = AndroidBitmap_unlockPixels(env, inputBitmap);
-    if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-        LOGE("Unable to unlock input bitmap");
-        return JNI_FALSE;
-    }
-
-    if (freeInputRGBA) {
-        delete inputBufferRGBA;
-    }
-
-    // Create debug bitmap from output image data
-    if (outputImage != NULL) {
-        // Get method handles, create inputs to createBitmap
-        jclass bitmapClass =
-                env->FindClass("android/graphics/Bitmap");
-        jclass bitmapConfigClass =
-                env->FindClass("android/graphics/Bitmap$Config");
-
-        jmethodID createBitmap = env->GetStaticMethodID(
-            bitmapClass, "createBitmap",
-            "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
-
-        jmethodID getConfig = env->GetStaticMethodID(
-            bitmapConfigClass, "valueOf",
-            "(Ljava/lang/String;)Landroid/graphics/Bitmap$Config;");
-
-        // Create bitmap config and bitmap
-        jstring bitmapConfigValue = env->NewStringUTF("ARGB_8888");
-        jobject rgbaConfig = env->CallStaticObjectMethod(bitmapConfigClass,
-                                                         getConfig,
-                                                         bitmapConfigValue);
-        jobject outputBitmap = env->CallStaticObjectMethod(bitmapClass,
-                                                           createBitmap,
-                                                           outputWidth,
-                                                           outputHeight,
-                                                           rgbaConfig);
-        // Copy output image into it
-        uint8_t *outputBuffer;
-        int result = AndroidBitmap_lockPixels(
-            env,
-            outputBitmap,
-            reinterpret_cast<void**>(&outputBuffer) );
-
-        if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-            LOGE("Unable to lock output bitmap");
-            return JNI_FALSE;
-        }
-
-        memcpy(outputBuffer, outputImage, outputWidth * outputHeight * 4);
-
-        result = AndroidBitmap_unlockPixels(env, outputBitmap);
-        if (result != ANDROID_BITMAP_RESUT_SUCCESS) {
-            LOGE("Unable to unlock output bitmap");
-            return JNI_FALSE;
-        }
-
-        // Write new Bitmap reference into mDebugOutput class member
-        env->SetObjectField(thiz, outputId, outputBitmap);
-
-        delete outputImage;
-    }
-    if (!success) return JNI_FALSE;
-
-    return JNI_TRUE;
-}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp
new file mode 100644
index 0000000..94e3ac2
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "FindColorCheckerJNI"
+#include <utils/Log.h>
+#include "com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h"
+
+#include <string.h>
+#include "android/bitmap.h"
+#include "colorcheckertest.h"
+#include "testingimage.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jint         debugHeight,
+        jint         debugWidth) {
+    ColorCheckerTest* testHandler = new ColorCheckerTest(debugHeight,
+                                                         debugWidth);
+    long testHandlerAddress = (long)testHandler;
+    return testHandlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress) {
+    ALOGV("JNI createColorCheckerClass starts!");
+
+    TestingImage *testImage = (TestingImage*) (long) inputImageAddress;
+    ColorCheckerTest *testHandler = (ColorCheckerTest*)
+            (long) inputHandlerAddress;
+
+    testHandler->addTestingImage(testImage);
+}
+
+jboolean Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_processColorCheckerTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    ColorCheckerTest *testHandler = (ColorCheckerTest*)
+            (long) inputHandlerAddress;
+    testHandler->processData();
+    return testHandler->getSuccess();
+}
+
+jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerRadiusAdd(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    ColorCheckerTest *testHandler = (ColorCheckerTest*)
+            (long) inputHandlerAddress;
+    long rtn = (long) testHandler->getCheckerRadiusAdd();
+    return rtn;
+}
+
+jlong Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerCenterAdd(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    ColorCheckerTest *testHandler = (ColorCheckerTest*)
+            (long) inputHandlerAddress;
+
+    long rtn = (long) testHandler->getCheckerCenterAdd();
+    return rtn;
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h
new file mode 100644
index 0000000..fb87735
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorCheckerTest.h
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_COLORCHECKERTEST_H
+#define JNI_CAMERAANALYZER_COLORCHECKERTEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerTest(
+    JNIEnv*      env,
+    jobject      thiz,
+    jint         output_height,
+    jint         output_width);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_createColorCheckerClass(
+    JNIEnv *env,
+    jobject thiz,
+    jlong buffer_address,
+    jlong handler_address);
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerRadiusAdd(
+    JNIEnv *env,
+    jobject thiz,
+    jlong handler_address);
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_getColorCheckerCenterAdd(
+    JNIEnv *env,
+    jobject thiz,
+    jlong handler_address);
+
+JNIEXPORT jboolean JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ColorCheckerTest_processColorCheckerTest(
+    JNIEnv*      env,
+    jobject      thiz,
+    jlong        handler_address);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
new file mode 100644
index 0000000..68c8256
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ExposureCompensationJNI"
+#include <utils/Log.h>
+#include <vector>
+#include <string.h>
+
+#include "android/bitmap.h"
+#include "testingimage.h"
+#include "exposurecompensationtest.h"
+#include "vec2.h"
+
+#include "com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
+      JNIEnv*      env,
+      jobject      thiz,
+      jint         debugHeight,
+      jint         debugWidth) {
+
+    ExposureCompensationTest* testHandler =
+            new ExposureCompensationTest(debugHeight, debugWidth);
+    long handlerAddress = (long)testHandler;
+
+    return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress,
+        jlong        checkerCenterAddress,
+        jlong        checkerRadiusAddress,
+        jfloat       exposureValue) {
+
+    ALOGV("JNI createExposureCompensationClass starts!");
+
+    long imageAddress = (long)inputImageAddress;
+    long handlerAddress = (long)inputHandlerAddress;
+
+    TestingImage *inputImage = (TestingImage*) imageAddress;
+    ExposureCompensationTest *testHandler =
+            (ExposureCompensationTest*) handlerAddress;
+
+    std::vector<std::vector< Vec2f > >* checkerCenter =
+            (std::vector<std::vector< Vec2f > >*) (long) checkerCenterAddress;
+    std::vector<std::vector< float > >* checkerRadius =
+            (std::vector<std::vector< float > >*) (long) checkerRadiusAddress;
+
+    const std::vector<Vec3f>* checkerValue =
+            inputImage->getColorChecker(3, 4, 0, 6,
+                                        checkerCenter, checkerRadius);
+    testHandler->addDataToList((float) exposureValue, checkerValue);
+    delete inputImage;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress) {
+
+    long handlerAddress = (long) inputHandlerAddress;
+    ExposureCompensationTest *testHandler =
+            (ExposureCompensationTest*) handlerAddress;
+
+    testHandler->processData();
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
new file mode 100644
index 0000000..c77f0e4
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ExposureCompensationTest.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
+#define JNI_CAMERAANALYZER_EXPOSURECOMPENSATIONTEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jint         debugHeight,
+        jint         debugWidth);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_createExposureCompensationClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress,
+        jlong        checkerCenterAddress,
+        jlong        checkerRadiusAddress,
+        jfloat       exposureValue);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_ExposureCompensationTest_processExposureCompensationTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputHandlerAddress);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp
new file mode 100644
index 0000000..faebe21
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.cpp
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "MeteringJNI"
+#include <utils/Log.h>
+#include "com_android_cts_verifier_camera_analyzer_MeteringTest.h"
+
+#include <vector>
+#include <string>
+#include <string.h>
+#include <math.h>
+
+#include "testingimage.h"
+#include "meteringtest.h"
+#include "vec2.h"
+#include "android/bitmap.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringTest(
+        JNIEnv*      env,
+        jobject      thiz) {
+
+    MeteringTest* testHandler = new MeteringTest();
+    long handlerAddress = (long)testHandler;
+    return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress,
+        jlong        checkercenterAddress,
+        jlong        checkerradiusAddress){
+
+    ALOGV("JNI createMeteringClass starts!");
+    long imageAddress = (long)inputImageAddress;
+    long handlerAddress = (long)inputHandlerAddress;
+
+    TestingImage *image = (TestingImage*) imageAddress;
+    MeteringTest *testHandler = (MeteringTest*) handlerAddress;
+
+    std::vector<std::vector< Vec2f > >* checkerCenter =
+            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
+    std::vector<std::vector< float > >* checkerRadius =
+            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
+    ALOGV("Classes recovered");
+
+    testHandler->addDataToList(image->getColorChecker(3, 4, 0, 6,
+                                                      checkerCenter,
+                                                      checkerRadius));
+
+    delete image;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_processMeteringTest(
+        JNIEnv*          env,
+        jobject          thiz,
+        jlong            inputHandlerAddress,
+        jbooleanArray    tempArray) {
+
+    ALOGV("Processing Auto Lock data!");
+
+    long handlerAddress = (long) inputHandlerAddress;
+    MeteringTest *testHandler = (MeteringTest*) handlerAddress;
+
+    testHandler->processData();
+
+    const std::vector<bool>* nativeComparisonResults =
+            testHandler->getComparisonResults();
+    jboolean jComparisonResults[nativeComparisonResults->size()];
+
+    for (int i = 0; i < nativeComparisonResults->size(); ++i) {
+        jComparisonResults[i] = (jboolean) (*nativeComparisonResults)[i];
+    }
+
+    env->SetBooleanArrayRegion(tempArray,
+                               0, nativeComparisonResults->size(),
+                               jComparisonResults);
+    testHandler->clearData();
+}
+
+// Find the gray checker borders from the native array of checker center and
+// radius. Convert the coordinate to the coordinates accepted by Android
+// Camera.Area type, which defines the top left corner to (-1000, -1000) and
+// bottom right corner to (1000, 1000).
+void Java_com_android_cts_verifier_camera_analyzer_MeteringTest_findGreyCoordinates(
+        JNIEnv*      env,
+        jobject      thiz,
+        jintArray    greyCoordinates,
+        jlong        checkercenterAddress,
+        jlong        checkerradiusAddress){
+
+    ALOGV("Start finding grey coordinates");
+
+    std::vector<std::vector< Vec2f > >* checkerCenter =
+            (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
+    std::vector<std::vector< float > >* checkerRadius =
+            (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
+
+    ALOGV("Checker recovered!");
+    int nativeGreyCoordinates[24];
+
+    for (int i = 0; i < 6; ++i) {
+        float radius = sqrt((*checkerRadius)[3][i]);
+        nativeGreyCoordinates[i * 4] = static_cast<int>(
+                ((*checkerCenter)[3][i].y() - radius)
+                / 160.0 * 2000.0 - 1000.0);
+        nativeGreyCoordinates[i * 4 + 1] = static_cast<int>(
+                ((*checkerCenter)[3][i].x() - radius)
+                / 120.0 * 2000.0 - 1000.0);
+        nativeGreyCoordinates[i * 4 + 2] = static_cast<int>(
+                ((*checkerCenter)[3][i].y() + radius)
+                / 160.0 * 2000.0 - 1000.0);
+        nativeGreyCoordinates[i * 4 + 3] = static_cast<int>(
+                ((*checkerCenter)[3][i].x() + radius)
+                / 120.0 * 2000.0 - 1000.0);
+
+        ALOGV("checker is bounded by %f, %f, %f",
+             (*checkerCenter)[3][i].x(), (*checkerCenter)[3][i].y(), radius);
+
+        ALOGV("Square is bounded by %d, %d, %d, %d",
+             nativeGreyCoordinates[i * 4], nativeGreyCoordinates[i * 4 + 1],
+             nativeGreyCoordinates[i * 4 + 2],
+             nativeGreyCoordinates[i * 4 + 3]);
+    }
+
+    env->SetIntArrayRegion(greyCoordinates, 0, 24, nativeGreyCoordinates);
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h
new file mode 100644
index 0000000..ecc1b96
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_MeteringTest.h
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_METERINGTEST_H
+#define JNI_CAMERAANALYZER_METERINGTEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringTest(
+        JNIEnv*      env,
+        jobject      thiz);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_MeteringTest_createMeteringClass(
+        JNIEnv *env,
+        jobject thiz,
+        jlong inputAddress,
+        jlong handlerAddress,
+        jlong checkercenterAddress,
+        jlong checkerradiusAddress);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_MeteringTest_processMeteringTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        handlerAddress,
+        jbooleanArray    tempArray);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_MeteringTest_findGreyCoordinates(
+        JNIEnv*      env,
+        jobject      thiz,
+        jintArray    greyCoordinates,
+        jlong        checkercenterAddress,
+        jlong        checkerradiusAddress);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
new file mode 100644
index 0000000..bce0fca
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "WhiteBalanceJNI"
+#include <utils/Log.h>
+#include "com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h"
+
+#include <vector>
+#include <string>
+#include <string.h>
+
+#include "testingimage.h"
+#include "whitebalancetest.h"
+#include "vec2.h"
+#include "android/bitmap.h"
+
+jlong Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceTest(
+        JNIEnv*      env,
+        jobject      thiz) {
+
+    WhiteBalanceTest* testHandler = new WhiteBalanceTest();
+    long handlerAddress = (long)testHandler;
+    return handlerAddress;
+}
+
+void Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceClass(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        inputImageAddress,
+        jlong        inputHandlerAddress,
+        jlong        checkercenterAddress,
+        jlong        checkerradiusAddress,
+        jstring      whiteBalance){
+
+    ALOGV("JNI createWhiteBalanceClass starts!");
+    long imageAddress = (long)inputImageAddress;
+    long handlerAddress = (long)inputHandlerAddress;
+
+    TestingImage *image = (TestingImage*) imageAddress;
+    WhiteBalanceTest *testHandler = (WhiteBalanceTest*) handlerAddress;
+
+    std::vector<std::vector< Vec2f > >* checkerCenter =
+        (std::vector<std::vector< Vec2f > >*) (long) checkercenterAddress;
+    std::vector<std::vector< float > >* checkerRadius =
+        (std::vector<std::vector< float > >*) (long) checkerradiusAddress;
+    ALOGV("Classes recovered");
+
+    jboolean isCopy;
+    const char* stringWhiteBalance =
+            env->GetStringUTFChars(whiteBalance, &isCopy);
+    ALOGV("White Balance is %s", stringWhiteBalance);
+
+    // Adds the gray checker's RGB values to the test handler.
+    testHandler->addDataToList(stringWhiteBalance,
+                               image->getColorChecker(3, 4, 0, 6,
+                                                      checkerCenter,
+                                                      checkerRadius));
+
+    env->ReleaseStringUTFChars(whiteBalance, stringWhiteBalance);
+    delete image;
+}
+
+jint Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_processWhiteBalanceTest(
+    JNIEnv*      env,
+    jobject      thiz,
+    jlong        inputHandlerAddress) {
+  ALOGV("Processing white balance test");
+
+  long handlerAddress = (long) inputHandlerAddress;
+  WhiteBalanceTest *testHandler = (WhiteBalanceTest*) handlerAddress;
+
+  testHandler->processData();
+
+  ALOGV("CCT is %d", testHandler->getCorrelatedColorTemp());
+  return testHandler->getCorrelatedColorTemp();
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h
new file mode 100644
index 0000000..88cf52e
--- /dev/null
+++ b/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_WhiteBalanceTest.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef JNI_CAMERAANALYZER_WHITEBALANCETEST_H
+#define JNI_CAMERAANALYZER_WHITEBALANCETEST_H
+
+#include <jni.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT jlong JNICALL
+Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceTest(
+        JNIEnv*      env,
+        jobject      thiz);
+
+JNIEXPORT void JNICALL
+Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_createWhiteBalanceClass(
+        JNIEnv *env,
+        jobject thiz,
+        jlong inputAddress,
+        jlong handlerAddress,
+        jlong checkercenterAddress,
+        jlong checkerradiusAddress,
+        jstring whiteBalance);
+
+JNIEXPORT jint JNICALL
+Java_com_android_cts_verifier_camera_analyzer_WhiteBalanceTest_processWhiteBalanceTest(
+        JNIEnv*      env,
+        jobject      thiz,
+        jlong        handlerAddress);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/apps/CtsVerifier/lib/colorchecker/Android.mk b/apps/CtsVerifier/lib/colorchecker/Android.mk
index 97f0089..38f595f 100644
--- a/apps/CtsVerifier/lib/colorchecker/Android.mk
+++ b/apps/CtsVerifier/lib/colorchecker/Android.mk
@@ -24,7 +24,16 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := libcolorchecker
 
-LOCAL_SRC_FILES += colorchecker.cpp
+LOCAL_SRC_FILES += testingimage.cpp \
+                   vec3.cpp \
+                   vec2.cpp \
+                   imagetesthandler.cpp \
+                   colorcheckertest.cpp \
+                   exposurecompensationtest.cpp \
+                   autolocktest.cpp \
+                   meteringtest.cpp \
+                   whitebalancetest.cpp
+
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../include/colorchecker
 LOCAL_SHARED_LIBRARIES := libstlport \
                           libcutils \
diff --git a/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp b/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp
new file mode 100644
index 0000000..6bfa922
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/autolocktest.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "AutoLockTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "autolocktest.h"
+
+const float kOverExposure = 230.f;
+const float kEqThreshold = 0.05f;
+// Processes the color checker values and compare the two values from
+// the same individual test.
+void AutoLockTest::processData() {
+    ALOGV("Start Processing Auto Lock Test Data!");
+
+    int numTests = mCheckerColors.size() / 2;
+    mNumPatches = 0;
+
+    if (numTests > 0) {
+        mNumPatches = mCheckerColors[0].size();
+    }
+
+    for (int i = 0; i < numTests; ++i) {
+        mComparisonResults.push_back(
+                IsBrighterThan((&mCheckerColors[i * 2]),
+                               (&mCheckerColors[i * 2 + 1])));
+        mComparisonResults.push_back(
+                IsEquivalentTo((&mCheckerColors[i * 2]),
+                               (&mCheckerColors[i * 2 + 1])));
+    }
+}
+
+// Compares whether one array of gray color patches is brighter than
+// another one.
+bool AutoLockTest::IsBrighterThan(
+        const std::vector<Vec3f>* colorCheckers1,
+        const std::vector<Vec3f>* colorCheckers2) const {
+    float meanRatio = 0.f;
+    int meanNumCount = 0;
+
+    for (int i = 0; i < mNumPatches; ++i) {
+        float luminance1 = (*colorCheckers1)[i].convertToLuminance();
+        float luminance2 = (*colorCheckers2)[i].convertToLuminance();
+
+        // Consider a 5% raise as a considerably large increase.
+        if ((luminance1 < kOverExposure) && (luminance2 != 0.f)) {
+            meanRatio += luminance1 / luminance2;
+            ++meanNumCount;
+        }
+    }
+    meanRatio = meanRatio / meanNumCount;
+
+    return (meanRatio > 1 + kEqThreshold);
+}
+
+// Compares whether one array of gray color patches is within a small range
+// of the other one to be considered equivalent.
+bool AutoLockTest::IsEquivalentTo(
+        const std::vector<Vec3f>* colorCheckers1,
+        const std::vector<Vec3f>* colorCheckers2) const {
+    float meanRatio = 0.f;
+    int meanNumCount = 0;
+
+    for (int i = 0; i < mNumPatches; ++i) {
+        float luminance1 = (*colorCheckers1)[i].convertToLuminance();
+        float luminance2 = (*colorCheckers2)[i].convertToLuminance();
+        ALOGV("Luma_1 and Luma_2 is %f, %f", luminance1, luminance2);
+
+        if ((luminance1 < kOverExposure) && (luminance2 < kOverExposure)) {
+              meanRatio += luminance2 / luminance1;
+              ++meanNumCount;
+        }
+    }
+    meanRatio = meanRatio / meanNumCount;
+
+    return ((meanRatio >= 1 - kEqThreshold) && (meanRatio <= 1 + kEqThreshold));
+}
+
+void AutoLockTest::clearData() {
+    mCheckerColors.clear();
+    mComparisonResults.clear();
+}
diff --git a/apps/CtsVerifier/lib/colorchecker/colorchecker.cpp b/apps/CtsVerifier/lib/colorchecker/colorchecker.cpp
deleted file mode 100644
index 1e0ae97..0000000
--- a/apps/CtsVerifier/lib/colorchecker/colorchecker.cpp
+++ /dev/null
@@ -1,714 +0,0 @@
-/*
- * 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.
- */
-
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#include "colorchecker.h"
-#include "grouping.h"
-#include <string>
-#include <vector>
-#include <set>
-#include <algorithm>
-#include <cmath>
-
-const int totalChannels = 4; // Input image channel count
-const int colorChannels = 3; // Input image color channel count
-const float gammaCorrection = 2.2; // Assumed gamma curve on input
-const int thresholdSq = 675; // Threshold on pixel difference to be considered
-                             // part of the same patch
-
-class PixelId {
-  public:
-    int id;
-    const unsigned char *p;
-
-    PixelId(): id(0), p(NULL) {}
-
-    bool operator!=(const PixelId &other) const {
-        int dR = ((int)p[0] - other.p[0]) * ((int)p[0] - other.p[0]);
-        int dG = ((int)p[1] - other.p[1]) * ((int)p[1] - other.p[1]);
-        int dB = ((int)p[2] - other.p[2]) * ((int)p[2] - other.p[2]);
-        int distSq = dR + dG + dB;
-        if (distSq > thresholdSq) return true;
-        else return false;
-    }
-};
-
-class ImageField: public Field<PixelId> {
-  public:
-    ImageField(int width, int height, const unsigned char *data):
-            mWidth(width), mHeight(height), pData(data) {
-    }
-
-    PixelId operator() (int y, int x) const {
-        PixelId pId;
-        pId.p = pData + (y * mWidth + x ) * totalChannels;
-        if (mask.size() != 0) {
-            pId.id = mask[y][x];
-        }
-        return pId;
-    }
-
-    int getWidth() const { return mWidth; }
-    int getHeight() const { return mHeight; }
-  private:
-    int mWidth;
-    int mHeight;
-    const unsigned char *pData;
-};
-
-class PixelGroup {
-  public:
-    PixelGroup(int id, const ImageField *src):
-        mId(id),
-        mMinX(1e7),
-        mMinY(1e7),
-        mMaxX(0),
-        mMaxY(0),
-        mArea(0),
-        mSrc(src),
-        mRNeighbor(NULL),
-        mDNeighbor(NULL),
-        mLNeighbor(NULL),
-        mUNeighbor(NULL) {
-        mSum[0] = 0;
-        mSum[1] = 0;
-        mSum[2] = 0;
-    }
-
-    struct IdCompare {
-        bool operator() (const PixelGroup* l, const PixelGroup* r) const {
-            return l->getId() < r->getId();
-        }
-    };
-
-    void growGroup(int x, int y) {
-        if (x < mMinX) mMinX = x;
-        if (x > mMaxX) mMaxX = x;
-        if (y < mMinY) mMinY = y;
-        if (y > mMaxY) mMaxY = y;
-        mArea++;
-        const unsigned char *p = (*mSrc)(y,x).p;
-        mSum[0] += p[0];
-        mSum[1] += p[1];
-        mSum[2] += p[2];
-    }
-
-    int getId() const {
-        return mId;
-    }
-
-    int getArea() const {
-        return mArea;
-    }
-
-    int getBoundArea() const {
-        return (mMaxX - mMinX) * (mMaxY - mMinY);
-    }
-
-    float getApproxAspectRatio() const {
-        return ((float)(mMaxY - mMinY)) / (mMaxX - mMinX);
-    }
-
-    void getApproxCenter(int *x, int *y) const {
-        *x = (mMaxX + mMinX)/2;
-        *y = (mMaxY + mMinY)/2;
-    }
-
-    void getBoundingBox(int *x1, int *y1, int *x2, int *y2) const {
-        *x1 = mMinX;
-        *x2 = mMaxX;
-        *y1 = mMinY;
-        *y2 = mMaxY;
-    }
-
-    void getAvgValue(unsigned char *p) const {
-        p[0] = mSum[0] / mArea;
-        p[1] = mSum[1] / mArea;
-        p[2] = mSum[2] / mArea;
-    }
-
-    bool operator<(const PixelGroup &other) const {
-        return mArea < other.getArea();
-    }
-
-    typedef std::set<PixelGroup*, PixelGroup::IdCompare> IdSet;
-    typedef std::set<PixelGroup*, PixelGroup::IdCompare>::iterator IdSetIter;
-
-    void findNeighbors(IdSet &candidates) {
-        int cX, cY;
-        getApproxCenter(&cX, &cY);
-        int rDistSq = 1e9; // Larger than any reasonable image distance
-        int dDistSq = rDistSq;
-
-        for (IdSetIter neighbor = candidates.begin();
-             neighbor != candidates.end();
-             neighbor++) {
-            if (*neighbor == this) continue;
-            int nX, nY;
-            (*neighbor)->getApproxCenter(&nX, &nY);
-            // 'right' means slope between (-1/3, 1/3), positive X change
-            if ( (nX - cX) > 0 ) {
-                float slope = ((float)(nY - cY)) / (nX - cX);
-                if (slope > -0.33 && slope < 0.33) {
-                    int distSq = (nX - cX) * (nX - cX) + (nY - cY) * (nY - cY);
-                    if (distSq < rDistSq) {
-                        setRNeighbor(*neighbor);
-                        rDistSq = distSq;
-                    }
-                }
-            }
-            // 'down' means inv slope between (-1/3, 1/3), positive Y change
-            if ( (nY - cY) > 0) {
-                float invSlope = ((float)(nX - cX)) / (nY - cY);
-                if (invSlope > -0.33 && invSlope < 0.33) {
-                    int distSq = (nX - cX) * (nX - cX) + (nY - cY) * (nY - cY);
-                    if (distSq < dDistSq) {
-                        setDNeighbor(*neighbor);
-                        dDistSq = distSq;
-                    }
-                }
-            }
-        }
-        // Do reverse links if possible
-        if (getRNeighbor() != NULL) {
-            getRNeighbor()->setLNeighbor(this);
-        }
-        if (getDNeighbor() != NULL) {
-            getDNeighbor()->setUNeighbor(this);
-        }
-
-    }
-
-    void setRNeighbor(PixelGroup *rNeighbor) {
-        mRNeighbor = rNeighbor;
-    }
-
-    PixelGroup* getRNeighbor(int distance = 1)  {
-        PixelGroup *current = this;
-        for (int i=0; i < distance; i++) {
-            if (current != NULL) {
-                current = current->mRNeighbor;
-            } else break;
-        }
-        return current;
-    }
-
-    void setDNeighbor(PixelGroup *dNeighbor) {
-        mDNeighbor = dNeighbor;
-    }
-
-    PixelGroup* getDNeighbor(int distance = 1) {
-        PixelGroup *current = this;
-        for (int i=0; i < distance; i++) {
-            if (current != NULL) {
-                current = current->mDNeighbor;
-            } else break;
-        }
-        return current;
-    }
-
-    void setLNeighbor(PixelGroup *lNeighbor) {
-        mLNeighbor = lNeighbor;
-    }
-
-    PixelGroup* getLNeighbor(int distance = 1) {
-        PixelGroup *current = this;
-        for (int i=0; i < distance; i++) {
-            if (current != NULL) {
-                current = current->mLNeighbor;
-            } else break;
-        }
-        return current;
-    }
-
-    void setUNeighbor(PixelGroup *uNeighbor) {
-        mUNeighbor = uNeighbor;
-    }
-
-    PixelGroup* getUNeighbor(int distance = 1) {
-        PixelGroup *current = this;
-        for (int i=0; i < distance; i++) {
-            if (current != NULL) {
-                current = current->mUNeighbor;
-            } else break;
-        }
-        return current;
-    }
-
-    float distanceSqTo(const PixelGroup* other) {
-        int mX, mY;
-        getApproxCenter(&mX, &mY);
-        int oX, oY;
-        other->getApproxCenter(&oX, &oY);
-        int dx = (oX - mX);
-        int dy = (oY - mY);
-        return dx * dx + dy * dy;
-    }
-
-    float distanceTo(const PixelGroup* other) {
-        return sqrt( distanceSqTo(other) );
-    }
-
-  private:
-    int mId;
-    int mMinX, mMinY;
-    int mMaxX, mMaxY;
-    int mArea;
-    int mSum[3];
-    const ImageField *mSrc;
-
-    PixelGroup *mRNeighbor;
-    PixelGroup *mDNeighbor;
-    PixelGroup *mLNeighbor;
-    PixelGroup *mUNeighbor;
-};
-
-/* Scales input down by factor of outScale to output. Assumes input size is
- * exactly output size times scale */
-void downsample(const unsigned char *input,
-                unsigned char *output,
-                int rowSpan,
-                int outWidth,
-                int outHeight,
-                int outScale) {
-    for (int oY = 0, iY = 0; oY < outHeight; oY++, iY += outScale) {
-        for (int oX = 0, iX = 0; oX < outWidth; oX++, iX += outScale) {
-            short out[3] = {0,0,0};
-            const unsigned char *in = input + iY * rowSpan + iX * totalChannels;
-            for (int j = 0; j < outScale; j++) {
-                for (int k = 0; k < outScale; k++) {
-                    for (int i = 0; i < colorChannels; i++) {
-                        out[i] += in[i];
-                    }
-                    in += totalChannels;
-                }
-                in += rowSpan - outScale * totalChannels;
-            }
-            output[0] = out[0] / (outScale * outScale);
-            output[1] = out[1] / (outScale * outScale);
-            output[2] = out[2] / (outScale * outScale);
-            output += totalChannels;
-        }
-    }
-}
-
-void drawLine(unsigned char *image,
-              int rowSpan,
-              int x0, int y0,
-              int x1, int y1,
-              int r, int g, int b) {
-    if ((x0 == x1) && (y0 == y1)) {
-        unsigned char *p = &image[(y0 * rowSpan + x0) * totalChannels];
-        if (r != -1) p[0] = r;
-        if (g != -1) p[1] = g;
-        if (b != -1) p[2] = b;
-        return;
-    }
-    if ( std::abs(x1-x0) > std::abs(y1-y0) ) {
-        if (x0 > x1) {
-            std::swap(x0, x1);
-            std::swap(y0, y1);
-        }
-        float slope = (float)(y1 - y0) / (x1 - x0);
-        for (int x = x0; x <= x1; x++) {
-            int y = y0 + slope * (x - x0);
-            unsigned char *p = &image[(y * rowSpan + x) * totalChannels];
-            if (r != -1) p[0] = r;
-            if (g != -1) p[1] = g;
-            if (b != -1) p[2] = b;
-        }
-    } else {
-        if (y0 > y1) {
-            std::swap(x0, x1);
-            std::swap(y0, y1);
-        }
-        float invSlope = (float)(x1 - x0) / (y1 - y0);
-        for (int y = y0; y <= y1; y++) {
-            int x = x0 + invSlope * (y - y0);
-            unsigned char *p = &image[(y*rowSpan + x) * totalChannels];
-            if (r != -1) p[0] = r;
-            if (g != -1) p[1] = g;
-            if (b != -1) p[2] = b;
-        }
-    }
-
-}
-bool findColorChecker(const unsigned char *image,
-                      int width,
-                      int rowSpan,
-                      int height,
-                      float *patchColors,
-                      unsigned char **outputImage,
-                      int *outputWidth,
-                      int *outputHeight) {
-    int64_t startTime = systemTime();
-
-    const int outTargetWidth = 160;
-    const int outScale = width / outTargetWidth;
-    const int outWidth = width / outScale;
-    const int outHeight = height / outScale;
-    LOGV("Debug image dimensions: %d, %d", outWidth, outHeight);
-
-    unsigned char *output = new unsigned char[outWidth * outHeight * totalChannels];
-
-    unsigned char *outP;
-    unsigned char *inP;
-
-    // First step, downsample for speed/noise reduction
-    downsample(image, output, rowSpan, outWidth, outHeight, outScale);
-
-    // Find connected components (groups)
-    ImageField outField(outWidth, outHeight, output);
-    Grouping(&outField);
-
-    // Calculate component bounds and areas
-    std::vector<PixelGroup> groups;
-    groups.reserve(outField.id_no);
-    for (int i = 0; i < outField.id_no; i++) {
-        groups.push_back(PixelGroup(i + 1, &outField));
-    }
-
-    inP = output;
-    for (int y = 0; y < outHeight; y++) {
-        for (int x = 0; x < outWidth; x++) {
-            groups[ outField(y, x).id - 1].growGroup(x, y);
-        }
-    }
-
-    // Filter out groups that are too small, too large, or have too
-    // non-square aspect ratio
-    PixelGroup::IdSet candidateGroups;
-
-    // Maximum/minimum width assuming pattern is fully visible and >
-    // 1/3 the image in width
-    const int maxPatchWidth = outWidth / 6;
-    const int minPatchWidth = outWidth / 3 / 7;
-    const int maxPatchArea = maxPatchWidth * maxPatchWidth;
-    const int minPatchArea = minPatchWidth * minPatchWidth;
-    // Assuming nearly front-on view of target, so aspect ratio should
-    // be quite close to square
-    const float maxAspectRatio = 5.f / 4.f;
-    const float minAspectRatio = 4.f / 5.f;
-    for (int i = 0; i < (int)groups.size(); i++) {
-        float aspect = groups[i].getApproxAspectRatio();
-        if (aspect < minAspectRatio || aspect > maxAspectRatio) continue;
-        // Check both boundary box area, and actual pixel count - they
-        // should both be within bounds for a roughly square patch.
-        int boundArea = groups[i].getBoundArea();
-        if (boundArea < minPatchArea || boundArea > maxPatchArea) continue;
-        int area = groups[i].getArea();
-        if (area < minPatchArea || area > maxPatchArea) continue;
-        candidateGroups.insert(&groups[i]);
-    }
-
-    // Find neighbors for candidate groups. O(n^2), but not many
-    // candidates to go through
-    for (PixelGroup::IdSetIter group = candidateGroups.begin();
-         group != candidateGroups.end();
-         group++) {
-        (*group)->findNeighbors(candidateGroups);
-    }
-
-    // Try to find a plausible 6x4 grid by taking each pixel group as
-    // the candidate top-left corner and try to build a grid from
-    // it. Assumes no missing patches.
-    float bestError = -1;
-    std::vector<int> bestGrid(6 * 4,0);
-    for (PixelGroup::IdSetIter group = candidateGroups.begin();
-         group != candidateGroups.end();
-         group++) {
-        int dex, dey; (*group)->getApproxCenter(&dex, &dey);
-        std::vector<int> grid(6 * 4, 0);
-        PixelGroup *tl = *group;
-        PixelGroup *bl, *tr, *br;
-
-        // Find the bottom-left and top-right corners
-        if ( (bl = tl->getDNeighbor(3)) == NULL ||
-             (tr = tl->getRNeighbor(5)) == NULL ) continue;
-        LOGV("Candidate at %d, %d", dex, dey);
-        LOGV("  Got BL and TR");
-
-        // Find the bottom-right corner
-        if ( tr->getDNeighbor(3) == NULL ) {
-            LOGV("  No BR from TR");
-            continue;
-        }
-        br = tr->getDNeighbor(3);
-        if ( br != bl->getRNeighbor(5) ) {
-            LOGV("  BR from TR and from BL don't agree");
-            continue;
-        }
-        br->getApproxCenter(&dex, &dey);
-        LOGV("  Got BR corner at %d, %d", dex, dey);
-
-        // Check that matching grid edge lengths are about the same
-        float gridTopWidth = tl->distanceTo(tr);
-        float gridBotWidth = bl->distanceTo(br);
-
-        if (gridTopWidth / gridBotWidth < minAspectRatio ||
-            gridTopWidth / gridBotWidth > maxAspectRatio) continue;
-        LOGV("  Got reasonable widths: %f %f", gridTopWidth, gridBotWidth);
-
-        float gridLeftWidth = tl->distanceTo(bl);
-        float gridRightWidth = tr->distanceTo(br);
-
-        if (gridLeftWidth / gridRightWidth < minAspectRatio ||
-            gridLeftWidth / gridRightWidth > maxAspectRatio) continue;
-        LOGV("  Got reasonable heights: %f %f", gridLeftWidth, gridRightWidth);
-
-        // Calculate average grid spacing
-        float gridAvgXGap = (gridTopWidth + gridBotWidth) / 2 / 5;
-        float gridAvgYGap = (gridLeftWidth + gridRightWidth) / 2 / 3;
-
-        // Calculate total error between average grid spacing and
-        // actual spacing Uses difference in expected squared distance
-        // and actual squared distance
-        float error = 0;
-        for (int x = 0; x < 6; x++) {
-            for (int y = 0; y < 4; y++) {
-                PixelGroup *node;
-                node = tl->getRNeighbor(x)->getDNeighbor(y);
-                if (node == NULL) {
-                    error += outWidth * outWidth;
-                    grid[y * 6 + x] = 0;
-                } else {
-                    grid[y * 6 + x] = node->getId();
-                    if (node == tl) continue;
-                    float dist = tl->distanceSqTo(node);
-                    float expXDist = (gridAvgXGap * x);
-                    float expYDist = (gridAvgYGap * y);
-                    float expDist =  expXDist * expXDist + expYDist * expYDist;
-                    error += fabs(dist - expDist);
-                }
-            }
-        }
-        if (bestError == -1 ||
-            bestError > error) {
-            bestGrid = grid;
-            bestError = error;
-            LOGV("  Best candidate, error %f", error);
-        }
-    }
-
-    // Check if a grid wasn't found
-    if (bestError == -1) {
-        LOGV("No color checker found!");
-    }
-
-    // Make sure black square is in bottom-right corner
-    if (bestError != -1) {
-        unsigned char tlValues[3];
-        unsigned char brValues[3];
-        int tlId = bestGrid[0];
-        int brId = bestGrid[23];
-
-        groups[tlId - 1].getAvgValue(tlValues);
-        groups[brId - 1].getAvgValue(brValues);
-
-        int tlSum = tlValues[0] + tlValues[1] + tlValues[2];
-        int brSum = brValues[0] + brValues[1] + brValues[2];
-        if (brSum > tlSum) {
-            // Grid is upside down, need to flip!
-            LOGV("Flipping grid to put grayscale ramp at bottom");
-            bestGrid = std::vector<int>(bestGrid.rbegin(), bestGrid.rend());
-        }
-    }
-
-    // Output average patch colors if requested
-    if (bestError != -1 && patchColors != NULL) {
-        for (int n = 0; n < 6 * 4 * colorChannels; n++) patchColors[n] = -1.f;
-
-        // Scan over original input image for grid regions, degamma, average
-        for (int px = 0; px < 6; px++) {
-            for (int py = 0; py < 4; py++) {
-                int id = bestGrid[py * 6 + px];
-                if (id == 0) continue;
-
-                PixelGroup &patch = groups[id - 1];
-                int startX, startY;
-                int endX, endY;
-                patch.getBoundingBox(&startX, &startY, &endX, &endY);
-
-                float sum[colorChannels] = {0.f};
-                int count = 0;
-                for (int y = startY; y <= endY; y++) {
-                    for (int x = startX; x < endX; x++) {
-                        if (outField(y,x).id != id) continue;
-                        for (int iY = y * outScale;
-                             iY < (y + 1) * outScale;
-                             iY++) {
-                            const unsigned char *inP = image +
-                                    (iY * rowSpan)
-                                    + (x * outScale * totalChannels);
-                            for (int iX = 0; iX < outScale; iX++) {
-                                for (int c = 0; c < colorChannels; c++) {
-                                    // Convert to float and normalize
-                                    float v = inP[c] / 255.f;
-                                    // Gamma correct to get back to
-                                    // roughly linear data
-                                    v = pow(v, gammaCorrection);
-                                    // Sum it up
-                                    sum[c] += v;
-                                }
-                                count++;
-                                inP += totalChannels;
-                            }
-                        }
-                    }
-                }
-                for (int c = 0 ; c < colorChannels; c++) {
-                    patchColors[ (py * 6  + px) * colorChannels + c ] =
-                            sum[c] / count;
-                }
-            }
-        }
-        // Print out patch colors
-        IF_LOGV() {
-            for (int y = 0; y < 4; y++) {
-                char tmpMsg[256];
-                int cnt = 0;
-                cnt = snprintf(tmpMsg, 256, "%02d:", y + 1);
-                for (int x = 0; x < 6; x++) {
-                    int id = bestGrid[y * 6 + x];
-                    if (id != 0) {
-                        float *p = &patchColors[ (y * 6 + x) * colorChannels];
-                        cnt += snprintf(tmpMsg + cnt, 256 - cnt,
-                                        "\t(%.3f,%.3f,%.3f)", p[0], p[1], p[2]);
-                    } else {
-                        cnt += snprintf(tmpMsg + cnt, 256 - cnt,
-                                        "\t(xxx,xxx,xxx)");
-                    }
-                }
-                LOGV("%s", tmpMsg);
-            }
-        }
-    }
-
-    // Draw output if requested
-    if (outputImage != NULL) {
-        *outputImage = output;
-        *outputWidth = outWidth;
-        *outputHeight = outHeight;
-
-        // Draw all candidate group bounds
-        for (PixelGroup::IdSetIter group = candidateGroups.begin();
-             group != candidateGroups.end();
-             group++) {
-
-            int x,y;
-            (*group)->getApproxCenter(&x, &y);
-
-            // Draw candidate bounding box
-            int x0, y0, x1, y1;
-            (*group)->getBoundingBox(&x0, &y0, &x1, &y1);
-            drawLine(output, outWidth,
-                     x0, y0, x1, y0,
-                     255, 0, 0);
-            drawLine(output, outWidth,
-                     x1, y0, x1, y1,
-                     255, 0, 0);
-            drawLine(output, outWidth,
-                     x1, y1, x0, y1,
-                     255, 0, 0);
-            drawLine(output, outWidth,
-                     x0, y1, x0, y0,
-                     255, 0, 0);
-
-            // Draw lines between neighbors
-            // Red for to-right and to-below of me connections
-            const PixelGroup *neighbor;
-            if ( (neighbor = (*group)->getRNeighbor()) != NULL) {
-                int nX, nY;
-                neighbor->getApproxCenter(&nX, &nY);
-                drawLine(output,
-                         outWidth,
-                         x, y, nX, nY,
-                         255, -1, -1);
-            }
-            if ( (neighbor = (*group)->getDNeighbor()) != NULL) {
-                int nX, nY;
-                neighbor->getApproxCenter(&nX, &nY);
-                drawLine(output,
-                         outWidth,
-                         x, y, nX, nY,
-                         255, -1, -1);
-            }
-            // Blue for to-left or to-above of me connections
-            if ( (neighbor = (*group)->getLNeighbor()) != NULL) {
-                int nX, nY;
-                neighbor->getApproxCenter(&nX, &nY);
-                drawLine(output,
-                         outWidth,
-                         x, y, nX, nY,
-                         -1, -1, 255);
-            }
-            if ( (neighbor = (*group)->getUNeighbor()) != NULL) {
-                int nX, nY;
-                neighbor->getApproxCenter(&nX, &nY);
-                drawLine(output,
-                         outWidth,
-                         x, y, nX, nY,
-                         -1, -1, 255);
-            }
-        }
-
-        // Mark found grid patch pixels
-        if (bestError != -1) {
-            for (int x=0; x < 6; x++) {
-                for (int y =0; y < 4; y++) {
-                    int id = bestGrid[y * 6 + x];
-                    if (id != 0) {
-                        int x0, y0, x1, y1;
-                        groups[id - 1].getBoundingBox(&x0, &y0, &x1, &y1);
-                        // Fill patch pixels with blue
-                        for (int px = x0; px < x1; px++) {
-                            for (int py = y0; py < y1; py++) {
-                                if (outField(py,px).id != id) continue;
-                                unsigned char *p =
-                                        &output[(py * outWidth + px)
-                                                * totalChannels];
-                                p[0] = 0;
-                                p[1] = 0;
-                                p[2] = 255;
-
-                            }
-                        }
-                        drawLine(output, outWidth,
-                                 x0, y0, x1, y1,
-                                 0, 255, 0);
-                        drawLine(output, outWidth,
-                                 x0, y1, x0, y1,
-                                 0, 255, 0);
-                    }
-                }
-            }
-        }
-
-    } else {
-        delete output;
-    }
-
-    int64_t endTime = systemTime();
-    LOGV("Process time: %f ms",
-         (endTime - startTime) / 1000000.);
-
-    if (bestError == -1) return false;
-
-    return true;
-}
diff --git a/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp b/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
new file mode 100644
index 0000000..bc421eb
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/colorcheckertest.cpp
@@ -0,0 +1,943 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ColorCheckerTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "colorcheckertest.h"
+
+const float GAMMA_CORRECTION = 2.2f;
+ColorCheckerTest::~ColorCheckerTest() {
+    ALOGV("Deleting color checker test handler");
+
+    if (mImage != NULL) {
+        delete mImage;
+    }
+    ALOGV("Image deleted");
+
+    int numHorizontalLines = mCandidateColors.size();
+    int numVerticalLines = mCandidateColors[0].size();
+
+    for (int i = 0; i < numHorizontalLines; ++i) {
+        for (int j = 0; j < numVerticalLines; ++j) {
+            if (mCandidateColors[i][j] != NULL) {
+                delete mCandidateColors[i][j];
+            }
+            if (mCandidatePositions[i][j] != NULL) {
+                delete mCandidatePositions[i][j];
+            }
+        }
+    }
+    ALOGV("Candidates deleted!");
+
+    for (int i = 0; i < 4; ++i) {
+        for (int j = 0; j < 6; ++j) {
+            if (mMatchPositions[i][j] != NULL) {
+                delete mMatchPositions[i][j];
+            }
+            if (mReferenceColors[i][j] != NULL) {
+                delete mReferenceColors[i][j];
+            }
+            if (mMatchColors[i][j] != NULL) {
+                delete mMatchColors[i][j];
+            }
+        }
+    }
+}
+
+// Adds a new image to the test handler.
+void ColorCheckerTest::addTestingImage(TestingImage* inputImage) {
+    if (mImage != NULL) {
+        delete mImage;
+    }
+    mImage = NULL;
+    ALOGV("Original image deleted");
+    mImage = inputImage;
+
+    if ((mImage->getHeight() == getDebugHeight()) &&
+        (mImage->getWidth() == getDebugWidth())) {
+        copyDebugImage(getDebugHeight(), getDebugWidth(), mImage->getImage());
+    }
+}
+
+void ColorCheckerTest::processData() {
+    mSuccess = false;
+    initializeRefColor();
+    edgeDetection();
+}
+
+void ColorCheckerTest::initializeRefColor() {
+    mReferenceColors.resize(4, std::vector<Vec3i*>(6, NULL));
+    mMatchPositions.resize(4, std::vector<Vec2f*>(6, NULL));
+    mMatchColors.resize(4, std::vector<Vec3f*>(6, NULL));
+    mMatchRadius.resize(4, std::vector<float>(6, 0.f));
+
+    mReferenceColors[0][0]= new Vec3i(115, 82, 68);
+    mReferenceColors[0][1]= new Vec3i(194, 150, 130);
+    mReferenceColors[0][2]= new Vec3i(98, 122, 157);
+    mReferenceColors[0][3]= new Vec3i(87, 108, 67);
+    mReferenceColors[0][4]= new Vec3i(133, 128, 177);
+    mReferenceColors[0][5]= new Vec3i(103, 189, 170);
+    mReferenceColors[1][0]= new Vec3i(214, 126, 44);
+    mReferenceColors[1][1]= new Vec3i(80, 91, 166);
+    mReferenceColors[1][2]= new Vec3i(193, 90, 99);
+    mReferenceColors[1][3]= new Vec3i(94,  60, 108);
+    mReferenceColors[1][4]= new Vec3i(157, 188, 64);
+    mReferenceColors[1][5]= new Vec3i(224, 163, 46);
+    mReferenceColors[2][0]= new Vec3i(56, 61, 150);
+    mReferenceColors[2][1]= new Vec3i(70, 148, 73);
+    mReferenceColors[2][2]= new Vec3i(175, 54, 60);
+    mReferenceColors[2][3]= new Vec3i(231, 199, 31);
+    mReferenceColors[2][4]= new Vec3i(187, 86, 149);
+    mReferenceColors[2][5]= new Vec3i(8, 133, 161);
+    mReferenceColors[3][0]= new Vec3i(243, 243, 242);
+    mReferenceColors[3][1]= new Vec3i(200, 200, 200);
+    mReferenceColors[3][2]= new Vec3i(160, 160, 160);
+    mReferenceColors[3][3]= new Vec3i(122, 122, 121);
+    mReferenceColors[3][4]= new Vec3i(85, 85, 85);
+    mReferenceColors[3][5]= new Vec3i(52, 52, 52);
+}
+
+void ColorCheckerTest::edgeDetection() {
+    int width = mImage->getWidth();
+    int height = mImage->getHeight();
+
+    bool* edgeMap = new bool[height * width];
+    unsigned char* grayImage = new unsigned char[height * width];
+
+    // If the image is a color image and can be converted to a luminance layer
+    if (mImage->rgbToGrayScale(grayImage)) {
+        float* gradientMap = new float[height * width * 2];
+
+        // Computes the gradient image on the luminance layer.
+        computeGradient(grayImage, gradientMap);
+
+        float* gradientMagnitude = new float[height * width];
+        int* gradientDirectionInt = new int[height * width];
+        float* gradientDirection = new float[height * width];
+
+        // Computes the absolute gradient of the image without padding.
+        for (int i = 1; i < height - 1; ++i) {
+            for (int j = 1; j < width - 1; ++j) {
+                gradientMagnitude[i * width + j] =
+                        sqrt(gradientMap[(i * width + j) * 2] *
+                             gradientMap[(i * width + j) * 2] +
+                             gradientMap[(i * width + j ) * 2 + 1] *
+                             gradientMap[(i * width + j ) * 2 + 1]);
+
+                // Computes the gradient direction of the image.
+                if (gradientMap[(i * width + j) * 2] == 0 ) {
+                    // If the vertical gradient is 0, the edge is horizontal
+                    // Mark the gradient direction as 90 degrees.
+                    gradientDirectionInt[i * width + j] = 2;
+                    gradientDirection[i * width + j] = 90.0f;
+                } else {
+                    // Otherwise the atan operation is valid and can decide
+                    // the gradient direction of the edge.
+                    float gradient = atan(gradientMap[(i * width + j) * 2 + 1]
+                            / gradientMap[(i * width + j) * 2])
+                            / (M_PI / 4);
+
+                    gradientDirection[i * width + j] = gradient * 45.0f;
+
+                    // Maps the gradient direction to 4 major directions with
+                    // 0 mapped to up and 2 mapped to right.
+                    if (gradient - floor(gradient) > 0.5) {
+                        gradientDirectionInt[i * width + j] =
+                                (static_cast<int>(ceil(gradient)) + 4) % 4;
+                    } else {
+                        gradientDirectionInt[i * width + j] =
+                                (static_cast<int>(floor(gradient)) + 4) % 4;
+                    }
+                }
+            }
+        }
+
+        // Compute a boolean map to show whether a pixel is on the edge.
+        for (int i = 1; i < height - 1; ++i) {
+            for (int j = 1; j < width - 1; ++j) {
+                edgeMap[i * width + j] = false;
+
+                switch (gradientDirectionInt[i * width + j]) {
+                    case 0:
+                        // If the gradient points rightwards, the pixel is
+                        // on an edge if it has a larger absolute gradient than
+                        // pixels on its left and right sides.
+                        if ((gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[i * width + j + 1]) &&
+                            (gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[i * width + j - 1])) {
+                            edgeMap[i * width + j] = true;
+                        }
+                        break;
+                    case 1:
+                        // If the gradient points right-downwards, the pixel is
+                        // on an edge if it has a larger absolute gradient than
+                        // pixels on its upper left and bottom right sides.
+                        if ((gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i + 1) * width + j + 1]) &&
+                            (gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i - 1) * width + j - 1])) {
+                            edgeMap[i * width + j] = true;
+                        }
+                        break;
+                    case 2:
+                        // If the gradient points upwards, the pixel is
+                        // on an edge if it has a larger absolute gradient than
+                        // pixels on its up and down sides.
+                        if ((gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i + 1) * width + j]) &&
+                            (gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i - 1) * width + j])) {
+                            edgeMap[i * width + j] = true;
+                        }
+                        break;
+                    case 3:
+                        // If the gradient points right-upwards, the pixel is
+                        // on an edge if it has a larger absolute gradient than
+                        // pixels on its bottom left and upper right sides.
+                        if ((gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i - 1) * width + j + 1]) &&
+                            (gradientMagnitude[i * width + j] >=
+                                gradientMagnitude[(i + 1) * width + j - 1])) {
+                            edgeMap[i * width + j] = true;
+                        }
+                  }
+
+             }
+        }
+
+        houghLineDetection(edgeMap, gradientMagnitude, gradientDirection);
+
+        // Cleans up
+        delete[] gradientMap;
+        delete[] gradientDirectionInt;
+        delete[] gradientMagnitude;
+        delete[] gradientDirection;
+
+    } else {
+        LOGE("Not a color image!");
+    }
+
+    delete[] edgeMap;
+    delete[] grayImage;
+}
+
+// Runs the hough voting algorithm to find the grid of the color checker
+// with the edge map, gradient direction and gradient magnitude as inputs.
+void ColorCheckerTest::houghLineDetection(bool* edgeMap,
+                                          float* gradientMagnitude,
+                                          float* gradientDirection) {
+    // Constructs a graph for Hough voting. The vertical axis counts the vote
+    // for a certain angle. The horizontal axis counts the vote for the distance
+    // of a line from the origin of the image.
+    int houghHeight = 180;
+    int houghWidth = 200;
+    int houghCounts[houghHeight][houghWidth];
+    int houghSum[houghHeight][houghWidth];
+
+    int** houghVote;
+    houghVote = new int*[180];
+    for (int i = 0; i < 180; ++i) {
+        houghVote[i] = new int[200];
+    }
+
+    for (int i = 0; i < houghHeight; ++i) {
+        for (int j = 0; j < houghWidth; ++j) {
+            houghCounts[i][j] = 0;
+            houghVote[i][j] = 0;
+            houghSum[i][j] = 0;
+        }
+    }
+
+    // Vectors to record lines in two orthogonal directions.
+    // Each line is represented by its direction and its distance to the origin.
+    std::vector<std::vector<int> > verticalLines;
+    std::vector<std::vector<int> > horizontalLines;
+    float radius;
+    int height = mImage->getHeight();
+    int width = mImage->getWidth();
+
+    // Processes the signicant edge pixels and cast vote for the corresponding
+    // edge passing this pixel.
+    for (int i = 1; i < height - 1; ++i) {
+        for (int j = 1; j < width - 1; ++j) {
+            // Sets threashold for the gradient magnitude to discount noises
+            if (edgeMap[i * width + j] &&
+                (gradientMagnitude[i * width + j] > 15)) {
+                int shiftedAngle;
+
+                // Shifts angles for 45 degrees so the vertical and horizontal
+                // direction is mapped to 45 and 135 degrees to avoid padding.
+                // This uses the assumption that the color checker is placed
+                // roughly parallel to the image boarders. So that the edges
+                // at the angle of 45 will be rare.
+                shiftedAngle = (static_cast<int>(
+                        -gradientDirection[i * width + j]) + 225 % 180);
+                float shiftedAngleRad = static_cast<float>(shiftedAngle)
+                        * M_PI / 180.0f;
+
+                // Computes the distance of the line from the origin.
+                float a, b;
+                a = static_cast<float>(i - j) / sqrt(2.0f);
+                b = static_cast<float>(i + j) / sqrt(2.0f);
+                radius = a * sin(shiftedAngleRad) - b * cos(shiftedAngleRad);
+
+                // Adds one vote for the line. The line's angle is shifted by
+                // 45 degrees to avoid avoid padding for the vertical lines,
+                // which is more common than diagonal lines. The line's
+                // distance is mapped to [0, 200] from [-200, 200].
+                ++houghCounts[shiftedAngle][static_cast<int>((radius / 2.0f) +
+                                                              100.0f)];
+
+                drawPoint(i, j, Vec3i(255, 255, 255));
+            }
+        }
+    }
+
+    int houghAngleSum[houghHeight];
+    int primaryVerticalAngle, primaryHorizontalAngle;
+    int max1 = 0;
+    int max2 = 0;
+
+    // Looking for the two primary angles of the lines.
+    for (int i = 5; i < houghHeight - 5; ++i) {
+        houghAngleSum[i] = 0;
+        for (int j = 0; j < houghWidth; ++j) {
+            for (int l = -5; l <= 5; ++l) {
+                houghSum[i][j] += houghCounts[i + l][j];
+            }
+            houghAngleSum[i] += houghSum[i][j];
+        }
+
+        if ((i < houghHeight / 2) && (houghAngleSum[i] > max1)) {
+            max1 = houghAngleSum[i];
+            primaryVerticalAngle = i;
+        } else if ((i > houghHeight / 2) && (houghAngleSum[i] > max2)) {
+            max2 = houghAngleSum[i];
+            primaryHorizontalAngle = i;
+        }
+    }
+
+    ALOGV("Primary angles are %d, %d",
+         primaryVerticalAngle, primaryHorizontalAngle);
+
+    int angle;
+
+    // For each primary angle, look for the highest voted lines.
+    for (int k = 0; k < 2; ++k) {
+        if (k == 0) {
+            angle = primaryVerticalAngle;
+        } else {
+            angle = primaryHorizontalAngle;
+        }
+
+        std::vector<int> line(2);
+        for (int j = 2; j < houghWidth - 2; ++j) {
+            houghVote[angle][j] = houghSum[angle][j];
+            houghSum[angle][j] = 0;
+        }
+
+        // For each radius, average the vote with nearby ones.
+        for (int j = 2; j < houghWidth - 2; ++j) {
+            for (int m = -2; m <= 2; ++m) {
+                houghSum[angle][j] += houghVote[angle][j + m];
+            }
+        }
+
+        bool isCandidate[houghWidth];
+
+        // Find whether a lines is a candidate by rejecting the ones that have
+        // lower vote than others in the neighborhood.
+        for (int j = 2; j < houghWidth - 2; ++j) {
+            isCandidate[j] = true;
+            for (int m = -2; ((isCandidate[j]) && (m <= 2)); ++m) {
+                if ((houghSum[angle][j] < 20) ||
+                    (houghSum[angle][j] < houghSum[angle][j + m])) {
+                    isCandidate[j] = false;
+                }
+            }
+        }
+
+        int iter1 = 0;
+        int iter2 = 0;
+        int count = 0;
+
+        // Finds the lines that are not too close to each other and add to the
+        // detected lines.
+        while (iter2 < houghWidth) {
+            while ((!isCandidate[iter2]) && (iter2 < houghWidth)) {
+                ++iter2;
+            }
+            if ((isCandidate[iter2]) && (iter2 - iter1 < 5)) {
+                iter1 = (iter2 + iter1) / 2;
+                ++iter2;
+            } else {
+                line[0] = angle;
+                line[1] = (iter1 - 100) * 2;
+                if (iter1 != 0) {
+                    if (k == 0) {
+                        verticalLines.push_back(line);
+                        Vec3i color(verticalLines.size() * 20, 0, 0);
+                        drawLine(line[0], line[1], color);
+                    } else {
+                        horizontalLines.push_back(line);
+                        Vec3i color(0, horizontalLines.size() * 20, 0);
+                        drawLine(line[0], line[1], color);
+                    }
+                }
+                iter1 = iter2;
+                ++iter2;
+                ALOGV("pushing back line %d %d", line[0], line[1]);
+            }
+        }
+    }
+
+    ALOGV("Numbers of lines in each direction is %d, %d",
+         verticalLines.size(), horizontalLines.size());
+
+    for (int i = 0; i < 180; ++i) {
+        delete[] houghVote[i];
+    }
+    delete[] houghVote;
+
+    findCheckerBoards(verticalLines, horizontalLines);
+}
+
+// Computes the gradient in both x and y direction of a layer
+void ColorCheckerTest::computeGradient(unsigned char* layer,
+                                       float* gradientMap) {
+    int width = mImage->getWidth();
+    int height = mImage->getHeight();
+
+    // Computes the gradient in the whole image except the image boarders.
+    for (int i = 1; i < height - 1; ++i) {
+        for (int j = 1; j < width - 1; ++j) {
+            gradientMap[(i * width + j) * 2] =
+                    0.5f * (layer[i * width + j + 1] -
+                            layer[i * width + j - 1]);
+            gradientMap[(i * width + j) * 2 + 1] =
+                    0.5f * (layer[(i + 1) * width + j] -
+                           layer[(i - 1) * width + j]);
+        }
+    }
+}
+
+// Tries to find the checker boards with the highest voted lines
+void ColorCheckerTest::findCheckerBoards(
+        std::vector<std::vector<int> > verticalLines,
+        std::vector<std::vector<int> > horizontalLines) {
+    ALOGV("Start looking for Color checker");
+    int numVerticalLines = verticalLines.size();
+    int numHorizontalLines = horizontalLines.size();
+    Vec2f pointUpperLeft;
+    Vec2f pointBottomRight;
+
+    mCandidateColors.resize(numHorizontalLines - 1);
+    mCandidatePositions.resize(numHorizontalLines - 1);
+
+    for (int i = numVerticalLines - 1; i >= 1; --i) {
+        for (int j = 0; j < numHorizontalLines - 1; ++j) {
+            // Finds the upper left and bottom right corner of each rectangle
+            // formed by two neighboring highest voted lines.
+            pointUpperLeft = findCrossing(verticalLines[i], horizontalLines[j]);
+            pointBottomRight = findCrossing(verticalLines[i - 1],
+                                            horizontalLines[j + 1]);
+
+            Vec3i* color = new Vec3i();
+            Vec2f* pointCenter = new Vec2f();
+            // Verifies if they are separated by a reasonable distance.
+            if (verifyPointPair(pointUpperLeft, pointBottomRight,
+                                pointCenter, color)) {
+                mCandidatePositions[j].push_back(pointCenter);
+                mCandidateColors[j].push_back(color);
+            } else {
+                mCandidatePositions[j].push_back(NULL);
+                mCandidateColors[j].push_back(NULL);
+                delete color;
+                delete pointCenter;
+            }
+        }
+    }
+
+    // Verifies whether the current line candidates form a valid color checker.
+    verifyColorGrid();
+}
+
+// Returns the corssing point of two lines given the lines.
+Vec2f ColorCheckerTest::findCrossing(std::vector<int> line1,
+                                     std::vector<int> line2) {
+    Vec2f crossingPoint;
+    float r1 = static_cast<float>(line1[1]);
+    float r2 = static_cast<float>(line2[1]);
+    float ang1, ang2;
+    float y1, y2;
+
+    ang1 = static_cast<float>(line1[0]) / 180.0f * M_PI;
+    ang2 = static_cast<float>(line2[0]) / 180.0f * M_PI;
+
+    float x, y;
+    x = (r1 * cos(ang2) - r2 * cos(ang1)) / sin(ang1 - ang2);
+    y = (r1 * sin(ang2) - r2 * sin(ang1)) / sin(ang1 - ang2);
+
+    crossingPoint.set((x + y) / sqrt(2.0), (y - x) / sqrt(2.0));
+
+    //ALOGV("Crosspoint at (%f, %f)", crossingPoint.x(), crossingPoint.y());
+    return crossingPoint;
+}
+
+// Verifies whether two opposite corners on a quadrilateral actually can be
+// the two corners of a color checker.
+bool ColorCheckerTest::verifyPointPair(Vec2f pointUpperLeft,
+                                       Vec2f pointBottomRight,
+                                       Vec2f* pointCenter,
+                                       Vec3i* color) {
+    bool success = true;
+
+    /** 5 and 30 are the threshold tuned for resolution 640*480*/
+    if ((pointUpperLeft.x() < 0) ||
+        (pointUpperLeft.x() >= mImage->getHeight()) ||
+        (pointUpperLeft.y() < 0) ||
+        (pointUpperLeft.y() >= mImage->getWidth()) ||
+        (pointBottomRight.x() < 0) ||
+        (pointBottomRight.x() >= mImage->getHeight()) ||
+        (pointBottomRight.y() < 0) ||
+        (pointBottomRight.y() >= mImage->getWidth()) ||
+        (abs(pointUpperLeft.x() - pointBottomRight.x()) <= 5) ||
+        (abs(pointUpperLeft.y() - pointBottomRight.y()) <= 5) ||
+        (abs(pointUpperLeft.x() - pointBottomRight.x()) >= 30) ||
+        (abs(pointUpperLeft.y() - pointBottomRight.y()) >= 30)) {
+
+        // If any of the quadrilateral corners are out of the image or if
+        // the distance between them are too large or too big, the quadrilateral
+        // could not be one of the checkers
+        success = false;
+    } else {
+        // Find the checker center if the corners of the rectangle meet criteria
+        pointCenter->set((pointUpperLeft.x() + pointBottomRight.x()) / 2.0f,
+                       (pointUpperLeft.y() + pointBottomRight.y()) / 2.0f);
+        color->set(mImage->getPixelValue(*pointCenter).r(),
+                   mImage->getPixelValue(*pointCenter).g(),
+                   mImage->getPixelValue(*pointCenter).b());
+        ALOGV("Color at (%f, %f) is (%d, %d, %d)", pointCenter->x(), pointCenter->y(),color->r(), color->g(), color->b());
+    }
+    return success;
+}
+
+// Verifies the color checker centers and finds the match between the detected
+// color checker and the reference MacBeth color checker
+void ColorCheckerTest::verifyColorGrid() {
+    ALOGV("Start looking for Color Grid");
+    int numHorizontalLines = mCandidateColors.size();
+    int numVerticalLines = mCandidateColors[0].size();
+    bool success = false;
+
+    // Computes the standard deviation of one row/column of the proposed color
+    // checker. Discards the row/column if the std is below a threshold.
+    for (int i = 0; i < numHorizontalLines; ++i) {
+        Vec3f meanColor(0.f, 0.f, 0.f);
+        int numNonZero = 0;
+
+        for (int j = 0; j < numVerticalLines; ++j) {
+            if (mCandidateColors[i][j] != NULL) {
+                ALOGV("candidate color (%d, %d) is (%d, %d, %d)", i, j, mCandidateColors[i][j]->r(), mCandidateColors[i][j]->g(), mCandidateColors[i][j]->b());
+
+                meanColor = meanColor + (*mCandidateColors[i][j]);
+                ++numNonZero;
+            }
+        }
+        if (numNonZero > 0) {
+            meanColor = meanColor / numNonZero;
+        }
+        ALOGV("Mean color for vertical direction computed!");
+
+        float std = 0;
+        for (int j = 0; j < numVerticalLines; ++j) {
+            if (mCandidateColors[i][j] != NULL) {
+                std += mCandidateColors[i][j]->squareDistance<float>(meanColor);
+            }
+        }
+        if (numNonZero > 0) {
+            std = sqrt(std / (3 * numNonZero));
+        }
+        ALOGV("st. deviation for the %d dir1 is %d", i, static_cast<int>(std));
+
+        if ((std <= 30) && (numNonZero > 1)) {
+            for (int j = 0; j < numVerticalLines; ++j) {
+                if (mCandidateColors[i][j] != NULL) {
+                    delete mCandidateColors[i][j];
+                    mCandidateColors[i][j] = NULL;
+                }
+            }
+        }
+    }
+
+    // Discards the column/row of the color checker if the std is below a
+    // threshold.
+    for (int j = 0; j < numVerticalLines; ++j) {
+        Vec3f meanColor(0.f, 0.f, 0.f);
+        int numNonZero = 0;
+
+        for (int i = 0; i < numHorizontalLines; ++i) {
+            if (mCandidateColors[i][j] != NULL) {
+                meanColor = meanColor + (*mCandidateColors[i][j]);
+                ++numNonZero;
+            }
+        }
+        if (numNonZero > 0) {
+            meanColor = meanColor / numNonZero;
+        }
+
+        float std = 0;
+        for (int i = 0; i < numHorizontalLines; ++i) {
+            if (mCandidateColors[i][j] != NULL) {
+                std += mCandidateColors[i][j]->squareDistance<float>(meanColor);
+            }
+        }
+        if (numNonZero > 0) {
+            std = sqrt(std / (3 * numNonZero));
+        }
+
+        ALOGV("st. deviation for the %d dir2 is %d", j, static_cast<int>(std));
+
+        if ((std <= 30) && (numNonZero > 1)) {
+            for (int i = 0; i < numHorizontalLines; ++i) {
+                if (mCandidateColors[i][j] != NULL) {
+                    delete mCandidateColors[i][j];
+                    mCandidateColors[i][j] = NULL;
+                }
+            }
+        }
+    }
+
+    for (int i = 0; i < numHorizontalLines; ++i) {
+        for (int j = 0; j < numVerticalLines; ++j) {
+            if (mCandidateColors[i][j] != NULL) {
+                ALOGV("position (%d, %d) is at (%f, %f) with color (%d, %d, %d)",
+                     i, j,
+                     mCandidatePositions[i][j]->x(),
+                     mCandidatePositions[i][j]->y(),
+                     mCandidateColors[i][j]->r(),
+                     mCandidateColors[i][j]->g(),
+                     mCandidateColors[i][j]->b());
+            } else {
+                ALOGV("position (%d, %d) is 0", i, j);
+            }
+        }
+    }
+
+    // Finds the match between the detected color checker and the reference
+    // MacBeth color checker.
+    int rowStart = 0;
+    int rowEnd = 0;
+
+    // Loops until all dectected color checker has been processed.
+    while (!success) {
+        int columnStart = 0;
+        int columnEnd = 0;
+        bool isRowStart = false;
+        bool isRowEnd = true;
+
+        // Finds the row start of the next block of detected color checkers.
+        while ((!isRowStart) && (rowStart <  numHorizontalLines)) {
+            for (int j = 0; j < numVerticalLines; ++j) {
+                if (mCandidateColors[rowStart][j] != NULL) {
+                    isRowStart = true;
+                }
+            }
+            ++rowStart;
+        }
+        rowStart--;
+        rowEnd = rowStart;
+        ALOGV("rowStart is %d", rowStart);
+
+        // Finds the row end of the next block of detected color checkers.
+        while ((isRowEnd) && (rowEnd < numHorizontalLines)) {
+            isRowEnd = false;
+            for (int j = 0; j < numVerticalLines; ++j) {
+                if (mCandidateColors[rowEnd][j] != NULL) {
+                    isRowEnd= true;
+                }
+            }
+            if (isRowEnd) {
+                ++rowEnd;
+            }
+        }
+        if ((!isRowEnd) && isRowStart) {
+            rowEnd--;
+        }
+        if ((isRowEnd) && (rowEnd == numHorizontalLines)) {
+            rowEnd--;
+            isRowEnd = false;
+        }
+        ALOGV("rowEnd is %d", rowEnd);
+
+        // Matches color checkers between the start row and the end row.
+        bool successVertical = false;
+
+        while (!successVertical) {
+            bool isColumnEnd = true;
+            bool isColumnStart = false;
+
+            // Finds the start column of the next block of color checker
+            while ((!isColumnStart) && (columnStart < numVerticalLines)) {
+                if (mCandidateColors[rowStart][columnStart] != NULL) {
+                    isColumnStart = true;
+                }
+                ++columnStart;
+            }
+            columnStart--;
+            columnEnd = columnStart;
+
+            // Finds the end column of the next block of color checker
+            while ((isColumnEnd) && (columnEnd < numVerticalLines)) {
+                isColumnEnd = false;
+                if (mCandidateColors[rowStart][columnEnd] != NULL)
+                    isColumnEnd = true;
+                if (isColumnEnd) {
+                    ++columnEnd;
+                }
+            }
+
+            if ((!isColumnEnd) && isColumnStart) {
+                columnEnd--;
+            }
+            if ((isColumnEnd) && (columnEnd == numVerticalLines)) {
+                columnEnd--;
+                isColumnEnd = false;
+            }
+
+            // Finds the best match on the MacBeth reference color checker for
+            // the continuous block of detected color checker
+            if (isRowStart && (!isRowEnd) &&
+                isColumnStart && (!isColumnEnd)) {
+                findBestMatch(rowStart, rowEnd, columnStart, columnEnd);
+            }
+            ALOGV("FindBestMatch for %d, %d, %d, %d", rowStart,
+                 rowEnd, columnStart, columnEnd);
+
+            // If the column search finishes, go out of the loop
+            if (columnEnd >= numVerticalLines - 1) {
+                successVertical = true;
+            } else {
+                columnStart = columnEnd + 1;
+            }
+        }
+        ALOGV("Continuing to search for direction 1");
+
+        // If the row search finishes, go out of the loop
+        if (rowEnd >= numHorizontalLines - 1) {
+            success = true;
+        } else {
+            rowStart = rowEnd + 1;
+        }
+    }
+
+    for (int i = 0; i < 4; ++i) {
+        for (int j = 0; j < 6; ++j) {
+            if (mMatchPositions[i][j] != NULL) {
+                ALOGV("Reference Match position for (%d, %d) is (%f, %f)", i, j,
+                     mMatchPositions[i][j]->x(), mMatchPositions[i][j]->y());
+            }
+        }
+    }
+
+    fillRefColorGrid();
+}
+
+// Finds the best match on the MacBeth color checker for the continuous block of
+// detected color checkers bounded by row i1, row i2 and column j1 and column j2
+// Assumes that the subsample is less than 4*6.
+void ColorCheckerTest::findBestMatch(int i1, int i2, int j1, int j2) {
+    int numHorizontalGrid = i2 - i1 + 1;
+    int numVerticalGrid = j2 - j1 + 1;
+
+    if (((numHorizontalGrid > 1) || (numVerticalGrid > 1)) &&
+        (numHorizontalGrid <= 4) && (numVerticalGrid <= 6)) {
+        ALOGV("i1, j2, j1, j2 is %d, %d, %d, %d", i1, i2, j1, j2);
+        float minError;
+        float error = 0.f;
+        int horizontalMatch, verticalMatch;
+
+        // Finds the match start point where the error is minimized.
+        for (int i = 0; i < numHorizontalGrid; ++i) {
+            for (int j = 0; j < numVerticalGrid; ++j) {
+                error += mCandidateColors[i1 + i][j1 + j]->squareDistance<int>(
+                        *mReferenceColors[i][j]);
+            }
+        }
+        ALOGV("Error is %f", error);
+        minError = error;
+        horizontalMatch = 0;
+        verticalMatch = 0;
+
+        for (int i = 0; i <= 4 - numHorizontalGrid; ++i) {
+            for (int j = 0; j <= 6 - numVerticalGrid; ++j) {
+                error = 0.f;
+
+                for (int id = 0; id < numHorizontalGrid; ++id) {
+                    for (int jd = 0; jd < numVerticalGrid; ++jd) {
+                        error += mCandidateColors[i1 + id][j1 + jd]->
+                                squareDistance<int>(
+                                        *mReferenceColors[i + id][j + jd]);
+                    }
+                }
+
+                if (error < minError) {
+                    minError = error;
+                    horizontalMatch = i;
+                    verticalMatch = j;
+                }
+                ALOGV("Processed %d, %d and error is %f", i, j, error );
+            }
+        }
+
+        for (int id = 0; id < numHorizontalGrid; ++id) {
+            for (int jd = 0; jd < numVerticalGrid; ++jd) {
+                mMatchPositions[horizontalMatch + id][verticalMatch + jd] =
+                         new Vec2f(mCandidatePositions[i1 + id][j1 + jd]->x(),
+                                   mCandidatePositions[i1 + id][j1 + jd]->y());
+            }
+        }
+        ALOGV("Grid match starts at %d, %d", horizontalMatch, verticalMatch);
+    }
+}
+
+// Finds the boundary of a color checker by its color similarity to the center.
+// Also predicts the location of unmatched checkers.
+void ColorCheckerTest::fillRefColorGrid() {
+    int rowStart = 0;
+    int columnStart = 0;
+    bool foundStart = true;
+
+    for (int i = 0; (i < 4) && foundStart; ++i) {
+        for (int j = 0; (j < 6) && foundStart; ++j) {
+            if (mMatchPositions[i][j] != NULL) {
+                rowStart = i;
+                columnStart = j;
+                foundStart = false;
+            }
+        }
+    }
+    ALOGV("First match found at (%d, %d)", rowStart, columnStart);
+
+    float rowDistance, columnDistance;
+    rowDistance = 0;
+    columnDistance = 0;
+    int numRowGrids = 0;
+    int numColumnGrids = 0;
+
+    for (int i = rowStart; i < 4; ++i) {
+        for (int j = columnStart; j < 6; ++j) {
+            if (mMatchPositions[i][j] != NULL) {
+                if (i > rowStart) {
+                    ++numRowGrids;
+                    rowDistance += (mMatchPositions[i][j]->x() -
+                                mMatchPositions[rowStart][columnStart]->x()) /
+                                static_cast<float>(i - rowStart);
+                }
+                if (j > columnStart) {
+                    ++numColumnGrids;
+                    columnDistance += (mMatchPositions[i][j]->y() -
+                                mMatchPositions[rowStart][columnStart]->y()) /
+                                static_cast<float>(j - columnStart);
+                }
+            }
+        }
+    }
+
+    if ((numRowGrids > 0) && (numColumnGrids > 0)) {
+        rowDistance = rowDistance / numRowGrids;
+        columnDistance = columnDistance / numColumnGrids;
+        ALOGV("delta is %f, %f", rowDistance, columnDistance);
+
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0 ; j < 6; ++j) {
+                if (mMatchPositions[i][j] == NULL) {
+                    mMatchPositions[i][j] = new Vec2f(
+                            mMatchPositions[rowStart][columnStart]->x() +
+                                    (i - rowStart) * rowDistance,
+                            mMatchPositions[rowStart][columnStart]->y() +
+                                    (j - columnStart) * columnDistance);
+                }
+            }
+        }
+        for (int i = 0; i < 4; ++i) {
+            for (int j = 0; j < 6; ++j) {
+                float radius = 0;
+                Vec3i color = mImage->getPixelValue(*mMatchPositions[i][j]);
+                Vec3f meanColor(0.f , 0.f, 0.f);
+
+                int numPixels = 0;
+                for (int ii  = static_cast<int>(mMatchPositions[i][j]->x() -
+                                                rowDistance/2);
+                     ii <= static_cast<int>(mMatchPositions[i][j]->x() +
+                                            rowDistance/2);
+                     ++ii) {
+                    for (int jj = static_cast<int>(mMatchPositions[i][j]->y() -
+                                                   columnDistance/2);
+                         jj <= static_cast<int>(mMatchPositions[i][j]->y() +
+                                                columnDistance/2);
+                         ++jj) {
+                        Vec3i pixelColor = mImage->getPixelValue(ii,jj);
+                        float error = color.squareDistance<int>(pixelColor);
+
+                        if (error < 200.f) {
+                            drawPoint(ii, jj, *mReferenceColors[i][j]);
+                            meanColor = meanColor + pixelColor;
+                            numPixels++;
+                            Vec2i pixelPosition(ii, jj);
+
+                            if (pixelPosition.squareDistance<float>(
+                                    *mMatchPositions[i][j]) > radius) {
+                                radius = pixelPosition.squareDistance<float>(
+                                        *mMatchPositions[i][j]);
+                            }
+                        }
+                    }
+                }
+
+                /** Computes the radius of the checker.
+                 * The above computed radius is the squared distance to the
+                 * furthest point with a matching color. To be conservative, we
+                 * only consider an area with radius half of the above computed
+                 * value. Since radius is computed as a squared root, the one
+                 * that will be recorded is 1/4 of the above computed value.
+                 */
+                mMatchRadius[i][j] = radius / 4.f;
+                mMatchColors[i][j] = new Vec3f(meanColor / numPixels);
+
+                ALOGV("Reference color at (%d, %d) is (%d, %d, %d)", i, j,
+                     mReferenceColors[i][j]->r(),
+                     mReferenceColors[i][j]->g(),
+                     mReferenceColors[i][j]->b());
+                ALOGV("Average color at (%d, %d) is (%f, %f, %f)", i, j,
+                     mMatchColors[i][j]->r(),
+                     mMatchColors[i][j]->g(),
+                     mMatchColors[i][j]->b());
+                ALOGV("Radius is %f", mMatchRadius[i][j]);
+            }
+        }
+
+        mSuccess = true;
+    }
+}
diff --git a/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp b/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
new file mode 100644
index 0000000..3e58141
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/exposurecompensationtest.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ExposureCompensationTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+#include <stdio.h>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "exposurecompensationtest.h"
+
+const float GAMMA_CORRECTION = 2.2f;
+void ExposureCompensationTest::processData() {
+    ALOGV("Start Processing Exposure Compensation Test Data!");
+    clearDebugImage();
+
+    int numTests = mExposureValues.size();
+    int numPatches = mCheckerColors[0].size();
+    ALOGV("Processing %d tests with %d patches", numTests, numPatches);
+
+    float minExposure = -3.0f;
+    float scale = 9.0f;
+    for (int i = 0; i < numTests; ++i) {
+        for (int j = 0; j < numPatches; ++j) {
+            int exposureRed = static_cast<int>((
+                log(static_cast<float>(mReferenceColors[j].r()))
+                / log(2.0f) * GAMMA_CORRECTION +
+                mExposureValues[i] - minExposure) * scale);
+            int exposureGreen = static_cast<int>((
+                log(static_cast<float>(mReferenceColors[j].g()))
+                / log(2.0f) * GAMMA_CORRECTION +
+                mExposureValues[i] - minExposure) * scale);
+            int exposureBlue = static_cast<int>((
+                log(static_cast<float>(mReferenceColors[j].b()))
+                / log(2.0f) * GAMMA_CORRECTION +
+                mExposureValues[i] - minExposure) * scale);
+
+            ALOGV("Match color at (%d, %d) is (%f, %f, %f)", i, j,
+                 mCheckerColors[i][j].r(),
+                 mCheckerColors[i][j].g(),
+                 mCheckerColors[i][j].b());
+            ALOGV("Response curve red (%d, %f), blue (%d, %f), green (%d, %f)",
+                 exposureRed, mCheckerColors[i][j].r(),
+                 exposureGreen, mCheckerColors[i][j].g(),
+                 exposureBlue, mCheckerColors[i][j].b());
+
+            Vec3i red(255, 0, 0);
+            Vec3i green(0, 255, 0);
+            Vec3i blue(0, 0, 255);
+
+            drawPoint(200 - exposureRed, mCheckerColors[i][j].r(), red);
+            drawPoint(200 - exposureGreen, mCheckerColors[i][j].g(), green);
+            drawPoint(200 - exposureBlue, mCheckerColors[i][j].b(), blue);
+        }
+    }
+    mExposureValues.clear();
+    mCheckerColors.clear();
+}
+
+void ExposureCompensationTest::initializeReferenceColors() {
+    mReferenceColors.resize(6);
+
+    mReferenceColors[0].set(243, 243, 242);
+    mReferenceColors[1].set(200, 200, 200);
+    mReferenceColors[2].set(160, 160, 160);
+    mReferenceColors[3].set(122, 122, 121);
+    mReferenceColors[4].set(85, 85, 85);
+    mReferenceColors[5].set(52, 52, 52);
+}
diff --git a/apps/CtsVerifier/lib/colorchecker/grouping.h b/apps/CtsVerifier/lib/colorchecker/grouping.h
deleted file mode 100755
index 3125f55..0000000
--- a/apps/CtsVerifier/lib/colorchecker/grouping.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/*

- * 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.

- */

-

-#include <vector>

-#include <utility>

-

-#ifndef FILTERPACK_CALIBRATION_GROUPING_H

-#define FILTERPACK_CALIBRATION_GROUPING_H

-

-// To use the Grouping function, derive one class from Field.

-// Field class provides the interface for the Grouping function.

-// FF_ID is the pixel class used to compare values,

-//  != operator must be defined in this class

-//  region number of the pixel

-

-typedef std::vector <std::vector<int> > MASK;

-typedef std::pair<int, int> POS;

-// FF_ID needs to implement the operator !=

-// bool  operator != (const FF_ID &id)

-template <class FF_ID>

-class Field {

-  public:

-    int id_no;

-    MASK mask;

-    virtual FF_ID operator () (int y, int x) const =0 ;

-    virtual int getWidth()  const = 0;

-    virtual int getHeight()  const= 0;

-    virtual ~Field() {}

-};

-

-template < class FF_ID>

-void FloodFill(int sx,

-               int sy,

-               int id_no,

-               const FF_ID &id,

-               Field<FF_ID> *pField,

-               POS *new_pos) {

-    std::vector<POS> stack;

-    stack.push_back(POS(sx,sy));

-    while (stack.size() > 0) {

-        sx = stack.back().first;

-        sy = stack.back().second;

-        stack.pop_back();

-

-        // fill the current line

-        int x;

-        for (x = sx-1; x >= 0; x--)

-        {

-            if (pField->mask[sy][x]!=0) break;

-            if (id != (*pField)(sy,x)) {

-                new_pos->first = x;

-                new_pos->second =sy;

-                break;

-            }

-            pField->mask[sy][x] = id_no;

-        }

-        int startx = x;

-        for (x = sx;x < pField->getWidth(); x++) {

-            if (pField->mask[sy][x]!=0) break;

-            if (id != (*pField)(sy,x)) {

-                new_pos->first = x;

-                new_pos->second =sy;

-                break;

-            }

-            pField->mask[sy][x] = id_no;

-        }

-        int endx = x;

-        if (endx >= pField->getWidth()) endx = pField->getWidth() - 1;

-        if (startx < 0) startx = 0;

-        // push the adjacent spans to the stack

-        if (sy>0) {

-            int bNew = true;

-            for (x = endx; x >= startx; x--) {

-                if (pField->mask[sy-1][x] != 0 || id != (*pField)(sy-1,x) ) {

-                    bNew = true;

-                    continue;

-                }

-                if (bNew) {

-                    stack.push_back( POS(x, sy-1));

-                    bNew = false;

-                }

-            }

-        }

-        if (sy < (pField->getHeight() - 1)) {

-            int bNew = true;

-            for (x = endx; x >= startx; x--) {

-                if (pField->mask[sy+1][x]!=0 || id != (*pField)(sy+1,x)) {

-                    bNew = true;

-                    continue;

-                }

-                if (bNew) {

-                    stack.push_back( POS(x, sy+1));

-                    bNew = false;

-                }

-            }

-        }

-    }

-}

-

-// Group the pixels in Field based on the FF_ID != operator.

-// All pixels will be labeled from 1. The total number of unique groups(regions)

-// is (pField->id_no - 1) after the call

-// The labeasl of the pixels are stored in the mask member of Field.

-

-template <class FF_ID>

-void Grouping(Field <FF_ID> *pField) {

-    int width = pField->getWidth();

-    int height = pField->getHeight();

-    pField->mask =  MASK(height, std::vector<int> (width, 0) );

-

-    FF_ID id;

-    pField->id_no = 1;

-    int sx = width / 2, sy = height / 2;

-    POS new_pos(-1,-1);

-    while (1) {

-        id = (*pField)(sy,sx);

-        int id_no = pField->id_no;

-        new_pos.first = -1;

-        new_pos.second = -1;

-        FloodFill(sx, sy, id_no, id, pField, &new_pos);

-        if (new_pos.first < 0) // no new position found, during the flood fill

-        {

-            const int kNumOfRetries = 10;

-            // try 10 times for the new unfilled position

-            for (int i = 0; i < kNumOfRetries; i++) {

-                sx = rand() % width;

-                sy = rand() % height;

-                if (pField->mask[sy][sx] == 0) {

-                    new_pos.first = sx;

-                    new_pos.second = sy;

-                    break;

-                }

-            }

-            if (new_pos.first < 0) { // still failed, search the whole image

-                for (int y = 0; y < height && new_pos.first < 0; y++)

-                    for (int x = 0; x < width; x++) {

-                        if (pField->mask[y][x] == 0) {

-                            new_pos.first = x;

-                            new_pos.second = y;

-                            break;

-                        }

-                    }

-            }

-            if (new_pos.first < 0) break; // finished

-        }

-        sx = new_pos.first;

-        sy = new_pos.second;

-        pField->id_no++;

-    }

-}

-

-#endif

diff --git a/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp b/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp
new file mode 100644
index 0000000..1c5bc17
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/imagetesthandler.cpp
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "ImageTestHandler"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "imagetesthandler.h"
+
+void ImageTestHandler::initDebugImage() {
+    mDebugOutput = NULL;
+}
+
+// Initializes the  debug image with a given height and width.
+void ImageTestHandler::initDebugImage(int debugHeight,
+                                      int debugWidth) {
+    mDebugOutput = NULL;
+    mDebugOutput = new unsigned char[debugHeight * debugWidth * 4];
+    memset(mDebugOutput, 0, debugHeight * debugWidth * 4);
+
+    mDebugHeight = debugHeight;
+    mDebugWidth = debugWidth;
+}
+
+// Copies an existing image to the debug image.
+void ImageTestHandler::copyDebugImage(int inputHeight, int inputWidth,
+                                      const unsigned char* inputImage) {
+    if ((inputHeight == mDebugHeight) && (inputWidth == mDebugWidth)) {
+        ALOGV("Copying debug images");
+        memcpy(mDebugOutput, inputImage, mDebugHeight * mDebugWidth * 4);
+    }
+}
+
+void ImageTestHandler::clearDebugImage() {
+    if (mDebugOutput != NULL) {
+        delete[] mDebugOutput;
+        mDebugOutput = new unsigned char[mDebugHeight * mDebugWidth * 4];
+        memset(mDebugOutput, 0, mDebugHeight * mDebugWidth * 4);
+    }
+}
+
+
+// Draws a point of a given color.
+void ImageTestHandler::drawPoint(int row, int column, const Vec3i &color) {
+    if ((row >= 0) && (column >= 0) &&
+        (column < mDebugWidth) && (row < mDebugHeight)) {
+        mDebugOutput[(row*mDebugWidth + column) * 4] = color.r();
+        mDebugOutput[(row*mDebugWidth + column) * 4+1] = color.g();
+        mDebugOutput[(row*mDebugWidth + column) * 4+2] = color.b();
+        mDebugOutput[(row*mDebugWidth + column) * 4+3] = 255;
+    }
+}
+
+// Draws a point in Vec2 format of a given color.
+void ImageTestHandler::drawPoint(const Vec2i &point, const Vec3i &color) {
+    drawPoint((int) point.y(), (int) point.x(), color);
+}
+
+// Draws a line of a given color.
+void ImageTestHandler::drawLine(int angle, int radius, const Vec3i &color) {
+    const int r = color.r();
+    const int g = color.g();
+    const int b = color.b();
+    const int a = 255;
+
+    int shiftedMin = -113;
+    int shiftedMax = 83;
+
+    float radiusDouble = static_cast<float>(radius);
+
+    float angleRad = static_cast<float>(angle) * M_PI / 180.0;
+
+    //ALOGV("draw line for (%d, %d)", angle, radius);
+    for (int i = shiftedMin; i <= shiftedMax; ++i) {
+        float j;
+
+        assert(angle != 0);
+        j = (i - radiusDouble / sin(angleRad)) * tan(angleRad);
+        float x = (static_cast<float>(i) + j) / sqrt(2.0);
+        float y = (j - static_cast<float>(i)) / sqrt(2.0);
+
+        drawPoint(x, y, color);
+    }
+}
diff --git a/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp b/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp
new file mode 100644
index 0000000..47de5d8
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/meteringtest.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "MeteringTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "meteringtest.h"
+
+const float kOverExposure = 230.f;
+const float kEqThreshold = 0.05f;
+// Processes the checker colors stored by comparing the pixel values from the
+// two scenarios in a test.
+void MeteringTest::processData() {
+    ALOGV("Start Processing Metering Test Data!");
+
+    int numTests = mCheckerColors.size() / 2;
+    mNumPatches = 0;
+
+    if (numTests > 0) {
+        mNumPatches = mCheckerColors[0].size();
+    }
+
+    for (int i = 0; i < numTests; ++i) {
+        mComparisonResults.push_back(
+                isEquivalentTo((&mCheckerColors[i * 2]),
+                               (&mCheckerColors[i * 2 + 1])));
+        mComparisonResults.push_back(
+                isDarkerThan((&mCheckerColors[i * 2]),
+                             (&mCheckerColors[i * 2 + 1])));
+    }
+}
+
+void MeteringTest::clearData() {
+    mComparisonResults.clear();
+    mCheckerColors.clear();
+}
+
+// Compares two given arrays of pixel values and decide whether the first one is
+// significantly darker than the second one.
+bool MeteringTest::isDarkerThan(
+        const std::vector<Vec3f>* checkerColors1,
+        const std::vector<Vec3f>* checkerColors2) const {
+    float meanRatio = 0.f;
+    int meanNumCount = 0;
+
+    for (int i = 0; i < mNumPatches; ++i) {
+        float luminance1 = (*checkerColors1)[i].convertToLuminance();
+        float luminance2 = (*checkerColors2)[i].convertToLuminance();
+
+        // Out of the saturation rage, define 5% as a margin for being
+        // significantly brighter.
+        if ((luminance2 < kOverExposure) && (luminance1 != 0.f)) {
+            meanRatio += luminance2 / luminance1;
+            ++meanNumCount;
+        }
+    }
+    meanRatio = meanRatio / meanNumCount;
+
+    return (meanRatio > 1 + kEqThreshold);
+}
+
+// Compares the two givn arrays of pixel values and decide whether they are
+// equivalent within an acceptable range.
+bool MeteringTest::isEquivalentTo(
+        const std::vector<Vec3f>* checkerColors1,
+        const std::vector<Vec3f>* checkerColors2) const {
+    float meanRatio = 0.f;
+    int meanNumCount = 0;
+
+    for (int i = 0; i < mNumPatches; ++i) {
+        float luminance1 = (*checkerColors1)[i].convertToLuminance();
+        float luminance2 = (*checkerColors2)[i].convertToLuminance();
+        ALOGV("Luma_1 and Luma_2 is %f, %f", luminance1, luminance2);
+
+        if ((luminance1 < kOverExposure) && (luminance2 < kOverExposure)) {
+              meanRatio += luminance2 / luminance1;
+              ++meanNumCount;
+        }
+    }
+    meanRatio = meanRatio / meanNumCount;
+
+    return ((meanRatio >= 1 - kEqThreshold) && (meanRatio <= 1 + kEqThreshold));
+}
diff --git a/apps/CtsVerifier/lib/colorchecker/testingimage.cpp b/apps/CtsVerifier/lib/colorchecker/testingimage.cpp
new file mode 100644
index 0000000..30725ec
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/testingimage.cpp
@@ -0,0 +1,186 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "TestingImage"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <string.h>
+#include <cmath>
+#include <vector>
+#include "vec3.h"
+
+#include "testingimage.h"
+
+const float GAMMA_CORRECTION = 2.2f;
+
+// Constructs an instance with the given image byte array.
+TestingImage::TestingImage(const unsigned char* inputImage,
+                           int inputHeight, int inputWidth,
+                           int inputChannel, int inputRowSpan) {
+    mImage = new unsigned char[inputRowSpan * inputHeight];
+
+    ALOGV("mImage format created! with size as %d, %d, %d",
+         inputRowSpan, inputHeight, inputChannel);
+    mWidth = inputWidth;
+    mHeight = inputHeight;
+    mChannels = inputChannel;
+    mRowSpan = mWidth * mChannels;
+
+    for (int i = 0; i < mHeight; ++i) {
+        for (int j = 0; j < mWidth; ++j) {
+            for (int k = 0; k < mChannels; ++k) {
+                mImage[i * mRowSpan + j* mChannels + k] =
+                        inputImage[i * inputRowSpan + j * inputChannel + k];
+            }
+        }
+    }
+    ALOGV("mImage converted!");
+}
+
+// Constructs an instance with the given image and resize it to a new size.
+TestingImage::TestingImage(const unsigned char* inputImage,
+                           int inputHeight, int inputWidth,
+                           int inputChannel, int inputRowSpan,
+                           int newHeight, int newWidth) {
+    mImage = new unsigned char[newHeight * newWidth * inputChannel];
+
+    ALOGV("mImage format created! with size as %d, %d, %d",
+         newHeight, newWidth, inputChannel);
+    mHeight = newHeight;
+    mWidth = newWidth;
+    mChannels = inputChannel;
+    mRowSpan = mWidth * mChannels;
+
+    // Computes how many pixels in the original image corresponds to one pixel
+    // in the new image.
+    int heightScale = inputHeight / newHeight;
+    int widthScale = inputWidth / newWidth;
+
+    // Average the corresponding pixels in the original image to compute the
+    // pixel value of the new image.
+    for (int i = 0; i < mHeight; ++i) {
+        for (int j = 0; j < mWidth; ++j) {
+            for (int k = 0; k < mChannels; ++k) {
+                int pixelValue = 0;
+
+                for (int l = 0; l < heightScale; ++l) {
+                    for (int m = 0; m < widthScale; ++m) {
+                        pixelValue += inputImage[
+                                (i * heightScale + l) * inputRowSpan
+                                + (j * widthScale + m) * inputChannel + k];
+                    }
+                }
+                pixelValue = pixelValue / (heightScale * widthScale);
+                mImage[i * mRowSpan + j * mChannels + k] =
+                        (unsigned char) pixelValue;
+            }
+        }
+    }
+}
+
+TestingImage::~TestingImage() {
+    if (mImage!=NULL) {
+        delete[] mImage;
+    }
+}
+
+int TestingImage::getPixelValue(int row, int column, int channel) const {
+    return (int)mImage[row * mRowSpan + column * mChannels + channel];
+}
+
+Vec3i TestingImage::getPixelValue(int row, int column) const {
+    Vec3i current_color(getPixelValue(row, column, 0),
+                        getPixelValue(row, column, 1),
+                        getPixelValue(row, column, 2));
+    return current_color;
+}
+
+Vec3i TestingImage::getPixelValue(const Vec2i &pixelPosition) const {
+    return getPixelValue(pixelPosition.x(), pixelPosition.y());
+}
+
+Vec3i TestingImage::getPixelValue(const Vec2f &pixelPosition) const {
+    return getPixelValue(static_cast<int>(pixelPosition.x()),
+                         static_cast<int>(pixelPosition.y()));
+}
+
+// Returns a vector of the colors in the requested block of color checkers.
+// The vector is formatted by going through the block from left to right and
+// from top to bottom.
+const std::vector<Vec3f>* TestingImage::getColorChecker(
+      int rowStart, int rowEnd, int columnStart, int columnEnd,
+      const std::vector<std::vector< Vec2f > >* centerAddress,
+      const std::vector<std::vector< float > >* radiusAddress) const {
+    std::vector<Vec3f>* checkerColors = new std::vector<Vec3f>;
+
+    // Average the pixel values of the pixels within the given radius to the
+    // given center position.
+    for (int i = rowStart; i < rowEnd; ++i) {
+        for (int j = columnStart; j < columnEnd; ++j) {
+            float radius = sqrt((*radiusAddress)[i][j]);
+            Vec2f center((*centerAddress)[i][j].x(),
+                               (*centerAddress)[i][j].y());
+            Vec3f meanColor(0.f, 0.f, 0.f);
+            int numPixels = 0;
+
+            for (int ii = static_cast<int>(center.x() - radius);
+                 ii < static_cast<int>(center.x() + radius); ++ii) {
+                for (int jj = static_cast<int>(center.y() - radius);
+                     jj < static_cast<int>(center.y() + radius); ++jj) {
+
+                    Vec2i pixelPosition(ii,jj);
+                    if (pixelPosition.squareDistance<float>(center) <
+                        (*radiusAddress)[i][j]) {
+                        meanColor = meanColor + getPixelValue(pixelPosition);
+                        ++numPixels;
+                    }
+                }
+            }
+            meanColor = meanColor / numPixels;
+            checkerColors->push_back(meanColor);
+        }
+    }
+
+    return checkerColors;
+}
+
+bool TestingImage::rgbToGrayScale(unsigned char* grayLayer) const {
+    if (mChannels == 4) {
+        for (int i = 0; i < mWidth; i++) {
+            for (int j = 0; j < mHeight; j++) {
+                float redLinear = pow(getPixelValue(j, i, 0),
+                                       GAMMA_CORRECTION);
+                float greenLinear = pow(getPixelValue(j,i,1),
+                                         GAMMA_CORRECTION);
+                float blueLinear = pow(getPixelValue(j,i,2),
+                                        GAMMA_CORRECTION);
+
+                // Computes the luminance value
+                grayLayer[j * mWidth + i] =
+                        (unsigned char)((int)pow((0.299f * redLinear
+                                                  + 0.587f * greenLinear
+                                                  + 0.114f * blueLinear),
+                                                  1/GAMMA_CORRECTION));
+            }
+        }
+
+        return true;
+    } else {
+
+        return false;
+    }
+}
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h b/apps/CtsVerifier/lib/colorchecker/vec2.cpp
similarity index 60%
copy from apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h
copy to apps/CtsVerifier/lib/colorchecker/vec2.cpp
index a9b4487..29736bb 100644
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h
+++ b/apps/CtsVerifier/lib/colorchecker/vec2.cpp
@@ -13,25 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_NDEBUG 0
 
-#ifndef JNI_CAMERAANALYZER_COLORCHECKER_H
-#define JNI_CAMERAANALYZER_COLORCHECKER_H
+#define LOG_TAG "Vec2"
+#include <utils/Log.h>
+#include <utils/Timers.h>
 
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jboolean JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorChecker_findNative(
-    JNIEnv *env,
-    jobject thiz,
-    jobject inputBitmap);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* JNI_CAMERAANALYZER_COLORCHECKER_H */
+#include "vec2.h"
diff --git a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h b/apps/CtsVerifier/lib/colorchecker/vec3.cpp
similarity index 60%
rename from apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h
rename to apps/CtsVerifier/lib/colorchecker/vec3.cpp
index a9b4487..ac16620 100644
--- a/apps/CtsVerifier/jni/cameraanalyzer/com_android_cts_verifier_camera_analyzer_ColorChecker.h
+++ b/apps/CtsVerifier/lib/colorchecker/vec3.cpp
@@ -13,25 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define LOG_NDEBUG 0
 
-#ifndef JNI_CAMERAANALYZER_COLORCHECKER_H
-#define JNI_CAMERAANALYZER_COLORCHECKER_H
+#define LOG_TAG "Vec3"
+#include <utils/Log.h>
+#include <utils/Timers.h>
 
-#include <jni.h>
-#include <stdio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-JNIEXPORT jboolean JNICALL
-Java_com_android_cts_verifier_camera_analyzer_ColorChecker_findNative(
-    JNIEnv *env,
-    jobject thiz,
-    jobject inputBitmap);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* JNI_CAMERAANALYZER_COLORCHECKER_H */
+#include "vec3.h"
diff --git a/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp b/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp
new file mode 100644
index 0000000..6413a2b
--- /dev/null
+++ b/apps/CtsVerifier/lib/colorchecker/whitebalancetest.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+#define LOG_NDEBUG 0
+
+#define LOG_TAG "WhiteBalanceTest"
+#include <utils/Log.h>
+#include <utils/Timers.h>
+#include <cmath>
+#include <string>
+
+#include "vec2.h"
+#include "vec3.h"
+#include "whitebalancetest.h"
+
+// White point in XYZ color space under 5200k illumination.
+const Vec3f kDaylightWhitePoint(0.9781f, 1.f, 0.9021f);
+
+// Process the data of checker colors collected under different white balance.
+// Assuming the Daylight CCT is set to 5200k, compute the CCT of other white
+// balance modes.
+void WhiteBalanceTest::processData() {
+    ALOGV("Start Processing White Balance Test Data!");
+
+    int numPatches = mCheckerColors.size();
+    ALOGV("Processing %d tests with %d patches", 2, numPatches);
+
+    std::vector<Vec3f> xyzColors(numPatches);
+    for (int j = 0; j < numPatches; ++j) {
+        Vec3f xyzCheckerColor = initializeFromRGB(mCheckerColors[j]);
+        xyzColors[j] = xyzCheckerColor;
+        ALOGV("XYZ coordinate is %f, %f, %f", xyzCheckerColor.r(),
+              xyzCheckerColor.g(), xyzCheckerColor.b());
+    }
+
+    Vec3f meanScale(0.f, 0.f, 0.f);
+
+    if (mMode == "daylight") {
+        mXyzColorsDaylight = xyzColors;
+        // For testing the auto white balance mode. Compute a CCT that would
+        // map the gray checkers to a white point.
+        for (int j = 1; j < numPatches; ++j) {
+            meanScale = meanScale +
+                    (mXyzColorsDaylight[j] / kDaylightWhitePoint);
+        }
+    } else {
+        for (int j = 1; j < numPatches; ++j) {
+            meanScale = meanScale + (mXyzColorsDaylight[j] / xyzColors[j]);
+        }
+    }
+
+    meanScale = meanScale / (numPatches - 1);
+    ALOGV("Scale: %f, %f, %f", meanScale.r(), meanScale.g(), meanScale.b());
+
+    Vec3f whitePoint;
+    whitePoint = meanScale * kDaylightWhitePoint;
+
+    ALOGV("White point is %f, %f, %f", whitePoint.r(),
+         whitePoint.g(), whitePoint.b());
+
+    mCorrelatedColorTemp = findCorrelatedColorTemp(whitePoint);
+    ALOGV("CCT is %d", mCorrelatedColorTemp);
+}
+
+// Given a white point, find the correlated color temperature.
+// Formula taken from the paper "Calculating Correlated Color Temperatures
+// Across the Entire Gamut of Daylight and Skylight Chromaticities" by Hernandez
+// Andres et al. in 1999. The numbers are fitting parameters.
+int WhiteBalanceTest::findCorrelatedColorTemp(const Vec3f &whitePoint) {
+    Vec2f chromaOfWhitePoint(
+        whitePoint.r() / (whitePoint.r() + whitePoint.g() + whitePoint.b()),
+        whitePoint.g() / (whitePoint.r() + whitePoint.g() + whitePoint.b()));
+
+    float n = (chromaOfWhitePoint.x() - 0.3366f)
+                / (chromaOfWhitePoint.y() - 0.1735f);
+    float y = -949.86315f + 6253.80338f * exp(-n / 0.92159f)
+               + 28.70599f * exp(-n / 0.20039f) + 0.00004f * exp(-n / 0.07125f);
+
+    return static_cast<int>(y);
+}
+
+// Converts a RGB pixel value to XYZ color space.
+Vec3f WhiteBalanceTest::initializeFromRGB(const Vec3f &rgb) {
+    float linearRed = convertToLinear(rgb.r());
+    float linearGreen = convertToLinear(rgb.g());
+    float linearBlue = convertToLinear(rgb.b());
+
+    float x = 0.4124f * linearRed + 0.3576f * linearGreen +
+            0.1805f * linearBlue;
+    float y = 0.2126f * linearRed + 0.7152f * linearGreen +
+            0.0722f * linearBlue;
+    float z = 0.0193f * linearRed + 0.1192f * linearGreen +
+            0.9505f * linearBlue;
+
+    return Vec3f(x, y, z);
+}
+
+float WhiteBalanceTest::convertToLinear(float color) {
+    float norm = color/ 255.0f;
+    float linearColor;
+
+    // Convert from sRGB space to linear RGB value
+    if (norm > 0.04045f) {
+        linearColor = pow(((norm + 0.055f) / 1.055f), 2.4f);
+    } else {
+        linearColor = norm / 12.92f;
+    }
+
+    return linearColor;
+}
diff --git a/apps/CtsVerifier/res/layout/ca_main.xml b/apps/CtsVerifier/res/layout/ca_main.xml
index 98ec049..c41bcf6 100644
--- a/apps/CtsVerifier/res/layout/ca_main.xml
+++ b/apps/CtsVerifier/res/layout/ca_main.xml
@@ -19,25 +19,60 @@
   android:orientation="vertical" android:layout_width="fill_parent"
   android:layout_height="fill_parent">
 
-  <Button android:id="@+id/runbutton" android:layout_width="fill_parent"
-    android:layout_height="wrap_content" android:text="@string/ca_run_label" />
 
-  <TextView android:id="@+id/resulttext" android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:text="@string/ca_result_label"
-            android:textSize="15sp" />
+  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal" android:layout_width="fill_parent"
+    android:layout_height="wrap_content">
+    <!--Button android:id="@+id/focusmodesbutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_focus_modes_label"
+      android:layout_weight="1" /-->
+    <Button android:id="@+id/findcheckerboardbutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_find_checkerboard_label"
+      android:layout_weight="1" />
+
+    <Button android:id="@+id/meteringbutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_metering_label"
+      android:layout_weight="1" />
+
+    <Button android:id="@+id/exposurecompensationbutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_exposure_test_label"
+      android:layout_weight="1"/>
+
+    <Button android:id="@+id/whitebalancebutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_wb_test_label"
+      android:layout_weight="1" />
+
+    <Button android:id="@+id/lockbutton" android:layout_width="0px"
+      android:layout_height="wrap_content" android:text="@string/ca_lock_test_label"
+      android:layout_weight="1" />
+  </LinearLayout>
 
   <LinearLayout android:orientation="horizontal"
-    android:layout_width="fill_parent" android:layout_height="wrap_content">
+    android:layout_width="fill_parent" android:layout_height="0px"
+    android:layout_weight="1">
 
-    <SurfaceView android:id="@+id/cameraview" android:layout_height="match_parent"
-      android:layout_width="match_parent"
-      android:layout_weight="1" />
+    <SurfaceView android:id="@+id/cameraview" android:layout_height="fill_parent"
+      android:layout_width="wrap_content"
+      android:layout_weight="0" />
 
-    <ImageView android:id="@+id/resultview" android:layout_height="match_parent"
-      android:layout_width="match_parent"
-      android:layout_weight="1" />
+    <LinearLayout android:orientation="vertical"
+      android:layout_width="fill_parent" android:layout_height="match_parent"
+      android:layout_weight="1">
+	       
+       <ListView android:id="@+id/ca_tests"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+	    android:layout_weight="1"
+            android:layout_marginLeft="10px"/>
+
+      <ImageView android:id="@+id/resultview" android:layout_height="wrap_content"
+        android:layout_width="fill_parent"
+        android:layout_weight="1" />
+    </LinearLayout>
 
   </LinearLayout>
+
+  <include layout="@layout/pass_fail_buttons" />
+
 </LinearLayout>
 
diff --git a/apps/CtsVerifier/res/layout/ca_row.xml b/apps/CtsVerifier/res/layout/ca_row.xml
new file mode 100644
index 0000000..0e09793
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ca_row.xml
@@ -0,0 +1,19 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    >
+    <TextView
+        android:id="@+id/caTestName"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginRight="10px"
+        />
+    <TextView
+        android:id="@+id/caTestResult"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="right"
+        android:layout_marginLeft="10px"
+        />
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/menu/ca_menu.xml b/apps/CtsVerifier/res/menu/ca_menu.xml
new file mode 100644
index 0000000..c33e7e8
--- /dev/null
+++ b/apps/CtsVerifier/res/menu/ca_menu.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+</menu>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 6e7d399..0b449a5 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -101,7 +101,7 @@
     <string name="da_screen_lock_test">Screen Lock Test</string>
     <string name="da_screen_lock_info">This test checks that the DevicePolicyManager\'s lockNow
         method immediately locks the screen. It should lock the screen immediately despite any
-        settings that may specify a timeout.\n\nClick the \"Force Lock\" button to lock the screen. 
+        settings that may specify a timeout.\n\nClick the \"Force Lock\" button to lock the screen.
         Your screen should be locked and require the password to be entered.
     </string>
     <string name="da_force_lock">Force Lock</string>
@@ -206,6 +206,11 @@
         button below to goto Settings and enable it.</string>
     <string name="nfc_settings">NFC Settings</string>
 
+    <string name="ndef_push_not_enabled">NDEF Push is not enabled!</string>
+    <string name="ndef_push_not_enabled_message">These tests require Android Beam to be enabled.
+        Click the button below to goto NFC Sharing Settings and enable it.</string>
+    <string name="ndef_push_settings">NFC Sharing Settings</string>
+
     <string name="nfc_pee_2_pee">Peer-to-Peer Data Exchange</string>
     <string name="nfc_ndef_push_sender">NDEF Push Sender</string>
     <string name="nfc_ndef_push_receiver">NDEF Push Receiver</string>
@@ -367,8 +372,14 @@
 
     <!-- Strings for Camera Analyzer -->
     <string name="camera_analyzer">Camera Analyzer</string>
-    <string name="ca_run_label">Find color checker</string>
-    <string name="ca_result_label">Patch values will be here</string>
+    <string name="ca_find_checkerboard_label">Find color checker</string>
+    <string name="ca_exposure_test_label">Exposure Comp. Test</string>
+    <string name="ca_result_label">Results will be here</string>
+    <string name="ca_wb_test_label">White Balance Test</string>
+    <string name="ca_lock_test_label">Auto Exposure Lock Test</string>
+    <string name="ca_metering_label">Metering Area Test</string>
+    <string name="ca_focus_modes_label">Focus Modes Test</string>
+    <string name="ca_info">This test checks the image quality of the camera of this device. It requires a MacBeth 4x6 color checker. With an ADK board and a lamp connected to it on the Relay 1 port, all tests can be run automatically. Without the ADK board, all the tests except the Auto Exposure Lock Test can be run automatically and the Auto Exposure Lock Test will require users to turn on/off a lamp according to the instruction given. </string>
 
     <!-- Strings for USB accessory test activity -->
     <string name="usb_accessory_test">USB Accessory Test</string>
diff --git a/apps/CtsVerifier/res/xml/accessory_filter_adk.xml b/apps/CtsVerifier/res/xml/accessory_filter_adk.xml
new file mode 100644
index 0000000..a5dc89a
--- /dev/null
+++ b/apps/CtsVerifier/res/xml/accessory_filter_adk.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <usb-accessory model="DemoKit" manufacturer="Google" version="1.0"/>
+</resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java
new file mode 100644
index 0000000..6b40d2a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/AutoLockTest.java
@@ -0,0 +1,1078 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+import android.view.SurfaceView;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements a test to verify whether the Auto Exposure Lock functions as
+ * described in the API.
+ *
+ * The test consists three sub-categories. The first set of tests focus on
+ * testing whether the auto exposure lock works in various situations.
+ * For all tests in this set, the lock is set during the period when the camera
+ * preview is open. In this way the lock locks exposure according to the
+ * lighting at the moment of setting the lock. The second set of tests focus on
+ * testing whether the auto exposure lock works as expected after turning the
+ * preview off and on. The lock is set during the period when the camera
+ * preview is turned off. The lock is expected to lock an exposure level
+ * identical to the one before the preview is turned off. One special case in
+ * this category is to set lock before the preview is turned on for the first
+ * time.
+ */
+public class AutoLockTest extends CameraTests {
+
+    private static final String TAG = "AutoLockTest";
+    /** USB permission to connect to ADK. */
+    private static final String ACTION_USB_PERMISSION = "com.android.cts.verifier.USB_PERMISSION";
+    /** Defines a long sleep period.*/
+    private static final int SHORT_SLEEP = 2000;
+    /** Defines a short sleep period. */
+    private static final int LONG_SLEEP = 4000;
+
+    /** Test results in text format. */
+    private String mDebugText = new String();
+    /** Detailed report. */
+    private String mResultText = new String();
+    /** Thread lock of the camera callbacks. */
+    private final Object mProcessingImage = new Object();
+    /** Memory address of the native test handler. */
+    private long mTestHandler;
+    /** Array storing the reference test results. */
+    private ArrayList<Boolean> mReferenceCompareResults;
+    /** Array storing the reference test scenario logs. */
+    private ArrayList<String> mReferenceLogs;
+    /** Number of tests so far. */
+    private int mTestCount;
+
+    /** Usb Manager of the USB connections. */
+    private UsbManager mUsbManager;
+    /** Intent for getting the permission to access the ADK. */
+    private PendingIntent mPermissionIntent;
+    /** Boolean to represent whether a permission is gained. */
+    private boolean mPermissionRequestPending;
+    /** USB accessory pointing to the ADK. */
+    private UsbAccessory mAccessory;
+    /** File descriptor of the USB communication port. */
+    private ParcelFileDescriptor mFileDescriptor;
+    /** Output stream to write commands for ADK to. */
+    private FileOutputStream mOutputStream;
+
+    /** Pointer to the CameraAnalyzerActivity activity. */
+    private CameraAnalyzerActivity mActivity;
+    /** Boolean to tell whether the accessory is opened. */
+    private boolean mSetupReady;
+    /** Thread lock for setting up the usb. */
+    private final Object mUsbSetup = new Object();
+    /** Boolean to indicate whether there is an ADK attached. */
+    private boolean mUsingUsb = false;
+    /** Test results.*/
+    private String[] mTestResults;
+    /** Number of tests. */
+    private int mNumTests;
+    /** Singleton test instance.*/
+    private static AutoLockTest singletonTest = null;
+
+    /**
+     * Receives the notice of whether the connection to ADK is granted or
+     * denied.
+     */
+    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            Log.v(TAG, String.format("Received USB broadcast with action %s ", action));
+
+            if (ACTION_USB_PERMISSION.equals(action)) {
+                synchronized (this) {
+                    UsbAccessory accessory =
+                        (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        // Grants the permission to connect to the ADK.
+                        Log.v(TAG, "Open accessory 3");
+                        openAccessory(accessory);
+                        // Overwrites the old camera instsance with the one currently opened
+                        // by the CameraAnalyzerActivity instance, since the permission
+                        // dialogue pauses the CameraAnalyzerActivity and forces the camera to
+                        // be released and reopened when the dialogue disappears.
+                        mTestCamera = mActivity.getCameraInstance();
+                    } else {
+                        // Denies the permission to connect to the ADK.
+                        Log.d(TAG, "permission denied for accessory " + accessory);
+                    }
+                    // Marks that the permission request has been processed.
+                    mPermissionRequestPending = false;
+                }
+            } else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+                // Invokes when the USB is detached.
+                // Closes the accessory if it has not been closed.
+                Log.v(TAG, "Usb device detached");
+                mUsingUsb = false;
+                UsbAccessory accessory =
+                    (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+                if (accessory != null && accessory.equals(mAccessory)) {
+                    closeAccessory();
+                }
+            }
+        }
+    };
+
+    /**
+     * Opens the ADK from USB and attaches the output stream with it.
+     *
+     * Notifies the tread lock that the USB setup is ready.
+     */
+    private void openAccessory(UsbAccessory accessory) {
+        Log.d(TAG, "openAccessory: " + accessory);
+	mFileDescriptor = mUsbManager.openAccessory(accessory);
+
+        if (mFileDescriptor != null) {
+	    mAccessory = accessory;
+	    FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+            mOutputStream = new FileOutputStream(fd);
+	    Log.d(TAG, "accessory opened");
+	} else {
+            Log.d(TAG, "accessory open fail");
+	}
+
+        // Unlocks the thread lock of waiting for the USB to be ready.
+        synchronized (mUsbSetup) {
+            mSetupReady = true;
+            Log.v(TAG, "Setup ready");
+            mUsbSetup.notifyAll();
+        }
+    }
+
+    /**
+     * Closes the ADK and detaches the output stream from it.
+     */
+    private void closeAccessory() {
+	try {
+	    if (mFileDescriptor != null) {
+                mFileDescriptor.close();
+	    }
+	} catch (IOException e) {
+        } finally {
+	    mFileDescriptor = null;
+	    mAccessory = null;
+        }
+    }
+
+    /**
+     * Constructs the AutoLockTest class, which can execute a series of tests
+     * to verify whether the device's Auto Exposure Lock is working properly.
+     *
+     * The test uses the LED lights on an ADK device as light source to change
+     * the lighting condition of the environment. The usb connection to the
+     * ADK board is established in the constructor.
+     *
+     * @param hostActivity pointer to the <code>CameraAnalyzerActivity</code>
+     * that instructs the Auto Lock Test
+     * @param mCamera pointer to the current camera instance
+     */
+    private AutoLockTest(){
+        super();
+    }
+
+    public static synchronized AutoLockTest getSingletonTest() {
+        if (singletonTest == null) {
+            Log.v(TAG, "Creating a new AutoLockTest instance");
+            singletonTest = new AutoLockTest();
+            singletonTest.initializeTest();
+        }
+        return singletonTest;
+    }
+
+    private void initializeTest() {
+        // Creates a native test handler with a 120x160 pixel debug output
+        mTestHandler = createAutoLockTest();
+        mReferenceCompareResults = new ArrayList<Boolean>();
+        mReferenceLogs = new ArrayList<String>();
+        mNumTests = 4;
+        mTestResults = new String[mNumTests];
+        for (int i = 0; i < mNumTests; ++i) {
+            mTestResults[i] = "...";
+        }
+    }
+
+    public void updateCamera() {}
+
+    public void setActivity(CameraAnalyzerActivity hostActivity){
+        if (mUsingUsb) {
+            closeConnection();
+        }
+
+        mActivity = hostActivity;
+
+        mSetupReady = false;
+
+        Log.v(TAG, "Start to test ADK connection");
+        // Starts to establish the connection to the ADK board.
+        mUsbManager = (UsbManager) mActivity.getSystemService(Context.USB_SERVICE);
+        mPermissionIntent = PendingIntent.getBroadcast(mActivity, 0,
+                                                       new Intent(ACTION_USB_PERMISSION), 0);
+        IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+        filter.addAction(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+        mActivity.registerReceiver(mUsbReceiver, filter);
+
+        if (mActivity.getLastNonConfigurationInstance() != null) {
+            mAccessory = (UsbAccessory) mActivity.getLastNonConfigurationInstance();
+            Log.v(TAG, "Open acceossory 1");
+            openAccessory(mAccessory);
+        }
+
+        // Skips the permission listener if the user already grants the ADK
+        // permission previously in the app.
+        UsbAccessory[] accessories = mUsbManager.getAccessoryList();
+        UsbAccessory accessory = (accessories == null ? null : accessories[0]);
+        if (accessory != null) {
+            if (mUsbManager.hasPermission(accessory)) {
+                Log.v(TAG, "Open accessory 2");
+                openAccessory(accessory);
+            } else {
+                synchronized (mUsbReceiver) {
+                    if (!mPermissionRequestPending) {
+                        mUsbManager.requestPermission(accessory, mPermissionIntent);
+                        mPermissionRequestPending = true;
+                    }
+                }
+            }
+            mUsingUsb = true;
+        } else {
+            Log.d(TAG, "accessory is null");
+            mUsingUsb = false;
+        }
+
+    }
+
+    /**
+     * Closes the accessories and unregister the USB listener at the end of
+     * tests.
+     */
+    public void closeConnection() {
+        closeAccessory();
+        mActivity.unregisterReceiver(mUsbReceiver);
+    }
+
+    protected void finalize ()  {
+        if (mUsingUsb) {
+            closeConnection();
+        }
+    }
+
+    /**
+     * Runs the Auto Lock tests. A total of 19 tests have been coded and
+     * included. Developers can freely comment out tests not interested. In
+     * the release version, all tests will be executed.
+     */
+    @Override
+    public synchronized void run(int index){
+        if (index == 0) {
+            for (int i = 1; i < mNumTests; ++i) {
+                run(i);
+            }
+            return;
+        }
+
+        Log.v(TAG, "AutoLockTest thread started!");
+
+        if (mUsingUsb && (!mSetupReady)) {
+            // USB connection is not set up. Locks thread and wait.
+            Log.v(TAG, "Setup not ready, waiting");
+            synchronized (mUsbSetup) {
+                try{
+                    Log.v(TAG, "Start waiting for Image");
+                    mUsbSetup.wait();
+                } catch (InterruptedException e) {
+                    Log.v(TAG, "Callback wait fails!");
+                }
+            }
+        }
+
+        // Restarts the camera intance and attach the preview to the corrent
+        // UI elements.
+        restartCamera();
+        startPreview();
+
+        mTestCount = 0;
+        switch (index) {
+            case 1:
+                Log.v(TAG, "SP -> TP1 -> SP -> +1 -> Lock -> -1 -> TP2");
+                test0();
+                Log.v(TAG, "SP -> TP1 -> SP -> Lock -> +1 -> TP2 -> -1");
+                test1();
+                Log.v(TAG, "SP -> Lock -> +1 -> TP1 -> SP -> -1 -> Lock -> TP2");
+                test2();
+                Log.v(TAG, "SP -> Lock -> +1 -> TP1 -> SP -> Lock -> -1 -> TP2");
+                test3();
+                break;
+            case 2:
+                Log.v(TAG, "SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2");
+                test4();
+                Log.v(TAG, "SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2");
+                test5();
+                Log.v(TAG, "SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
+                test6();
+                Log.v(TAG, "SP -> TP1 -> +1 -> Lock -> SP -> TP2");
+                test7();
+                Log.v(TAG, "SP -> TP1 -> Lock -> SP -> +1 -> TP2");
+                test8();
+                Log.v(TAG, "SP -> +1 -> Lock -> -1 -> TP1 -> Lock -> SP -> TP2");
+                test9();
+                Log.v(TAG, "SP -> +1 -> Lock -> TP1 -> -1 -> Lock -> SP -> TP2");
+                test10();
+                Log.v(TAG, "SP -> Lock -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
+                test11();
+                break;
+            case 3:
+                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Restart -> Lock -> SP -> +1 -> TP2");
+                test12();
+                Log.v(TAG, "Restart -> Lock -> SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2");
+                test13();
+                Log.v(TAG, "Restart -> Lock -> SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2");
+                test14();
+                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2");
+                test15();
+                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> TP2");
+                test16();
+                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Lock -> SP -> +1 -> TP2");
+                test17();
+                Log.v(TAG, "Restart -> Lock -> SP -> TP1 -> Lock -> SP -> TP2");
+                test18();
+                break;
+            default:
+                break;
+        }
+
+        releaseLock();
+
+        Log.v(TAG, "Ready to process data");
+        boolean[] testCompareResults = new boolean[2 * mTestCount];
+
+        // Processes the data stored in the native test handler instance.
+        // Stores the test results into a boolean array.
+        processAutoLockTest(mTestHandler, testCompareResults);
+
+        // Prepares the test result text output with the booelan result array.
+        prepareDebugText(testCompareResults, index);
+        mReferenceCompareResults.clear();
+        mReferenceLogs.clear();
+    }
+
+    /**
+     * Compares two images taken under the same lighting, Image 1 without AE
+     * lock and Image 2 with AE locked under a bright light. Image 1 is
+     * expected to be brighter than Image 2.
+     * Tests whether AE lock works compared to no AE lock.
+     */
+    private void test0() {
+        releaseLock();
+        takePicture();
+        startPreview();
+        turnOnLight();
+        setLock();
+        turnOffLight();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Same lighting condition with one different lock");
+        ++mTestCount;
+    }
+
+    /**
+     * Compares two images taken under different lighting, Image 1 without AE
+     * lock and Image 2 with with AE locked under the same light Image 1 is
+     * taken. Image 2 is taken under a bright light. Image 1 is expected to be
+     * darker than Image 2.
+     * Tests whether AE lock works compared to no AE lock.
+     */
+    private void test1() {
+        releaseLock();
+        takePicture();
+        startPreview();
+        setLock();
+        turnOnLight();
+        takePicture();
+        turnOffLight();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("One same lock with different lighting");
+        ++mTestCount;
+    }
+
+    /**
+     * Compares two images taken under different light, both with AE locked
+     * under the same lighting. Image 1 is taken under a brighter light.
+     * Image 1 is expected to be brighter than Image 2.
+     * Tests whether AE locks the exposure to the same level in the same
+     * lighting condition after preview restarts.
+     */
+     private void test2() {
+        releaseLock();
+        setLock();
+        turnOnLight();
+        takePicture();
+        startPreview();
+        turnOffLight();
+        setLock();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Same locking locations with different lighting");
+        ++mTestCount;
+    }
+
+    /**
+     * Compares two images taken under different light, Image 1 with AE locked
+     * under normal light and Image 2 with AE locked under a bright light.
+     * Image 1 is taken under a bright light and Image 2 is taken in the normal
+     * lighting. Image 1 is expected to be brighter than Image 2.
+     * Tests whether AE lock can adjust to change of lighting conditions.
+     */
+    private void test3() {
+        releaseLock();
+        setLock();
+        turnOnLight();
+        takePicture();
+        startPreview();
+        setLock();
+        turnOffLight();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Different locking locations with different lighting");
+        ++mTestCount;
+    }
+
+    /**
+     * Compares two images taken under different lighting, Image 1 without
+     * AE lock and Image 2 with AE lock set before camera preview resumes.
+     * Image 1 is taken under a bright light and the light is turned off before
+     * camera preview starts again. Image 1 is expected to be brighter than
+     * Image 2.
+     * Tests whether setting AE lock between camera preview stops and restarts
+     * can retain the exposure level of the previous AE-unlocked photo.
+     */
+    private void test4() {
+        releaseLock();
+        turnOnLight();
+        takePicture();
+        turnOffLight();
+        setLock();
+        startPreview();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after takePicture and light change, before preview");
+        ++mTestCount;
+    }
+
+    /**
+     * Compares two images taken under different lighting, Image 1 without
+     * AE lock and Image 2 with AE lock set before camera preview resumes.
+     * Image 1 is taken under a bright light and the light is turned off after
+     * preview restars but before Image 2 is taken. Image 1 is expected to be
+     * brighter than Image 2.
+     * Tests whether setting AE lock between camera preview stops and restarts
+     * can retain the exposure level of the previous AE-unlocked photo.
+     */
+    private void test5() {
+        releaseLock();
+        turnOnLight();
+        takePicture();
+        setLock();
+        startPreview();
+        turnOffLight();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock between takePicture and light change, w/o light change");
+        ++mTestCount;
+    }
+
+    private void test6() {
+        releaseLock();
+        takePicture();
+        turnOnLight();
+        setLock();
+        startPreview();
+        turnOffLight();
+        takePicture();
+        startPreview();
+        releaseLock();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add("Lock after takePicture and light change, before preview.");
+        ++mTestCount;
+    }
+
+    private void test7() {
+        releaseLock();
+        takePicture();
+        turnOnLight();
+        setLock();
+        startPreview();
+        takePicture();
+        startPreview();
+        releaseLock();
+        turnOffLight();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after takePicture and light change, before preview.");
+        ++mTestCount;
+    }
+
+    private void test8() {
+        releaseLock();
+        takePicture();
+        setLock();
+        startPreview();
+        turnOnLight();
+        takePicture();
+        startPreview();
+        releaseLock();
+        turnOffLight();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after takePicture and before startPreview.");
+        ++mTestCount;
+    }
+
+    private void test9() {
+        releaseLock();
+        turnOnLight();
+        setLock();
+        turnOffLight();
+        takePicture();
+        setLock();
+        startPreview();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test10() {
+        releaseLock();
+        turnOnLight();
+        setLock();
+        takePicture();
+        turnOffLight();
+        setLock();
+        startPreview();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test11() {
+        releaseLock();
+        setLock();
+        takePicture();
+        turnOnLight();
+        setLock();
+        startPreview();
+        turnOffLight();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test12() {
+        //"Restart -> Lock -> SP -> TP1 -> Restart -> Lock -> SP -> +1 -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        takePicture();
+        releaseLock();
+        restartCamera();
+        setLock();
+        startPreview();
+        turnOnLight();
+        takePicture();
+        releaseLock();
+        turnOffLight();
+        startPreview();
+        //mTestCamera.release();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock before first preview");
+        ++mTestCount;
+    }
+
+    private void test13() {
+        //"Restart -> Lock -> SP -> +1 -> TP1 -> -1 -> Lock -> SP -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        turnOnLight();
+        takePicture();
+        turnOffLight();
+        setLock();
+        startPreview();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test14() {
+        //"Restart -> Lock -> SP -> +1 -> TP1 -> Lock -> SP -> -1 -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        turnOnLight();
+        takePicture();
+        setLock();
+        startPreview();
+        turnOffLight();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test15() {
+        //"Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> -1 -> TP2"
+         restartCamera();
+        setLock();
+        startPreview();
+        takePicture();
+        turnOnLight();
+        setLock();
+        startPreview();
+        turnOffLight();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test16() {
+        //"Restart -> Lock -> SP -> TP1 -> +1 -> Lock -> SP -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        takePicture();
+        turnOnLight();
+        setLock();
+        startPreview();
+        takePicture();
+        turnOffLight();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test17() {
+        //"Restart -> Lock -> SP -> TP1 -> Lock -> SP -> +1 -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        takePicture();
+        setLock();
+        startPreview();
+        turnOnLight();
+        takePicture();
+        turnOffLight();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    private void test18() {
+        //"Restart -> Lock -> SP -> TP1 -> Lock -> SP -> TP2"
+        restartCamera();
+        setLock();
+        startPreview();
+        takePicture();
+        setLock();
+        startPreview();
+        takePicture();
+        releaseLock();
+        startPreview();
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add("Lock after first lock with changing light");
+        ++mTestCount;
+    }
+
+    /**
+     * Restarts the camera by releasing the current instance and get a new
+     * instance. Also connects this new camera instance's preview to the proper
+     * UI surfaceview.
+     */
+    private void restartCamera() {
+        Log.v(TAG, "Restarting Camera");
+
+        mTestCamera.release();
+        Log.v(TAG, "Camera released");
+
+        try {
+            mTestCamera = Camera.open(mActivity.getCameraIdx());
+        } catch (RuntimeException e) {
+            throw new RuntimeException("Failed to open the camera", e);
+        }
+
+        Camera.Parameters params = mTestCamera.getParameters();
+        params.setPictureFormat(ImageFormat.JPEG);
+        params.setPictureSize(640, 480);
+        mTestCamera.setParameters(params);
+
+        try {
+            mTestCamera.setPreviewDisplay(super.getCameraView().getHolder());
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to connect camera to display: " + e);
+        }
+    }
+
+    /**
+     * Starts Camera preview with a delay of 2 seconds to let it adjust to
+     * the lighting condition.
+     */
+    private void startPreview() {
+        mTestCamera.startPreview();
+        try{
+            Log.v(TAG, "Waiting");
+            Thread.sleep(2000);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e){}
+    }
+
+    /**
+     * Sends command to ADK to turn on all the LED lights to white.
+     * Waits for 4 seconds for the camera to adjust to the new lighting.
+     */
+    private void turnOnLight() {
+        Log.v(TAG, "Turn on light");
+        if (mUsingUsb) {
+            byte[] buffer = new byte[3];
+
+            buffer[0] = (byte) 3;
+            buffer[1] = (byte) 0;
+            buffer[2] = (byte) 1;
+            if (mOutputStream != null && buffer[1] != -1) {
+                try {
+                    mOutputStream.write(buffer);
+                } catch (IOException e) {
+                    Log.e(TAG, "write failed", e);
+                }
+            }
+        } else {
+            mActivity.runOnUiThread(new Runnable() {
+                public void run() {
+                    Toast.makeText(mActivity.getApplicationContext(), "Turn on light!", 4).show();
+
+                }
+            });
+        }
+
+        try{
+            Log.v(TAG, "Waiting, Please Turn on light");
+            Thread.sleep(LONG_SLEEP);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e){}
+    }
+
+    /**
+     * Sends command to ADK to turn off all LED lights.
+     * Waits for 4 seconds for the camera to adjust to the new lighting.
+     */
+    private void turnOffLight() {
+        Log.v(TAG, "Turn off light");
+        if (mUsingUsb) {
+            byte[] buffer = new byte[3];
+
+            buffer[0] = (byte) 3;
+            buffer[1] = (byte) 0;
+            buffer[2] = (byte) 0;
+            if (mOutputStream != null && buffer[1] != -1) {
+                try {
+                    mOutputStream.write(buffer);
+                } catch (IOException e) {
+                    Log.e(TAG, "write failed", e);
+                }
+            }
+        } else {
+            mActivity.runOnUiThread(new Runnable() {
+                public void run() {
+                    Toast.makeText(mActivity.getApplicationContext(), "Turn off light!", 4).show();
+
+                }
+            });
+        }
+
+        try{
+            Log.v(TAG, "Waiting, Please Turn off light");
+            Thread.sleep(LONG_SLEEP);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e){}
+    }
+
+    /**
+     * Sets the Auto Exposure Lock.
+     * Waits for 2 seonds for the lock to function.
+     */
+    private void setLock() {
+        Camera.Parameters params = mTestCamera.getParameters();
+
+        params.setAutoExposureLock(true);
+        params.setAutoWhiteBalanceLock(true);
+        mTestCamera.setParameters(params);
+        try{
+            Log.v(TAG, "Waiting to set lock");
+            Thread.sleep(2000);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e){}
+    }
+
+    /**
+     * Releases the Auto Exposure Lock.
+     * Waits for 4 seconds afterwards for the Auto Exposure to be adjusted
+     * to the lighting condition.
+     */
+    private void releaseLock() {
+        Camera.Parameters params = mTestCamera.getParameters();
+
+        params.setAutoExposureLock(false);
+        params.setAutoWhiteBalanceLock(false);
+        mTestCamera.setParameters(params);
+        try{
+            Log.v(TAG, "Waiting to release lock");
+            Thread.sleep(LONG_SLEEP);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e){}
+
+    }
+
+    /**
+     * Takes a picture and locks thread until the picture callback finishes.
+     */
+    private void takePicture(){
+        mTestCamera.takePicture(null, null, null, mTestJpegListener);
+
+        synchronized (mProcessingImage) {
+            try{
+                Log.v(TAG, "Start waiting for Image");
+              //  System.gc();
+                mProcessingImage.wait();
+            } catch (InterruptedException e){
+                 Log.v(TAG, "Callback wait fails!");
+            }
+        }
+    }
+
+    /**
+     * Prepare for the result to be shown in the UI. The result for each single
+     * test is shown in green if it matches the reference result. It is shown
+     * in red otherwise.
+     */
+    private void prepareDebugText(boolean[] testCompareResults, int index) {
+        boolean groupTestPassed = true;
+         for (int i = 0; i < mTestCount; ++i) {
+              String testLog;
+              boolean testPassed = true;
+              testLog = mReferenceLogs.get(i);
+              mDebugText += (testLog + "<br/>");
+
+              if (testCompareResults[i * 2] == mReferenceCompareResults.get(i * 2)) {
+                  mDebugText += String.format(
+                      "Picture 1 brighter than Picture 2 is %b \n",
+                      testCompareResults[i * 2]);
+              } else {
+                  mDebugText += String.format(
+                      "Picture 1 brighter than Picture 2 is %b \n",
+                      testCompareResults[i * 2]);
+                  testPassed = false;
+              }
+
+              if (testCompareResults[i * 2 + 1] == mReferenceCompareResults.get(i * 2 + 1)) {
+                  mDebugText += String.format(
+                      "Picture 1 is equivalent to Picture 2 is %b \n",
+                      testCompareResults[i * 2 + 1]);
+              } else {
+                  mDebugText += String.format(
+                      "Picture 1 is equivalent to Picture 2 is %b \n",
+                      testCompareResults[i * 2 + 1]);
+                  testPassed = false;
+              }
+
+              if (testPassed) {
+                  mDebugText += "Test passed! \n";
+              } else {
+                  mDebugText += "Test failed! \n";
+                  groupTestPassed = false;
+              }
+         }
+        if (groupTestPassed) {
+            mTestResults[index] = "Passed";
+        } else {
+            mTestResults[index] = "Failed";
+        }
+    }
+
+    /**
+     * Clears the debug text so that new test results can be added.
+     */
+    public void clearDebugText() {
+        mDebugText = "";
+    }
+
+    @Override
+    public String getDebugText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getResultText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getTestName() {
+        return "Auto Exposure Lock test: \n";
+    }
+
+    @Override
+    public String getTestName(int index) {
+        switch (index) {
+            case 0:
+                return "Run all tests";
+            case 1:
+                return "Compulsory tests";
+            case 2:
+                return "Recommended tests (preview behavior)";
+            case 3:
+                return "Optional tests (default lock)";
+            default:
+                return "";
+        }
+    }
+
+    @Override
+    public String getResult(int index) {
+        return mTestResults[index];
+    }
+
+    @Override
+    public int getNumTests() {
+        return mNumTests;
+    }
+
+    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+        public void onPictureTaken(byte[] data, Camera mCamera) {
+            Log.v(TAG, "Shutter pressed down!");
+            Bitmap inputImage;
+
+            // Decodes the camera input data into Bitmap.
+            // Constructs a native image class with the image.
+            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+            long bufferAddress = findNative(inputImage);
+            Log.v(TAG, "findNative method finishes");
+
+            // Cleans up memory taken by the Bitmap.
+            data = null;
+            inputImage.recycle();
+            inputImage = null;
+            System.gc();
+
+            // Passes data from the native image class to the native
+            // test handler.
+            createAutoLockClass(bufferAddress, mTestHandler,
+                                getCheckerCenter(), getCheckerRadius());
+
+            // Unlocks the thread lock.
+            synchronized (mProcessingImage) {
+                mProcessingImage.notifyAll();
+            }
+        }
+    };
+
+    private native long createAutoLockTest();
+
+    private native void createAutoLockClass(long bufferAddress, long handlerAddress,
+                                            long checkerCenterAddress,
+                                            long checkerRadiusAddress);
+
+    private native void processAutoLockTest(long handlerAddress, boolean[] testCompareResults);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
index b50dd9e..ffe9d06 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraAnalyzerActivity.java
@@ -15,6 +15,7 @@
  */
 package com.android.cts.verifier.camera.analyzer;
 
+import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
 
 import android.app.Activity;
@@ -22,112 +23,459 @@
 import android.graphics.BitmapFactory;
 import android.graphics.ImageFormat;
 import android.hardware.Camera;
+import android.hardware.Camera.CameraInfo;
+import android.hardware.Camera.Size;
+import android.os.AsyncTask;
 import android.os.Bundle;
+import android.text.Html;
+import android.text.method.ScrollingMovementMethod;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
+import android.widget.Button;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.content.Context;
 
 import java.io.IOException;
+import java.lang.Thread;
+import java.util.List;
 
-public class CameraAnalyzerActivity extends Activity {
+/**
+ * Controls the UI activities of the camera quality test app. It is created
+ * as soon as the app started. Users can launch different quality tests with
+ * the buttons in the UI. This class will manage the threading for different
+ * tests. Also it will provide debug output or debug text results for tests.
+ */
+public class CameraAnalyzerActivity extends PassFailButtons.Activity {
 
-    Bitmap mInputImage;
-    TextView mResultText;
-    SurfaceView mCameraView;
-    ImageView mResultView;
-    Camera mCamera;
-    boolean mProcessingPicture = false;
+    private static final String TAG = "CameraAnalyzer";
+    private SurfaceView mCameraView;
+    private ImageView mResultView;
+    private Button mFindCheckerButton;
+    private Button mExposureCompensationButton;
+    private Button mWhiteBalanceButton;
+    private Button mAutoLockButton;
+    private Button mMeteringButton;
+    private ListView mTestList;
+    private TwoColumnAdapter mAdapter;
+
+    private Camera mCamera;
+    private int mCameraIdx = 0;
+    private boolean mIsCameraOpen = false;
+
+    private PowerManager mPowerManager;
+    private PowerManager.WakeLock mWakeLock;
+
+    private boolean mProcessingPicture = false;
+    private boolean mTestInProgress = false;
+    private final Object mProcessingTest = new Object();
+    private CameraTests mCurrentTest = null;
+
+    private long mCheckerCenterAddress;
+    private long mCheckerRadiusAddress;
+
+    private String mResultReport = "";
+    static final String[] TESTS = new String[] {"Test1", "Test2"};
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.ca_main);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.camera_analyzer, R.string.ca_info, -1);
 
-        findViewById(R.id.runbutton).setOnClickListener(mRunListener);
+        mFindCheckerButton = (Button) findViewById(R.id.findcheckerboardbutton);
+        mExposureCompensationButton = (Button) findViewById(R.id.exposurecompensationbutton);
+        mWhiteBalanceButton = (Button) findViewById(R.id.whitebalancebutton);
+        mAutoLockButton = (Button) findViewById(R.id.lockbutton);
+        mMeteringButton = (Button) findViewById(R.id.meteringbutton);
+        mCameraView = (SurfaceView) findViewById(R.id.cameraview);
+        mResultView = (ImageView) findViewById(R.id.resultview);
+        mTestList = (ListView) findViewById(R.id.ca_tests);
+        mAdapter = new TwoColumnAdapter(this);
 
-        mCameraView = (SurfaceView)findViewById(R.id.cameraview);
-        mResultView = (ImageView)findViewById(R.id.resultview);
-        mResultText = (TextView)findViewById(R.id.resulttext);
+        // Initialize the list view.
+        initializeAdapter();
+        mTestList.setAdapter(mAdapter);
+        mTestList.setOnItemClickListener(mListListener);
+
+        mFindCheckerButton.setOnClickListener(mFindCheckerListener);
+        mExposureCompensationButton.setOnClickListener(mExposureCompensationListener);
+        mWhiteBalanceButton.setOnClickListener(mWhiteBalanceListener);
+        mAutoLockButton.setOnClickListener(mAutoLockListener);
+        mMeteringButton.setOnClickListener(mMeteringListener);
         mCameraView.getHolder().addCallback(mSurfaceChangeListener);
+
+        // Disables all test buttons except the color checker test one.
+        // They will be enabled after the color checker is located.
+        mExposureCompensationButton.setEnabled(false);
+        mWhiteBalanceButton.setEnabled(false);
+        mAutoLockButton.setEnabled(false);
+        mMeteringButton.setEnabled(false);
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        mCamera = Camera.open(0);
+
+        openCamera(mCameraIdx);
         Camera.Parameters params = mCamera.getParameters();
         params.setPictureFormat(ImageFormat.JPEG);
+        params.setPictureSize(640, 480);
         mCamera.setParameters(params);
+        Log.v(TAG, "Set resolution to 640*480");
     }
 
     @Override
     public void onPause() {
         super.onPause();
-        mCamera.release();
+        CameraTests.getCamera().release();
+        mIsCameraOpen = false;
     }
 
-    private View.OnClickListener mRunListener = new View.OnClickListener() {
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        MenuInflater inflater = getMenuInflater();
+        inflater.inflate(R.menu.ca_menu, menu);
+
+        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+        int cameraCount = Camera.getNumberOfCameras();
+        for (int camIdx = 0; camIdx < cameraCount; ++camIdx) {
+            MenuItem cameraMenuItem = menu.add(0, camIdx, Menu.NONE,
+                                               String.format("Open Camera %d", camIdx));
+        }
+      return true;
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        if (item.getItemId() != mCameraIdx) {
+            mCameraIdx = item.getItemId();
+            new SwitchCameraTask().execute(mCameraIdx);
+        }
+        return false;
+    }
+
+    private class SwitchCameraTask extends AsyncTask<Integer, Void, Void> {
+        @Override
+        protected Void doInBackground(Integer... camIdx) {
+            if (mTestInProgress) {
+                synchronized (mProcessingTest) {
+                    try{
+                        Log.v(TAG, "Waiting for test to finish");
+                        mProcessingTest.wait();
+                    } catch (InterruptedException e){
+                         Log.v(TAG, "test wait fails!");
+                    }
+                }
+            }
+
+            openCamera((int)camIdx[0]);
+            return null;
+        }
+    }
+
+    private synchronized void openCamera(int camIdx) {
+        if (mIsCameraOpen) {
+            CameraTests.getCamera().release();
+            Log.v(TAG, "Releasing the cameratests camera");
+        }
+        try {
+            mCamera = Camera.open(camIdx);
+            mIsCameraOpen = true;
+        } catch (RuntimeException e) {
+            throw new RuntimeException("Failed to open the camera", e);
+        }
+
+        try {
+            mCamera.setPreviewDisplay(mCameraView.getHolder());
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to connect camera to display: " + e);
+        }
+        mCamera.startPreview();
+        CameraTests.setCamera(mCamera);
+
+        ColorCheckerTest.getSingletonTest().updateCamera();
+        WhiteBalanceTest.getSingletonTest().updateCamera();
+        ExposureCompensationTest.getSingletonTest().updateCamera();
+        MeteringTest.getSingletonTest().updateCamera();
+        AutoLockTest.getSingletonTest().updateCamera();
+    }
+
+    public Camera getCameraInstance() {
+        return mCamera;
+    }
+
+    public void disableAll() {
+        mExposureCompensationButton.setEnabled(false);
+        mWhiteBalanceButton.setEnabled(false);
+        mAutoLockButton.setEnabled(false);
+        mMeteringButton.setEnabled(false);
+        mFindCheckerButton.setEnabled(false);
+    }
+
+    public void enableAll() {
+        mExposureCompensationButton.setEnabled(true);
+        mWhiteBalanceButton.setEnabled(true);
+        mAutoLockButton.setEnabled(true);
+        mMeteringButton.setEnabled(true);
+        mFindCheckerButton.setEnabled(true);
+    }
+
+    /**
+     * Provides an abstraction for the Camera tests. The camera tests will
+     * run in the background and the results will be shown in the UI thread
+     * after the tests are processed.
+     */
+    private class DebugOutputProcessingTask extends AsyncTask<Integer,
+                                                              Integer,
+                                                              Integer> {
+        @Override
+        protected Integer doInBackground(Integer... cameraTestIndex) {
+            Log.v(TAG, "Do in Background started!");
+
+            mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+            mWakeLock = mPowerManager.newWakeLock(
+                    PowerManager.SCREEN_DIM_WAKE_LOCK, "CameraQualityTest");
+            mWakeLock.acquire();
+
+            mTestInProgress = true;
+
+            // Processes the camera tests one by one and publishes their
+            // debug output or debug text results after each test is done.
+            mCurrentTest.run((int)cameraTestIndex[0]);
+            publishProgress(cameraTestIndex);
+
+            Log.v(TAG, "Do in Background thread returns!");
+            return cameraTestIndex[0];
+        }
+
+        @Override
+        protected void onProgressUpdate(Integer... cameraTestIndex) {
+            Log.v(TAG, "Prepare to get debug output!");
+
+            // Copies the debug output image or text results to the UI.
+            mResultView.setImageBitmap(mCurrentTest.getDebugOutput());
+            mResultReport += (mCurrentTest.getTestName() + mCurrentTest.getDebugText());
+            mAdapter.notifyDataSetChanged();
+        }
+
+        @Override
+        protected void onPostExecute(Integer cameraTestIndex) {
+
+            // If the test is to find the color checker, copy the memory
+            // address of the found color checker centers and radius to the
+            // CameraTests class' static fields.
+            if (mCurrentTest.copyCheckerAddress()) {
+                mCheckerCenterAddress = CameraTests.getCheckerCenter();
+                mCheckerRadiusAddress = CameraTests.getCheckerRadius();
+            }
+
+            if (mCurrentTest.copyCheckerAddress() ||
+                !mCurrentTest.getTestName().contains("Color Checker")) {
+                // Enables the button of all other tests after the color checker
+                // is found. Now the user can start all other available tests.
+                enableAll();
+            }
+
+            mWakeLock.release();
+            mTestInProgress = false;
+            synchronized (mProcessingTest) {
+                mProcessingTest.notifyAll();
+            }
+
+        }
+    }
+
+    // Creates and runs a new test to find color checker in the captured image.
+    // It is invoked when users press the Find color checker button in the UI.
+    private View.OnClickListener mFindCheckerListener = new View.OnClickListener() {
         @Override
         public void onClick(View v) {
-            if (!mProcessingPicture) {
-                mCamera.takePicture(null, null, null, mJpegListener);
-                mProcessingPicture = true;
-            }
+            Log.v(TAG, "Running new color checker finding tests!");
+            ColorCheckerTest colorCheckerTest = ColorCheckerTest.getSingletonTest();
+
+            mCurrentTest = colorCheckerTest;
+            initializeAdapter();
         }
     };
 
-    private Camera.PictureCallback mJpegListener = new Camera.PictureCallback() {
-        public void onPictureTaken(byte[] data, Camera mCamera) {
-            mCamera.startPreview();
-            mInputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
-            ColorChecker checker = new ColorChecker(mInputImage);
-            mResultView.setImageBitmap(checker.getDebugOutput());
-            if (checker.isValid()) {
-                String patchValueTxt = new String();
-                for (int y = 0; y < 4; y++) {
-                    for (int x = 0; x < 6; x++) {
-                        patchValueTxt +=
-                                String.format("[ %.3f, %.3f, %.3f] ",
-                                              checker.getPatchValue(x,y,0),
-                                              checker.getPatchValue(x,y,1),
-                                              checker.getPatchValue(x,y,2));
-                    }
-                    patchValueTxt += "\n";
-                }
-                mResultText.setText(patchValueTxt);
-            } else {
-                mResultText.setText("Can't find color checker!");
+    // Creates and runs a new test to test the exposure compensation function.
+    // It is invoked when users press the Exposure Compensation Test button
+    // in the UI.
+    private View.OnClickListener mExposureCompensationListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            Log.v(TAG, "Running new exposure compensation tests!");
+
+            ExposureCompensationTest exposureCompensationTest =
+                    ExposureCompensationTest.getSingletonTest();
+
+            mCurrentTest = exposureCompensationTest;
+            initializeAdapter();
+
+            // Loads the memory address of the checker centers and radius
+            // from the this class and set the two values for the new test.
+            ExposureCompensationTest.setCheckerAddress(mCheckerCenterAddress,
+                                                   mCheckerRadiusAddress);
+        }
+    };
+
+    // Creates and runs a new test to test the white balance function.
+    // It is invoked when users press the White Balance Test button in the UI.
+    private View.OnClickListener mWhiteBalanceListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            Log.v(TAG, "Running new white balance tests!");
+
+            WhiteBalanceTest whiteBalanceTest = WhiteBalanceTest.getSingletonTest();
+
+            mCurrentTest = whiteBalanceTest;
+            initializeAdapter();
+
+            // Loads the memory address of the checker centers and radius
+            // from the this class and set the two values for the new test.
+            WhiteBalanceTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
+        }
+    };
+
+    // Creates and runs a new test to test the camera metering function.
+    // It is invoked when users press the Metering Test button in the UI.
+    private View.OnClickListener mMeteringListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            Log.v(TAG, "Running new metering tests!");
+
+            MeteringTest meteringTest = MeteringTest.getSingletonTest();
+
+            mCurrentTest = meteringTest;
+            initializeAdapter();
+
+            // Loads the memory address of the checker centers and radius
+            // from the this class and set the two values for the new test.
+            MeteringTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
+        }
+    };
+
+    // Creates and runs new tests to test the camera auto exposure lock.
+    // It is invoked when users press the AWB and AE Lock Test button
+    // in the UI.
+    private View.OnClickListener mAutoLockListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            Log.v(TAG, "Running New auto exposure/wb lock tests!");
+
+            // Loads the memory address of the checker centers and radius
+            // from the this class and set the two values for the new test.
+            AutoLockTest.setCheckerAddress(mCheckerCenterAddress, mCheckerRadiusAddress);
+
+            // Construct all base case test scenearios for the Auto Lock test.
+            // Detailed documentation on each test can be found in native code.
+            AutoLockTest autoLockTest = AutoLockTest.getSingletonTest();
+            autoLockTest.setActivity(CameraAnalyzerActivity.this);
+
+            mCurrentTest = autoLockTest;
+            initializeAdapter();
+
+        }
+    };
+
+    // Creates a list listner that launches the experiment with the user's click
+    private AdapterView.OnItemClickListener mListListener = new AdapterView.OnItemClickListener() {
+        @Override
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            Log.v(TAG, String.format("Item %d selected!", position));
+            if (!mTestInProgress) {
+                DebugOutputProcessingTask captureTask = new DebugOutputProcessingTask();
+                disableAll();
+                captureTask.execute(position);
             }
-            mProcessingPicture = false;
         }
     };
 
     private SurfaceHolder.Callback mSurfaceChangeListener =
             new SurfaceHolder.Callback() {
+
+        // Sets the aspect ratio of the camera preview to 4:3
         @Override
         public void surfaceChanged(SurfaceHolder holder,
                                    int format,
                                    int width,
                                    int height) {
+            int x = mCameraView.getWidth();
+            int y = mCameraView.getHeight();
+            Log.v(TAG, String.format("Measures are %d, %d", x, y));
 
-        }
+            if ( x > 4.0 / 3.0 * y) {
+                android.view.ViewGroup.LayoutParams lp = mCameraView.getLayoutParams();
+                lp.height =  y;
+                lp.width = (int)(4.0 / 3.0 * lp.height);
+                Log.v(TAG, String.format("params are %d, %d", lp.width, lp.height));
+                mCameraView.setLayoutParams(lp);
+            }
 
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {
             try {
                 mCamera.setPreviewDisplay(mCameraView.getHolder());
             } catch (IOException e) {
                 throw new RuntimeException("Unable to connect camera to display: " + e);
             }
+            CameraTests.setCameraView(mCameraView);
             mCamera.startPreview();
         }
 
         @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
+        public void surfaceCreated(SurfaceHolder holder) {}
 
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {}
+    };
+
+    @Override
+    public String getTestDetails() {
+        return mResultReport;
+    }
+
+    class TwoColumnAdapter extends ArrayAdapter<String> {
+        TwoColumnAdapter(Context context) {
+            super(context, R.layout.ca_row);
         }
 
-    };
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            LayoutInflater inflater = getLayoutInflater();
+            View row = inflater.inflate(R.layout.ca_row, parent, false);
+            TextView nameField = (TextView) row.findViewById(R.id.caTestName);
+            TextView resultField = (TextView) row.findViewById(R.id.caTestResult);
+            if (mCurrentTest != null) {
+                nameField.setText(mCurrentTest.getTestName(position));
+                resultField.setText(mCurrentTest.getResult(position));
+            }
+            return row;
+        }
+    }
+
+    private void initializeAdapter() {
+        mAdapter.clear();
+        if (mCurrentTest != null) {
+            for (int i = 0; i < mCurrentTest.getNumTests(); ++i) {
+                mAdapter.add(mCurrentTest.getTestName(i));
+            }
+        }
+    }
+
+    public int getCameraIdx() {
+        return mCameraIdx;
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java
new file mode 100644
index 0000000..7cea762
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/CameraTests.java
@@ -0,0 +1,197 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.hardware.Camera;
+import android.os.Environment;
+import android.util.Log;
+import android.view.SurfaceView;
+
+import java.io.FileOutputStream;
+import java.io.File;
+import java.lang.Runnable;
+
+/**
+ * Provides an abstraction for all camera tests and allows communication
+ * between camera test classes with the UI thread. This base class provides
+ * functions to contruct and access debug output images. It can access and
+ * set the pointer address of checkerboard centers and radius. It also provides
+ * native methods to convert an image shot by the camera into a native
+ * character array. Another native method it provides is to create a native
+ * test handler with desired debug height and width.
+ */
+public abstract class CameraTests{
+
+    private static final String TAG = "CameraTests";
+
+    /** Memory address of the color checker centers. */
+    private static long sCheckerCenterAddress = 0;
+    /** Memory address of the color checker radius. */
+    private static long sCheckerRadiusAddress = 0;
+    /** The surface view linked with the camera preview. */
+    private static SurfaceView sCameraView;
+    /** Image debug output. */
+    private Bitmap mDebugOutput;
+    /** Shared camera instance. */
+    protected static Camera mTestCamera = null;
+
+    /**
+     * Constructs the base CameraTests class.
+     */
+    public CameraTests() {}
+
+    /**
+     * Returns debug Bitmap image. In the test to find the color checker,
+     * the debug image will be the captured image with a matched color checker
+     * overlay on top. In the exposure compensation test, the debug image
+     * will be the response curve of the camera.
+     * @return A low-resolution Bitmap to be displayed in the UI.
+     */
+    public Bitmap getDebugOutput() {
+        return mDebugOutput;
+    }
+
+    public String getDebugText() {
+        return "";
+    }
+
+    public abstract String getTestName();
+
+    /**
+     * Gets the detailed report for CTS output.
+     */
+    public String getResultText(){
+        return "Details not available \n";
+    }
+
+    /**
+     * Provides a polymorphism to start the run() method for all child classes.
+     */
+    public abstract void run(int index);
+
+    public SurfaceView getCameraView() {
+        return sCameraView;
+    }
+
+    public static void setCameraView(SurfaceView cameraView) {
+        sCameraView = cameraView;
+    }
+
+    /**
+     * Refreshes the camera instance when the activity opens a new camera.
+     */
+    public static void setCamera(Camera newCamera) {
+        mTestCamera = newCamera;
+    }
+
+    public static Camera getCamera() {
+        return mTestCamera;
+    }
+
+    /**
+     * Sets the memory address of the checker centers and checker radius.
+     *
+     * @param inputCenterAddress the new memory address of
+     *                           the color checker centers
+     * @param inputRadiusAddress the new memory address of
+     *                           the color checker radius
+     */
+    public static void setCheckerAddress(long inputCenterAddress, long inputRadiusAddress) {
+        sCheckerCenterAddress = inputCenterAddress;
+        sCheckerRadiusAddress = inputRadiusAddress;
+    }
+
+    /**
+     * Provides polymorphism to indicate whether the checker memory addresses
+     * should be copied.
+     *
+     * @return <code>true</code> if the class invoking the method needs to
+     *                           update the memory address of the color checker
+     *                           centers and radius;
+     *         <code>false</code> if the class invoking the method does NOT
+     *                           update the memory address of the color checker
+     *                           centers and radius.
+     */
+    public boolean copyCheckerAddress() {
+        return false;
+    }
+
+    public void cleanUp() {
+    }
+
+    public static long getCheckerCenter() {
+        return sCheckerCenterAddress;
+    }
+
+    public static long getCheckerRadius() {
+        return sCheckerRadiusAddress;
+    }
+
+    public abstract String getTestName(int index);
+
+    public abstract String getResult(int index);
+
+    public abstract int getNumTests();
+
+    /**
+     * Provides a native method to convert the input Bitmap of the captured
+     * image into a native character array and constructs a native image class
+     * with this character array. This method currently supports conversion
+     * of Bitmaps in the formats of RGB_565 and RGB_8888.
+     *
+     * @param input the input Bitmap, which is decoded from the camrea data.
+     *
+     * @return the memory address of the native image class which contains
+     * the character array.
+     */
+    public native long findNative(Bitmap input);
+
+    /**
+     * Provides a native method to create a native image handler class. The
+     * native image handler class is the base class for all test classes and
+     * contains the debug output as a character array.
+     *
+     * @param outputHeight the desired height for the debug output
+     * @param outputWidth the desired width for the debug output
+     *
+     * @return the memory address of the native test handler class.
+     */
+    public native long createImageTestHandler(int outputHeight, int outputWidth);
+
+    /**
+     * Provides a native method to clean up the memory taken by the handler.
+     *
+     * @param handlerAddress the memory address of the native test handler,
+     * which contains the debug output.
+     */
+    public native void cleanUpHandler(long handlerAddress);
+
+    /**
+     * Provides a native method to convert the native debug output from
+     * character array back to Bitmap and copy it to the debug output of this
+     * class.
+     *
+     * @param handlerAddress the memory address of the native test handler,
+     * which contains the debug output.
+     */
+    public native void displayHandlerDebugOutput(long handlerAddress);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorChecker.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorChecker.java
deleted file mode 100644
index c9df24a..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorChecker.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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.cts.verifier.camera.analyzer;
-
-import android.graphics.Bitmap;
-
-/** The ColorChecker class is used to locate a Xrite Classic Color Checker grid
- * pattern in an image, and return the average value of each color patch.
- *
- * The pattern is a 6x4 grid of square color patches. The detection routine
- * assumes the pattern is placed roughly facing the camera, with the long size
- * roughly horizontal. It doesn't matter whether the pattern is upside down or
- * not - the returned array will have the grayscale squares of the pattern on
- * the bottom row.
- */
-class ColorChecker {
-
-    private float[] mPatchValues;
-    private Bitmap mDebugOutput;
-    private boolean mSuccess = false;
-
-    /** Construct a ColorChecker from a source Bitmap.
-     *
-     * @param source The source image to scan through for the 6x4 Xrite Classic
-     *        Color Checker pattern.
-     */
-    public ColorChecker(Bitmap source) {
-        mPatchValues = new float[6 * 4 * 3];
-        mSuccess =  findNative(source);
-     }
-
-    /** Returns whether the ColorChecker pattern was found in the source bitmap
-     *
-     * @return true if the pattern was found in the source Bitmap. false
-     *         otherwise.
-     */
-    public boolean isValid() {
-        return mSuccess;
-    }
-
-    /** Returns patch RGB triplet for patch (x, y), or null if the pattern wasn't
-     * found.
-     *
-     * @param x Column of the patch
-     * @param y Row of the patch
-     * @return A 3-entry float array representing the R, G, and B values of the
-     *         patch in roughly linear luminance, mapped to the 0-1 range.
-     */
-    public float[] getPatchRGB(int x, int y) {
-        if (!mSuccess) throw new RuntimeException("No color checker found!");
-        float[] rgb = {
-            mPatchValues[(y * 6 + x) * 3 + 0],
-            mPatchValues[(y * 6 + x) * 3 + 1],
-            mPatchValues[(y * 6 + x) * 3 + 2]
-        };
-        return rgb;
-    }
-
-    /** Returns patch (x, y) color channel c.
-     *
-     * @param x Column of the patch
-     * @param y Row of the patch
-     * @param c Color channel of the patch (0 = R, 1 = G, 2 = B)
-     * @return The float value for that color channel in roughly linear
-     *         luminance, mapped to the 0-1 range.
-     */
-    public float getPatchValue(int x, int y, int c) {
-        if (!mSuccess) throw new RuntimeException("No color checker found!");
-        return mPatchValues[(y * 6 + x) * 3 + c];
-    }
-
-    /** Returns debug Bitmap image showing detected candidate patches and the
-     * grid if it was found. Valid even if the pattern wasn't found. Candiate
-     * patches will have red bounding boxes. In addition, patches that are part
-     * of the color checker pattern are have a green diagonal, and all their
-     * member pixels are colored in solid blue.
-     *
-     * @return A low-resolution version of the source Bitmap with overlaid
-     *         detection results.
-     */
-    public Bitmap getDebugOutput() {
-        return mDebugOutput;
-    }
-
-    native boolean findNative(Bitmap input);
-
-    static {
-        System.loadLibrary("cameraanalyzer");
-    }
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java
new file mode 100644
index 0000000..dd2a966
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ColorCheckerTest.java
@@ -0,0 +1,293 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.hardware.Camera;
+import android.util.Log;
+import android.widget.ImageView;
+
+import java.util.List;
+
+/** Locates a Xrite Classic Color Checker grid pattern in an image, stores the
+ * center positions and the color checker radius, and provides a function to
+ * get the memory address of these two properties.
+ *
+ * The pattern is a 6x4 grid of square color patches. The detection routine
+ * assumes the pattern is placed roughly facing the camera, with the long size
+ * roughly horizontal. It also assumes that the grey squares are in the bottom
+ * row.
+ */
+public class ColorCheckerTest extends CameraTests {
+
+    private static final String TAG = "ColorCheckerTest";
+
+    /** Memory address of the image class instance that contains the image. */
+    private long mClassAddress;
+    /** Memory address of the image test class instance. */
+    private long mTestHandler;
+    /** Thread lock. */
+    private final Object mProcessingImage = new Object();
+    /** Boolean to tell whether auto focus has succeded.*/
+    private boolean mAutoFocusSuccess;
+    /** Boolean to tell whether auto focus is supported.*/
+    private boolean mAutoFocusEnabled = false;
+    /** Singleton instance of the class.*/
+    private static ColorCheckerTest singletonTest = null;
+
+    private boolean mFindCheckerSuccess = false;
+
+    /**
+     * Constructs a <code>ColorCheckerTest</code> instance with a given
+     * Camera pointer.
+     */
+    private ColorCheckerTest() {
+        super();
+    }
+
+    /**
+     * Updates the camera and parameter when the activity switches camera.
+     */
+    public void updateCamera() {
+        Camera.Parameters params = mTestCamera.getParameters();
+        List<String> supportedFocusModes = params.getSupportedFocusModes();
+
+        // Sets camera focus mode to Auto focus if it is supported.
+        if (supportedFocusModes.contains(params.FOCUS_MODE_AUTO)) {
+            Log.v(TAG, "Auto focus possible");
+            params.setFocusMode(params.FOCUS_MODE_AUTO);
+            mTestCamera.setParameters(params);
+            mAutoFocusEnabled = true;
+        } else {
+            mAutoFocusEnabled = false;
+        }
+    }
+
+    public static synchronized ColorCheckerTest getSingletonTest() {
+        if (singletonTest == null) {
+            Log.v(TAG, "Creating a new ColorCheckerTest instance");
+            singletonTest = new ColorCheckerTest();
+            singletonTest.initializeTest();
+        }
+        return singletonTest;
+    }
+
+    private void initializeTest() {
+        // Creates a native test handler with a 120x160 pixel debug output
+        mTestHandler = createColorCheckerTest(120, 160);
+    }
+
+    @Override
+    public synchronized void run(int index) {
+        Log.v(TAG, "ColorCheckerTest thread started!");
+        mAutoFocusSuccess = false;
+        mFindCheckerSuccess = false;
+        // Sets camera focus mode to Auto focus if it is supported.
+        if (mAutoFocusEnabled) {
+            while (!mAutoFocusSuccess) {
+                // Starts the auto focus process of the camera.
+                mTestCamera.autoFocus(mAutoFocusListener);
+
+                // Locks thread until the camera finishes taking picture.
+                synchronized (mProcessingImage) {
+                    try{
+                        Log.v(TAG, "Start waiting for Image");
+                        mProcessingImage.wait();
+                    } catch (InterruptedException e) {
+                        Log.v(TAG, "Callback wait fails!");
+                    }
+                }
+            }
+        } else {
+            mTestCamera.takePicture(null, null, null, mTestJpegListener);
+            synchronized (mProcessingImage) {
+                try{
+                    Log.v(TAG, "Start waiting for Image");
+                    mProcessingImage.wait();
+                } catch (InterruptedException e) {
+                    Log.v(TAG, "Callback wait fails!");
+                }
+            }
+        }
+
+        // Launches the native method to find the color checker in the image.
+        mFindCheckerSuccess = processColorCheckerTest(mTestHandler);
+        // Displays the debug output from the native test handler instance.
+        displayHandlerDebugOutput(mTestHandler);
+
+        Log.v(TAG, "Callback has returned!");
+    }
+
+    private Camera.AutoFocusCallback mAutoFocusListener = new Camera.AutoFocusCallback() {
+        public void onAutoFocus(boolean mSuccess, Camera mCamera) {
+            if (mSuccess) {
+                mAutoFocusSuccess = true;
+                Log.v(TAG, "Autofocus success!");
+                mCamera.takePicture(null, null, null, mTestJpegListener);
+            } else {
+                try{
+                    Log.v(TAG, "Autofocus failed. Please adjust!");
+                    Thread.sleep(4000);
+                    Log.v(TAG, "END Waiting");
+                } catch (InterruptedException e){}
+
+                synchronized (mProcessingImage) {
+                    mProcessingImage.notifyAll();
+                }
+            }
+        }
+    };
+
+    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+        public void onPictureTaken(byte[] data, Camera mCamera) {
+            Log.v(TAG, "Shutter pressed down!");
+
+            // Changes the focus mode to fixed to avoid focus shift after
+            // auto focus is successful.
+            //Camera.Parameters params = mCamera.getParameters();
+            //params.setFocusMode(params.FOCUS_MODE_FIXED);
+            //mCamera.setParameters(params);
+
+            // Decodes the camera data to Bitmap and creates a native image
+            // class with the Bitmap.
+            Bitmap inputImage;
+            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+            long bufferAddress = findNative(inputImage);
+            Log.v(TAG, "findNative method finishes");
+
+            // Cleans up the Bitmap memory space.
+            inputImage.recycle();
+            data = null;
+            inputImage = null;
+            System.gc();
+
+            // Constructs a test handler class to handle the image.
+            createColorCheckerClass(bufferAddress, mTestHandler);
+
+            mCamera.startPreview();
+
+            // Notifies the thread lock the image capture is done.
+            synchronized (mProcessingImage) {
+                mProcessingImage.notifyAll();
+            }
+        }
+    };
+
+    /**
+     * Overrides the base class method and use the memory addresses of the
+     * checker centers and radius computed by the native test handler class
+     * to update the values stored in the base class.
+     *
+     * @return <code>true</code> indicating a memory address upload is needed.
+     */
+    @Override
+    public boolean copyCheckerAddress() {
+        if (mFindCheckerSuccess) {
+            setCheckerAddress(getColorCheckerCenterAdd(mTestHandler),
+                              getColorCheckerRadiusAdd(mTestHandler));
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    @Override
+    public void cleanUp() {
+        cleanUpHandler(mTestHandler);
+    }
+
+    @Override
+    public String getTestName() {
+        return "Color Checker test: \n";
+    }
+
+    @Override
+    public String getTestName(int index) {
+        return "Find color checker";
+    }
+
+    @Override
+    public String getResult(int index) {
+        if (mFindCheckerSuccess) {
+          return "Passed";
+        } else {
+          return "Failed";
+        }
+    }
+
+    @Override
+    public int getNumTests() {
+        return 1;
+    }
+
+    /**
+     * Gets the memory address of the vector storing the color checker centers
+     * from the native test handler instance.
+     *
+     * @param handlerAddress the memory address of the native test handler
+     * instance
+     *
+     * @return memory address of the native vector storing the color checker
+     * centers' coordinates
+     */
+    private native long getColorCheckerRadiusAdd(long handlerAddress);
+
+    /**
+     * Gets the memory address of the vector storing the color checker radius
+     * from the native test handler instance.
+     *
+     * @param handlerAddress the memory address of the native test handler
+     * instance.
+     *
+     * @return memory address of the native vector storing the color checker
+     * centers' coordinates
+     */
+    private native long getColorCheckerCenterAdd(long handlerAddress);
+
+    /**
+     * Creates a native color checker test handler instance.
+     *
+     * @param outputWidth the desired width for the debug output
+     * @param outputHeight the desired height of the debug output
+     *
+     * @return memory address of the native test handler instance
+     */
+    private native long createColorCheckerTest(int outputWidth, int outputHeight);
+
+    /**
+     * Loads a native image class instances and extracts data from it to add
+     * to the test handler.
+     *
+     * @param bufferAddress the memory address of the image class instance
+     * @param handlerAddress the memory address of the test handler instance
+     */
+    private native void createColorCheckerClass(long bufferAddress, long handlerAddress);
+
+    /**
+     * Processes the data in the native test handler instance. Computes test
+     * results with all the data and construct a debug image or debug text
+     * outputs.
+     *
+     * @param handlerAddress the memory address of the test handler instance
+     */
+    private native boolean processColorCheckerTest(long handlerAddress);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
new file mode 100644
index 0000000..828840d
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/ExposureCompensationTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.util.Log;
+import android.widget.ImageView;
+
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.Random;
+
+public class ExposureCompensationTest extends CameraTests {
+
+    private static final String TAG = "ExposureCompensationTest";
+
+    private float mExposureLevel;
+    private final Object mProcessingImage = new Object();
+    private final Object mAutoFocusing = new Object();
+    private long mTestHandler;
+    private String[] mTestResults;
+    private int mNumTests;
+    private Camera.Parameters mParams;
+
+    private static ExposureCompensationTest singletonTest = null;
+
+    private ExposureCompensationTest(){
+        super();
+    }
+
+    public void updateCamera() {
+        mParams = mTestCamera.getParameters();
+        Log.v(TAG, String.format("Exposure level is from %d to %d",
+                                 mParams.getMinExposureCompensation(),
+                                 mParams.getMaxExposureCompensation()));
+        mNumTests = (int) ((float) (mParams.getMaxExposureCompensation() -
+                                    mParams.getMinExposureCompensation())
+                            * mParams.getExposureCompensationStep());
+        mTestResults = new String[mNumTests + 1];
+        for (int i = 0; i < mNumTests + 1; ++i) {
+            mTestResults[i] = "...";
+        }
+    }
+
+    public static synchronized ExposureCompensationTest getSingletonTest() {
+        if (singletonTest == null) {
+            Log.v(TAG, "Creating a new ExposureCompensationTest instance");
+            singletonTest = new ExposureCompensationTest();
+            singletonTest.initializeTest();
+        }
+        return singletonTest;
+    }
+
+    private void initializeTest() {
+        // Creates a native test handler with a 120x160 pixel debug output
+        mTestHandler = createExposureCompensationTest(200, 280);
+    }
+
+    @Override
+    public synchronized void run(int index){
+        Log.v(TAG, "ExposureCompensationTest thread started!");
+
+        int testRangeMin, testRangeMax;
+        if (index == 0) {
+            testRangeMin = mParams.getMinExposureCompensation();
+            testRangeMax = mParams.getMaxExposureCompensation();
+        } else {
+            testRangeMin = (int) ((float)(index - 1) / mParams.getExposureCompensationStep())
+                    + mParams.getMinExposureCompensation();
+            testRangeMax = (int) ((float)(index) / mParams.getExposureCompensationStep())
+                    + mParams.getMinExposureCompensation();
+        }
+
+        for (int i = testRangeMin;
+                i <= testRangeMax; i += 1){
+            mExposureLevel = i * mParams.getExposureCompensationStep();
+            Log.v(TAG, String.format("Current exposure level is %d", i));
+            int mCameraExposure;
+
+            do{
+                mParams.setExposureCompensation(i);
+                mTestCamera.setParameters(mParams);
+
+                try{
+                    Log.v(TAG, "Waiting");
+                    Thread.sleep(4000);
+                    Log.v(TAG, "END Waiting");
+                } catch (InterruptedException e){
+                    //TODO: error handling.
+                }
+
+                mParams = mTestCamera.getParameters();
+                mCameraExposure = mParams.getExposureCompensation();
+                Log.v(TAG, String.format("Camera exposure level is %d", mCameraExposure));
+            } while (mCameraExposure != i);
+
+            mTestCamera.takePicture(null, null, null, mTestJpegListener);
+
+            synchronized (mProcessingImage) {
+                try{
+                    Log.v(TAG, "Start waiting for Image");
+                    mProcessingImage.wait();
+                } catch (InterruptedException e){
+                    Log.v(TAG, "Callback wait fails!");
+                }
+            }
+        }
+        processExposureCompensationTest(mTestHandler);
+        displayHandlerDebugOutput(mTestHandler);
+
+        Log.v(TAG, "Callback has returned!");
+        mParams.setExposureCompensation(0);
+        mTestCamera.setParameters(mParams);
+    }
+
+    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+        public void onPictureTaken(byte[] data, Camera mCamera) {
+            Log.v(TAG, "Shutter pressed down!");
+            Log.v(TAG, String.format("Current exposure is %f", mExposureLevel));
+
+            try {
+                FileOutputStream outStream = new FileOutputStream(
+                    String.format("/sdcard/exposure%d.jpg", System.currentTimeMillis()));
+                outStream.write(data);
+                outStream.close();
+            } catch (FileNotFoundException e) {
+            } catch (IOException e) {}
+
+            Bitmap inputImage;
+
+            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+            long bufferAddress = findNative(inputImage);
+            Log.v(TAG, "findNative method finishes");
+
+            inputImage.recycle();
+            data = null;
+            inputImage = null;
+            System.gc();
+
+            createExposureCompensationClass(bufferAddress, mTestHandler,
+                                            getCheckerCenter(), getCheckerRadius(),
+                                            mExposureLevel);
+            mCamera.startPreview();
+
+            synchronized (mProcessingImage) {
+                mProcessingImage.notifyAll();
+            }
+        }
+    };
+
+    @Override
+    public String getTestName(int index) {
+        switch (index) {
+            case 0:
+                return "EC All Range";
+            default:
+                return String.format("EC %d -> %d", (index - mNumTests / 2 - 1) * 10,
+                                     (index - mNumTests / 2) * 10);
+        }
+    }
+
+    @Override
+    public String getResult(int index) {
+        return mTestResults[index];
+    }
+
+    @Override
+    public int getNumTests() {
+        return mNumTests + 1;
+    }
+
+    @Override
+    public String getTestName() {
+        return "Exposure Compensation Test: \n";
+    }
+
+    private native long createExposureCompensationTest(int outputHeight, int outputWidth);
+
+    private native void createExposureCompensationClass(long bufferAddress, long handlerAddress,
+            long checkerCenterAddress, long checkerAadiusAddress, float mExposureLevel);
+
+    private native void processExposureCompensationTest(long handlerAddress);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java
new file mode 100644
index 0000000..ff5067a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/MeteringTest.java
@@ -0,0 +1,685 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.graphics.Rect;
+import android.hardware.Camera;
+import android.hardware.Camera.Area;
+import android.util.Log;
+import android.widget.ImageView;
+
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Implements a test to verify whether the camera metering system works as
+ * described in the API.
+ *
+ * The test consists two sub-categories. The first one has tests with only
+ * one metering area defined. The second one has tests with two metering areas
+ * defined. For each single sub-test, we use a random number generator to
+ * decide where to put some of the metering areas to and how much weight should
+ * be assigned to each area. For different tests, we use different ways to
+ * define other metering areas and their weight, in order to cover all possible
+ * fail cases. The metering areas are contrained to the grey squares in the
+ * bottom of the color checker.
+ */
+public class MeteringTest extends CameraTests {
+
+    private static final String TAG = "MeteringTest";
+
+    /** A long wait.*/
+    private static final int LONG_SLEEP = 4000;
+    /** Debug result in text. */
+    private String mDebugText;
+    /** Thread lock. */
+    private final Object mProcessingImage = new Object();
+    /** Memory address of the native test handler. */
+    private long mTestHandler;
+    /** The maximum number of metering area the device supports. */
+    private int mMaxNumMeteringArea;
+    /** The metering areas. */
+    private List<Camera.Area> mGreyAreas;
+    /** The coordinates of the grey squares on the color checker. */
+    private int[] mGreyCoordinates = new int[24];
+    /** Random number generator. */
+    private final Random mRandomGenerator = new Random();
+    /** Reference comparison result for tests. */
+    private ArrayList<Boolean>  mReferenceCompareResults;
+    /** Number of tests in the same instance. */
+    private int mTestCount;
+    /** Reference test logs. */
+    private ArrayList<String> mReferenceLogs;
+    /** Test result to show. */
+    private String[] mTestResults;
+    /** Number of tests. */
+    private int mNumTests;
+    /** Camera Parameters. */
+    private Camera.Parameters mParams;
+    /** Singleton test instance. */
+    private static MeteringTest singletonTest = null;
+
+    /** Constructs a <code>MeteringTest</code> instance with the given
+     * camera pointer.
+     */
+    private MeteringTest() {
+        super();
+    }
+
+    public void updateCamera() {
+        // Looks up how many metering area the device supports.
+        mParams = mTestCamera.getParameters();
+        mMaxNumMeteringArea = mParams.getMaxNumMeteringAreas();
+        Log.v(TAG, String.format("Maximum number if metering area is %d", mMaxNumMeteringArea));
+        if (mMaxNumMeteringArea == 0) {
+            mDebugText = "Custom Metering not supported!";
+            Log.v(TAG, "Custom Metering not supported");
+        }
+    }
+
+    public static synchronized MeteringTest getSingletonTest() {
+        if (singletonTest == null) {
+            Log.v(TAG, "Creating a new MeteringTest instance");
+            singletonTest = new MeteringTest();
+            singletonTest.initializeTest();
+        }
+        return singletonTest;
+    }
+
+    private void initializeTest() {
+        // Creates a native metering test handler.
+        mTestHandler = createMeteringTest();
+        mDebugText = new String();
+        mReferenceCompareResults = new ArrayList<Boolean>();
+        mReferenceLogs = new ArrayList<String>();
+        mNumTests = 3;
+        mTestResults = new String[mNumTests];
+        for (int i = 0; i < mNumTests; ++i) {
+            mTestResults[i] = "...";
+        }
+    }
+
+    /**
+     * Runs the metering test instance.
+     */
+    @Override
+    public synchronized void run(int index) {
+        if (index == 0) {
+            run(1);
+            run(2);
+            return;
+        }
+        Log.v(TAG, "MeteringTest thread started!");
+
+        // Finds the coordinates of the grey squares on the color checker.
+        // The coordinate system has (-1000, -1000) on the upper left corner.
+        // And (1000, 1000) on the bottom right corner.
+        findGreyCoordinates(mGreyCoordinates, getCheckerCenter(), getCheckerRadius());
+
+        if (mMaxNumMeteringArea > 0) {
+            mTestCount = 0;
+            // Runs the metering tests category by category.
+            switch (index) {
+                case 1:
+                    runOneAreaTest();
+                    break;
+                case 2:
+                    if (mMaxNumMeteringArea > 1) {
+                        runTwoAreasTest();
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        mParams = mTestCamera.getParameters();
+        mParams.setMeteringAreas(null);
+        mTestCamera.setParameters(mParams);
+
+        boolean[] testCompareResults = new boolean[2 * mTestCount];
+
+        // Processes the image data taken so far and stores the test results.
+        processMeteringTest(mTestHandler, testCompareResults);
+        // Prepares debug output based on the test results.
+        prepareDebugText(testCompareResults, index);
+
+        mReferenceCompareResults.clear();
+        mReferenceLogs.clear();
+    }
+
+    /**
+     * Prepares the test results in HTML text string to show in the UI.
+     *
+     * If the test result is the same as the reference result, the text will be
+     * shown in green. Otherwise it would be shown as red.
+     *
+     * @param testCompareResults the array storing the comparison results from
+     * the data taken by the camera so far.
+     */
+    private void prepareDebugText(boolean[] testCompareResults, int index) {
+        mDebugText = "";
+        boolean groupTestPassed = true;
+        for (int i = 0; i < mTestCount; ++i) {
+              String testLog;
+              boolean testPassed = true;
+              testLog = mReferenceLogs.get(i);
+              mDebugText += (testLog + "<br/>");
+
+              if (testCompareResults[i * 2] == mReferenceCompareResults.get(i * 2)) {
+                  mDebugText += String.format(
+                      "Picture 1 equivalent to Picture 2 is %b \n",
+                      testCompareResults[i * 2]);
+              } else {
+                  mDebugText += String.format(
+                      "Picture 1 equivalent to Picture 2 is %b \n",
+                      testCompareResults[i * 2]);
+                  testPassed = false;
+              }
+
+              if (testCompareResults[i * 2 + 1] == mReferenceCompareResults.get(i * 2 + 1)) {
+                  mDebugText += String.format(
+                      "Picture 1 darker than Picture 2 is %b \n",
+                      testCompareResults[i * 2 + 1]);
+              } else {
+                  mDebugText += String.format(
+                      "Picture 1 darker than Picture 2 is %b \n",
+                      testCompareResults[i * 2 + 1]);
+                  testPassed = false;
+              }
+
+              if (testPassed) {
+                  mDebugText += "Test passed! \n";
+              } else {
+                  mDebugText += "Test failed! \n";
+                  groupTestPassed = false;
+              }
+              Log.v(TAG, String.format("%s", mDebugText));
+         }
+
+        if (groupTestPassed) {
+            mTestResults[index] = "Passed";
+        } else {
+            mTestResults[index] = "Failed";
+        }
+
+    }
+
+    /**
+     * Runs tests to check whether the metering functionalities work properly
+     * when one metering area is added.
+     */
+    private void runOneAreaTest() {
+        int weight1;
+        int weight2;
+        int square1;
+        int square2;
+
+        Log.v(TAG, "Running one area Test");
+
+        // Test case 1: Two images have the same metering area. Image 1 has
+        // a diffent weight than Image 2. The result images should be
+        // identical.
+        // Tests whether weight normalization works.
+        square1 = mRandomGenerator.nextInt(6);
+        weight1 = mRandomGenerator.nextInt(100) + 1;
+        runSingleTest(square1, square1, weight1);
+
+        square2 = square1;
+        weight2 = mRandomGenerator.nextInt(100) + 901;
+        runSingleTest(square2, square2, weight2);
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        Log.v(TAG, String.format("Running test for %d square with weights %d, %d",
+                                 square1, weight1, weight2));
+        mReferenceLogs.add(String.format(
+            "Running test for %d 1x1 square with weights %d, %d", square1, weight1, weight2));
+        ++mTestCount;
+
+        // Test case 2: Two images have different metering areas. Image 1 has
+        // one of the grey squares as its metering area. Image 2 has a darker
+        // grey square as its metering area. The weights for both images are
+        // the same. Image 1 is expected to be darker than Image 2.
+        // Tests whether metering on uni-brightness patches work.
+        square1 = mRandomGenerator.nextInt(5);
+        weight1 = mRandomGenerator.nextInt(1000) + 1;
+        runSingleTest(square1, square1, weight1);
+
+        square2 = mRandomGenerator.nextInt(6 - square1 - 1) + square1 + 1;
+        weight2 = weight1;
+        runSingleTest(square2, square2, weight2);
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add(String.format(
+            "Running test for %d, %d 1x1 square with weight %d", square1, square2, weight1));
+        ++mTestCount;
+
+        // Test case 3: Two images have different metering areas. Image one has
+        // one of the grey squares as its metering area. Image 2 has a
+        // rectangle which contains Image 1's metering area and the neighboring
+        // darker grey square. The weights for both tests are the same. Image 1
+        // is expected to be darker than Image 2.
+        // Tests whether metering on patches with different brightness works.
+        square1 = mRandomGenerator.nextInt(5);
+        weight1 = mRandomGenerator.nextInt(1000) + 1;
+        runSingleTest(square1, square1, weight1);
+
+        square2 = square1;
+        weight2 = weight1;
+        runSingleTest(square2, square2 + 1, weight2);
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add(String.format(
+            "Running test for %d 1x1, 1x2 square with weight %d", square1, weight1));
+        ++mTestCount;
+
+        // Test case 4: Two images have different metering areas. Image one has
+        // two neighboring grey squares as its metering area. Image 2 has two
+        // darker neighboring grey squares as its metering area. Weights are
+        // the same for both images. Image 1 is expected to be darker than
+        // Image 2.
+        // Tests whether metering on two mixed-brightness patches work.
+        square1 = mRandomGenerator.nextInt(4);
+        weight1 = mRandomGenerator.nextInt(1000) + 1;
+        runSingleTest(square1, square1 + 1, weight1);
+
+        square2 = mRandomGenerator.nextInt(5 - square1 - 1) + square1 + 1;
+        weight2 = weight1;
+        runSingleTest(square2, square2 + 1, weight2);
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add(String.format(
+            "Running test for %d, %d 1x2 square with weight %d", square1, square2, weight1));
+        ++mTestCount;
+
+        // Test case 5: Two images have different metering areas. Image one has
+        // three neighboring grey squares as its metering area. Image 2 has
+        // three darker neighboring grey squares as its metering area. Weights
+        // are the same. Image 1 is expected to be darker than Image 2.
+        // Tests whether metering on three mixed-brightness patches work.
+        square1 = mRandomGenerator.nextInt(3);
+        weight1 = mRandomGenerator.nextInt(1000) + 1;
+        runSingleTest(square1, square1 + 2, weight1);
+
+        square2 = mRandomGenerator.nextInt(4 - square1 - 1) + square1 + 1;
+        weight2 = weight1;
+        runSingleTest(square2, square2 + 2, weight2);
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add(String.format(
+            "Running test for %d, %d 1x3 square with weight %d", square1, square2, weight1));
+        ++mTestCount;
+    }
+
+    /**
+     * Runs metering tests to verify the functionalities when there are two
+     * areas set as the metering area.
+     */
+    private void runTwoAreasTest() {
+        int[] weight1 = new int[2];
+        int[] weight2 = new int[2];
+        int[] square1Start = new int[2];
+        int[] square2Start = new int[2];
+        int[] square1End = new int[2];
+        int[] square2End = new int[2];
+
+        Log.v(TAG, "Running two-area Test");
+
+        // Test case 1: Image 1 has two metering areas. They are two adjacent
+        // grey squares (each set as a metering area). The two areas have the
+        // same weight. Image 2 has one metering area, which is the combination
+        // of Image 1's two metering areas as a rectangle. The weight is the
+        // same as that of Image 1's individual area. Image 1 is expected to
+        // be equivalent to Image 2.
+        // Tests whether having seperating a metering area into two will yield
+        // the same result.
+        square1Start[0] = mRandomGenerator.nextInt(5);
+        square1End[0] = square1Start[0];
+        weight1[0] = mRandomGenerator.nextInt(1000) + 1;
+        square1Start[1] = square1Start[0] + 1;
+        square1End[1] = square1Start[1];
+        weight1[1] = weight1[0];
+        runMultipleAreaTest(square1Start, square1End, weight1);
+
+        square2Start[0] = square1Start[0];
+        weight2[0] = weight1[0];
+        runSingleTest(square2Start[0], square2Start[0] + 1, weight2[0]);
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add(String.format(
+            "Running test for %d, %d 1x1 square with weight %d",
+            square1Start[0], square1Start[1], weight1[0]));
+        ++mTestCount;
+
+        // Test case 2: Image 1 has two metering areas. They are two random
+        // grey squareson the color checker. The brighter square has a larger
+        // weight than the darker square. Image 2 has the same two metering
+        // areas as Image 1. The weights for both are equal to the weight of
+        // the darker square in Image 1, which is smaller than the weight of
+        // the brighter square in Image 1. Image 1 is expected to be darker
+        // than Image 2.
+        // Tests whether giving one of the two metering areas a different
+        // weight would change the image in the correct way.
+        square1Start[0] = mRandomGenerator.nextInt(4);
+        square1End[0] = square1Start[0];
+        weight1[0] = mRandomGenerator.nextInt(100) + 901;
+        square1Start[1] = mRandomGenerator.nextInt(5 - square1Start[0] - 1) + square1Start[0] + 1;
+        square1End[1] = square1Start[1];
+        weight1[1] = mRandomGenerator.nextInt(100) + 1;
+        runMultipleAreaTest(square1Start, square1End, weight1);
+
+        square2Start[0] = square1Start[0];
+        square2End[0] = square2Start[0];
+        weight2[0] = weight1[1];
+        square2Start[1] = square1Start[1];
+        square2End[1] = square1End[1];
+        weight2[1] = weight2[0];
+        runMultipleAreaTest(square2Start, square2End, weight2);
+        mReferenceCompareResults.add(false);
+        mReferenceCompareResults.add(true);
+        mReferenceLogs.add(String.format(
+            "Running test for %d, %d 1x1 square with weight %d, %d",
+            square1Start[0], square1Start[1], weight1[0], weight2[1]));
+        ++mTestCount;
+
+        // Test case 3: Image 1 has two metering areas. Both are set to the
+        // same random grey square on the color checker. The weight for both
+        // are the same. Image 2 has one meterig area, which is the same as
+        // Image 1's chosen grey square. The weight for it is the same as
+        // Image 1's weight for one metering area. Image 1 is expected to be
+        // equivalent to Image 2.
+        // Tests whether defining overlapping metering area works.
+        square1Start[0] = mRandomGenerator.nextInt(6);
+        square1End[0] = square1Start[0];
+        weight1[0] = mRandomGenerator.nextInt(1000) + 1;
+        square1Start[1] = square1Start[0];
+        square1End[1] = square1Start[1];
+        weight1[1] = weight1[0];
+        runMultipleAreaTest(square1Start, square1End, weight1);
+
+        square2Start[0] = square1Start[0];
+        square2End[0] = square2Start[0];
+        weight2[0] = weight1[0];
+        runSingleTest(square2Start[0], square2End[0], weight2[0]);
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add(String.format(
+            "Running test for %d 1x1 square with weight %d,", square1Start[0], weight1[0]));
+        ++mTestCount;
+
+        // Test case 4: Image 1 has two metering areas. The first one is a
+        // grey square on the color checker. The second one is a rectangle
+        // containing the first metering area's grey square and its neighboring
+        // darker square. The weights for both metering area are the same.
+        // Image 2 has two metering areas. The first one is the same grey
+        // square as Image 1's first metering area. The second one is the
+        // neighboring darker grey square. The weight for the brighter square
+        // is double the weight of Image 1's weights for each metering area.
+        // The weight for the Image 2's darker grey square is the same as
+        // Image 1's weight for each of its metering areas. Image 1 is expected
+        // to be equivalent to Image 2.
+        // Tests whether the weights for overlapping metering area add up.
+        square1Start[0] = mRandomGenerator.nextInt(2);
+        square1End[0] = square1Start[0];
+        weight1[0] = mRandomGenerator.nextInt(500) + 1;
+        square1Start[1] = square1Start[0];
+        square1End[1] = square1Start[1] + 1;
+        weight1[1] = weight1[0];
+        runMultipleAreaTest(square1Start, square1End, weight1);
+
+        square2Start[0] = square1Start[0];
+        square2End[0] = square1End[0];
+        weight2[0] = weight1[0] * 2;
+        square2Start[1] = square2Start[0] + 1;
+        square2End[1] = square2Start[1];
+        weight2[1] = weight1[1];
+        runMultipleAreaTest(square2Start, square2End, weight2);
+        mReferenceCompareResults.add(true);
+        mReferenceCompareResults.add(false);
+        mReferenceLogs.add(String.format(
+            "Running test for %d 1x2 1x1 and 1x2 square with weight %d,",
+            square1Start[0], weight1[0]));
+        ++mTestCount;
+    }
+
+    /**
+     * Runs the metering test when multiple metering areas are defined.
+     *
+     * @param startIndex the array storing the index of the grey square where
+     * one metering area starts
+     * @param endIndex the array storing the index of the grey square where one
+     * metering area ends.
+     * @param weight the array storing the weight for each metering area.
+     */
+    private void runMultipleAreaTest(int[] startIndex, int[] endIndex, int[] weight) {
+        int numAreas = startIndex.length;
+        mParams = mTestCamera.getParameters();
+        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
+
+        for (int i = 0; i < numAreas; ++i) {
+            meteringAreas.add(makeArea(startIndex[i], endIndex[i], weight[i]));
+            Log.v(TAG, String.format("Add metering area for %d, %d, %d",
+                                     startIndex[i], endIndex[i], weight[i]));
+        }
+        mParams.setMeteringAreas(meteringAreas);
+        mTestCamera.setParameters(mParams);
+        takePicture();
+    }
+
+    /**
+     * Runs the metering test when one metering area is defined.
+     *
+     * @param startIndex the index of the grey square where the metering area
+     * starts
+     * @param endIndex the index of the grey square where the metering area
+     * ends.
+     * @param weight the weight for the metering area.
+     */
+    private void runSingleTest(int startIndex, int endIndex, int weight) {
+        mParams = mTestCamera.getParameters();
+        List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();
+
+        Log.v(TAG, String.format("Single test for %d, %d, %d", startIndex, endIndex, weight));
+        meteringAreas.add(makeArea(startIndex, endIndex, weight));
+        mParams.setMeteringAreas(meteringAreas);
+        mTestCamera.setParameters(mParams);
+        takePicture();
+    }
+
+    /**
+     * Takes picture with the camera instance linked to this test class.
+     */
+    private void takePicture() {
+        // Waits for the metering to be stable
+        try{
+            Log.v(TAG, "Waiting for metering");
+            Thread.sleep(LONG_SLEEP);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e) {}
+
+        mTestCamera.takePicture(null, null, null, mTestJpegListener);
+
+        // Locks thread until picture is taken and ready for processing.
+        synchronized (mProcessingImage) {
+            try{
+                Log.v(TAG, "Start waiting for Image");
+
+                mProcessingImage.wait();
+            } catch (InterruptedException e) {
+                Log.v(TAG, "Callback wait fails!");
+            }
+        }
+    }
+
+    /**
+     * Constructs a <code>Camera.Area</code> object of the metering area.
+     * Given the start and end index of one metering area, it takes the upper
+     * left corner of the starting square and the bottom right corner of the
+     * end square to construct an Area.
+     *
+     * @param startIndex the index of the grey square where the metering area
+     * starts
+     * @param endIndex the index of the grey square where the metering area
+     * ends
+     * @param weight the weight of this metering area.
+     *
+     * @return a <code>Camera.Area</code> object which represents this metering
+     * area
+     */
+    private Camera.Area makeArea(int startIndex, int endIndex, int weight) {
+        Rect areaRect = new Rect(mGreyCoordinates[startIndex * 4],
+                                 mGreyCoordinates[startIndex * 4 + 1],
+                                 mGreyCoordinates[endIndex * 4 + 2],
+                                 mGreyCoordinates[endIndex * 4 + 3]);
+        Camera.Area area = new Camera.Area(areaRect, weight);
+
+        return area;
+    }
+
+    @Override
+    public String getDebugText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getResultText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getTestName() {
+        return "Metering Test: \n";
+    }
+
+    @Override
+    public String getTestName(int index) {
+        switch (index) {
+            case 0:
+                return "Run all tests";
+            case 1:
+                return "One metering area tests";
+            case 2:
+                return "Multiple metering areas tests";
+            default:
+                return "";
+        }
+    }
+
+    @Override
+    public String getResult(int index) {
+        return mTestResults[index];
+    }
+
+    @Override
+    public int getNumTests() {
+        return mNumTests;
+    }
+
+    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+        public void onPictureTaken(byte[] data, Camera mCamera) {
+            Log.v(TAG, "Shutter pressed down!");
+            Bitmap inputImage;
+            try {
+                FileOutputStream outStream = new FileOutputStream(
+                    String.format("/sdcard/metering%d.jpg", System.currentTimeMillis()));
+                outStream.write(data);
+                outStream.close();
+            } catch (FileNotFoundException e) {
+            } catch (IOException e) {}
+
+            // Decodes the input data of the camera.
+            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+
+            // Records the memory address of the native image class instance.
+            long bufferAddress = findNative(inputImage);
+            Log.v(TAG, "findNative method finishes");
+
+            // Cleans up the memory taken by the bitmap.
+            inputImage.recycle();
+            data = null;
+            inputImage = null;
+            System.gc();
+
+            // Add the image data to the native test handler.
+            createMeteringClass(bufferAddress, mTestHandler,
+                                getCheckerCenter(), getCheckerRadius());
+            mCamera.startPreview();
+
+            // Releases thread lock after the image is processed.
+            synchronized (mProcessingImage) {
+                mProcessingImage.notifyAll();
+            }
+        }
+    };
+
+    /**
+     * Finds the coordinates of the grey squares on the color checker.
+     * The coordinates are computed by using the checker center and radius.
+     * The coordinates are converted to a system with (-1000, -1000) in the
+     * upper left corner and (1000, 1000) in the  bottom right corner.
+     *
+     * @param greyCoordinates the array to store the coordinates of the grey
+     * squares
+     * @param checkerCenterAddress the memory address pointing to the vector
+     * storing the color checker's centers.
+     * @param checkerRadiusAddress the memory address pointing to the vetor
+     * storing the color checker's radius.
+     */
+    private native void findGreyCoordinates(int[] greyCoordinates,
+                                            long checkerCenterAddress, long checkerRadiusAddress);
+
+    /**
+     * Creates the native metering test handler with no debug image.
+     *
+     * @return the memory address pointing to the native test handler instance
+     */
+    private native long createMeteringTest();
+
+    /**
+     * Adds the data from the native image class instance to the native test
+     * handler.
+     *
+     * @param bufferAddress the meory address of the native image class
+     * @param handlerAddress the memory address of the native test handler
+     * @param checkerCenterAddress the memory address of the checker cneters
+     * @param checkerRadiusAddress the meory address of the checker radius
+     */
+    private native void createMeteringClass(long bufferAddress, long handlerAddress,
+                                            long checkerCenterAddress,
+                                            long checkerRadiusAddress);
+
+    /**
+     * Process the data stored in the native test handler and stores the
+     * comparison results.
+     *
+     * @param handlerAddress the memory address of the native test handler
+     * @param testCompareResults the boolean array to store the test comparison
+     * results
+     */
+    private native void processMeteringTest(long handlerAddress, boolean[] testCompareResults);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java
new file mode 100644
index 0000000..f3bab86
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/analyzer/WhiteBalanceTest.java
@@ -0,0 +1,398 @@
+/*
+ * 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.cts.verifier.camera.analyzer;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.hardware.Camera;
+import android.util.Log;
+import android.widget.ImageView;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+import java.util.List;
+
+/**
+ * Implements a test to verify whether the correlated color temperatures (CTT)
+ * of the supported white balance modes are inside the range camera
+ * manufacturers generally agree on.
+ *
+ * The test assumes that the Daylight white balance mode has a CCT of 5200K,
+ * which is widely agreed in industry and academics. It then use this as a
+ * benchmark and compare images taken with other white balance settings.
+ * Using the pixel values of the grey squares on the color checker, the CCT
+ * of other white balance modes can be computed. The reference ranges were
+ * summarized with the help of online resources. For the Auto mode, the
+ * reference CCT is computed as the CCT that will keep the grey squares appear
+ * grey in the result image.
+ */
+public class WhiteBalanceTest extends CameraTests {
+
+    private static final String TAG = "WhiteBalanceTest";
+
+    /** Current white balance mode. */
+    private String mWhiteBalance;
+    /** Array to store the reference CCT's of each mode. */
+    private int[][] mReferenceTemperature;
+    /** List of supported white balance mode on a device. */
+    private List<String> mWhiteBalanceList;
+    /** The index of the white balance mode "Auto". */
+    private int mAutoId;
+
+    /** Debug results in text. */
+    private String mDebugText;
+    /** Memory address of the native test handler instance. */
+    private long mTestHandler;
+    /** Thread lock. */
+    private final Object mProcessingImage = new Object();
+    /** Test result to show. */
+    private String[] mTestResults;
+    /** Number of test. */
+    private int mNumTests;
+    /** Camera Parameters. */
+    private Camera.Parameters mParams;
+    /** Singleton test instance. */
+    private static WhiteBalanceTest singletonTest = null;
+    /** Boolean to check whehter daylight wb has been recorded. */
+    private boolean mHasDaylight = false;
+
+    /**
+     * Constructs a <code>WhiteBalanceTest</code> instance with a given
+     * Camera pointer.
+     */
+    private WhiteBalanceTest() {
+        super();
+    }
+
+    public void updateCamera() {
+        mAutoId = 0;
+        mHasDaylight = false;
+        mParams = mTestCamera.getParameters();
+        mWhiteBalanceList = mParams.getSupportedWhiteBalance();
+        mNumTests = mWhiteBalanceList.size() + 1;
+        mTestResults = new String[mNumTests];
+        for (int i = 0; i < mNumTests; ++i) {
+            mTestResults[i] = "...";
+        }
+
+        if (mWhiteBalanceList != null) {
+            mReferenceTemperature = new int[mWhiteBalanceList.size()][2];
+
+            // Sets the reference CCT of the supported white balance modes
+            for (int i = 0; i < mWhiteBalanceList.size(); i++) {
+                setReferenceTemperature(i, mWhiteBalanceList.get(i));
+                if (mWhiteBalanceList.get(i).equals("auto")) {
+                    mAutoId = i;
+                }
+            }
+        }
+    }
+
+    public static synchronized WhiteBalanceTest getSingletonTest() {
+        if (singletonTest == null) {
+            Log.v(TAG, "Creating a new WhiteBalanceTest instance");
+            singletonTest = new WhiteBalanceTest();
+            singletonTest.initializeTest();
+        }
+        return singletonTest;
+    }
+
+    private void initializeTest() {
+        mDebugText = new String();
+        // Creates a native white balance test handler.
+        // mTestHandler stores the memory address of this instance.
+        mTestHandler = createWhiteBalanceTest();
+    }
+
+    private void initializeWhiteBalanceTest() {
+        mWhiteBalance = "daylight";
+        takePicture(mWhiteBalance);
+        int colorTemperature = processWhiteBalanceTest(mTestHandler);
+
+        setReferenceTemperature(mAutoId, colorTemperature);
+        mHasDaylight = true;
+    }
+
+    private void takePicture(String whiteBalance) {
+        mParams.setWhiteBalance(whiteBalance);
+        mTestCamera.setParameters(mParams);
+
+        try{
+            Log.v(TAG, "Waiting for white balance to adjust");
+            Thread.sleep(4000);
+            Log.v(TAG, "END Waiting");
+        } catch (InterruptedException e) {}
+
+        mTestCamera.takePicture(null, null, null, mTestJpegListener);
+
+        // Thread locks until image capture is done
+        synchronized (mProcessingImage) {
+            try{
+                Log.v(TAG, "Start waiting for Image");
+                mProcessingImage.wait();
+            } catch (InterruptedException e) {
+                Log.v(TAG, "Callback wait fails!");
+            }
+        }
+    }
+
+    /**
+     * Runs the white balance camera test instance.
+     */
+    @Override
+    public synchronized void run(int index) {
+        Log.v(TAG, "WhiteBalanceTest thread started!");
+
+        if (!mHasDaylight) {
+            initializeWhiteBalanceTest();
+        }
+
+        if (index != 0) {
+            // Retrieves the list of supported white balance mode.
+            mParams = mTestCamera.getParameters();
+
+            int i = index - 1;
+            mWhiteBalance = mWhiteBalanceList.get(i);
+
+            Log.v(TAG, "Current white balance is " + mWhiteBalance);
+
+            takePicture(mWhiteBalance);
+
+            // Processes the white balance test data in the native code.
+            // Returns an array of CCT of each white balance modes, given the CCT
+            // of the "Daylight" mode is 5200K.
+            int colorTemperature = 0;
+
+            Log.v(TAG, "Finished taking picture, ready to process");
+            colorTemperature = processWhiteBalanceTest(mTestHandler);
+
+            // Records the index of the "Auto" white balance mode
+            if (mWhiteBalance.equals("daylight")) {
+                setReferenceTemperature(mAutoId, colorTemperature);
+                prepareDebugText(5200, index);
+                // Computes the reference CCT range of the "Auto" mode. Assuming that
+                // all grey squares on the color checker should be imaged as grey under
+                // a CCT, this CCT is used as a middle point to provide a range.
+                //setReferenceTemperature(mAutoId, colorTemperature[mWhiteBalanceList.size()]);
+            } else {
+                // Prepares the debug output.
+                prepareDebugText(colorTemperature, index);
+            }
+        } else {
+            for (int i = 0; i < mWhiteBalanceList.size(); i++) {
+                run(i + 1);
+            }
+        }
+
+        mParams.setWhiteBalance("auto");
+        mTestCamera.setParameters(mParams);
+    }
+
+    /**
+     * Prepares the debug results in HTML text. For each white balance mode,
+     * the CCT will be printed in green if it is in the reference range and
+     * red otherwise. The reference CCT range is also printed below, with
+     * green meaning the CCT range is satisfied and red otherwise.
+     *
+     * @param colorTemperature the CCT of the supported white balance modes
+     */
+    private void prepareDebugText(int colorTemperature, int index) {
+        mDebugText += String.format("CCT Ref is %d, %d, and CCT is %d",
+                                  mReferenceTemperature[index - 1][0],
+                                  mReferenceTemperature[index - 1][1],
+                                  colorTemperature);
+        Log.v(TAG, String.format("CCT Ref is %d, %d, and CCT is %d",
+                                  mReferenceTemperature[index - 1][0],
+                                  mReferenceTemperature[index - 1][1],
+                                  colorTemperature));
+        if ((colorTemperature >= mReferenceTemperature[index - 1][0]) &&
+                (colorTemperature <= mReferenceTemperature[index - 1][1])) {
+            mTestResults[index] = "Passed";
+        } else {
+            mTestResults[index] = "Failed";
+        }
+
+    }
+
+    @Override
+    public String getDebugText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getResultText() {
+        return mDebugText;
+    }
+
+    @Override
+    public String getTestName() {
+        return "White Balance Test: \n";
+    }
+
+    @Override
+    public String getTestName(int index) {
+        if (index != 0){
+            return String.format("%s mode test", mWhiteBalanceList.get(index - 1));
+        } else {
+            return "Run all tests";
+        }
+    }
+
+    @Override
+    public String getResult(int index) {
+        return mTestResults[index];
+    }
+
+    @Override
+    public int getNumTests() {
+        return mNumTests;
+    }
+
+    /**
+     * Sets the reference temperatures for the white balance modes of
+     * incandescent, fluorescent, warm-fluorescent, daylight, cloudy, shade
+     * and twilight. These are the currently supported White balance mode
+     * listed on the Android camera API.
+     *
+     * The reference range are summarized based on the published settings of
+     * Canon, Nikon and the references from Wikipedia on color temperature.
+     *
+     * @param i the index of the current white balance mode
+     * @param referenceWhiteBalance the name of the white balance mode.
+     */
+    private void setReferenceTemperature(int i, String referenceWhiteBalance) {
+        if (referenceWhiteBalance.equals("incandescent")) {
+            mReferenceTemperature[i][0] = 2500;
+            mReferenceTemperature[i][1] = 3500;
+        } else if (referenceWhiteBalance.equals("fluorescent")) {
+            mReferenceTemperature[i][0] = 3000;
+            mReferenceTemperature[i][1] = 6500;
+        } else if (referenceWhiteBalance.equals("warm-fluorescent")) {
+            mReferenceTemperature[i][0] = 2500;
+            mReferenceTemperature[i][1] = 3000;
+        } else if (referenceWhiteBalance.equals("daylight")) {
+            mReferenceTemperature[i][0] = 5000;
+            mReferenceTemperature[i][1] = 5400;
+        } else if (referenceWhiteBalance.equals("cloudy-daylight")) {
+            mReferenceTemperature[i][0] = 5500;
+            mReferenceTemperature[i][1] = 7500;
+        } else if (referenceWhiteBalance.equals("shade")) {
+            mReferenceTemperature[i][0] = 6800;
+            mReferenceTemperature[i][1] = 8000;
+        } else if (referenceWhiteBalance.equals("twilight")) {
+            mReferenceTemperature[i][0] = 10000;
+            mReferenceTemperature[i][1] = 14000;
+        }
+    }
+
+    /** Sets a reference range of CCT based on a given middle point CCT.
+     * The rerence range is from -10% of the CCT value to +10%.
+     *
+     * @param i the index of the current white balance mode
+     * @param t the middle point CCT.
+     */
+    private void setReferenceTemperature(int i, int t) {
+        mReferenceTemperature[i][0] = (int)((double)t * 0.9);
+        mReferenceTemperature[i][1] = (int)((double)t * 1.1);
+    }
+
+    private Camera.PictureCallback mTestJpegListener = new Camera.PictureCallback() {
+        public void onPictureTaken(byte[] data, Camera mCamera) {
+            Log.v(TAG, "Shutter pressed down!");
+            Bitmap inputImage;
+            try {
+                FileOutputStream outStream = new FileOutputStream(
+                        String.format("/sdcard/wb%d.jpg", System.currentTimeMillis()));
+                outStream.write(data);
+                outStream.close();
+            } catch (FileNotFoundException e) {
+            } catch (IOException e) {}
+            // Decodes the camera data to Bitmap and creates a native image
+            // class with the Bitmap.
+            inputImage = BitmapFactory.decodeByteArray(data, 0, data.length);
+            long bufferAddress = findNative(inputImage);
+            Log.v(TAG, "findNative method finishes");
+
+            // Cleans up the Bitmap memory space.
+            inputImage.recycle();
+            data = null;
+            inputImage = null;
+            System.gc();
+
+            // Adds the data from the current image base class to the native
+            // white balance test handler.
+            createWhiteBalanceClass(bufferAddress, mTestHandler,
+                                    getCheckerCenter(), getCheckerRadius(), mWhiteBalance);
+
+            mCamera.startPreview();
+
+            // Notifies the thread lock that the image capture is finished
+            synchronized (mProcessingImage) {
+                mProcessingImage.notifyAll();
+            }
+        }
+    };
+
+    /**
+     * Creates a native white balance test handler.
+     *
+     * @return the memory address of the test handler
+     */
+    private native long createWhiteBalanceTest();
+
+    /**
+     * Adds the data of interest from the image class pointed by
+     * <code>bufferAddress</code> to the handler class pointed by
+     * <code>handlerAddress</code> by using the color checker coordinates.
+     * Also sets the white balance of this test.
+     *
+     * @param bufferAddress the memory address of the native image class
+     * containing the current camera captured image
+     * @param handlerAddress the memory address of the native white balance
+     * test handler instance
+     * @param checkerCenterAddress the memory address of the color checker
+     * center coordinates
+     * @param checkerRadiusAddress the memory address of the color checker
+     * radius
+     * @param whiteBalance the white balance mode used for shooting the image
+     */
+    private native void createWhiteBalanceClass(long bufferAddress, long handlerAddress,
+                                                long checkerCenterAddress,
+                                                long checkerRadiusAddress,
+                                                String whiteBalance);
+
+    /**
+     * Processes the white balance test in the native code. This is executed
+     * after the images are taken with all possible white balance modes. It
+     * uses the "Daylight" white balance mode as reference and computes the
+     * CCT of other white balance modes.
+     *
+     * @param handlerAddress the memory address of the native white balance
+     * test handler instance.
+     * @param colorTemperature the array to store the computed CCT of all white
+     * balance modes.
+     */
+    private native int processWhiteBalanceTest(long handlerAddress);
+
+    private native int getAutoTemperature(long handlerAddress);
+
+    static {
+        System.loadLibrary("cameraanalyzer");
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 3ea9451..3736711 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -164,10 +164,6 @@
             new Feature("android.hardware.screen.portrait", false),
     };
 
-    public static final Feature[] ALL_ICE_CREAM_SANDWICH_FEATURES = {
-            new Feature(PackageManager.FEATURE_WIFI_DIRECT, false),
-    };
-
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -198,9 +194,6 @@
 
         // add features from latest to last so that the latest requirements are put in the set first
         int apiVersion = Build.VERSION.SDK_INT;
-        if (apiVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            Collections.addAll(features, ALL_ICE_CREAM_SANDWICH_FEATURES);
-        }
         if (apiVersion >= Build.VERSION_CODES.HONEYCOMB_MR2) {
             Collections.addAll(features, ALL_HONEYCOMB_MR2_FEATURES);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
index f976a45..0697be2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushReceiverActivity.java
@@ -61,15 +61,19 @@
         mNfcAdapter = nfcManager.getDefaultAdapter();
         mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
                 .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
-
-        if (!mNfcAdapter.isEnabled()) {
-            showDialog(NFC_NOT_ENABLED_DIALOG_ID);
-        }
     }
 
     @Override
     protected void onResume() {
         super.onResume();
+
+        if (!mNfcAdapter.isEnabled()) {
+            showDialog(NFC_NOT_ENABLED_DIALOG_ID);
+        }
+
+        /* Only the sender requires mNfcAdapter.isNdefPushEnabled == true,
+         * so no need to check it here in the receiver. */
+
         mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
     }
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushSenderActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushSenderActivity.java
index 2a507d3..f3f37c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushSenderActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NdefPushSenderActivity.java
@@ -37,6 +37,7 @@
     static final NdefMessage TEST_MESSAGE = getTestMessage();
 
     private static final int NFC_NOT_ENABLED_DIALOG_ID = 1;
+    private static final int NDEF_PUSH_NOT_ENABLED_DIALOG_ID = 2;
 
     private NfcAdapter mNfcAdapter;
 
@@ -52,10 +53,6 @@
 
         NfcManager nfcManager = (NfcManager) getSystemService(NFC_SERVICE);
         mNfcAdapter = nfcManager.getDefaultAdapter();
-
-        if (!mNfcAdapter.isEnabled()) {
-            showDialog(NFC_NOT_ENABLED_DIALOG_ID);
-        }
     }
 
     private static NdefMessage getTestMessage() {
@@ -71,6 +68,14 @@
     @Override
     protected void onResume() {
         super.onResume();
+
+        if (!mNfcAdapter.isEnabled()) {
+            showDialog(NFC_NOT_ENABLED_DIALOG_ID);
+        } else if (!mNfcAdapter.isNdefPushEnabled()) {
+            /* Sender must have NDEF push enabled */
+            showDialog(NDEF_PUSH_NOT_ENABLED_DIALOG_ID);
+        }
+
         mNfcAdapter.enableForegroundNdefPush(this, TEST_MESSAGE);
     }
 
@@ -85,7 +90,8 @@
         switch (id) {
             case NFC_NOT_ENABLED_DIALOG_ID:
                 return NfcDialogs.createNotEnabledDialog(this);
-
+            case NDEF_PUSH_NOT_ENABLED_DIALOG_ID:
+                return NfcDialogs.createNdefPushNotEnabledDialog(this);
             default:
                 return super.onCreateDialog(id, args);
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
index 1130f2d..c78062b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcDialogs.java
@@ -35,7 +35,22 @@
                 .setPositiveButton(R.string.nfc_settings, new DialogInterface.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
+                        Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);
+                        context.startActivity(intent);
+                    }
+                })
+                .create();
+    }
+
+    static AlertDialog createNdefPushNotEnabledDialog(final Context context) {
+        return new AlertDialog.Builder(context)
+                .setIcon(android.R.drawable.ic_dialog_alert)
+                .setTitle(R.string.ndef_push_not_enabled)
+                .setMessage(R.string.ndef_push_not_enabled_message)
+                .setPositiveButton(R.string.ndef_push_settings, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        Intent intent = new Intent(Settings.ACTION_NFCSHARING_SETTINGS);
                         context.startActivity(intent);
                     }
                 })
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
index 082c143..85a9de5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/TagVerifierActivity.java
@@ -104,10 +104,6 @@
             mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
                     .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
 
-            if (!mNfcAdapter.isEnabled()) {
-                showDialog(NFC_NOT_ENABLED_DIALOG_ID);
-            }
-
             goToWriteStep();
         } else {
             finish();
@@ -128,6 +124,10 @@
     @Override
     protected void onResume() {
         super.onResume();
+        if (!mNfcAdapter.isEnabled()) {
+            showDialog(NFC_NOT_ENABLED_DIALOG_ID);
+        }
+
         mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
     }
 
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 8fef728..454198e 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -948,6 +948,15 @@
 
         <activity android:name="android.opengl.cts.EglConfigStubActivity"/>
 
+        <activity android:name="android.opengl.cts.CompressedTextureStubActivity"
+            android:label="CompressedTextureStubActivity"
+            android:screenOrientation="nosensor">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.preference.cts.PreferenceStubActivity">
             <meta-data android:name="android.preference" 
                     android:resource="@xml/preferences_from_intent" />
@@ -971,6 +980,7 @@
                   android:label="RenderscriptGLStub"/>
     </application>
 
+
     <!--Test for PackageManager, please put this at the very beginning-->
     <instrumentation android:name="android.content.pm.cts.TestPmInstrumentation"
         android:targetPackage="android"
diff --git a/tests/res/raw/basetex.png b/tests/res/raw/basetex.png
new file mode 100644
index 0000000..c47a8a5
--- /dev/null
+++ b/tests/res/raw/basetex.png
Binary files differ
diff --git a/tests/res/raw/ddstex.dds b/tests/res/raw/ddstex.dds
new file mode 100644
index 0000000..a865693
--- /dev/null
+++ b/tests/res/raw/ddstex.dds
Binary files differ
diff --git a/tests/res/raw/pvrtex.pvr b/tests/res/raw/pvrtex.pvr
new file mode 100644
index 0000000..c92962d
--- /dev/null
+++ b/tests/res/raw/pvrtex.pvr
Binary files differ
diff --git a/tests/src/android/app/cts/IntentServiceStub.java b/tests/src/android/app/cts/IntentServiceStub.java
index af4cd279..043ff85 100644
--- a/tests/src/android/app/cts/IntentServiceStub.java
+++ b/tests/src/android/app/cts/IntentServiceStub.java
@@ -18,9 +18,9 @@
 
 import android.app.IntentService;
 import android.content.Intent;
+import android.cts.util.PollingCheck;
 import android.os.Binder;
 import android.os.IBinder;
-import android.view.animation.cts.DelayedCheck;
 
 public class IntentServiceStub extends IntentService {
     public IntentServiceStub() {
@@ -50,7 +50,7 @@
     }
 
     public static void waitToFinish(long timeout) throws Throwable {
-        new DelayedCheck(timeout) {
+        new PollingCheck(timeout) {
             @Override
             protected boolean check() {
                 return IntentServiceStub.onDestroyCalled;
diff --git a/tests/src/android/view/animation/cts/DelayedCheck.java b/tests/src/android/cts/util/PollingCheck.java
similarity index 83%
rename from tests/src/android/view/animation/cts/DelayedCheck.java
rename to tests/src/android/cts/util/PollingCheck.java
index 7179426..8870fb9 100644
--- a/tests/src/android/view/animation/cts/DelayedCheck.java
+++ b/tests/src/android/cts/util/PollingCheck.java
@@ -14,25 +14,28 @@
  * limitations under the License.
  */
 
-package android.view.animation.cts;
+package android.cts.util;
 
 import junit.framework.Assert;
 
-public abstract class DelayedCheck {
-    private static final long TIME_SLICE = 200;
+public abstract class PollingCheck {
+    private static final long TIME_SLICE = 50;
     private long mTimeout = 3000;
 
-    public DelayedCheck() {
-
+    public PollingCheck() {
     }
 
-    public DelayedCheck(long timeout) {
+    public PollingCheck(long timeout) {
         mTimeout = timeout;
     }
 
     protected abstract boolean check();
 
     public void run() {
+        if (check()) {
+            return;
+        }
+
         long timeout = mTimeout;
         while (timeout > 0) {
             try {
diff --git a/tests/src/android/opengl/cts/CompressedTextureLoader.java b/tests/src/android/opengl/cts/CompressedTextureLoader.java
new file mode 100644
index 0000000..2cb6910
--- /dev/null
+++ b/tests/src/android/opengl/cts/CompressedTextureLoader.java
@@ -0,0 +1,485 @@
+/*
+ * 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 android.opengl.cts;
+
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.Buffer;
+import java.nio.ByteOrder;
+import java.util.HashMap;
+
+import com.android.cts.stub.R;
+
+import android.app.Activity;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Log;
+
+import android.opengl.ETC1;
+import android.opengl.ETC1Util;
+import android.opengl.GLES20;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+
+public class CompressedTextureLoader {
+    private static final String TAG = "CompressedTextureLoader";
+
+    public static final String TEXTURE_UNCOMPRESSED = "UNCOMPRESSED";
+    public static final String TEXTURE_ETC1 = "ETC1";
+    public static final String TEXTURE_S3TC = "S3TC";
+    public static final String TEXTURE_ATC = "ATC";
+    public static final String TEXTURE_PVRTC = "PVRTC";
+
+    public static class Texture {
+        public Texture(int width, int height, int internalformat, ByteBuffer data,
+                       String formatName) {
+            mWidth = width;
+            mHeight = height;
+            mInternalFormat = internalformat;
+            mData = data;
+            mFormatName = formatName;
+        }
+
+        /**
+         * Get the width of the texture in pixels.
+         * @return the width of the texture in pixels.
+         */
+        public int getWidth() { return mWidth; }
+
+        /**
+         * Get the height of the texture in pixels.
+         * @return the width of the texture in pixels.
+         */
+        public int getHeight() { return mHeight; }
+
+        /**
+         * Get the compressed data of the texture.
+         * @return the texture data.
+         */
+        public ByteBuffer getData() { return mData; }
+
+        /**
+         * Get the format of the texture.
+         * @return the internal format.
+         */
+        public int getFormat() { return mInternalFormat; }
+
+        /**
+         * Get the format of the texture.
+         * @return the internal format.
+         */
+        public boolean isSupported() { return isFormatSupported(mFormatName); }
+
+        private int mWidth;
+        private int mHeight;
+        private int mInternalFormat;
+        private ByteBuffer mData;
+        private String mFormatName;
+    }
+
+    /*  .pvr header is described by the following c struct
+        typedef struct PVR_TEXTURE_HEADER_TAG{
+            unsigned int  dwHeaderSize;   // size of the structure
+            unsigned int  dwHeight;    // height of surface to be created
+            unsigned int  dwWidth;    // width of input surface
+            unsigned int  dwMipMapCount;   // number of MIP-map levels requested
+            unsigned int  dwpfFlags;   // pixel format flags
+            unsigned int  dwDataSize;   // Size of the compress data
+            unsigned int  dwBitCount;   // number of bits per pixel
+            unsigned int  dwRBitMask;   // mask for red bit
+            unsigned int  dwGBitMask;   // mask for green bits
+            unsigned int  dwBBitMask;   // mask for blue bits
+            unsigned int  dwAlphaBitMask;   // mask for alpha channel
+            unsigned int  dwPVR;    // should be 'P' 'V' 'R' '!'
+            unsigned int  dwNumSurfs;   //number of slices for volume textures or skyboxes
+        } PVR_TEXTURE_HEADER;
+    */
+    static final int PVR_HEADER_SIZE = 13 * 4;
+    static final int PVR_2BPP = 24;
+    static final int PVR_4BPP = 25;
+    static final int PVR_MAGIC_NUMBER = 559044176;
+
+    static final int GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
+    static final int GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
+    static final int GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
+    static final int GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;
+
+    static class PVRHeader {
+        int mHeaderSize;   // size of the structure
+        int mHeight;    // height of surface to be created
+        int mWidth;    // width of input surface
+        int mMipMapCount;   // number of MIP-map levels requested
+        int mpfFlags;   // pixel format flags
+        int mDataSize;   // Size of the compress data
+        int mBitCount;   // number of bits per pixel
+        int mRBitMask;   // mask for red bit
+        int mGBitMask;   // mask for green bits
+        int mBBitMask;   // mask for blue bits
+        int mAlphaBitMask;   // mask for alpha channel
+        int mPVR;    // should be 'P' 'V' 'R' '!'
+        int mNumSurfs;   //number of slices for volume textures or skyboxes
+    }
+
+    protected static PVRHeader readPVRHeader(InputStream is) {
+
+        byte[] headerData = new byte[PVR_HEADER_SIZE];
+        try {
+            is.read(headerData);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to read data");
+        }
+
+        ByteBuffer headerBuffer = ByteBuffer.allocateDirect(PVR_HEADER_SIZE)
+                .order(ByteOrder.nativeOrder());
+        headerBuffer.put(headerData, 0, PVR_HEADER_SIZE).position(0);
+
+        PVRHeader header = new PVRHeader();
+
+        header.mHeaderSize = headerBuffer.getInt();
+        header.mHeight = headerBuffer.getInt();
+        header.mWidth = headerBuffer.getInt();
+        header.mMipMapCount = headerBuffer.getInt();
+        header.mpfFlags = headerBuffer.getInt();
+        header.mDataSize = headerBuffer.getInt();
+        header.mBitCount = headerBuffer.getInt();
+        header.mRBitMask = headerBuffer.getInt();
+        header.mGBitMask = headerBuffer.getInt();
+        header.mBBitMask = headerBuffer.getInt();
+        header.mAlphaBitMask = headerBuffer.getInt();
+        header.mPVR = headerBuffer.getInt();
+        header.mNumSurfs = headerBuffer.getInt();
+
+        if (header.mHeaderSize != PVR_HEADER_SIZE ||
+            header.mPVR != PVR_MAGIC_NUMBER) {
+            throw new RuntimeException("Invalid header data");
+        }
+
+        return header;
+    }
+
+    public static Texture loadTextureATC(Resources res, int id) {
+        Texture tex = new Texture(0, 0, 0, null, "Stub!");
+        return tex;
+    }
+
+    private static ETC1Util.ETC1Texture compressTexture(Buffer input,
+                                                        int width, int height,
+                                                        int pixelSize, int stride){
+        int encodedImageSize = ETC1.getEncodedDataSize(width, height);
+        ByteBuffer compressedImage = ByteBuffer.allocateDirect(encodedImageSize).
+            order(ByteOrder.nativeOrder());
+        ETC1.encodeImage(input, width, height, pixelSize, stride, compressedImage);
+        return new ETC1Util.ETC1Texture(width, height, compressedImage);
+    }
+
+    public static Texture createFromUncompressedETC1(Bitmap bitmap) {
+        int dataSize = bitmap.getRowBytes() * bitmap.getHeight();
+
+        ByteBuffer dataBuffer;
+        dataBuffer = ByteBuffer.allocateDirect(dataSize).order(ByteOrder.nativeOrder());
+        bitmap.copyPixelsToBuffer(dataBuffer);
+        dataBuffer.position(0);
+
+        int bytesPerPixel = bitmap.getRowBytes() / bitmap.getWidth();
+        ETC1Util.ETC1Texture compressed = compressTexture(dataBuffer,
+                                                          bitmap.getWidth(),
+                                                          bitmap.getHeight(),
+                                                          bytesPerPixel,
+                                                          bitmap.getRowBytes());
+
+        Texture tex = new Texture(compressed.getWidth(), compressed.getHeight(),
+                                  ETC1.ETC1_RGB8_OES, compressed.getData(), TEXTURE_ETC1);
+
+        return tex;
+    }
+
+    private static ByteBuffer read(InputStream is, int dataSize) {
+        ByteBuffer dataBuffer;
+        dataBuffer = ByteBuffer.allocateDirect(dataSize).order(ByteOrder.nativeOrder());
+        byte[] ioBuffer = new byte[4096];
+        for (int i = 0; i < dataSize; ) {
+            int chunkSize = Math.min(ioBuffer.length, dataSize - i);
+            try {
+                is.read(ioBuffer, 0, chunkSize);
+            } catch (Exception e) {
+                throw new RuntimeException("Unable to read data");
+            }
+            dataBuffer.put(ioBuffer, 0, chunkSize);
+            i += chunkSize;
+        }
+        dataBuffer.position(0);
+        return dataBuffer;
+    }
+
+    public static Texture loadTexturePVRTC(Resources res, int id) {
+        InputStream is = null;
+        try {
+            is = res.openRawResource(id);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to open resource " + id);
+        }
+
+        PVRHeader header = readPVRHeader(is);
+
+        int format = header.mpfFlags & 0xFF;
+        int internalFormat = 0;
+        if (format == PVR_2BPP && header.mAlphaBitMask == 1) {
+            internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+        } else if (format == PVR_2BPP && header.mAlphaBitMask == 0) {
+            internalFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+        } else if (format == PVR_4BPP && header.mAlphaBitMask == 1) {
+            internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+        } else if (format == PVR_4BPP && header.mAlphaBitMask == 0) {
+            internalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+        }
+
+        // only load the first mip level for now
+        int dataSize = (header.mWidth * header.mHeight * header.mBitCount) >> 3;
+        ByteBuffer dataBuffer = read(is, dataSize);
+        Texture tex = new Texture(header.mWidth, header.mHeight,
+                                  internalFormat, dataBuffer,
+                                  TEXTURE_PVRTC);
+        try {
+            is.close();
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to close resource stream " + id);
+        }
+        return tex;
+    }
+
+    /* DDS Header is described by the following structs
+       typedef struct {
+          DWORD           dwSize;
+          DWORD           dwFlags;
+          DWORD           dwHeight;
+          DWORD           dwWidth;
+          DWORD           dwPitchOrLinearSize;
+          DWORD           dwDepth;
+          DWORD           dwMipMapCount;
+          DWORD           dwReserved1[11];
+          DDS_PIXELFORMAT ddspf;
+          DWORD           dwCaps;
+          DWORD           dwCaps2;
+          DWORD           dwCaps3;
+          DWORD           dwCaps4;
+          DWORD           dwReserved2;
+        } DDS_HEADER;
+
+        struct DDS_PIXELFORMAT {
+          DWORD dwSize;
+          DWORD dwFlags;
+          DWORD dwFourCC;
+          DWORD dwRGBBitCount;
+          DWORD dwRBitMask;
+          DWORD dwGBitMask;
+          DWORD dwBBitMask;
+          DWORD dwABitMask;
+        };
+
+        In the file it looks like this
+        DWORD               dwMagic;
+        DDS_HEADER          header;
+        DDS_HEADER_DXT10    header10; // If the DDS_PIXELFORMAT dwFlags is set to DDPF_FOURCC
+                                      // and dwFourCC is DX10
+
+    */
+
+    static final int DDS_HEADER_STRUCT_SIZE = 124;
+    static final int DDS_PIXELFORMAT_STRUCT_SIZE = 32;
+    static final int DDS_HEADER_SIZE = 128;
+    static final int DDS_MAGIC_NUMBER = 0x20534444;
+    static final int DDS_DDPF_FOURCC = 0x4;
+    static final int DDS_DXT1 = 0x31545844;
+    static final int DDS_DXT5 = 0x35545844;
+
+    static final int COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
+    static final int COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
+    static final int COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;
+
+    static class DDSHeader {
+        int mMagic;
+        int mSize;
+        int mFlags;
+        int mHeight;
+        int mWidth;
+        int mPitchOrLinearSize;
+        int mDepth;
+        int mMipMapCount;
+        int[] mReserved1;
+        // struct DDS_PIXELFORMAT {
+            int mPixelFormatSize;
+            int mPixelFormatFlags;
+            int mPixelFormatFourCC;
+            int mPixelFormatRGBBitCount;
+            int mPixelFormatRBitMask;
+            int mPixelFormatGBitMask;
+            int mPixelFormatBBitMask;
+            int mPixelFormatABitMask;
+        // };
+        int mCaps;
+        int mCaps2;
+        int mCaps3;
+        int mCaps4;
+        int mReserved2;
+
+        DDSHeader() {
+            mReserved1 = new int[11];
+        }
+    }
+
+    protected static DDSHeader readDDSHeader(InputStream is) {
+
+        byte[] headerData = new byte[DDS_HEADER_SIZE];
+        try {
+            is.read(headerData);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to read data");
+        }
+
+        ByteBuffer headerBuffer = ByteBuffer.allocateDirect(DDS_HEADER_SIZE)
+                .order(ByteOrder.nativeOrder());
+        headerBuffer.put(headerData, 0, DDS_HEADER_SIZE).position(0);
+
+        DDSHeader header = new DDSHeader();
+
+        header.mMagic = headerBuffer.getInt();
+        header.mSize = headerBuffer.getInt();
+        header.mFlags = headerBuffer.getInt();
+        header.mHeight = headerBuffer.getInt();
+        header.mWidth = headerBuffer.getInt();
+        header.mPitchOrLinearSize = headerBuffer.getInt();
+        header.mDepth = headerBuffer.getInt();
+        header.mMipMapCount = headerBuffer.getInt();
+        for (int i = 0; i < header.mReserved1.length; i ++) {
+            header.mReserved1[i] = headerBuffer.getInt();
+        }
+        // struct DDS_PIXELFORMAT {
+            header.mPixelFormatSize = headerBuffer.getInt();
+            header.mPixelFormatFlags = headerBuffer.getInt();
+            header.mPixelFormatFourCC = headerBuffer.getInt();
+            header.mPixelFormatRGBBitCount = headerBuffer.getInt();
+            header.mPixelFormatRBitMask = headerBuffer.getInt();
+            header.mPixelFormatGBitMask = headerBuffer.getInt();
+            header.mPixelFormatBBitMask = headerBuffer.getInt();
+            header.mPixelFormatABitMask = headerBuffer.getInt();
+        // };
+        header.mCaps = headerBuffer.getInt();
+        header.mCaps2 = headerBuffer.getInt();
+        header.mCaps3 = headerBuffer.getInt();
+        header.mCaps4 = headerBuffer.getInt();
+        header.mReserved2 = headerBuffer.getInt();
+
+        if (header.mSize != DDS_HEADER_STRUCT_SIZE ||
+            header.mPixelFormatSize != DDS_PIXELFORMAT_STRUCT_SIZE ||
+            header.mMagic != DDS_MAGIC_NUMBER) {
+            throw new RuntimeException("Invalid header data");
+        }
+
+        return header;
+    }
+
+    // Very simple loader that only reads in the header and a DXT1 mip level 0
+    public static Texture loadTextureDXT(Resources res, int id) {
+        InputStream is = null;
+        try {
+            is = res.openRawResource(id);
+        } catch (Exception e) {
+            throw new RuntimeException("Unable to open resource " + id);
+        }
+
+        DDSHeader header = readDDSHeader(is);
+
+        if (header.mPixelFormatFlags != DDS_DDPF_FOURCC) {
+            throw new RuntimeException("Unsupported DXT data");
+        }
+
+        int internalFormat = 0;
+        int bpp = 0;
+        switch (header.mPixelFormatFourCC) {
+        case DDS_DXT1:
+            internalFormat = COMPRESSED_RGB_S3TC_DXT1_EXT;
+            bpp = 4;
+            break;
+        case DDS_DXT5:
+            internalFormat = COMPRESSED_RGBA_S3TC_DXT5_EXT;
+            bpp = 8;
+            break;
+        default:
+            throw new RuntimeException("Unsupported DXT data");
+        }
+
+        // only load the first mip level for now
+        int dataSize = (header.mWidth * header.mHeight * bpp) >> 3;
+        if (dataSize != header.mPitchOrLinearSize) {
+            throw new RuntimeException("Expected data and header mismatch");
+        }
+        ByteBuffer dataBuffer = read(is, dataSize);
+
+        Texture tex = new Texture(header.mWidth, header.mHeight, internalFormat,
+                                  dataBuffer, TEXTURE_S3TC);
+        return tex;
+    }
+
+    static HashMap<String, Boolean> sExtensionMap;
+    static HashMap<String, Boolean> sFormatMap;
+
+    private static synchronized void updateSupportedFormats() {
+        if (sExtensionMap != null) {
+            return;
+        }
+
+        sExtensionMap = new HashMap<String, Boolean>();
+        sFormatMap = new HashMap<String, Boolean>();
+        String extensionList = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+
+        for (String extension : extensionList.split(" ")) {
+            sExtensionMap.put(extension, true);
+        }
+
+        // Check ETC1
+        sFormatMap.put(TEXTURE_ETC1, ETC1Util.isETC1Supported());
+        // Check ATC
+        if (sExtensionMap.get("GL_AMD_compressed_ATC_texture") != null ||
+            sExtensionMap.get("GL_ATI_compressed_texture_atitc") != null ||
+            sExtensionMap.get("GL_ATI_texture_compression_atitc") != null) {
+            sFormatMap.put(TEXTURE_ATC, true);
+        }
+        // Check DXT
+        if (sExtensionMap.get("GL_EXT_texture_compression_dxt1") != null ||
+            sExtensionMap.get("GL_EXT_texture_compression_s3tc") != null ||
+            sExtensionMap.get("OES_texture_compression_S3TC") != null) {
+            sFormatMap.put(TEXTURE_S3TC, true);
+        }
+        // Check DXT
+        if (sExtensionMap.get("GL_IMG_texture_compression_pvrtc") != null) {
+            sFormatMap.put(TEXTURE_PVRTC, true);
+        }
+
+        /*Log.i(TAG, "mIsSupportedETC1 " + sFormatMap.get(TEXTURE_ETC1));
+        Log.i(TAG, "mIsSupportedATC " + sFormatMap.get(TEXTURE_ATC));
+        Log.i(TAG, "mIsSupportedDXT " + sFormatMap.get(TEXTURE_S3TC));
+        Log.i(TAG, "mIsSupportedPVRTC " + sFormatMap.get(TEXTURE_PVRTC));*/
+    }
+
+    private static boolean isFormatSupported(String format) {
+        updateSupportedFormats();
+        Boolean supported = sFormatMap.get(format);
+        return supported != null ? supported : false;
+    }
+}
diff --git a/tests/src/android/opengl/cts/CompressedTextureStubActivity.java b/tests/src/android/opengl/cts/CompressedTextureStubActivity.java
new file mode 100644
index 0000000..bf098eb
--- /dev/null
+++ b/tests/src/android/opengl/cts/CompressedTextureStubActivity.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.opengl.cts;
+
+import com.android.cts.stub.R;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.util.Log;
+
+
+public class CompressedTextureStubActivity extends Activity {
+
+    private static final String TAG = "CompressedTextureStubActivity";
+
+    protected Resources mResources;
+
+    private CompressedTextureSurfaceView mCompressedTextureView = null;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Bundle extras = getIntent().getExtras();
+        String formatTest = extras.getString("TextureFormat", null);
+
+        Log.i(TAG, "Testing format " + formatTest);
+
+        mResources = getResources();
+
+        CompressedTextureLoader.Texture compressed = null;
+
+        BitmapFactory.Options optionsRGB = new BitmapFactory.Options();
+        optionsRGB.inPreferredConfig = Bitmap.Config.RGB_565;
+        Bitmap bitmap = BitmapFactory.decodeResource(mResources, R.raw.basetex, optionsRGB);
+
+        if (formatTest.equals(CompressedTextureLoader.TEXTURE_ETC1)) {
+            compressed = CompressedTextureLoader.createFromUncompressedETC1(bitmap);
+        } else if (formatTest.equals(CompressedTextureLoader.TEXTURE_S3TC)) {
+            compressed = CompressedTextureLoader.loadTextureDXT(mResources, R.raw.ddstex); //stub for now
+        } else if (formatTest.equals(CompressedTextureLoader.TEXTURE_ATC)) {
+            compressed = CompressedTextureLoader.loadTextureATC(mResources, 0); //stub for now
+        } else if (formatTest.equals(CompressedTextureLoader.TEXTURE_PVRTC)) {
+            compressed = CompressedTextureLoader.loadTexturePVRTC(mResources, R.raw.pvrtex);
+        }
+
+        mCompressedTextureView = new CompressedTextureSurfaceView(this, bitmap, compressed);
+        setContentView(mCompressedTextureView);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mCompressedTextureView.onResume();
+    }
+}
diff --git a/tests/src/android/opengl/cts/CompressedTextureSurfaceView.java b/tests/src/android/opengl/cts/CompressedTextureSurfaceView.java
new file mode 100644
index 0000000..8d28efa0
--- /dev/null
+++ b/tests/src/android/opengl/cts/CompressedTextureSurfaceView.java
@@ -0,0 +1,402 @@
+/*
+ * 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 android.opengl.cts;
+
+import java.io.IOException;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import com.android.cts.stub.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.graphics.SurfaceTexture;
+import android.opengl.ETC1;
+import android.opengl.ETC1Util;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLUtils;
+import android.opengl.Matrix;
+import android.util.Log;
+import android.view.Surface;
+
+class CompressedTextureSurfaceView extends GLSurfaceView {
+    private static final String TAG = "CompressedTextureSurfaceView";
+    private static final int SLEEP_TIME_MS = 1000;
+
+    CompressedTextureRender mRenderer;
+
+    public CompressedTextureSurfaceView(Context context,
+                                        Bitmap base,
+                                        CompressedTextureLoader.Texture compressed) {
+        super(context);
+
+        setEGLContextClientVersion(2);
+        mRenderer = new CompressedTextureRender(context, base, compressed);
+        setRenderer(mRenderer);
+        setRenderMode(RENDERMODE_WHEN_DIRTY);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    private static class CompressedTextureRender implements GLSurfaceView.Renderer {
+        private static String TAG = "CompressedTextureRender";
+
+        private static final int ALLOWED_DELTA = 25;
+        private static final int FBO_PIXEL_SIZE_BYTES = 4;
+        private static final int FLOAT_SIZE_BYTES = 4;
+        private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+        private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+        private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+        private final float[] mTriangleVerticesData = {
+            // X, Y, Z, U, V
+            -1.0f, -1.0f, 0, 0.f, 0.f,
+            1.0f, -1.0f, 0, 1.f, 0.f,
+            -1.0f,  1.0f, 0, 0.f, 1.f,
+            1.0f,  1.0f, 0, 1.f, 1.f,
+        };
+
+        private FloatBuffer mTriangleVertices;
+
+        private final String mVertexShader =
+                "uniform mat4 uMVPMatrix;\n" +
+                "attribute vec4 aPosition;\n" +
+                "attribute vec4 aTextureCoord;\n" +
+                "varying vec2 vTextureCoord;\n" +
+                "void main() {\n" +
+                "  gl_Position = uMVPMatrix * aPosition;\n" +
+                "  vTextureCoord = aTextureCoord.xy;\n" +
+                "}\n";
+
+        private final String mFragmentShader =
+                "precision mediump float;\n" +
+                "varying vec2 vTextureCoord;\n" +
+                "uniform sampler2D sTexture;\n" +
+                "void main() {\n" +
+                "  gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+                "}\n";
+
+        private float[] mMVPMatrix = new float[16];
+        private float[] mSTMatrix = new float[16];
+
+        private int mProgram;
+        private int mTextureID;
+        private int muMVPMatrixHandle;
+        private int maPositionHandle;
+        private int maTextureHandle;
+        private int msTextureHandle;
+
+        private int mColorTargetID;
+        private int mFrameBufferObjectID;
+
+        private boolean updateSurface = false;
+
+        Bitmap mBaseTexture;
+        CompressedTextureLoader.Texture mCompressedTexture;
+
+        int mWidth;
+        int mHeight;
+
+        ByteBuffer mReadBackBuffer;
+
+        public CompressedTextureRender(Context context,
+                                       Bitmap base,
+                                       CompressedTextureLoader.Texture compressed) {
+            mBaseTexture = base;
+            mCompressedTexture = compressed;
+            mTriangleVertices = ByteBuffer.allocateDirect(
+                mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
+                    .order(ByteOrder.nativeOrder()).asFloatBuffer();
+            mTriangleVertices.put(mTriangleVerticesData).position(0);
+
+            Matrix.setIdentityM(mSTMatrix, 0);
+
+            int byteBufferSize = mBaseTexture.getWidth() *
+                                 mBaseTexture.getHeight() *
+                                 FBO_PIXEL_SIZE_BYTES;
+            mReadBackBuffer = ByteBuffer.allocateDirect(byteBufferSize);
+        }
+
+        private void renderQuad(int textureID) {
+            GLES20.glUseProgram(mProgram);
+            checkGlError("glUseProgram");
+
+            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureID);
+
+            mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+            GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+            checkGlError("glVertexAttribPointer maPosition");
+            GLES20.glEnableVertexAttribArray(maPositionHandle);
+            checkGlError("glEnableVertexAttribArray maPositionHandle");
+
+            mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+            GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+            checkGlError("glVertexAttribPointer maTextureHandle");
+            GLES20.glEnableVertexAttribArray(maTextureHandle);
+            checkGlError("glEnableVertexAttribArray maTextureHandle");
+
+            Matrix.setIdentityM(mMVPMatrix, 0);
+            GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+
+            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+            checkGlError("glDrawArrays");
+        }
+
+        private int getUnsignedByte(byte val) {
+            return 0xFF & ((int)val);
+        }
+
+        private boolean comparePixel(int x, int y) {
+            int w = mBaseTexture.getWidth();
+            int sampleStart = (y * w + x) * FBO_PIXEL_SIZE_BYTES;
+
+            int R = getUnsignedByte(mReadBackBuffer.get(sampleStart));
+            int G = getUnsignedByte(mReadBackBuffer.get(sampleStart + 1));
+            int B = getUnsignedByte(mReadBackBuffer.get(sampleStart + 2));
+
+            int original = mBaseTexture.getPixel(x, y);
+
+            int deltaR = Math.abs(R - Color.red(original));
+            int deltaG = Math.abs(G - Color.green(original));
+            int deltaB = Math.abs(B - Color.blue(original));
+
+            if (deltaR <= ALLOWED_DELTA &&
+                deltaG <= ALLOWED_DELTA &&
+                deltaB <= ALLOWED_DELTA) {
+                return true;
+            }
+
+            Log.i("PIXEL DELTA", "R: " + deltaR + " G: " + deltaG + " B: " + deltaB);
+
+            return false;
+        }
+
+        private void comparePixels() {
+            int w = mBaseTexture.getWidth();
+            int h = mBaseTexture.getWidth();
+            int wOver4 = w / 4;
+            int hOver4 = h / 4;
+
+            // Sample 4 points in the image. Test is designed so that
+            // sample areas are low frequency and easy to compare
+            boolean sample1Matches = comparePixel(wOver4, hOver4);
+            boolean sample2Matches = comparePixel(wOver4 * 3, hOver4);
+            boolean sample3Matches = comparePixel(wOver4, hOver4 * 3);
+            boolean sample4Matches = comparePixel(wOver4 * 3, hOver4 * 3);
+
+            if (!sample1Matches || !sample2Matches || !sample3Matches || !sample4Matches) {
+                throw new RuntimeException("Compressed colors incorrect");
+            }
+        }
+
+        public void onDrawFrame(GL10 glUnused) {
+            if (mProgram == 0) {
+                return;
+            }
+
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferObjectID);
+            GLES20.glViewport(0, 0, mBaseTexture.getWidth(), mBaseTexture.getHeight());
+            GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+            renderQuad(mTextureID);
+            GLES20.glReadPixels(0, 0, mBaseTexture.getWidth(), mBaseTexture.getHeight(),
+                                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mReadBackBuffer);
+            comparePixels();
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+
+            GLES20.glViewport(0, 0, mWidth, mHeight);
+            GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+            GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+
+            renderQuad(mColorTargetID);
+
+            GLES20.glFinish();
+        }
+
+        public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+            mWidth = width;
+            mHeight = height;
+        }
+
+        private void setupSamplers() {
+            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+                    GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,
+                    GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                    GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+            GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D,
+                    GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+        }
+
+        private void initFBO() {
+            int[] textures = new int[1];
+            GLES20.glGenTextures(1, textures, 0);
+
+            mColorTargetID = textures[0];
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mColorTargetID);
+            checkGlError("glBindTexture mColorTargetID");
+            setupSamplers();
+            GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA,
+                                mBaseTexture.getWidth(), mBaseTexture.getHeight(), 0,
+                                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
+            checkGlError("glTexImage2D mColorTargetID");
+
+            GLES20.glGenFramebuffers(1, textures, 0);
+            mFrameBufferObjectID = textures[0];
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mFrameBufferObjectID);
+
+            GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0,
+                                          GLES20.GL_TEXTURE_2D, mColorTargetID, 0);
+
+            int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+            if(status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
+                throw new RuntimeException("Failed to initialize framebuffer object");
+            }
+
+            GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+        }
+
+        public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+            if (mCompressedTexture != null && !mCompressedTexture.isSupported()) {
+                return;
+            }
+
+            initFBO();
+
+            mProgram = createProgram(mVertexShader, mFragmentShader);
+            if (mProgram == 0) {
+                return;
+            }
+            maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
+            checkGlError("glGetAttribLocation aPosition");
+            if (maPositionHandle == -1) {
+                throw new RuntimeException("Could not get attrib location for aPosition");
+            }
+            maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
+            checkGlError("glGetAttribLocation aTextureCoord");
+            if (maTextureHandle == -1) {
+                throw new RuntimeException("Could not get attrib location for aTextureCoord");
+            }
+
+            muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+            checkGlError("glGetUniformLocation uMVPMatrix");
+            if (muMVPMatrixHandle == -1) {
+                throw new RuntimeException("Could not get attrib location for uMVPMatrix");
+            }
+
+            int[] textures = new int[1];
+            GLES20.glGenTextures(1, textures, 0);
+
+            mTextureID = textures[0];
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
+            checkGlError("glBindTexture mTextureID");
+            setupSamplers();
+
+            if (mCompressedTexture == null) {
+                GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBaseTexture, 0);
+                checkGlError("texImage2D mBaseTexture");
+            } else {
+                GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D,
+                                              0,
+                                              mCompressedTexture.getFormat(),
+                                              mCompressedTexture.getWidth(),
+                                              mCompressedTexture.getHeight(),
+                                              0,
+                                              mCompressedTexture.getData().remaining(),
+                                              mCompressedTexture.getData());
+                checkGlError("glCompressedTexImage2D mTextureID");
+            }
+        }
+
+        synchronized public void onFrameAvailable(SurfaceTexture surface) {
+            updateSurface = true;
+        }
+
+        private int loadShader(int shaderType, String source) {
+            int shader = GLES20.glCreateShader(shaderType);
+            if (shader != 0) {
+                GLES20.glShaderSource(shader, source);
+                GLES20.glCompileShader(shader);
+                int[] compiled = new int[1];
+                GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+                if (compiled[0] == 0) {
+                    Log.e(TAG, "Could not compile shader " + shaderType + ":");
+                    Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+                    GLES20.glDeleteShader(shader);
+                    shader = 0;
+                }
+            }
+            return shader;
+        }
+
+        private int createProgram(String vertexSource, String fragmentSource) {
+            int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+            if (vertexShader == 0) {
+                return 0;
+            }
+            int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+            if (pixelShader == 0) {
+                return 0;
+            }
+
+            int program = GLES20.glCreateProgram();
+            if (program != 0) {
+                GLES20.glAttachShader(program, vertexShader);
+                checkGlError("glAttachShader");
+                GLES20.glAttachShader(program, pixelShader);
+                checkGlError("glAttachShader");
+                GLES20.glLinkProgram(program);
+                int[] linkStatus = new int[1];
+                GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+                if (linkStatus[0] != GLES20.GL_TRUE) {
+                    Log.e(TAG, "Could not link program: ");
+                    Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+                    GLES20.glDeleteProgram(program);
+                    program = 0;
+                }
+            }
+            return program;
+        }
+
+        private void checkGlError(String op) {
+            int error;
+            while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+                Log.e(TAG, op + ": glError " + error);
+                throw new RuntimeException(op + ": glError " + error);
+            }
+        }
+
+    }  // End of class CompressedTextureRender.
+
+}  // End of class CompressedTextureSurfaceView.
diff --git a/tests/src/android/view/animation/cts/AnimationTestUtils.java b/tests/src/android/view/animation/cts/AnimationTestUtils.java
index 3ee22c7..a2b786d 100644
--- a/tests/src/android/view/animation/cts/AnimationTestUtils.java
+++ b/tests/src/android/view/animation/cts/AnimationTestUtils.java
@@ -17,6 +17,7 @@
 package android.view.animation.cts;
 
 import android.app.Instrumentation;
+import android.cts.util.PollingCheck;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Animation;
@@ -66,7 +67,7 @@
         });
 
         // check whether it has started
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return animation.hasStarted();
@@ -74,7 +75,7 @@
         }.run();
 
         // check whether it has ended after duration
-        new DelayedCheck(duration + TIMEOUT_DELTA) {
+        new PollingCheck(duration + TIMEOUT_DELTA) {
             @Override
             protected boolean check() {
                 return animation.hasEnded();
diff --git a/tests/tests/app/src/android/app/cts/DialogTest.java b/tests/tests/app/src/android/app/cts/DialogTest.java
index 37ded56..67470a0 100644
--- a/tests/tests/app/src/android/app/cts/DialogTest.java
+++ b/tests/tests/app/src/android/app/cts/DialogTest.java
@@ -32,6 +32,7 @@
 import android.content.DialogInterface.OnKeyListener;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.cts.util.PollingCheck;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.drawable.Drawable;
@@ -42,7 +43,6 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -684,7 +684,7 @@
         mInstrumentation.waitForIdleSync();
 
         // Wait until TestDialog#OnWindowFocusChanged() is called
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return d.isOnWindowFocusChangedCalled;
             }
diff --git a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
index a225749..1da6af9 100644
--- a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -22,12 +22,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.cts.CtsTestServer;
 
 import java.io.File;
@@ -314,7 +314,7 @@
     }
 
     private void assertDownloadQueryableByStatus(final int status) {
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 Cursor cursor= null;
diff --git a/tests/tests/app/src/android/app/cts/IntentServiceTest.java b/tests/tests/app/src/android/app/cts/IntentServiceTest.java
index d844aa9..0d2f11b 100644
--- a/tests/tests/app/src/android/app/cts/IntentServiceTest.java
+++ b/tests/tests/app/src/android/app/cts/IntentServiceTest.java
@@ -21,8 +21,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.cts.util.PollingCheck;
 import android.os.IBinder;
-import android.view.animation.cts.DelayedCheck;
 
 import dalvik.annotation.TestLevel;
 import dalvik.annotation.TestTargetClass;
@@ -106,7 +106,7 @@
     public void testIntentServiceLifeCycle() throws Throwable {
         // start service
         mContext.startService(mIntent);
-        new DelayedCheck(TIMEOUT_MSEC) {
+        new PollingCheck(TIMEOUT_MSEC) {
             protected boolean check() {
                 return IntentServiceStub.onHandleIntentCalled > 0;
             }
@@ -117,7 +117,7 @@
         // bind service
         ServiceConnection conn = new TestConnection();
         mContext.bindService(mIntent, conn, Context.BIND_AUTO_CREATE);
-        new DelayedCheck(TIMEOUT_MSEC) {
+        new PollingCheck(TIMEOUT_MSEC) {
             protected boolean check() {
                 return mConnected;
             }
diff --git a/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java b/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
index ae02e0a..ca6bba7 100644
--- a/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
+++ b/tests/tests/content/src/android/content/cts/ClipboardManagerListenerTest.java
@@ -18,9 +18,9 @@
 
 import android.content.ClipData;
 import android.content.ClipboardManager.OnPrimaryClipChangedListener;
+import android.cts.util.PollingCheck;
 import android.net.Uri;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 
 
 public class ClipboardManagerListenerTest
@@ -57,7 +57,7 @@
     }
 
     private void assertClipChangedCount(final int expectedCount) {
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return expectedCount == mListener.getCount();
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index b866375..9378e63 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -29,13 +29,13 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.res.AssetFileDescriptor;
+import android.cts.util.PollingCheck;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
-import android.view.animation.cts.DelayedCheck;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -637,7 +637,7 @@
         values.put(COLUMN_KEY_NAME, "key10");
         values.put(COLUMN_VALUE_NAME, 10);
         mContentResolver.update(TABLE1_URI, values, null, null);
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return mco.hadOnChanged();
@@ -689,7 +689,7 @@
         assertFalse(mco.hadOnChanged());
 
         mContentResolver.notifyChange(TABLE1_URI, mco);
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return mco.hadOnChanged();
@@ -713,7 +713,7 @@
         assertFalse(mco.hadOnChanged());
 
         mContentResolver.notifyChange(TABLE1_URI, mco, false);
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return mco.hadOnChanged();
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
index 6ad14e0..3e1e3e4 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
@@ -35,6 +35,7 @@
 import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteCursorDriver;
 import android.database.sqlite.SQLiteDatabase;
@@ -48,7 +49,6 @@
 import android.os.IBinder;
 import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
-import android.view.animation.cts.DelayedCheck;
 
 import java.io.File;
 import java.io.IOException;
@@ -176,7 +176,7 @@
 
         final Intent broadcastIntent = new Intent(ResultReceiver.MOCK_ACTION);
         mContextWrapper.sendOrderedBroadcast(broadcastIntent, null);
-        new DelayedCheck(BROADCAST_TIMEOUT) {
+        new PollingCheck(BROADCAST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return highPriorityReceiver.hasReceivedBroadCast()
@@ -188,7 +188,7 @@
             highPriorityReceiver.notify();
         }
 
-        new DelayedCheck(BROADCAST_TIMEOUT) {
+        new PollingCheck(BROADCAST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return highPriorityReceiver.hasReceivedBroadCast()
@@ -957,7 +957,7 @@
 
         mContextWrapper.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION));
 
-        new DelayedCheck(BROADCAST_TIMEOUT){
+        new PollingCheck(BROADCAST_TIMEOUT){
             @Override
             protected boolean check() {
                 return receiver.hasReceivedBroadCast();
@@ -977,7 +977,7 @@
 
         mContextWrapper.sendBroadcast(new Intent(ResultReceiver.MOCK_ACTION), null);
 
-        new DelayedCheck(BROADCAST_TIMEOUT){
+        new PollingCheck(BROADCAST_TIMEOUT){
             @Override
             protected boolean check() {
                 return receiver.hasReceivedBroadCast();
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
index 3edaad8..17ab976 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimationDrawableTest.java
@@ -30,12 +30,12 @@
 import android.app.Activity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.cts.util.PollingCheck;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableContainer.DrawableContainerState;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Xml;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.ImageView;
 import android.widget.cts.ImageViewStubActivity;
 
@@ -107,7 +107,7 @@
         assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX),
                 mAnimationDrawable.getCurrent());
 
-        delayedCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
+        pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -159,7 +159,7 @@
         assertTrue(mAnimationDrawable.isRunning());
         assertSame(mAnimationDrawable.getFrame(FIRST_FRAME_INDEX),
                 mAnimationDrawable.getCurrent());
-        delayedCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
+        pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -167,7 +167,7 @@
                 mAnimationDrawable.start();
             }
         });
-        delayedCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
+        pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -210,7 +210,7 @@
         });
 
         assertTrue(mAnimationDrawable.isRunning());
-        delayedCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
+        pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -342,10 +342,10 @@
                 mAnimationDrawable.start();
             }
         });
-        delayedCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
-        delayedCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
+        pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
+        pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
         // begin to repeat
-        delayedCheckDrawable(FIRST_FRAME_INDEX, THIRD_FRAME_DURATION);
+        pollingCheckDrawable(FIRST_FRAME_INDEX, THIRD_FRAME_DURATION);
 
         runTestOnUiThread(new Runnable() {
             public void run() {
@@ -355,8 +355,8 @@
                 mAnimationDrawable.start();
             }
         });
-        delayedCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
-        delayedCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
+        pollingCheckDrawable(SECOND_FRAME_INDEX, FIRST_FRAME_DURATION);
+        pollingCheckDrawable(THIRD_FRAME_INDEX, SECOND_FRAME_DURATION);
         // do not repeat
         assertStoppedAnimation(THIRD_FRAME_INDEX, THIRD_FRAME_DURATION);
     }
@@ -471,12 +471,12 @@
     }
 
     /**
-     * Delayed check specific frame should be current one in timeout.
+     * Polling check specific frame should be current one in timeout.
      * @param index - expected index of frame.
      * @param timeout - timeout.
      */
-    private void delayedCheckDrawable(final int index, long timeout) {
-        new DelayedCheck(timeout + TOLERANCE) {
+    private void pollingCheckDrawable(final int index, long timeout) {
+        new PollingCheck(timeout + TOLERANCE) {
             Drawable expected = mAnimationDrawable.getFrame(index);
             @Override
             protected boolean check() {
diff --git a/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
new file mode 100644
index 0000000..3676d66
--- /dev/null
+++ b/tests/tests/graphics/src/android/opengl/cts/CompressedTextureTest.java
@@ -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 android.opengl.cts;
+
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ */
+public class CompressedTextureTest extends ActivityInstrumentationTestCase2<CompressedTextureStubActivity> {
+
+    public CompressedTextureTest() {
+        super("com.android.cts.stub", CompressedTextureStubActivity.class);
+    }
+
+    private void launchTest(String format) throws Exception {
+        Bundle extras = new Bundle();
+        extras.putString("TextureFormat", format);
+        CompressedTextureStubActivity activity = launchActivity("com.android.cts.stub",
+                CompressedTextureStubActivity.class, extras);
+        activity.finish();
+    }
+
+    public void testTextureUncompressed() throws Exception {
+        launchTest(CompressedTextureLoader.TEXTURE_UNCOMPRESSED);
+    }
+
+    public void testTextureETC1() throws Exception {
+        launchTest(CompressedTextureLoader.TEXTURE_ETC1);
+    }
+
+    public void testTexturePVRTC() throws Exception {
+        launchTest(CompressedTextureLoader.TEXTURE_PVRTC);
+    }
+
+    public void testTextureS3TC() throws Exception {
+        launchTest(CompressedTextureLoader.TEXTURE_S3TC);
+    }
+
+    /*public void testTextureATC() throws Exception {
+        launchTest(CompressedTextureLoader.TEXTURE_ATC);
+    }*/
+}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index a07c704..1ddcdd5 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -47,9 +47,6 @@
     protected void setUp() throws Exception {
         super.setUp();
 
-        if (!hasMicrophone()) {
-            return;
-        }
         /*
          * InstrumentationTestRunner.onStart() calls Looper.prepare(), which creates a looper
          * for the current thread. However, since we don't actually call loop() in the test,
@@ -83,10 +80,8 @@
 
     @Override
     protected void tearDown() throws Exception {
-        if (hasMicrophone()) {
-            mAudioRecord.release();
-            mLooper.quit();
-        }
+        mAudioRecord.release();
+        mLooper.quit();
         super.tearDown();
     }
 
diff --git a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
index 504a304..e597827 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecord_BufferSizeTest.java
@@ -17,12 +17,12 @@
 package android.media.cts;
 
 import android.content.pm.PackageManager;
+import android.cts.util.PollingCheck;
 import android.media.AudioFormat;
 import android.media.AudioRecord;
 import android.media.MediaRecorder.AudioSource;
 import android.test.AndroidTestCase;
 import android.util.Log;
-import android.view.animation.cts.DelayedCheck;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -85,7 +85,7 @@
     }
 
     private void checkRecordingState(final int state) {
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return mAudioRecord.getRecordingState() == state;
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
index cc25d07..2c9fe1a 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerConnectionTest.java
@@ -26,12 +26,12 @@
 
 import android.content.ComponentName;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
 import android.os.IBinder;
 import android.test.AndroidTestCase;
-import android.view.animation.cts.DelayedCheck;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -157,12 +157,12 @@
     }
 
     private void checkMediaScannerConnection() {
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             protected boolean check() {
                 return mMediaScannerConnectionClient.isOnMediaScannerConnectedCalled;
             }
         }.run();
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             protected boolean check() {
                 return mMediaScannerConnectionClient.mediaPath != null;
             }
@@ -170,7 +170,7 @@
     }
 
     private void checkConnectionState(final boolean expected) {
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             protected boolean check() {
                 return mMediaScannerConnection.isConnected() == expected;
             }
diff --git a/tests/tests/nativemedia/Android.mk b/tests/tests/nativemedia/Android.mk
index 928ebcd..1d4ec7f 100644
--- a/tests/tests/nativemedia/Android.mk
+++ b/tests/tests/nativemedia/Android.mk
@@ -1,34 +1 @@
-# Build the unit tests.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_C_INCLUDES:= \
-    bionic \
-    bionic/libstdc++/include \
-    external/gtest/include \
-    system/media/wilhelm/include \
-    external/stlport/stlport \
-    system/media/wilhelm/src/ut
-
-LOCAL_SRC_FILES:= \
-    src/SLObjectCreationTest.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-  libutils \
-  libOpenSLES \
-  libstlport
-
-LOCAL_STATIC_LIBRARIES := \
-    libOpenSLESUT \
-    libgtest
-
-LOCAL_CFLAGS += -DXP_UNIX
-
-LOCAL_MODULE:= NativeMediaTest
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
-
-include $(BUILD_EXECUTABLE)
\ No newline at end of file
+include $(call all-subdir-makefiles)
\ No newline at end of file
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
new file mode 100644
index 0000000..b68976e
--- /dev/null
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -0,0 +1,32 @@
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_C_INCLUDES:= \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    system/media/wilhelm/include \
+    external/stlport/stlport \
+    system/media/wilhelm/src/ut
+
+LOCAL_SRC_FILES:= \
+    src/SLObjectCreationTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+  libutils \
+  libOpenSLES \
+  libstlport
+
+LOCAL_STATIC_LIBRARIES := \
+    libOpenSLESUT \
+    libgtest
+
+LOCAL_MODULE:= NativeMediaTest_SL
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+
+include $(BUILD_EXECUTABLE)
\ No newline at end of file
diff --git a/tests/tests/nativemedia/src/SLObjectCreationTest.cpp b/tests/tests/nativemedia/sl/src/SLObjectCreationTest.cpp
similarity index 95%
rename from tests/tests/nativemedia/src/SLObjectCreationTest.cpp
rename to tests/tests/nativemedia/sl/src/SLObjectCreationTest.cpp
index e63e42fa3..450b32e 100644
--- a/tests/tests/nativemedia/src/SLObjectCreationTest.cpp
+++ b/tests/tests/nativemedia/sl/src/SLObjectCreationTest.cpp
@@ -79,7 +79,7 @@
 
     /* Test setup*/
     virtual void SetUp() {
-        LOGV("Test Setup()");
+        ALOGV("Test Setup()");
         res = SL_RESULT_UNKNOWN_ERROR;
         engineItf = NULL;
         engineObj = NULL;
@@ -96,7 +96,7 @@
     }
 
     virtual void TearDown() {
-        LOGV("Test TearDown()");
+        ALOGV("Test TearDown()");
         if (audioPlayerObj) {
             (*audioPlayerObj)->Destroy(audioPlayerObj);
             audioPlayerObj = NULL;
@@ -306,60 +306,60 @@
 
 //-------------------------------------------------------------------------------------------------
 TEST_F(SLObjectCreationTest, testEngineCreation) {
-    LOGV("Test Fixture: EngineCreation");
+    ALOGV("Test Fixture: EngineCreation");
     // nothing to do here that isn't done in SetUp()
 }
 
 TEST_F(SLObjectCreationTest, testOutputMixCreation) {
-    LOGV("Test Fixture: OutputMixCreation");
+    ALOGV("Test Fixture: OutputMixCreation");
     OutputMixCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromUriCreation) {
-    LOGV("Test Fixture: AudioPlayerFromUriCreation");
+    ALOGV("Test Fixture: AudioPlayerFromUriCreation");
     // required for AudioPlayer creation
     OutputMixCreation();
     AudioPlayerFromUriCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromFdCreation) {
-    LOGV("Test Fixture: AudioPlayerFromFdCreation");
+    ALOGV("Test Fixture: AudioPlayerFromFdCreation");
     // required for AudioPlayer creation
     OutputMixCreation();
     AudioPlayerFromFdCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromPcmBqCreation) {
-    LOGV("Test Fixture: AudioPlayerFromPcmBqCreation");
+    ALOGV("Test Fixture: AudioPlayerFromPcmBqCreation");
     // required for AudioPlayer creation
     OutputMixCreation();
     AudioPlayerFromPcmBqCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromTsAbqCreation) {
-    LOGV("Test Fixture: AudioPlayerFromTsAbqCreation");
+    ALOGV("Test Fixture: AudioPlayerFromTsAbqCreation");
     // required for AudioPlayer creation
     OutputMixCreation();
     AudioPlayerFromTsAbqCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromUriToPcmBqCreation) {
-    LOGV("Test Fixture: AudioPlayerFromUriToPcmBqCreation");
+    ALOGV("Test Fixture: AudioPlayerFromUriToPcmBqCreation");
     AudioPlayerFromUriToPcmBqCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromFdToPcmBqCreation) {
-    LOGV("Test Fixture: AudioPlayerFromFdToPcmBqCreation");
+    ALOGV("Test Fixture: AudioPlayerFromFdToPcmBqCreation");
     AudioPlayerFromFdToPcmBqCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioPlayerFromAdtsAbqToPcmBqCreation) {
-    LOGV("Test Fixture: AudioPlayerFromAdtsAbqToPcmBqCreation");
+    ALOGV("Test Fixture: AudioPlayerFromAdtsAbqToPcmBqCreation");
     AudioPlayerFromAdtsAbqToPcmBqCreation();
 }
 
 TEST_F(SLObjectCreationTest, testAudioRecorderCreation) {
-    LOGV("Test Fixture: AudioRecorderCreation");
+    ALOGV("Test Fixture: AudioRecorderCreation");
     AudioRecorderCreation();
 }
 
diff --git a/tests/tests/nativemedia/xa/Android.mk b/tests/tests/nativemedia/xa/Android.mk
new file mode 100644
index 0000000..36c7f6c
--- /dev/null
+++ b/tests/tests/nativemedia/xa/Android.mk
@@ -0,0 +1,31 @@
+# Build the unit tests.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_C_INCLUDES:= \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    system/media/wilhelm/include \
+    external/stlport/stlport \
+    system/media/wilhelm/src/ut
+
+LOCAL_SRC_FILES:= \
+    src/XAObjectCreationTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+  libutils \
+  libOpenMAXAL \
+  libstlport
+
+LOCAL_STATIC_LIBRARIES := \
+    libgtest
+
+LOCAL_MODULE:= NativeMediaTest_XA
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+
+include $(BUILD_EXECUTABLE)
\ No newline at end of file
diff --git a/tests/tests/nativemedia/xa/src/XAObjectCreationTest.cpp b/tests/tests/nativemedia/xa/src/XAObjectCreationTest.cpp
new file mode 100644
index 0000000..3ff84c2
--- /dev/null
+++ b/tests/tests/nativemedia/xa/src/XAObjectCreationTest.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test for testing the creation of OpenMAX AL objects.
+ * The tests verify the creation and completion of the call to Realize() for the following objects:
+ *   - Engine
+ *   - OutputMix
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "XAObjectCreationTest"
+
+#include <utils/Log.h>
+#include "OMXAL/OpenMAXAL.h"
+#include "OMXAL/OpenMAXAL_Android.h"
+//#include <android/native_window_jni.h>
+#include <gtest/gtest.h>
+
+//-----------------------------------------------------------------
+/* Checks for error and displays the error code if any */
+bool IsOk(XAresult res) {
+    if (XA_RESULT_SUCCESS != res) {
+        fprintf(stderr, "IsOk failure: 0x%x, exiting\n", res);
+        return false;
+    }
+    return true;
+}
+
+//-----------------------------------------------------------------
+class XAObjectCreationTest : public ::testing::Test {
+
+protected:
+    XAresult res;
+    XAObjectItf engineObj, outputMixObj, mediaPlayerObj;
+    XAEngineItf engineItf;
+
+    XADataSource mediaSource;
+    XADataSink   audioSink;
+    XADataLocator_URI locatorUriSrc;
+    XADataLocator_AndroidBufferQueue locatorAbqSrc;
+    XADataLocator_AndroidFD locatorFdSrc;
+    XADataFormat_MIME formatMimeSrc;
+
+    XADataLocator_OutputMix locatorOutputmixSink;
+    XADataFormat_PCM formatPcmSink;
+
+    XADataLocator_NativeDisplay locatorVideoSink;
+    XADataSink imageSink;
+
+    //ANativeWindow* pNativeWindow;
+
+    XAObjectCreationTest() { }
+
+    virtual ~XAObjectCreationTest() { }
+
+    /* Test setup*/
+    virtual void SetUp() {
+        ALOGV("Test Setup()");
+        res = XA_RESULT_UNKNOWN_ERROR;
+        engineItf = NULL;
+        engineObj = NULL;
+        outputMixObj = NULL;
+        mediaPlayerObj = NULL;
+        // Engine creation
+        res = xaCreateEngine(&engineObj, 0, NULL, 0, NULL, NULL);
+        ASSERT_TRUE(IsOk(res));
+        res = (*engineObj)->Realize(engineObj, XA_BOOLEAN_FALSE);
+        ASSERT_TRUE(IsOk(res));
+        res = (*engineObj)->GetInterface(engineObj, XA_IID_ENGINE, &engineItf);
+        ASSERT_TRUE(IsOk(res));
+        ASSERT_TRUE(NULL != engineItf);
+    }
+
+    virtual void TearDown() {
+        ALOGV("Test TearDown()");
+        if (mediaPlayerObj) {
+            (*mediaPlayerObj)->Destroy(mediaPlayerObj);
+            mediaPlayerObj = NULL;
+        }
+        if (outputMixObj) {
+            (*outputMixObj)->Destroy(outputMixObj);
+            outputMixObj = NULL;
+        }
+        if (engineObj){
+            (*engineObj)->Destroy(engineObj);
+            engineObj = NULL;
+        }
+    }
+
+    //---------------------------------------------------------------------------------------------
+    // Tests
+
+    /* Test case for creating an MediaPlayer object */
+    void OutputMixCreation() {
+        res = (*engineItf)->CreateOutputMix(engineItf, &outputMixObj,
+                0, NULL/*iidArray*/, NULL/*required*/);
+        ASSERT_TRUE(IsOk(res));
+        ASSERT_TRUE(NULL != outputMixObj);
+        res = (*outputMixObj)->Realize(outputMixObj, XA_BOOLEAN_FALSE);
+        ASSERT_TRUE(IsOk(res));
+    }
+
+};
+
+//-------------------------------------------------------------------------------------------------
+TEST_F(XAObjectCreationTest, testEngineCreation) {
+    ALOGV("Test Fixture: EngineCreation");
+    // nothing to do here that isn't done in SetUp()
+}
+
+TEST_F(XAObjectCreationTest, testOutputMixCreation) {
+    ALOGV("Test Fixture: OutputMixCreation");
+    OutputMixCreation();
+}
+
+int main(int argc, char **argv) {
+    testing::InitGoogleTest(&argc, argv);
+
+    return RUN_ALL_TESTS();
+}
+
diff --git a/tests/tests/ndef/src/android/ndef/cts/BasicNdefTest.java b/tests/tests/ndef/src/android/ndef/cts/BasicNdefTest.java
index 6e2ac3c..8e10575 100644
--- a/tests/tests/ndef/src/android/ndef/cts/BasicNdefTest.java
+++ b/tests/tests/ndef/src/android/ndef/cts/BasicNdefTest.java
@@ -16,6 +16,7 @@
 
 package android.ndef.cts;
 
+import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
 import android.nfc.FormatException;
@@ -33,6 +34,29 @@
             (byte) 0x6f, (byte) 0x6d
     };
 
+    public static final String URI_WWW_STRING = "http://www.nfc.com";
+    public static final byte[] URI_WWW_BYTES = new byte[] {
+            (byte) 0xd1, (byte) 0x01, (byte) 0x08, (byte) 0x55, (byte) 0x01, (byte) 0x6e,
+            (byte) 0x66, (byte) 0x63, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d
+    };
+
+    public static final String URI_TELEPHONE_NUMBER_STRING = "tel:+35891234567";
+    public static final byte[] URI_TELEPHONE_NUMBER_BYTES = new byte[] {
+            (byte) 0xd1, (byte) 0x01, (byte) 0x0d, (byte) 0x55, (byte) 0x05, (byte) 0x2b,
+            (byte) 0x33, (byte) 0x35, (byte) 0x38, (byte) 0x39, (byte) 0x31, (byte) 0x32,
+            (byte) 0x33, (byte) 0x34, (byte) 0x35, (byte) 0x36, (byte) 0x37
+    };
+
+    public void test_uriParser() {
+        NdefRecord wwwRecord = NdefRecord.createUri(Uri.parse(URI_WWW_STRING));
+        System.out.println(new String(wwwRecord.getPayload()));
+        assertByteArrayEquals(URI_WWW_BYTES, wwwRecord.toByteArray());
+
+        NdefRecord telRecord = NdefRecord.createUri(Uri.parse(URI_TELEPHONE_NUMBER_STRING));
+        System.out.println(new String(telRecord.getPayload()));
+        assertByteArrayEquals(URI_TELEPHONE_NUMBER_BYTES, telRecord.toByteArray());
+    }
+
     public void test_parseSmartPoster() throws FormatException {
         NdefMessage msg = new NdefMessage(SMART_POSTER_URL_NO_TEXT);
         NdefRecord[] records = msg.getRecords();
diff --git a/tests/tests/net/src/android/net/cts/ListeningPortsTest.java b/tests/tests/net/src/android/net/cts/ListeningPortsTest.java
deleted file mode 100644
index bcec0fe..0000000
--- a/tests/tests/net/src/android/net/cts/ListeningPortsTest.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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 android.net.cts;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Scanner;
-import java.util.regex.Pattern;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
-public class ListeningPortsTest extends TestCase {
-
-    /** Address patterns used to check whether we're checking the right column in /proc/net. */
-    private static final List<String> ADDRESS_PATTERNS = new ArrayList<String>(2);
-
-    static {
-        ADDRESS_PATTERNS.add("[0-9A-F]{8}:[0-9A-F]{4}");
-        ADDRESS_PATTERNS.add("[0-9A-F]{32}:[0-9A-F]{4}");
-    }
-
-    /** Ports that are allowed to be listening on the emulator. */
-    private static final List<String> EXCEPTION_PATTERNS = new ArrayList<String>(6);
-
-    static {
-        // IPv4 exceptions
-        EXCEPTION_PATTERNS.add("00000000:15B3"); // 0.0.0.0:5555   - emulator port
-        EXCEPTION_PATTERNS.add("0F02000A:15B3"); // 10.0.2.15:5555 - net forwarding for emulator
-        EXCEPTION_PATTERNS.add("[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4 Loopback
-
-        // IPv6 exceptions
-        EXCEPTION_PATTERNS.add("[0]{25}1[0]{6}:[0-9A-F]{4}"); // IPv6 Loopback
-        EXCEPTION_PATTERNS.add("[0]{16}[0]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion
-        EXCEPTION_PATTERNS.add("[0]{16}[F]{4}[0]{4}[0-9A-F]{6}7F:[0-9A-F]{4}"); // IPv4-6 Conversion
-    }
-
-    public void testNoListeningTcpPorts() {
-        assertNoListeningPorts("/proc/net/tcp", true);
-    }
-
-    public void testNoListeningTcp6Ports() {
-        assertNoListeningPorts("/proc/net/tcp6", true);
-    }
-
-    public void testNoListeningUdpPorts() throws Exception {
-        assertNoListeningUdpPorts("/proc/net/udp");
-    }
-
-    public void testNoListeningUdp6Ports() throws Exception {
-        assertNoListeningUdpPorts("/proc/net/udp6");
-    }
-
-    private static final int RETRIES_MAX = 6;
-
-    /**
-     * UDP tests can be flaky due to DNS lookups.  Compensate.
-     */
-    private static void assertNoListeningUdpPorts(String procFilePath) throws Exception {
-        for (int i = 0; i < RETRIES_MAX; i++) {
-            try {
-                assertNoListeningPorts(procFilePath, false);
-                return;
-            } catch (ListeningPortsAssertionError e) {
-                if (i == RETRIES_MAX - 1) {
-                    throw e;
-                }
-                Thread.sleep(2 * 1000 * i);
-            }
-        }
-        throw new IllegalStateException("unreachable");
-    }
-
-    private static void assertNoListeningPorts(String procFilePath, boolean isTcp) {
-
-        /*
-         * Sample output of "cat /proc/net/tcp" on emulator:
-         *
-         * sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  ...
-         * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0   ...
-         * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0   ...
-         * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000     0   ...
-         *
-         */
-
-        File procFile = new File(procFilePath);
-        Scanner scanner = null;
-        try {
-            scanner = new Scanner(procFile);
-            while (scanner.hasNextLine()) {
-                String line = scanner.nextLine().trim();
-
-                // Skip column headers
-                if (line.startsWith("sl")) {
-                    continue;
-                }
-
-                String[] fields = line.split("\\s+");
-                final int expectedNumColumns = 12;
-                assertTrue(procFilePath + " should have at least " + expectedNumColumns
-                        + " columns of output " + fields, fields.length >= expectedNumColumns);
-
-                String localAddress = fields[1];
-                String state = fields[3];
-                String uid = fields[7];
-
-                assertTrue(procFilePath + " should have an IP address in the second column",
-                        isAddress(localAddress));
-
-                String localIp = localAddress.split(":")[0];
-                int localPort = Integer.parseInt(localAddress.split(":")[1], 16);
-
-                if (!isException(localAddress) && isPortListening(state, isTcp)) {
-                    throw new ListeningPortsAssertionError(
-                            "Found port listening on addr=" + localIp + ", port="
-                                + localPort + ", UID=" + uid + " in " + procFilePath);
-                }
-            }
-        } catch (FileNotFoundException notFound) {
-            fail("Could not open file " + procFilePath + " to check for listening ports.");
-        } finally {
-            if (scanner != null) {
-                scanner.close();
-            }
-        }
-    }
-
-    private static boolean isAddress(String localAddress) {
-        return isPatternMatch(ADDRESS_PATTERNS, localAddress);
-    }
-
-    private static boolean isException(String localAddress) {
-        return isPatternMatch(EXCEPTION_PATTERNS, localAddress);
-    }
-
-    private static boolean isPatternMatch(List<String> patterns, String input) {
-        for (String pattern : patterns) {
-            if (Pattern.matches(pattern, input)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static boolean isPortListening(String state, boolean isTcp) {
-        // 0A = TCP_LISTEN from include/net/tcp_states.h
-        String listeningState = isTcp ? "0A" : "07";
-        return listeningState.equals(state);
-    }
-
-    private static class ListeningPortsAssertionError extends AssertionFailedError {
-        private ListeningPortsAssertionError(String msg) {
-            super(msg);
-        }
-    }
-}
diff --git a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
index 94300b6..f5eca5e 100644
--- a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
+++ b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
@@ -21,9 +21,9 @@
 import dalvik.annotation.TestTargetNew;
 import dalvik.annotation.TestTargets;
 
+import android.cts.util.PollingCheck;
 import android.os.AsyncTask;
 import android.test.InstrumentationTestCase;
-import android.view.animation.cts.DelayedCheck;
 
 import java.util.concurrent.TimeUnit;
 
@@ -108,7 +108,7 @@
         }
 
         // wait for the task to finish completely (including onPostResult()).
-        new DelayedCheck(DURATION) {
+        new PollingCheck(DURATION) {
             protected boolean check() {
                 return mAsyncTask.getStatus() == AsyncTask.Status.FINISHED;
             }
@@ -132,7 +132,7 @@
         }
 
         // wait for progress update to be processed (happens asynchronously)
-        new DelayedCheck(DURATION) {
+        new PollingCheck(DURATION) {
             protected boolean check() {
                 return mAsyncTask.updateValue != null;
             }
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index c222e7b..317ed83 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -170,9 +170,14 @@
 
     /**
      * Verify that any publicly readable directories reachable from
-     * the root directory are not writable.  World writable directories
-     * are a security hole and an application should only be able to
-     * write to it's own home directory.
+     * the root directory are not writable.  An application should only be
+     * able to write to it's own home directory. World writable directories
+     * are a security hole because they enable a number of different attacks.
+     * <ul>
+     *   <li><a href="http://en.wikipedia.org/wiki/Symlink_race">Symlink Races</a></li>
+     *   <li>Data destruction by deleting or renaming files you don't own</li>
+     *   <li>Data substitution by replacing trusted files with untrusted files</li>
+     * </ul>
      *
      * Note: Because not all directories are readable, this is a best-effort
      * test only.  Writable directories within unreadable subdirectories
@@ -195,6 +200,7 @@
                     "/data/btips/TI",
                     "/data/btips/TI/opp",
                     "/data/dalvik-cache",
+                    "/data/data",
                     "/data/data/.drm",
                     "/data/data/.drm/.wmdrm",
                     "/data/dontpanic",
@@ -228,9 +234,15 @@
 
     /**
      * Verify that directories not discoverable by
-     * testAllOtherDirectoriesNotWritable are not writable.  World
-     * writable directories are a security hole and an application
-     * should only be able to write to it's own home directory.
+     * testAllOtherDirectoriesNotWritable are not writable.  An application
+     * should only be able to write to it's own home directory. World
+     * writable directories are a security hole because they enable a
+     * number of different attacks.
+     * <ul>
+     *   <li><a href="http://en.wikipedia.org/wiki/Symlink_race">Symlink Races</a></li>
+     *   <li>Data destruction by deleting or renaming files you don't own</li>
+     *   <li>Data substitution by replacing trusted files with untrusted files</li>
+     * </ul>
      *
      * Because /data and /data/data are not readable, we blindly try to
      * poke around in there looking for bad directories.  There has to be
diff --git a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
index 1395de1..13ef4c8 100644
--- a/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
+++ b/tests/tests/provider/src/android/provider/cts/SearchRecentSuggestionsTest.java
@@ -24,11 +24,11 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.SearchRecentSuggestions;
 import android.test.ProviderTestCase2;
-import android.view.animation.cts.DelayedCheck;
 
 @TestTargetClass(android.provider.SearchRecentSuggestions.class)
 public class SearchRecentSuggestionsTest extends
@@ -227,7 +227,7 @@
 
     private void waitForCursorCount(final Uri uri, final String[] projection,
             final int expectedCount) {
-        new DelayedCheck() {
+        new PollingCheck() {
             protected boolean check() {
                 Cursor cursor = null;
                 try {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ForEachTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ForEachTest.java
index 12c8fb0..a64d1d9 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ForEachTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ForEachTest.java
@@ -67,8 +67,10 @@
         t = new Type.Builder(mRS, Element.U8(mRS)).setX(x).create();
         Allocation out = Allocation.createTyped(mRS, t);
         fe_i8.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -82,8 +84,10 @@
         t = new Type.Builder(mRS, Element.U8_2(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -97,8 +101,10 @@
         t = new Type.Builder(mRS, Element.U8_3(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -112,8 +118,10 @@
         t = new Type.Builder(mRS, Element.U8_4(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -125,8 +133,10 @@
         t = new Type.Builder(mRS, Element.U16(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i16.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i16.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -140,8 +150,10 @@
         t = new Type.Builder(mRS, Element.U16_2(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i16_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i16_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -155,8 +167,10 @@
         t = new Type.Builder(mRS, Element.U16_3(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i16_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i16_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -170,8 +184,10 @@
         t = new Type.Builder(mRS, Element.U16_4(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i16_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i16_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -183,8 +199,10 @@
         t = new Type.Builder(mRS, Element.U32(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i32.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i32.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -198,8 +216,10 @@
         t = new Type.Builder(mRS, Element.U32_2(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i32_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i32_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -213,8 +233,10 @@
         t = new Type.Builder(mRS, Element.U32_3(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i32_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i32_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -228,8 +250,10 @@
         t = new Type.Builder(mRS, Element.U32_4(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i32_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i32_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -241,8 +265,10 @@
         t = new Type.Builder(mRS, Element.U64(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i64.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i64.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -256,8 +282,10 @@
         t = new Type.Builder(mRS, Element.U64_2(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i64_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i64_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -271,8 +299,10 @@
         t = new Type.Builder(mRS, Element.U64_3(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i64_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i64_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -286,8 +316,10 @@
         t = new Type.Builder(mRS, Element.U64_4(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i64_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i64_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -298,8 +330,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f32.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f32.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -313,8 +347,10 @@
         t = new Type.Builder(mRS, Element.F32_2(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_f32_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f32_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -327,8 +363,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f32_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f32_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -341,8 +379,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f32_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f32_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -353,8 +393,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f64.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f64.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -367,8 +409,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f64_2.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f64_2.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -381,8 +425,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f64_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f64_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -395,8 +441,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_f64_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_f64_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -408,8 +456,10 @@
         in = new ScriptField_fe_test(mRS, x).getAllocation();
         out = new ScriptField_fe_test(mRS, x).getAllocation();
         fe_struct.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_struct.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -420,8 +470,10 @@
         in = Allocation.createTyped(mRS, t);
         out = Allocation.createTyped(mRS, t);
         fe_bool.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_bool.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -432,8 +484,10 @@
         t = new Type.Builder(mRS, Element.A_8(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -444,8 +498,10 @@
         t = new Type.Builder(mRS, Element.RGBA_8888(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8_4.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8_4.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
@@ -456,8 +512,10 @@
         t = new Type.Builder(mRS, Element.RGB_888(mRS)).setX(x).create();
         out = Allocation.createTyped(mRS, t);
         fe_i8_3.forEach_root(in, out);
+        mRS.finish();
         try {
             fe_i8_3.forEach_root(in, badOut);
+            mRS.finish();
             fail("should throw RSRuntimeException");
         } catch (RSRuntimeException e) {
         }
diff --git a/tests/tests/security/src/android/security/cts/AslrTest.java b/tests/tests/security/src/android/security/cts/AslrTest.java
new file mode 100644
index 0000000..a4c4f80
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/AslrTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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 android.security.cts;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Verify that ASLR is properly enabled on Android Compatible devices.
+ */
+public class AslrTest extends TestCase {
+
+    public void testOneExecutableIsPie() throws IOException {
+        assertTrue(ReadElf.read(new File("/system/bin/cat")).isPIE());
+    }
+
+    public void testVaRandomize() throws IOException {
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader("/proc/sys/kernel/randomize_va_space"));
+            int level = Integer.parseInt(in.readLine().trim());
+            assertTrue("Expected /proc/sys/kernel/randomize_va_space to be "
+                    + "greater than or equal to 2, got " + level,
+                    level >= 2);
+        } catch (FileNotFoundException e) {
+            // Odd. The file doesn't exist... Assume ASLR is enabled.
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+
+}
diff --git a/tests/tests/security/src/android/security/cts/KernelSettingsTest.java b/tests/tests/security/src/android/security/cts/KernelSettingsTest.java
new file mode 100644
index 0000000..17ec7b5
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/KernelSettingsTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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 android.security.cts;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+
+/**
+ * Verify that the kernel is configured how we expect it to be
+ * configured.
+ */
+public class KernelSettingsTest extends TestCase {
+
+    /**
+     * /proc/kallsyms will show the address of exported kernel symbols. This
+     * information can be used to write a reliable kernel exploit that can run
+     * on many platforms without using hardcoded pointers. To make this more
+     * difficult for attackers, don't export kernel symbols.
+     */
+    public void testKptrRestrict() throws IOException {
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new FileReader("/proc/sys/kernel/kptr_restrict"));
+            assertEquals("2", in.readLine().trim());
+        } catch (FileNotFoundException e) {
+            // Odd. The file doesn't exist... Assume we're ok.
+        } finally {
+            if (in != null) {
+                in.close();
+            }
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/ListeningPortsTest.java b/tests/tests/security/src/android/security/cts/ListeningPortsTest.java
new file mode 100644
index 0000000..f3112a3
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/ListeningPortsTest.java
@@ -0,0 +1,309 @@
+/*
+ * 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 android.security.cts;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+import java.util.regex.Pattern;
+
+/**
+ * Verifies that Android devices are not listening on accessible
+ * open ports. Open ports are often targeted by attackers looking to break
+ * into computer systems remotely, and minimizing the number of open ports
+ * is considered a security best practice.
+ */
+public class ListeningPortsTest extends TestCase {
+
+    /** Ports that are allowed to be listening. */
+    private static final List<String> EXCEPTION_PATTERNS = new ArrayList<String>(6);
+
+    static {
+        // IPv4 exceptions
+        EXCEPTION_PATTERNS.add("0.0.0.0:5555");   // emulator port
+        EXCEPTION_PATTERNS.add("10.0.2.15:5555"); // net forwarding for emulator
+        EXCEPTION_PATTERNS.add("127.0.0.1:5037"); // adb daemon "smart sockets"
+    }
+
+    /**
+     * Remotely accessible ports are often used by attackers to gain
+     * unauthorized access to computers systems without user knowledge or
+     * awareness.
+     */
+    public void testNoRemotelyAccessibleListeningTcpPorts() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/tcp", true, false);
+    }
+
+    /**
+     * Remotely accessible ports are often used by attackers to gain
+     * unauthorized access to computers systems without user knowledge or
+     * awareness.
+     */
+    public void testNoRemotelyAccessibleListeningTcp6Ports() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/tcp6", true, false);
+    }
+
+    /**
+     * Remotely accessible ports are often used by attackers to gain
+     * unauthorized access to computers systems without user knowledge or
+     * awareness.
+     */
+    public void testNoRemotelyAccessibleListeningUdpPorts() throws Exception {
+        assertNoRemotelyAccessibleListeningUdpPorts("/proc/net/udp", false);
+    }
+
+    /**
+     * Remotely accessible ports are often used by attackers to gain
+     * unauthorized access to computers systems without user knowledge or
+     * awareness.
+     */
+    public void testNoRemotelyAccessibleListeningUdp6Ports() throws Exception {
+        assertNoRemotelyAccessibleListeningUdpPorts("/proc/net/udp6", false);
+    }
+
+    /**
+     * Locally accessible ports are often targeted by malicious locally
+     * installed programs to gain unauthorized access to program data or
+     * cause system corruption.
+     *
+     * In all cases, a local listening IP port can be replaced by a UNIX domain
+     * socket. Unix domain sockets can be protected with unix filesystem
+     * permission. Alternatively, you can use getsockopt(SO_PEERCRED) to
+     * determine if a program is authorized to connect to your socket.
+     *
+     * Please convert loopback IP connections to unix domain sockets.
+     */
+    public void testNoListeningLoopbackTcpPorts() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/tcp", true, true);
+    }
+
+    /**
+     * Locally accessible ports are often targeted by malicious locally
+     * installed programs to gain unauthorized access to program data or
+     * cause system corruption.
+     *
+     * In all cases, a local listening IP port can be replaced by a UNIX domain
+     * socket. Unix domain sockets can be protected with unix filesystem
+     * permission. Alternatively, you can use getsockopt(SO_PEERCRED) to
+     * determine if a program is authorized to connect to your socket.
+     *
+     * Please convert loopback IP connections to unix domain sockets.
+     */
+    public void testNoListeningLoopbackTcp6Ports() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/tcp6", true, true);
+    }
+
+    /**
+     * Locally accessible ports are often targeted by malicious locally
+     * installed programs to gain unauthorized access to program data or
+     * cause system corruption.
+     *
+     * In all cases, a local listening IP port can be replaced by a UNIX domain
+     * socket. Unix domain sockets can be protected with unix filesystem
+     * permission.  Alternately, or you can use setsockopt(SO_PASSCRED) to
+     * send credentials, and recvmsg to retrieve the passed credentials.
+     *
+     * Please convert loopback IP connections to unix domain sockets.
+     */
+    public void testNoListeningLoopbackUdpPorts() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/udp", false, true);
+    }
+
+    /**
+     * Locally accessible ports are often targeted by malicious locally
+     * installed programs to gain unauthorized access to program data or
+     * cause system corruption.
+     *
+     * In all cases, a local listening IP port can be replaced by a UNIX domain
+     * socket. Unix domain sockets can be protected with unix filesystem
+     * permission.  Alternately, or you can use setsockopt(SO_PASSCRED) to
+     * send credentials, and recvmsg to retrieve the passed credentials.
+     *
+     * Please convert loopback IP connections to unix domain sockets.
+     */
+    public void testNoListeningLoopbackUdp6Ports() throws Exception {
+        assertNoAccessibleListeningPorts("/proc/net/udp6", false, true);
+    }
+
+    private static final int RETRIES_MAX = 6;
+
+    /**
+     * UDP tests can be flaky due to DNS lookups.  Compensate.
+     */
+    private static void assertNoRemotelyAccessibleListeningUdpPorts(
+            String procFilePath, boolean loopback)
+            throws Exception {
+        for (int i = 0; i < RETRIES_MAX; i++) {
+            try {
+                assertNoAccessibleListeningPorts(procFilePath, false, loopback);
+                return;
+            } catch (ListeningPortsAssertionError e) {
+                if (i == RETRIES_MAX - 1) {
+                    throw e;
+                }
+                Thread.sleep(2 * 1000 * i);
+            }
+        }
+        throw new IllegalStateException("unreachable");
+    }
+
+    /**
+     * Remotely accessible ports (loopback==false) are often used by
+     * attackers to gain unauthorized access to computers systems without
+     * user knowledge or awareness.
+     *
+     * Locally accessible ports (loopback==true) are often targeted by
+     * malicious locally installed programs to gain unauthorized access to
+     * program data or cause system corruption.
+     */
+    private static void assertNoAccessibleListeningPorts(
+            String procFilePath, boolean isTcp, boolean loopback) throws IOException {
+        String errors = "";
+        List<ParsedProcEntry> entries = ParsedProcEntry.parse(procFilePath);
+        for (ParsedProcEntry entry : entries) {
+            String addrPort = entry.localAddress.getHostAddress() + ':' + entry.port;
+
+            if (isPortListening(entry.state, isTcp)
+                && !isException(addrPort)
+                && (!entry.localAddress.isLoopbackAddress() ^ loopback)) {
+                errors += "\nFound port listening on addr="
+                        + entry.localAddress.getHostAddress() + ", port="
+                        + entry.port + ", UID=" + entry.uid + " in "
+                        + procFilePath;
+            }
+        }
+        if (!errors.equals("")) {
+            fail(errors);
+        }
+    }
+
+    private static boolean isException(String localAddress) {
+        return isPatternMatch(EXCEPTION_PATTERNS, localAddress);
+    }
+
+    private static boolean isPatternMatch(List<String> patterns, String input) {
+        for (String pattern : patterns) {
+            pattern = Pattern.quote(pattern);
+            if (Pattern.matches(pattern, input)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean isPortListening(String state, boolean isTcp) {
+        // 0A = TCP_LISTEN from include/net/tcp_states.h
+        String listeningState = isTcp ? "0A" : "07";
+        return listeningState.equals(state);
+    }
+
+    private static class ListeningPortsAssertionError extends AssertionFailedError {
+        private ListeningPortsAssertionError(String msg) {
+            super(msg);
+        }
+    }
+
+    private static class ParsedProcEntry {
+        private final InetAddress localAddress;
+        private final int port;
+        private final String state;
+        private final int uid;
+
+        private ParsedProcEntry(InetAddress addr, int port, String state, int uid) {
+            this.localAddress = addr;
+            this.port = port;
+            this.state = state;
+            this.uid = uid;
+        }
+
+
+        private static List<ParsedProcEntry> parse(String procFilePath) throws IOException {
+
+            List<ParsedProcEntry> retval = new ArrayList<ParsedProcEntry>();
+            /*
+            * Sample output of "cat /proc/net/tcp" on emulator:
+            *
+            * sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  ...
+            * 0: 0100007F:13AD 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0   ...
+            * 1: 00000000:15B3 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0   ...
+            * 2: 0F02000A:15B3 0202000A:CE8A 01 00000000:00000000 00:00000000 00000000     0   ...
+            *
+            */
+
+            File procFile = new File(procFilePath);
+            Scanner scanner = null;
+            try {
+                scanner = new Scanner(procFile);
+                while (scanner.hasNextLine()) {
+                    String line = scanner.nextLine().trim();
+
+                    // Skip column headers
+                    if (line.startsWith("sl")) {
+                        continue;
+                    }
+
+                    String[] fields = line.split("\\s+");
+                    final int expectedNumColumns = 12;
+                    assertTrue(procFilePath + " should have at least " + expectedNumColumns
+                            + " columns of output " + fields, fields.length >= expectedNumColumns);
+
+                    String state = fields[3];
+                    int uid = Integer.parseInt(fields[7]);
+                    InetAddress localIp = addrToInet(fields[1].split(":")[0]);
+                    int localPort = Integer.parseInt(fields[1].split(":")[1], 16);
+
+                    retval.add(new ParsedProcEntry(localIp, localPort, state, uid));
+                }
+            } finally {
+                if (scanner != null) {
+                    scanner.close();
+                }
+            }
+            return retval;
+        }
+
+        /**
+         * Convert a string stored in little endian format to an IP address.
+         */
+        private static InetAddress addrToInet(String s) throws UnknownHostException {
+            int len = s.length();
+            if (len != 8 && len != 32) {
+                throw new IllegalArgumentException(len + "");
+            }
+            byte[] retval = new byte[len / 2];
+
+            for (int i = 0; i < len / 2; i += 4) {
+                retval[i] = (byte) ((Character.digit(s.charAt(2*i + 6), 16) << 4)
+                        + Character.digit(s.charAt(2*i + 7), 16));
+                retval[i + 1] = (byte) ((Character.digit(s.charAt(2*i + 4), 16) << 4)
+                        + Character.digit(s.charAt(2*i + 5), 16));
+                retval[i + 2] = (byte) ((Character.digit(s.charAt(2*i + 2), 16) << 4)
+                        + Character.digit(s.charAt(2*i + 3), 16));
+                retval[i + 3] = (byte) ((Character.digit(s.charAt(2*i), 16) << 4)
+                        + Character.digit(s.charAt(2*i + 1), 16));
+            }
+            return InetAddress.getByAddress(retval);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/ReadElf.java b/tests/tests/security/src/android/security/cts/ReadElf.java
new file mode 100644
index 0000000..e311c9b
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/ReadElf.java
@@ -0,0 +1,257 @@
+/*
+ * 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 android.security.cts;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * A poor man's implementation of the readelf command. This program is
+ * designed to parse ELF (Executable and Linkable Format) files.
+ */
+class ReadElf {
+    /** The magic values for the ELF identification. */
+    private static final byte[] ELF_IDENT = {
+            (byte) 0x7F, (byte) 'E', (byte) 'L', (byte) 'F',
+    };
+
+    /** Size of the e_ident[] structure in the ELF header. */
+    private static final int EI_NIDENT = 16;
+
+    /** Offset from end of ident structure in half-word sizes. */
+    private static final int OFFSET_TYPE = 0;
+
+    /** Machine type. */
+    private static final int OFFSET_MACHINE = 1;
+
+    /** ELF version. */
+    private static final int OFFSET_VERSION = 2;
+
+    /**
+     * The offset to which the system transfers control. e.g., the first thing
+     * executed.
+     */
+    private static final int OFFSET_ENTRY = 4;
+
+    /** Program header offset in bytes. */
+    private static final int OFFSET_PHOFF = 6;
+
+    /** Segment header offset in bytes. */
+    private static final int OFFSET_SHOFF = 8;
+
+    /** Processor-specific flags for binary. */
+    private static final int OFFSET_FLAGS = 10;
+
+    /** ELF header size in bytes. */
+    private static final int OFFSET_EHSIZE = 12;
+
+    /** All program headers entry size in bytes. */
+    private static final int OFFSET_PHENTSIZE = 13;
+
+    /** Number of program headers in ELF. */
+    private static final int OFFSET_PHNUM = 14;
+
+    /** All segment headers entry size in bytes. */
+    private static final int OFFSET_SHENTSIZE = 15;
+
+    /** Number of segment headers in ELF. */
+    private static final int OFFSET_SHNUM = 16;
+
+    /** The section header index that refers to string table. */
+    private static final int OFFSET_SHTRNDX = 17;
+
+    /** Program header offset for type of this program header. */
+    private static final int PHOFF_TYPE = 0;
+
+    /** Program header offset for absolute offset in file. */
+    private static final int PHOFF_OFFSET = 2;
+
+    /** Program header offset for virtual address. */
+    private static final int PHOFF_VADDR = 4;
+
+    /** Program header offset for physical address. */
+    private static final int PHOFF_PADDR = 6;
+
+    /** Program header offset for file size in bytes. */
+    private static final int PHOFF_FILESZ = 8;
+
+    /** Program header offset for memory size in bytes. */
+    private static final int PHOFF_MEMSZ = 10;
+
+    /** Program header offset for flags. */
+    private static final int PHOFF_FLAGS = 12;
+
+    /**
+     * Program header offset for required alignment. 0 or 1 means no alignment
+     * necessary.
+     */
+    private static final int PHOFF_ALIGN = 14;
+
+    /** Index into string pool for segment name. */
+    private static final int SHOFF_NAME = 0;
+
+    /** Segment header type. */
+    private static final int SHOFF_TYPE = 2;
+
+    /** Data is presented in LSB format. */
+    private static final int ELFDATA2LSB = 1;
+
+    /** Date is presented in MSB format. */
+    private static final int ELFDATA2MSB = 2;
+
+    private static final int ELFCLASS32 = 1;
+
+    private static final int ELFCLASS64 = 2;
+
+    private static final long PT_LOAD = 1;
+
+    private RandomAccessFile mFile = null;
+    private final byte[] mBuffer = new byte[512];
+    private int mClass;
+    private int mEndian;
+    private boolean mIsDynamic;
+    private boolean mIsPIE;
+    private int mType;
+    private int mWordSize;
+    private int mHalfWordSize;
+
+    static ReadElf read(File file) throws IOException {
+        return new ReadElf(file);
+    }
+
+    boolean isDynamic() {
+        return mIsDynamic;
+    }
+
+    int getType() {
+        return mType;
+    }
+
+    boolean isPIE() {
+        return mIsPIE;
+    }
+
+    private ReadElf(File file) throws IOException {
+        try {
+            mFile = new RandomAccessFile(file, "r");
+
+            readIdent();
+
+            readHeader();
+        } finally {
+            if (mFile != null) {
+                mFile.close();
+            }
+        }
+    }
+
+    private void readHeader() throws IOException {
+        mType = readHalf(getHeaderOffset(OFFSET_TYPE));
+
+        final long shOffset = readWord(getHeaderOffset(OFFSET_SHOFF));
+        final int shNumber = readHalf(getHeaderOffset(OFFSET_SHNUM));
+        final int shSize = readHalf(getHeaderOffset(OFFSET_SHENTSIZE));
+
+        readSectionHeaders(shOffset, shNumber, shSize);
+
+        final long phOffset = readWord(getHeaderOffset(OFFSET_PHOFF));
+        final int phNumber = readHalf(getHeaderOffset(OFFSET_PHNUM));
+        final int phSize = readHalf(getHeaderOffset(OFFSET_PHENTSIZE));
+
+        readProgramHeaders(phOffset, phNumber, phSize);
+    }
+
+    private void readSectionHeaders(long shOffset, int shNumber, int shSize) throws IOException {
+        for (int i = 0; i < shNumber; i++) {
+            final long type = readWord(shOffset + i * shSize + mHalfWordSize * SHOFF_TYPE);
+            if (type == 6) {
+                mIsDynamic = true;
+            }
+        }
+    }
+
+    private void readProgramHeaders(long phOffset, int phNumber, int phSize) throws IOException {
+        for (int i = 0; i < phNumber; i++) {
+            final long baseOffset = phOffset + i * phSize;
+            final long type = readWord(baseOffset);
+            if (type == PT_LOAD) {
+                final long virtAddress = readWord(baseOffset + mHalfWordSize * PHOFF_VADDR);
+                if (virtAddress == 0) {
+                    mIsPIE = true;
+                }
+            }
+        }
+    }
+
+    private int getHeaderOffset(int halfWorldOffset) {
+        return EI_NIDENT + halfWorldOffset * mHalfWordSize;
+    }
+
+    private int readHalf(long offset) throws IOException {
+        mFile.seek(offset);
+        mFile.readFully(mBuffer, 0, mWordSize);
+
+        final int answer;
+        if (mEndian == ELFDATA2LSB) {
+            answer = mBuffer[1] << 8 | mBuffer[0];
+        } else {
+            answer = mBuffer[0] << 8 | mBuffer[1];
+        }
+
+        return answer;
+    }
+
+    private long readWord(long offset) throws IOException {
+        mFile.seek(offset);
+        mFile.readFully(mBuffer, 0, mWordSize);
+
+        int answer = 0;
+        if (mEndian == ELFDATA2LSB) {
+            for (int i = mWordSize - 1; i >= 0; i--) {
+                answer = (answer << 8) | (mBuffer[i] & 0xFF);
+            }
+        } else {
+            final int N = mWordSize - 1;
+            for (int i = 0; i <= N; i++) {
+                answer = (answer << 8) | mBuffer[i];
+            }
+        }
+
+        return answer;
+    }
+
+    private void readIdent() throws IOException {
+        mFile.seek(0);
+        mFile.readFully(mBuffer, 0, EI_NIDENT);
+
+        if (mBuffer[0] != ELF_IDENT[0] || mBuffer[1] != ELF_IDENT[1] || mBuffer[2] != ELF_IDENT[2]
+                || mBuffer[3] != ELF_IDENT[3]) {
+            throw new IllegalArgumentException("Invalid ELF file");
+        }
+
+        mClass = mBuffer[4];
+        if (mClass == ELFCLASS32) {
+            mWordSize = 4;
+            mHalfWordSize = 2;
+        } else {
+            throw new IOException("Invalid executable type " + mClass + ": not ELFCLASS32!");
+        }
+
+        mEndian = mBuffer[5];
+    }
+}
diff --git a/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java b/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
index 1c45735..23891e0 100644
--- a/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/PhoneNumberUtilsTest.java
@@ -455,11 +455,6 @@
 
         // Test isWellFormedSmsAddress
         assertTrue(PhoneNumberUtils.isWellFormedSmsAddress("+17005554141"));
-        // KT allow a to be a dialable character, the network portion of 'android' is 'a'
-        if (TelephonyUtils.isKt(tm)) {
-            assertTrue(PhoneNumberUtils.isWellFormedSmsAddress("android"));
-        } else {
-            assertFalse(PhoneNumberUtils.isWellFormedSmsAddress("android"));
-        }
+        assertFalse(PhoneNumberUtils.isWellFormedSmsAddress("android"));
     }
 }
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
index c0c26ef..ddce3cd 100755
--- a/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsManagerTest.java
@@ -27,12 +27,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.os.Bundle;
 import android.os.SystemClock;
 import android.telephony.SmsManager;
-import android.telephony.SmsMessage;
 import android.telephony.TelephonyManager;
 import android.test.AndroidTestCase;
+import android.telephony.SmsMessage;
+import android.os.Bundle;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -46,6 +46,7 @@
 @TestTargetClass(SmsManager.class)
 public class SmsManagerTest extends AndroidTestCase {
 
+    private static final int NUM_TEXT_PARTS = 3;
     private static final String LONG_TEXT =
         "This is a very long text. This text should be broken into three " +
         "separate messages.This is a very long text. This text should be broken into " +
@@ -156,21 +157,9 @@
     public void testDivideMessage() {
         ArrayList<String> dividedMessages = divideMessage(LONG_TEXT);
         assertNotNull(dividedMessages);
-        int numParts;
-        if (TelephonyUtils.isSkt(mTelephonyManager)) {
-            numParts = 5;
-        } else if (TelephonyUtils.isKt(mTelephonyManager)) {
-            numParts = 4;
-        } else {
-            numParts = 3;
-        }
-        assertEquals(numParts, dividedMessages.size());
-
-        String actualMessage = "";
-        for (int i = 0; i < numParts; i++) {
-            actualMessage += dividedMessages.get(i);
-        }
-        assertEquals(LONG_TEXT, actualMessage);
+        assertEquals(NUM_TEXT_PARTS, dividedMessages.size());
+        assertEquals(LONG_TEXT,
+                dividedMessages.get(0) + dividedMessages.get(1) + dividedMessages.get(2));
     }
 
     @TestTargets({
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
index 27f290b..8c6ad01 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
@@ -188,7 +188,7 @@
         int[] result = SmsMessage.calculateLength(sms.getMessageBody(), true);
         assertEquals(SMS_NUMBER1, result[0]);
         assertEquals(sms.getMessageBody().length(), result[1]);
-        assertEquals(getNumSeptets() - sms.getMessageBody().length(), result[2]);
+        assertEquals(SmsMessage.MAX_USER_DATA_SEPTETS - sms.getMessageBody().length(), result[2]);
         assertEquals(SmsMessage.ENCODING_7BIT, result[3]);
         assertEquals(pdu, toHexString(sms.getPdu()));
 
@@ -220,7 +220,7 @@
         result = SmsMessage.calculateLength(msgBody, false);
         assertEquals(SMS_NUMBER2, result[0]);
         assertEquals(sms.getMessageBody().length(), result[1]);
-        assertEquals(getNumSeptets() - sms.getMessageBody().length(), result[2]);
+        assertEquals(SmsMessage.MAX_USER_DATA_SEPTETS - sms.getMessageBody().length(), result[2]);
         assertEquals(SmsMessage.ENCODING_7BIT, result[3]);
 
         // Test createFromPdu Ucs to Sms
@@ -231,20 +231,10 @@
         result = SmsMessage.calculateLength(sms.getMessageBody(), true);
         assertEquals(SMS_NUMBER3, result[0]);
         assertEquals(sms.getMessageBody().length(), result[1]);
-        assertEquals(getNumSeptets() - sms.getMessageBody().length(), result[2]);
+        assertEquals(SmsMessage.MAX_USER_DATA_SEPTETS - sms.getMessageBody().length(), result[2]);
         assertEquals(SmsMessage.ENCODING_7BIT, result[3]);
     }
 
-    private int getNumSeptets() {
-        if (TelephonyUtils.isSkt(mTelephonyManager)) {
-            return 80;
-        } else if (TelephonyUtils.isKt(mTelephonyManager)) {
-            return 90;
-        } else {
-            return SmsMessage.MAX_USER_DATA_SEPTETS;
-        }
-    }
-
     @TestTargets({
         @TestTargetNew(
             level = TestLevel.COMPLETE,
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyUtils.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyUtils.java
deleted file mode 100644
index c2ca833..0000000
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyUtils.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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 android.telephony.cts;
-
-import android.telephony.TelephonyManager;
-
-class TelephonyUtils {
-
-    public static boolean isSkt(TelephonyManager telephonyManager) {
-        return isOperator(telephonyManager, "45005");
-    }
-
-    public static boolean isKt(TelephonyManager telephonyManager) {
-        return isOperator(telephonyManager, "45002")
-                || isOperator(telephonyManager, "45004")
-                || isOperator(telephonyManager, "45008");
-    }
-
-    private static boolean isOperator(TelephonyManager telephonyManager, String operator) {
-        String simOperator = telephonyManager.getSimOperator();
-        return simOperator != null && simOperator.equals(operator);
-    }
-
-    private TelephonyUtils() {
-    }
-}
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index 6dde08d..087b930 100755
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -22,6 +22,7 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.graphics.Rect;
 import android.provider.Settings.SettingNotFoundException;
 import android.provider.Settings.System;
@@ -30,7 +31,6 @@
 import android.text.method.PasswordTransformationMethod;
 import android.view.KeyCharacterMap;
 import android.view.View;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.LinearLayout;
@@ -175,7 +175,7 @@
         assertTrue(mMethod.hasCalledAfterTextChanged());
 
         // it will get transformed after a while
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 // "******"
diff --git a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
index 6343da6..447ec84 100644
--- a/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
+++ b/tests/tests/view/src/android/view/animation/cts/AnimationTest.java
@@ -26,6 +26,7 @@
 
 import android.app.Activity;
 import android.content.res.XmlResourceParser;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.AttributeSet;
 import android.util.Xml;
@@ -355,7 +356,7 @@
         // test repeat mode REVERSE
         anim.setRepeatCount(1);
         anim.setRepeatMode(Animation.REVERSE);
-        // we have to DelayedCheck the animation status on test thread,
+        // we have to PollingCheck the animation status on test thread,
         // it cannot be done on UI thread, so we invoke runOnMainSync method here.
         getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
@@ -364,7 +365,7 @@
         });
 
         // check whether animation has started
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return anim.hasStarted();
@@ -386,7 +387,7 @@
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new DelayedCheck(duration * 2 + 1000) {
+        new PollingCheck(duration * 2 + 1000) {
             @Override
             protected boolean check() {
                 return anim.hasEnded();
@@ -414,7 +415,7 @@
 
         // test repeat mode RESTART
         anim.setRepeatMode(Animation.RESTART);
-        // we have to DelayedCheck the animation status on test thread,
+        // we have to PollingCheck the animation status on test thread,
         // it cannot be done on UI thread, so we invoke runOnMainSync method here.
         getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
@@ -423,7 +424,7 @@
         });
 
         // check whether animation has started
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return anim.hasStarted();
@@ -445,7 +446,7 @@
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new DelayedCheck(duration * 2 + 1000) {
+        new PollingCheck(duration * 2 + 1000) {
             @Override
             protected boolean check() {
                 return anim.hasEnded();
@@ -627,7 +628,7 @@
         final Animation anim = AnimationUtils.loadAnimation(mActivity, R.anim.accelerate_alpha);
         assertFalse(anim.hasStarted());
 
-        // we have to DelayedCheck the animation status on test thread,
+        // we have to PollingCheck the animation status on test thread,
         // it cannot be done on UI thread, so we invoke runOnMainSync method here.
         getInstrumentation().runOnMainSync(new Runnable() {
             public void run() {
@@ -636,7 +637,7 @@
         });
 
         // check whether animation has started
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return anim.hasStarted();
@@ -662,7 +663,7 @@
 
         // wait for animation has ended.
         // timeout is larger than duration, in case the system is sluggish
-        new DelayedCheck(2000) {
+        new PollingCheck(2000) {
             @Override
             protected boolean check() {
                 return anim.hasEnded();
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index be60976..aee9075 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -69,7 +70,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
-import android.view.animation.cts.DelayedCheck;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
@@ -287,7 +287,7 @@
         assertTrue(view.hasCalledOnAnimationStart());
 
         // check whether it has ended after duration, and alpha changed during this time.
-        new DelayedCheck(duration + TIMEOUT_DELTA) {
+        new PollingCheck(duration + TIMEOUT_DELTA) {
             @Override
             protected boolean check() {
                 return view.hasCalledOnSetAlpha() && view.hasCalledOnAnimationEnd();
@@ -2257,7 +2257,7 @@
         // mAttachInfo is not null
         final View view2 = mActivity.findViewById(R.id.fit_windows);
         // Wait until the window has been focused.
-        new DelayedCheck(TIMEOUT_DELTA) {
+        new PollingCheck(TIMEOUT_DELTA) {
             @Override
             protected boolean check() {
                 return view2.hasWindowFocus();
@@ -4429,7 +4429,7 @@
         viewGroup.addView(editText);
         editText.requestFocus();
 
-        new DelayedCheck(TIMEOUT_DELTA) {
+        new PollingCheck(TIMEOUT_DELTA) {
             @Override
             protected boolean check() {
                 return editText.isFocused();
diff --git a/tests/tests/view/src/android/view/cts/View_AnimationTest.java b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
index 144e670..d2085c6 100644
--- a/tests/tests/view/src/android/view/cts/View_AnimationTest.java
+++ b/tests/tests/view/src/android/view/cts/View_AnimationTest.java
@@ -17,12 +17,12 @@
 package android.view.cts;
 
 import android.app.Activity;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.View;
 import android.view.animation.Animation;
 import android.view.animation.TranslateAnimation;
 import android.view.animation.cts.AnimationTestUtils;
-import android.view.animation.cts.DelayedCheck;
 
 import com.android.cts.stub.R;
 
@@ -155,7 +155,7 @@
             }
         });
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mAnimation.hasStarted();
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
index 2cf6b58..1556cc3 100755
--- a/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/BaseInputConnectionTest.java
@@ -25,6 +25,7 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.os.Bundle;
 import android.test.ActivityInstrumentationTestCase2;
 import android.text.Editable;
@@ -35,7 +36,6 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.Window;
-import android.view.animation.cts.DelayedCheck;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedTextRequest;
@@ -260,7 +260,7 @@
         // dummy mode
         BaseInputConnection dummyConnection = new BaseInputConnection(mView, false);
         dummyConnection.commitText(inputText, inputText.length());
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return text2.toString().equals(mView.getText().toString());
@@ -323,7 +323,7 @@
         BaseInputConnection dummyConnection = new BaseInputConnection(mView, false);
         dummyConnection.setComposingText(str, str.length());
         dummyConnection.finishComposingText();
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return text.toString().equals(mView.getText().toString());
@@ -359,7 +359,7 @@
             mInstrumentation.sendStringSync("q");
             mInstrumentation.waitForIdleSync();
         }
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return "q".equals(mView.getText().toString());
diff --git a/tests/tests/webkit/src/android/webkit/cts/CacheManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CacheManagerTest.java
index bebb1fa..bc3918e 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CacheManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CacheManagerTest.java
@@ -22,8 +22,8 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.CacheManager;
 import android.webkit.WebView;
 import android.webkit.CacheManager.CacheResult;
@@ -32,8 +32,8 @@
 
 @TestTargetClass(android.webkit.CacheManager.class)
 public class CacheManagerTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
-    private static final long CACHEMANAGER_INIT_TIMEOUT = 5000l;
-    private static final long NETWORK_OPERATION_DELAY = 10000l;
+    private static final long CACHEMANAGER_INIT_TIMEOUT = 5000L;
+    private static final long NETWORK_OPERATION_TIMEOUT = 10000L;
 
     private WebView mWebView;
     private CtsTestServer mWebServer;
@@ -98,7 +98,7 @@
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.EMBEDDED_IMG_URL);
 
         // Wait for CacheManager#init() finish.
-        new DelayedCheck(CACHEMANAGER_INIT_TIMEOUT) {
+        new PollingCheck(CACHEMANAGER_INIT_TIMEOUT) {
             @Override
             protected boolean check() {
                 return CacheManager.getCacheFileBaseDir() != null;
@@ -106,7 +106,7 @@
         }.run();
 
         mWebView.clearCache(true);
-        new DelayedCheck(NETWORK_OPERATION_DELAY) {
+        new PollingCheck(NETWORK_OPERATION_TIMEOUT) {
             @Override
             protected boolean check() {
                 CacheResult result = CacheManager.getCacheFile(url, null);
@@ -115,7 +115,7 @@
         }.run();
 
         loadUrl(url);
-        new DelayedCheck(NETWORK_OPERATION_DELAY) {
+        new PollingCheck(NETWORK_OPERATION_TIMEOUT) {
             @Override
             protected boolean check() {
                 CacheResult result = CacheManager.getCacheFile(url, null);
@@ -141,7 +141,7 @@
     private void loadUrl(String url){
         mWebView.loadUrl(url);
         // check whether loadURL successfully
-        new DelayedCheck(NETWORK_OPERATION_DELAY) {
+        new PollingCheck(NETWORK_OPERATION_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/CacheManager_CacheResultTest.java b/tests/tests/webkit/src/android/webkit/cts/CacheManager_CacheResultTest.java
index 48a6a1f..e5077cc 100755
--- a/tests/tests/webkit/src/android/webkit/cts/CacheManager_CacheResultTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CacheManager_CacheResultTest.java
@@ -24,8 +24,8 @@
 import org.apache.http.HttpStatus;
 import org.apache.http.impl.cookie.DateUtils;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.CacheManager;
 import android.webkit.WebChromeClient;
 import android.webkit.WebView;
@@ -37,7 +37,7 @@
 @TestTargetClass(android.webkit.CacheManager.CacheResult.class)
 public class CacheManager_CacheResultTest
         extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
-    private static final long NETWORK_OPERATION_DELAY = 10000l;
+    private static final long NETWORK_OPERATION_TIMEOUT = 10000L;
 
     private WebView mWebView;
     private CtsTestServer mWebServer;
@@ -139,7 +139,7 @@
         mWebServer.setDocumentValidity(validity);
 
         mWebView.clearCache(true);
-        new DelayedCheck(NETWORK_OPERATION_DELAY) {
+        new PollingCheck(NETWORK_OPERATION_TIMEOUT) {
             @Override
             protected boolean check() {
                 CacheResult result =
@@ -175,7 +175,7 @@
     private void loadUrl(String url){
         mWebView.loadUrl(url);
         // check whether loadURL successfully
-        new DelayedCheck(NETWORK_OPERATION_DELAY) {
+        new PollingCheck(NETWORK_OPERATION_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
index 712d641..f938e62 100755
--- a/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieManagerTest.java
@@ -22,8 +22,8 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 import android.webkit.WebChromeClient;
@@ -37,7 +37,7 @@
 public class CookieManagerTest extends
         ActivityInstrumentationTestCase2<CookieSyncManagerStubActivity> {
 
-    private static final int TEST_DELAY = 5000;
+    private static final int TEST_TIMEOUT = 5000;
 
     private WebView mWebView;
     private CookieManager mCookieManager;
@@ -116,7 +116,7 @@
         String url = server.getCookieUrl("conquest.html");
         loadUrl(url);
         assertEquals(null, mWebView.getTitle()); // no cookies passed
-        Thread.sleep(TEST_DELAY);
+        Thread.sleep(500);
         assertNull(mCookieManager.getCookie(url));
 
         mCookieManager.setAcceptCookie(true);
@@ -187,7 +187,7 @@
 
         // sync cookie from RAM to FLASH, because hasCookies() only counts FLASH cookies
         CookieSyncManager.getInstance().sync();
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mCookieManager.hasCookies();
@@ -196,7 +196,7 @@
 
         // clean up all cookies
         mCookieManager.removeAllCookie();
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return !mCookieManager.hasCookies();
@@ -247,7 +247,7 @@
         assertTrue(allCookies.contains(cookie3));
 
         mCookieManager.removeSessionCookie();
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 String c = mCookieManager.getCookie(url);
                 return !c.contains(cookie1) && c.contains(cookie2) && c.contains(cookie3);
@@ -256,7 +256,7 @@
 
         Thread.sleep(expiration + 1000); // wait for cookie to expire
         mCookieManager.removeExpiredCookie();
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 String c = mCookieManager.getCookie(url);
                 return !c.contains(cookie1) && c.contains(cookie2) && !c.contains(cookie3);
@@ -264,7 +264,7 @@
         }.run();
 
         mCookieManager.removeAllCookie();
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return mCookieManager.getCookie(url) == null;
             }
@@ -273,7 +273,7 @@
 
     private void loadUrl(String url) {
         mWebView.loadUrl(url);
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return mWebView.getProgress() == 100;
             }
@@ -281,7 +281,7 @@
     }
 
     private void waitForCookie(final String url) {
-        new DelayedCheck(TEST_DELAY) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return mCookieManager.getCookie(url) != null;
             }
diff --git a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
index 9450c70..8093a10 100644
--- a/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/CookieSyncManagerTest.java
@@ -22,8 +22,8 @@
 import dalvik.annotation.TestTargets;
 
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 
@@ -31,6 +31,8 @@
 public class CookieSyncManagerTest
         extends ActivityInstrumentationTestCase2<CookieSyncManagerStubActivity> {
 
+    private final static int COOKIE_MANAGER_TIMEOUT = 5000;
+
     public CookieSyncManagerTest() {
         super("com.android.cts.stub", CookieSyncManagerStubActivity.class);
     }
@@ -65,7 +67,7 @@
 
         // Remove all cookies from the database.
         cookieManager.removeAllCookie();
-        new DelayedCheck(30000) {
+        new PollingCheck(COOKIE_MANAGER_TIMEOUT) {
             @Override
             protected boolean check() {
                 return !cookieManager.hasCookies();
@@ -83,7 +85,7 @@
 
         // Store the cookie to the database.
         csm1.sync();
-        new DelayedCheck(30000) {
+        new PollingCheck(COOKIE_MANAGER_TIMEOUT) {
             @Override
             protected boolean check() {
                 return cookieManager.hasCookies();
@@ -92,7 +94,7 @@
 
         // Remove all cookies from the database.
         cookieManager.removeAllCookie();
-        new DelayedCheck(30000) {
+        new PollingCheck(COOKIE_MANAGER_TIMEOUT) {
             @Override
             protected boolean check() {
                 return !cookieManager.hasCookies();
diff --git a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
index 8721326..f7e5402 100644
--- a/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/HttpAuthHandlerTest.java
@@ -23,8 +23,8 @@
 
 import org.apache.http.HttpStatus;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.HttpAuthHandler;
 import android.webkit.WebChromeClient;
 import android.webkit.WebView;
@@ -133,7 +133,7 @@
 
     private void assertLoadUrlSuccessfully(String url) throws InterruptedException {
         mWebView.loadUrl(url);
-        new DelayedCheck(TIMEOUT) {
+        new PollingCheck(TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
index 6cddfb3..66730bb 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebBackForwardListTest.java
@@ -21,8 +21,8 @@
 import dalvik.annotation.TestTargetNew;
 import dalvik.annotation.TestTargets;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebHistoryItem;
 import android.webkit.WebView;
@@ -90,7 +90,7 @@
     }
 
     private void checkBackForwardList(final WebView view, final String... url) {
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 if (view.getProgress() < 100) {
                     return false;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
index cf20217..b40bfc9 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebChromeClientTest.java
@@ -21,10 +21,10 @@
 import dalvik.annotation.TestTargetNew;
 import dalvik.annotation.TestTargets;
 
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.JsPromptResult;
 import android.webkit.JsResult;
 import android.webkit.WebChromeClient;
@@ -79,7 +79,7 @@
         assertFalse(webChromeClient.hadOnProgressChanged());
         mWebView.loadUrl(TestHtmlConstants.HELLO_WORLD_URL);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnProgressChanged();
@@ -102,7 +102,7 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnReceivedTitle();
@@ -140,7 +140,7 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnReceivedIcon();
@@ -180,14 +180,14 @@
         // after which the child will be closed
         loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.JS_WINDOW_URL));
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnCreateWindow();
             }
         }.run();
         assertFalse(webChromeClient.hadOnRequestFocus());
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnCloseWindow();
@@ -216,7 +216,7 @@
         // unload should trigger when we try to navigate away
         loadUrl(mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL));
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnJsBeforeUnload();
@@ -245,7 +245,7 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_ALERT_URL);
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnJsAlert();
@@ -274,7 +274,7 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_CONFIRM_URL);
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnJsConfirm();
@@ -305,14 +305,14 @@
         String url = mWebServer.getAssetUrl(TestHtmlConstants.JS_PROMPT_URL);
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.hadOnJsPrompt();
             }
         }.run();
         // the result returned by the client gets set as the page title
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return mWebView.getTitle().equals(promptResult);
             }
@@ -322,7 +322,7 @@
 
     private void loadUrl(String url) {
         mWebView.loadUrl(url);
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return mWebView.getProgress() == 100;
             }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
index 71ba504..bcb2924 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebHistoryItemTest.java
@@ -23,9 +23,9 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.WebBackForwardList;
 import android.webkit.WebChromeClient;
 import android.webkit.WebHistoryItem;
@@ -107,7 +107,7 @@
     private void assertLoadUrlSuccessfully(final WebView view, String url) {
         view.loadUrl(url);
         // wait for the page load to complete
-        new DelayedCheck(10000) {
+        new PollingCheck(10000) {
             @Override
             protected boolean check() {
                 return view.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 639f795..4fad3ed 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -21,10 +21,10 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.os.Build;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.MimeTypeMap;
 import android.webkit.WebChromeClient;
 import android.webkit.WebSettings;
@@ -44,6 +44,7 @@
 @TestTargetClass(android.webkit.WebSettings.class)
 public class WebSettingsTest extends ActivityInstrumentationTestCase2<WebViewStubActivity> {
 
+    private static final int WEBVIEW_TIMEOUT = 5000;
     private static final String LOG_TAG = "WebSettingsTest";
 
     private WebView mWebView;
@@ -252,7 +253,7 @@
         assertFalse(mSettings.getBlockNetworkImage());
         assertTrue(mSettings.getLoadsImagesAutomatically());
         loadAssetUrl(url);
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return !mWebServer.getLastRequestUrl().endsWith(ext);
@@ -543,7 +544,7 @@
         mSettings.setJavaScriptCanOpenWindowsAutomatically(false);
         assertFalse(mSettings.getJavaScriptCanOpenWindowsAutomatically());
         loadAssetUrl(TestHtmlConstants.POPUP_URL);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             protected boolean check() {
                 String title = mWebView.getTitle();
                 return title != null && title.length() > 0;
@@ -554,7 +555,7 @@
         mSettings.setJavaScriptCanOpenWindowsAutomatically(true);
         assertTrue(mSettings.getJavaScriptCanOpenWindowsAutomatically());
         loadAssetUrl(TestHtmlConstants.POPUP_URL);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             protected boolean check() {
                 String title = mWebView.getTitle();
                 return title != null && title.length() > 0;
@@ -579,7 +580,7 @@
         mSettings.setJavaScriptEnabled(true);
         assertTrue(mSettings.getJavaScriptEnabled());
         loadAssetUrl(TestHtmlConstants.JAVASCRIPT_URL);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getTitle() != null;
@@ -590,7 +591,7 @@
         mSettings.setJavaScriptEnabled(false);
         assertFalse(mSettings.getJavaScriptEnabled());
         loadAssetUrl(TestHtmlConstants.JAVASCRIPT_URL);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getTitle() != null;
@@ -1013,7 +1014,7 @@
         mSettings.setJavaScriptEnabled(true);
 
         loadUrl(url);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             protected boolean check() {
                 return mWebView.getTitle() != null && mWebView.getTitle().equals("Done");
             }
@@ -1021,7 +1022,7 @@
 
         mSettings.setAppCachePath("/data/foo");
         loadUrl(url);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             protected boolean check() {
                 return mWebView.getTitle() != null && mWebView.getTitle().equals("Done");
             }
@@ -1061,7 +1062,7 @@
      */
     private void loadUrl(String url) {
         mWebView.loadUrl(url);
-        new DelayedCheck(10000) {
+        new PollingCheck(WEBVIEW_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 2cd2deb..86b8070 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -22,11 +22,11 @@
 import dalvik.annotation.TestTargets;
 import dalvik.annotation.ToBeFixed;
 
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.os.Message;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.KeyEvent;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.HttpAuthHandler;
 import android.webkit.WebSettings;
 import android.webkit.WebView;
@@ -99,19 +99,19 @@
         assertFalse(webViewClient.hasOnPageFinishedCalled());
         mWebView.loadUrl(url);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasOnPageStartedCalled();
             }
         }.run();
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasOnLoadResourceCalled();
             }
         }.run();
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasOnPageFinishedCalled();
             }
@@ -155,7 +155,7 @@
         assertFalse(url.equals(mWebView.getUrl()));
         // reloading the current URL should trigger the callback
         mWebView.reload();
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasOnFormResubmissionCalled();
             }
@@ -177,7 +177,7 @@
         String url2 = mWebServer.getAssetUrl(TestHtmlConstants.BR_TAG_URL);
         assertLoadUrlSuccessfully(mWebView, url1);
         assertLoadUrlSuccessfully(mWebView, url2);
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasDoUpdateVisitedHistoryCalled();
             }
@@ -231,7 +231,7 @@
         assertFalse(webViewClient.hasOnUnhandledKeyEventCalled());
         sendKeys(KeyEvent.KEYCODE_1);
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return webViewClient.hasOnUnhandledKeyEventCalled();
             }
@@ -260,7 +260,7 @@
     private void assertLoadUrlSuccessfully(final WebView view, String url) {
         view.loadUrl(url);
         // wait until load is complete
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return view.getProgress() == 100;
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 3eb49b3..fe24012 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -25,6 +25,7 @@
 
 import android.content.Context;
 import android.content.res.AssetManager;
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -48,7 +49,6 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.animation.cts.DelayedCheck;
 import android.webkit.CacheManager;
 import android.webkit.CacheManager.CacheResult;
 import android.webkit.ConsoleMessage;
@@ -472,7 +472,7 @@
         String url = mWebServer.getDelayedAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mWebView.loadUrl(url);
         mWebView.stopLoading();
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return 100 == mWebView.getProgress();
@@ -524,37 +524,37 @@
         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
 
         assertLoadUrlSuccessfully(url1);
-        delayedCheckWebBackForwardList(url1, 0, 1);
+        pollingCheckWebBackForwardList(url1, 0, 1);
         assertGoBackOrForwardBySteps(false, -1);
         assertGoBackOrForwardBySteps(false, 1);
 
         assertLoadUrlSuccessfully(url2);
-        delayedCheckWebBackForwardList(url2, 1, 2);
+        pollingCheckWebBackForwardList(url2, 1, 2);
         assertGoBackOrForwardBySteps(true, -1);
         assertGoBackOrForwardBySteps(false, 1);
 
         assertLoadUrlSuccessfully(url3);
-        delayedCheckWebBackForwardList(url3, 2, 3);
+        pollingCheckWebBackForwardList(url3, 2, 3);
         assertGoBackOrForwardBySteps(true, -2);
         assertGoBackOrForwardBySteps(false, 1);
 
         mWebView.goBack();
-        delayedCheckWebBackForwardList(url2, 1, 3);
+        pollingCheckWebBackForwardList(url2, 1, 3);
         assertGoBackOrForwardBySteps(true, -1);
         assertGoBackOrForwardBySteps(true, 1);
 
         mWebView.goForward();
-        delayedCheckWebBackForwardList(url3, 2, 3);
+        pollingCheckWebBackForwardList(url3, 2, 3);
         assertGoBackOrForwardBySteps(true, -2);
         assertGoBackOrForwardBySteps(false, 1);
 
         mWebView.goBackOrForward(-2);
-        delayedCheckWebBackForwardList(url1, 0, 3);
+        pollingCheckWebBackForwardList(url1, 0, 3);
         assertGoBackOrForwardBySteps(false, -1);
         assertGoBackOrForwardBySteps(true, 2);
 
         mWebView.goBackOrForward(2);
-        delayedCheckWebBackForwardList(url3, 2, 3);
+        pollingCheckWebBackForwardList(url3, 2, 3);
         assertGoBackOrForwardBySteps(true, -2);
         assertGoBackOrForwardBySteps(false, 1);
     }
@@ -864,7 +864,7 @@
                 assertLoadUrlSuccessfully(url);
             }
         });
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return listener.callCount > 0;
             }
@@ -879,7 +879,7 @@
                 assertLoadUrlSuccessfully(newUrl);
             }
         });
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             protected boolean check() {
                 return listener.callCount > oldCallCount;
             }
@@ -931,7 +931,7 @@
             });
 
             // File saving is done in a separate thread.
-            new DelayedCheck() {
+            new PollingCheck() {
                 @Override
                 protected boolean check() {
                     return f.length() > 0;
@@ -1243,7 +1243,7 @@
     public void testFindNext() throws Throwable {
         final ScrollRunnable runnable = new ScrollRunnable();
 
-        final class StopScrollingDelayedCheck extends DelayedCheck {
+        final class StopScrollingPollingCheck extends PollingCheck {
             private int mPreviousScrollY = -1;
             @Override
             protected boolean check() {
@@ -1292,25 +1292,25 @@
 
         // Focus "all" in the second page and assert that the view scrolls.
         runTestOnUiThread(new FindNextRunnable(true));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() > previousScrollY);
         previousScrollY = runnable.getScrollY();
 
         // Focus "all" in the first page and assert that the view scrolls.
         runTestOnUiThread(new FindNextRunnable(true));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() < previousScrollY);
         previousScrollY = runnable.getScrollY();
 
         // Focus "all" in the second page and assert that the view scrolls.
         runTestOnUiThread(new FindNextRunnable(false));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() > previousScrollY);
         previousScrollY = runnable.getScrollY();
 
         // Focus "all" in the first page and assert that the view scrolls.
         runTestOnUiThread(new FindNextRunnable(false));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() < previousScrollY);
         previousScrollY = runnable.getScrollY();
 
@@ -1324,11 +1324,11 @@
 
         // can not scroll any more
         runTestOnUiThread(new FindNextRunnable(false));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() == previousScrollY);
 
         runTestOnUiThread(new FindNextRunnable(true));
-        new StopScrollingDelayedCheck().run();
+        new StopScrollingPollingCheck().run();
         assertTrue(runnable.getScrollY() == previousScrollY);
     }
 
@@ -1377,7 +1377,7 @@
                 mWebView.documentHasImages(response);
             }
         });
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return handler.hasCalledHandleMessage();
@@ -1558,7 +1558,7 @@
         final String url = mWebServer.getAssetUrl(TestHtmlConstants.HELLO_WORLD_URL);
         mWebView.loadUrl(url);
         waitForLoadComplete();
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 CacheResult result = CacheManager.getCacheFile(url, null);
@@ -1575,7 +1575,7 @@
 
         mWebView.clearCache(true);
         // check the files are deleted
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return cacheFileBaseDir.list().length == 0;
@@ -1714,7 +1714,7 @@
                 mWebView.requestFocusNodeHref(hrefMsg);
             }
         });
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return handler.hasCalledHandleMessage();
@@ -1732,7 +1732,7 @@
                 mWebView.requestFocusNodeHref(hrefMsg2);
             }
         });
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return handler.hasCalledHandleMessage();
@@ -1800,7 +1800,7 @@
                 mWebView.requestImageRef(msg);
             }
         });
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return handler.hasCalledHandleMessage();
@@ -1989,18 +1989,18 @@
         String url3 = mWebServer.getAssetUrl(TestHtmlConstants.HTML_URL3);
 
         assertLoadUrlSuccessfully(url1);
-        delayedCheckWebBackForwardList(url1, 0, 1);
+        pollingCheckWebBackForwardList(url1, 0, 1);
 
         assertLoadUrlSuccessfully(url2);
-        delayedCheckWebBackForwardList(url2, 1, 2);
+        pollingCheckWebBackForwardList(url2, 1, 2);
 
         assertLoadUrlSuccessfully(url3);
-        delayedCheckWebBackForwardList(url3, 2, 3);
+        pollingCheckWebBackForwardList(url3, 2, 3);
 
         mWebView.clearHistory();
 
         // only current URL is left after clearing
-        delayedCheckWebBackForwardList(url3, 0, 1);
+        pollingCheckWebBackForwardList(url3, 0, 1);
     }
 
     @TestTargets({
@@ -2033,11 +2033,11 @@
 
         // make a history list
         assertLoadUrlSuccessfully(url1);
-        delayedCheckWebBackForwardList(url1, 0, 1);
+        pollingCheckWebBackForwardList(url1, 0, 1);
         assertLoadUrlSuccessfully(url2);
-        delayedCheckWebBackForwardList(url2, 1, 2);
+        pollingCheckWebBackForwardList(url2, 1, 2);
         assertLoadUrlSuccessfully(url3);
-        delayedCheckWebBackForwardList(url3, 2, 3);
+        pollingCheckWebBackForwardList(url3, 2, 3);
 
         // save the list
         Bundle bundle = new Bundle();
@@ -2063,7 +2063,7 @@
         assertEquals(2, saveList.getCurrentIndex());
         /* ToBeFixed: The WebHistoryItems do not get inflated. Uncomment remaining tests when fixed.
         // wait for the list items to get inflated
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return restoreList.getItemAtIndex(0).getUrl() != null &&
@@ -2169,7 +2169,7 @@
 
         runTestOnUiThread(new Runnable() {
             public void run() {
-                new DelayedCheck(TEST_TIMEOUT) {
+                new PollingCheck(TEST_TIMEOUT) {
                     @Override
                     protected boolean check() {
                         return mWebView.getCertificate() == null;
@@ -2213,7 +2213,7 @@
 
         runTestOnUiThread(new Runnable() {
             public void run() {
-                new DelayedCheck(TEST_TIMEOUT) {
+                new PollingCheck(TEST_TIMEOUT) {
                     @Override
                     protected boolean check() {
                         return mWebView.getCertificate() != null;
@@ -2508,7 +2508,7 @@
         });
         getInstrumentation().waitForIdleSync();
         getInstrumentation().sendKeyDownUpSync(KeyEvent.KEYCODE_DPAD_CENTER);
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return listener.called;
@@ -2607,7 +2607,7 @@
         });
         getInstrumentation().waitForIdleSync();
 
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return webChromeClient.onProgressChangedCalled();
@@ -2837,9 +2837,9 @@
         }
     }
 
-    private void delayedCheckWebBackForwardList(final String currUrl, final int currIndex,
+    private void pollingCheckWebBackForwardList(final String currUrl, final int currIndex,
             final int size) {
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 WebBackForwardList list = mWebView.copyBackForwardList();
@@ -2935,7 +2935,7 @@
     }
 
     private void waitForLoadComplete() {
-        new DelayedCheck(TEST_TIMEOUT) {
+        new PollingCheck(TEST_TIMEOUT) {
             @Override
             protected boolean check() {
                 return mWebView.getProgress() == 100;
diff --git a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
index 9627b6f..e2dd2fd 100644
--- a/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CursorAdapterTest.java
@@ -19,6 +19,7 @@
 import java.io.File;
 
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.database.ContentObserver;
 import android.database.Cursor;
 import android.database.DataSetObserver;
@@ -29,7 +30,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.CursorAdapter;
 import android.widget.Filter;
 import android.widget.FilterQueryProvider;
@@ -428,7 +428,7 @@
         assertFalse(mMockCursorAdapter.hasContentChanged());
         // insert a new row
         mDatabase.execSQL("INSERT INTO test (number) VALUES ('" + FIRST_NUMBER + "');");
-        new DelayedCheck(TEST_TIME_OUT) {
+        new PollingCheck(TEST_TIME_OUT) {
             @Override
             protected boolean check() {
                 return mMockCursorAdapter.hasContentChanged();
diff --git a/tests/tests/widget/src/android/widget/cts/FilterTest.java b/tests/tests/widget/src/android/widget/cts/FilterTest.java
index 862cb03..1306bd28 100644
--- a/tests/tests/widget/src/android/widget/cts/FilterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FilterTest.java
@@ -20,8 +20,8 @@
 import dalvik.annotation.TestTargetClass;
 import dalvik.annotation.TestTargetNew;
 
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.Filter;
 import android.widget.Filter.FilterListener;
 
@@ -70,7 +70,7 @@
             }
         });
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mMockFilter.hadPerformedFiltering();
@@ -78,7 +78,7 @@
         }.run();
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPerformFilteringConstraint());
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mMockFilter.hadPublishedResults();
@@ -102,7 +102,7 @@
             }
         });
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mMockFilter.hadPerformedFiltering();
@@ -110,7 +110,7 @@
         }.run();
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPerformFilteringConstraint());
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mMockFilter.hadPublishedResults();
@@ -119,7 +119,7 @@
         assertEquals(TEST_CONSTRAINT, mMockFilter.getPublishResultsConstraint());
         assertSame(mMockFilter.getExpectResults(), mMockFilter.getResults());
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return mockFilterListener.hasCalledOnFilterComplete();
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
index 31b0b7b..c6302f9 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewTest.java
@@ -28,6 +28,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -39,7 +40,6 @@
 import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.HorizontalScrollView;
 import android.widget.TextView;
 
@@ -363,7 +363,7 @@
                 mScrollView.fullScroll(View.FOCUS_RIGHT);
             }
         });
-        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
         assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
 
         runTestOnUiThread(new Runnable() {
@@ -371,7 +371,7 @@
                 mScrollView.fullScroll(View.FOCUS_LEFT);
             }
         });
-        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
         assertEquals(0, mScrollView.getScrollX());
     }
 
@@ -521,7 +521,7 @@
                 mScrollView.smoothScrollBy(SCROLL_RIGHT, 0);
             }
         });
-        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
         assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
         assertEquals(0, mScrollView.getScrollY());
 
@@ -530,7 +530,7 @@
                 mScrollView.smoothScrollBy(-SCROLL_RIGHT, 0);
             }
         });
-        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(0, mScrollView.getScrollY());
     }
@@ -549,7 +549,7 @@
                 mScrollView.smoothScrollTo(SCROLL_RIGHT, 0);
             }
         });
-        delayedCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
+        pollingCheckSmoothScrolling(0, SCROLL_RIGHT, 0, 0);
         assertEquals(SCROLL_RIGHT, mScrollView.getScrollX());
         assertEquals(0, mScrollView.getScrollY());
 
@@ -558,7 +558,7 @@
                 mScrollView.smoothScrollTo(0, 0);
             }
         });
-        delayedCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
+        pollingCheckSmoothScrolling(SCROLL_RIGHT, 0, 0, 0);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(0, mScrollView.getScrollY());
     }
@@ -677,7 +677,7 @@
                 mScrollView.fling(velocityX);
             }
         });
-        delayedCheckFling(0, true);
+        pollingCheckFling(0, true);
 
         final int currentX = mScrollView.getScrollX();
         // fling towards left
@@ -686,7 +686,7 @@
                 mScrollView.fling(-velocityX);
             }
         });
-        delayedCheckFling(currentX, false);
+        pollingCheckFling(currentX, false);
     }
 
     @TestTargetNew(
@@ -832,7 +832,7 @@
         return current <= from && current >= to;
     }
 
-    private void delayedCheckSmoothScrolling(final int fromX, final int toX,
+    private void pollingCheckSmoothScrolling(final int fromX, final int toX,
             final int fromY, final int toY) {
 
         if (fromX == toX && fromY == toY) {
@@ -840,7 +840,7 @@
         }
 
         if (fromY != toY) {
-            new DelayedCheck() {
+            new PollingCheck() {
                 @Override
                 protected boolean check() {
                     return isInRange(mScrollView.getScrollY(), fromY, toY);
@@ -849,7 +849,7 @@
         }
 
         if (fromX != toX) {
-            new DelayedCheck() {
+            new PollingCheck() {
                 @Override
                 protected boolean check() {
                     return isInRange(mScrollView.getScrollX(), fromX, toX);
@@ -857,7 +857,7 @@
             }.run();
         }
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
@@ -865,8 +865,8 @@
         }.run();
     }
 
-    private void delayedCheckFling(final int startPosition, final boolean movingRight) {
-        new DelayedCheck() {
+    private void pollingCheckFling(final int startPosition, final boolean movingRight) {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 if (movingRight) {
@@ -876,7 +876,7 @@
             }
         }.run();
 
-        new DelayedCheck() {
+        new PollingCheck() {
             private int mPreviousScrollX = mScrollView.getScrollX();
 
             @Override
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
index 9f27138..dc007e4 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
@@ -29,6 +29,7 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
@@ -36,7 +37,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
@@ -222,7 +222,7 @@
         assertTrue(mMediaController.isShowing());
 
         // isShowing() should return false, but MediaController still shows, this may be a bug.
-        new DelayedCheck(timeout + 500) {
+        new PollingCheck(timeout + 500) {
             @Override
             protected boolean check() {
                 return mMediaController.isShowing();
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 681e641..cd336da 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -28,6 +28,7 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.graphics.Rect;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
@@ -39,7 +40,6 @@
 import android.view.ViewGroup;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup.LayoutParams;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.ScrollView;
 import android.widget.TextView;
 
@@ -382,7 +382,7 @@
                 mScrollView.fullScroll(View.FOCUS_DOWN);
             }
         });
-        delayedCheckSmoothScrolling(0, 0, 0, mScrollBottom);
+        pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
         assertEquals(mScrollBottom, mScrollView.getScrollY(), TOLERANCE);
 
         runTestOnUiThread(new Runnable() {
@@ -390,7 +390,7 @@
                 mScrollView.fullScroll(View.FOCUS_UP);
             }
         });
-        delayedCheckSmoothScrolling(0, 0, mScrollBottom, 0);
+        pollingCheckSmoothScrolling(0, 0, mScrollBottom, 0);
         assertEquals(0, mScrollView.getScrollY());
     }
 
@@ -547,7 +547,7 @@
             }
         });
         // smoothScrollBy doesn't scroll in X
-        delayedCheckSmoothScrolling(0, 0, 0, mScrollBottom);
+        pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(mScrollBottom, mScrollView.getScrollY());
 
@@ -556,7 +556,7 @@
                 mScrollView.smoothScrollBy(-mScrollRight, -mScrollBottom);
             }
         });
-        delayedCheckSmoothScrolling(mScrollRight, 0, mScrollBottom, 0);
+        pollingCheckSmoothScrolling(mScrollRight, 0, mScrollBottom, 0);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(0, mScrollView.getScrollY());
     }
@@ -576,7 +576,7 @@
             }
         });
         // smoothScrollTo doesn't scroll in X
-        delayedCheckSmoothScrolling(0, 0, 0, mScrollBottom);
+        pollingCheckSmoothScrolling(0, 0, 0, mScrollBottom);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(mScrollBottom, mScrollView.getScrollY());
 
@@ -585,7 +585,7 @@
                 mScrollView.smoothScrollTo(mPageWidth, mPageHeight);
             }
         });
-        delayedCheckSmoothScrolling(0, 0, mScrollBottom, mPageHeight);
+        pollingCheckSmoothScrolling(0, 0, mScrollBottom, mPageHeight);
         assertEquals(0, mScrollView.getScrollX());
         assertEquals(mPageHeight, mScrollView.getScrollY());
     }
@@ -706,7 +706,7 @@
                 mScrollView.fling(2000);
             }
         });
-        delayedCheckFling(0, true);
+        pollingCheckFling(0, true);
 
         final int currentY = mScrollView.getScrollY();
         // fling towards top
@@ -715,7 +715,7 @@
                 mScrollView.fling(-2000);
             }
         });
-        delayedCheckFling(currentY, false);
+        pollingCheckFling(currentY, false);
     }
 
     @TestTargetNew(
@@ -860,7 +860,7 @@
         return current <= from && current >= to;
     }
 
-    private void delayedCheckSmoothScrolling(final int fromX, final int toX,
+    private void pollingCheckSmoothScrolling(final int fromX, final int toX,
             final int fromY, final int toY) {
 
         if (fromX == toX && fromY == toY) {
@@ -868,7 +868,7 @@
         }
 
         if (fromY != toY) {
-            new DelayedCheck() {
+            new PollingCheck() {
                 @Override
                 protected boolean check() {
                     return isInRange(mScrollView.getScrollY(), fromY, toY);
@@ -877,7 +877,7 @@
         }
 
         if (fromX != toX) {
-            new DelayedCheck() {
+            new PollingCheck() {
                 @Override
                 protected boolean check() {
                     return isInRange(mScrollView.getScrollX(), fromX, toX);
@@ -885,7 +885,7 @@
             }.run();
         }
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return toX == mScrollView.getScrollX() && toY == mScrollView.getScrollY();
@@ -893,8 +893,8 @@
         }.run();
     }
 
-    private void delayedCheckFling(final int startPosition, final boolean movingDown) {
-        new DelayedCheck() {
+    private void pollingCheckFling(final int startPosition, final boolean movingDown) {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 if (movingDown) {
@@ -904,7 +904,7 @@
             }
         };
 
-        new DelayedCheck() {
+        new PollingCheck() {
             private int mPreviousScrollY = mScrollView.getScrollY();
 
             @Override
diff --git a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
index 3207a15..70310de 100644
--- a/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SlidingDrawerTest.java
@@ -28,13 +28,13 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.ImageView;
 import android.widget.SlidingDrawer;
 import android.widget.TextView;
@@ -192,7 +192,7 @@
         assertFalse(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return !drawer.isMoving();
@@ -210,7 +210,7 @@
         assertTrue(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return !drawer.isMoving();
@@ -253,7 +253,7 @@
         assertFalse(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return !drawer.isMoving();
@@ -271,7 +271,7 @@
         assertTrue(drawer.isOpened());
         assertEquals(View.GONE, content.getVisibility());
 
-        new DelayedCheck() {
+        new PollingCheck() {
             @Override
             protected boolean check() {
                 return !drawer.isMoving();
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index c714d8a..dcf574c 100755
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -35,6 +35,7 @@
 import android.content.Intent;
 import android.content.res.ColorStateList;
 import android.content.res.Resources.NotFoundException;
+import android.cts.util.PollingCheck;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.Paint;
@@ -86,7 +87,6 @@
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.View.OnLongClickListener;
-import android.view.animation.cts.DelayedCheck;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
@@ -2580,7 +2580,7 @@
         mInstrumentation.waitForIdleSync();
 
         // it will get transformed after a while
-        new DelayedCheck(TIMEOUT) {
+        new PollingCheck(TIMEOUT) {
             @Override
             protected boolean check() {
                 // "******"
@@ -3432,7 +3432,7 @@
 
         // wait for the marquee to run
         // fading is shown on both sides if the marquee runs for a while
-        new DelayedCheck(TIMEOUT) {
+        new PollingCheck(TIMEOUT) {
             @Override
             protected boolean check() {
                 return textView.getLeftFadingEdgeStrength() > 0.0f
@@ -3446,7 +3446,7 @@
         // wait for the marquee to continue
         // the left fading becomes thicker while the right fading becomes thiner
         // as the text moves towards left
-        new DelayedCheck(TIMEOUT) {
+        new PollingCheck(TIMEOUT) {
             @Override
             protected boolean check() {
                 return leftFadingEdgeStrength < textView.getLeftFadingEdgeStrength()
diff --git a/tests/tests/widget/src/android/widget/cts/ToastTest.java b/tests/tests/widget/src/android/widget/cts/ToastTest.java
index c54b205..c5f1c9f 100644
--- a/tests/tests/widget/src/android/widget/cts/ToastTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ToastTest.java
@@ -26,6 +26,7 @@
 
 import android.app.Activity;
 import android.app.Instrumentation;
+import android.cts.util.PollingCheck;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
@@ -33,7 +34,6 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.ImageView;
 import android.widget.Toast;
 
@@ -78,7 +78,7 @@
     }
 
     private void assertShowToast(final View view) {
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return null != view.getParent();
@@ -88,7 +88,7 @@
 
     private void assertShowAndHide(final View view) {
         assertShowToast(view);
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return null == view.getParent();
diff --git a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
index 57ea598..6b3cc4e 100644
--- a/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/VideoViewTest.java
@@ -26,13 +26,13 @@
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
+import android.cts.util.PollingCheck;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
 import android.test.ActivityInstrumentationTestCase2;
 import android.view.View.MeasureSpec;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
@@ -214,7 +214,7 @@
                 mVideoView.setVideoPath(mVideoPath);
             }
         });
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return preparedListener.isTriggered();
@@ -228,7 +228,7 @@
             }
         });
         // wait time is longer than duration in case system is sluggish
-        new DelayedCheck(mVideoView.getDuration() + TIME_OUT) {
+        new PollingCheck(mVideoView.getDuration() + TIME_OUT) {
             @Override
             protected boolean check() {
                 return completionListener.isTriggered();
@@ -254,7 +254,7 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return listener.isTriggered();
@@ -278,7 +278,7 @@
         });
         mInstrumentation.waitForIdleSync();
 
-        new DelayedCheck(TIME_OUT) {
+        new PollingCheck(TIME_OUT) {
             @Override
             protected boolean check() {
                 return prepareListener.isTriggered();
diff --git a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
index 4bb412c..f98528a 100644
--- a/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ZoomButtonTest.java
@@ -27,13 +27,13 @@
 import org.xmlpull.v1.XmlPullParser;
 
 import android.app.Activity;
+import android.cts.util.PollingCheck;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.UiThreadTest;
 import android.util.AttributeSet;
 import android.util.Xml;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.view.animation.cts.DelayedCheck;
 import android.widget.ListView;
 import android.widget.ZoomButton;
 
@@ -157,7 +157,7 @@
 
         assertFalse(listener.hasOnClickCalled());
         mZoomButton.performLongClick();
-        new DelayedCheck(speed + 500) {
+        new PollingCheck(speed + 500) {
             @Override
             protected boolean check() {
                 return listener.hasOnClickCalled();
diff --git a/tools/utils/host_config.xml b/tools/utils/host_config.xml
index 1a99e75..661b1a3 100644
--- a/tools/utils/host_config.xml
+++ b/tools/utils/host_config.xml
@@ -34,7 +34,7 @@
     <!-- Max time [ms] from start of package in batch mode and the first test status update. -->
     <IntValue name="batchStartTimeoutMs" value="1800000" />
     <!-- Max time [ms] from start of test in individual mode to the first test status update. -->
-    <IntValue name="individualStartTimeoutMs" value="600000" />
+    <IntValue name="individualStartTimeoutMs" value="300000" />
     <!-- Timeout [ms] for the signature check. -->
     <IntValue name="signatureTestTimeoutMs" value="600000" />
     <!-- Timeout [ms] for package installations. -->