Merge "Scroll list of documents when offscreen." into lmp-mr1-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 50edde6..9b52490 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.android.cts.verifier"
       android:versionCode="5"
-      android:versionName="5.0_r1.93">
+      android:versionName="5.0_r1.94">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
 
@@ -1031,6 +1031,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
 
         <activity android:name=".notifications.PackagePriorityVerifierActivity"
@@ -1040,6 +1042,8 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+            <meta-data android:name="test_excluded_features"
+                    android:value="android.hardware.type.watch" />
         </activity>
 
         <service android:name=".notifications.MockListener"
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 c0895d7..105e92b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -220,6 +220,9 @@
             new Feature(PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY, false),
             new Feature(PackageManager.FEATURE_VERIFIED_BOOT, false),
 
+            // Features explicitly made optional in L
+            new Feature("PackageManager.FEATURE_LOCATION_NETWORK", false),
+
             // New hidden features in L
             new Feature("android.hardware.ethernet", false),
             new Feature("android.hardware.hdmi.cec", false),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
index 18d9d43..77de71d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
@@ -150,6 +150,8 @@
     public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
         Log.i(TAG, "onSurfaceTextureSizeChanged " + surface.toString() + "w: " + width + " h: "
                 + height);
+        mWidth = width;
+        mHeight = height;
     }
 
     @Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
index 5dddf5c..46abaaa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
@@ -50,7 +50,7 @@
         setContentView(view);
 
         for (int i = 0; i < NUM_ITEMS; ++i) {
-            mItemList.add("Item #" + 1 + i);
+            mItemList.add("Item #" + (1 + i));
         }
 
         ListView listView = (ListView) view.findViewById(R.id.pla_list);
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
index 5378266..cf16307 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
@@ -429,6 +429,7 @@
         boolean mHaveResult = false;
         boolean mGoodResult = false;
         boolean mSucceeded = false;
+        static final int TIMEOUT_MS = 30000;
         
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -456,10 +457,10 @@
                 final long startTime = SystemClock.uptimeMillis();
                 while (!mHaveResult) {
                     try {
-                        wait(5000);
+                        wait(TIMEOUT_MS);
                     } catch (InterruptedException e) {
                     }
-                    if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+                    if (SystemClock.uptimeMillis() >= (startTime + TIMEOUT_MS)) {
                         throw new RuntimeException("Timeout");
                     }
                 }
@@ -477,10 +478,10 @@
                 final long startTime = SystemClock.uptimeMillis();
                 while (!mHaveResult) {
                     try {
-                        wait(5000);
+                        wait(TIMEOUT_MS);
                     } catch (InterruptedException e) {
                     }
-                    if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+                    if (SystemClock.uptimeMillis() >= (startTime + TIMEOUT_MS)) {
                         throw new RuntimeException("Timeout");
                     }
                 }
diff --git a/hostsidetests/theme/assets/21/hdpi.zip b/hostsidetests/theme/assets/21/hdpi.zip
index 9cc179c..0fa67b7 100644
--- a/hostsidetests/theme/assets/21/hdpi.zip
+++ b/hostsidetests/theme/assets/21/hdpi.zip
Binary files differ
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index d81ce35..c0875c1 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -22,6 +22,23 @@
   bug: 17595050
 },
 {
+  description: "the SSLCertificateSocketFactoryTest often fails because of lack of live internet or short timeout, it should be refactored to do a local server testing",
+  names: [
+    "android.net.cts.SSLCertificateSocketFactoryTest#testCreateSocket",
+    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind",
+    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple",
+    "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping"
+  ],
+  bug: 18682315
+},
+{
+  description: "the test result are too much dependent on live-internet connection, which for some devices might not exist",
+  names: [
+    "android.net.wifi.cts.NsdManagerTest#testAndroidTestCaseSetupProperly"
+  ],
+  bug: 18680089
+},
+{
   description: "AudioPolicyBinder tests are not yet robust enough",
   names: [
     "android.security.cts.AudioPolicyBinderTest"
diff --git a/tests/tests/app/src/android/app/cts/ServiceTest.java b/tests/tests/app/src/android/app/cts/ServiceTest.java
index b66f4c8..8ba1816 100644
--- a/tests/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/tests/app/src/android/app/cts/ServiceTest.java
@@ -448,4 +448,17 @@
             // expected
         }
     }
+
+    @MediumTest
+    public void testImplicitIntentFailsOnApiLevel21() throws Exception {
+        Intent intent = new Intent(LocalService.SERVICE_LOCAL);
+        EmptyConnection conn = new EmptyConnection();
+        try {
+            mContext.bindService(intent, conn, 0);
+            mContext.unbindService(conn);
+            fail("Implicit intents should be disallowed for apps targeting API 21+");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index 303099a..47d0bc3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -18,6 +18,7 @@
 
 import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
 
+import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.ImageFormat;
 import android.graphics.PointF;
@@ -492,6 +493,23 @@
         }
     }
 
+    public static void dumpFile(String fileName, Bitmap data) {
+        FileOutputStream outStream;
+        try {
+            Log.v(TAG, "output will be saved as " + fileName);
+            outStream = new FileOutputStream(fileName);
+        } catch (IOException ioe) {
+            throw new RuntimeException("Unable to create debug output file " + fileName, ioe);
+        }
+
+        try {
+            data.compress(Bitmap.CompressFormat.JPEG, /*quality*/90, outStream);
+            outStream.close();
+        } catch (IOException ioe) {
+            throw new RuntimeException("failed writing data to file " + fileName, ioe);
+        }
+    }
+
     public static void dumpFile(String fileName, byte[] data) {
         FileOutputStream outStream;
         try {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 40db2d2..ebfe3d7 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -16,27 +16,40 @@
 
 package android.hardware.camera2.cts;
 
-import static android.hardware.camera2.cts.CameraTestUtils.*;
-
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Color;
 import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraDevice;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
-import android.util.Size;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.hardware.camera2.utils.ArrayUtils;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.ConditionVariable;
 import android.util.Log;
+import android.util.Size;
 import android.view.Surface;
 
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.hardware.camera2.cts.CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS;
+import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
+import static android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
+import static android.hardware.camera2.cts.CameraTestUtils.dumpFile;
+import static android.hardware.camera2.cts.CameraTestUtils.getValueNotNull;
+
 /**
  * <p>Basic test for ImageReader APIs. It uses CameraDevice as producer, camera
  * sends the data to the surface provided by imageReader. Below image formats
@@ -50,10 +63,16 @@
 public class ImageReaderTest extends Camera2AndroidTestCase {
     private static final String TAG = "ImageReaderTest";
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     // number of frame (for streaming requests) to be verified.
     private static final int NUM_FRAME_VERIFIED = 2;
     // Max number of images can be accessed simultaneously from ImageReader.
     private static final int MAX_NUM_IMAGES = 5;
+    // Max difference allowed between YUV and JPEG patches. This tolerance is intentionally very
+    // generous to avoid false positives due to punch/saturation operations vendors apply to the
+    // JPEG outputs.
+    private static final double IMAGE_DIFFERENCE_TOLERANCE = 30;
 
     private SimpleImageListener mListener;
 
@@ -194,6 +213,305 @@
         }
     }
 
+    /**
+     * Check that the center patches for YUV and JPEG outputs for the same frame match for each YUV
+     * resolution and format supported.
+     */
+    public void testAllOutputYUVResolutions() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing all YUV image resolutions for camera " + id);
+                openDevice(id);
+
+                // NV21 isn't supported by ImageReader.
+                final int[] YUVFormats = new int[] {ImageFormat.YUV_420_888, ImageFormat.YV12};
+
+                CameraCharacteristics.Key<StreamConfigurationMap> key =
+                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
+                StreamConfigurationMap config = mStaticInfo.getValueFromKeyNonNull(key);
+                int[] supportedFormats = config.getOutputFormats();
+                List<Integer> supportedYUVFormats = new ArrayList<>();
+                for (int format : YUVFormats) {
+                    if (ArrayUtils.contains(supportedFormats, format)) {
+                        supportedYUVFormats.add(format);
+                    }
+                }
+
+                Size[] jpegSizes = mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.JPEG,
+                        StaticMetadata.StreamDirection.Output);
+                assertFalse("JPEG output not supported for camera " + id +
+                        ", at least one JPEG output is required.", jpegSizes.length == 0);
+
+                Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+
+                for (int format : supportedYUVFormats) {
+                    Size[] targetCaptureSizes =
+                            mStaticInfo.getAvailableSizesForFormatChecked(format,
+                            StaticMetadata.StreamDirection.Output);
+
+                    for (Size captureSz : targetCaptureSizes) {
+                        if (VERBOSE) {
+                            Log.v(TAG, "Testing yuv size " + captureSz + " and jpeg size "
+                                    + maxJpegSize + " for camera " + mCamera.getId());
+                        }
+
+                        ImageReader jpegReader = null;
+                        ImageReader yuvReader = null;
+                        try {
+                            // Create YUV image reader
+                            SimpleImageReaderListener yuvListener = new SimpleImageReaderListener();
+                            yuvReader = createImageReader(captureSz, format, MAX_NUM_IMAGES,
+                                    yuvListener);
+                            Surface yuvSurface = yuvReader.getSurface();
+
+                            // Create JPEG image reader
+                            SimpleImageReaderListener jpegListener =
+                                    new SimpleImageReaderListener();
+                            jpegReader = createImageReader(maxJpegSize,
+                                    ImageFormat.JPEG, MAX_NUM_IMAGES, jpegListener);
+                            Surface jpegSurface = jpegReader.getSurface();
+
+                            // Capture images.
+                            List<Surface> outputSurfaces = new ArrayList<Surface>();
+                            outputSurfaces.add(yuvSurface);
+                            outputSurfaces.add(jpegSurface);
+                            CaptureRequest.Builder request =
+                                    prepareCaptureRequestForSurfaces(outputSurfaces);
+                            SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+
+                            startCapture(request.build(), /*repeating*/false, resultListener,
+                                    mHandler);
+
+                            // Verify capture result and images
+                            resultListener.getCaptureResult(CAPTURE_WAIT_TIMEOUT_MS);
+
+                            Image yuvImage = yuvListener.getImage(CAPTURE_WAIT_TIMEOUT_MS);
+                            Image jpegImage = jpegListener.getImage(CAPTURE_WAIT_TIMEOUT_MS);
+
+                            //Validate captured images.
+                            CameraTestUtils.validateImage(yuvImage, captureSz.getWidth(),
+                                    captureSz.getHeight(), format, /*filePath*/null);
+                            CameraTestUtils.validateImage(jpegImage, maxJpegSize.getWidth(),
+                                    maxJpegSize.getHeight(), ImageFormat.JPEG, /*filePath*/null);
+
+                            // Compare the image centers.
+                            RectF jpegDimens = new RectF(0, 0, jpegImage.getWidth(),
+                                    jpegImage.getHeight());
+                            RectF yuvDimens = new RectF(0, 0, yuvImage.getWidth(),
+                                    yuvImage.getHeight());
+
+                            // Find scale difference between YUV and JPEG output
+                            Matrix m = new Matrix();
+                            m.setRectToRect(yuvDimens, jpegDimens, Matrix.ScaleToFit.START);
+                            RectF scaledYuv = new RectF();
+                            m.mapRect(scaledYuv, yuvDimens);
+                            float scale = scaledYuv.width() / yuvDimens.width();
+
+                            final int PATCH_DIMEN = 40; // pixels in YUV
+
+                            // Find matching square patch of pixels in YUV and JPEG output
+                            RectF tempPatch = new RectF(0, 0, PATCH_DIMEN, PATCH_DIMEN);
+                            tempPatch.offset(yuvDimens.centerX() - tempPatch.centerX(),
+                                    yuvDimens.centerY() - tempPatch.centerY());
+                            Rect yuvPatch = new Rect();
+                            tempPatch.roundOut(yuvPatch);
+
+                            tempPatch.set(0, 0, PATCH_DIMEN * scale, PATCH_DIMEN * scale);
+                            tempPatch.offset(jpegDimens.centerX() - tempPatch.centerX(),
+                                    jpegDimens.centerY() - tempPatch.centerY());
+                            Rect jpegPatch = new Rect();
+                            tempPatch.roundOut(jpegPatch);
+
+                            // Decode center patches
+                            int[] yuvColors = convertPixelYuvToRgba(yuvPatch.width(),
+                                    yuvPatch.height(), yuvPatch.left, yuvPatch.top, yuvImage);
+                            Bitmap yuvBmap = Bitmap.createBitmap(yuvColors, yuvPatch.width(),
+                                    yuvPatch.height(), Bitmap.Config.ARGB_8888);
+
+                            byte[] compressedJpegData = CameraTestUtils.getDataFromImage(jpegImage);
+                            BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+                                    compressedJpegData, /*offset*/0, compressedJpegData.length,
+                                    /*isShareable*/true);
+                            BitmapFactory.Options opt = new BitmapFactory.Options();
+                            opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
+                            Bitmap fullSizeJpegBmap = decoder.decodeRegion(jpegPatch, opt);
+                            Bitmap jpegBmap = Bitmap.createScaledBitmap(fullSizeJpegBmap,
+                                    yuvPatch.width(), yuvPatch.height(), /*filter*/true);
+
+                            // Compare two patches using average of per-pixel differences
+                            double difference = findDifferenceMetric(yuvBmap, jpegBmap);
+
+                            Log.i(TAG, "Difference for resolution " + captureSz + " is: " +
+                                    difference);
+                            if (difference > IMAGE_DIFFERENCE_TOLERANCE) {
+                                // Dump files if running in verbose mode
+                                if (DEBUG) {
+                                    String jpegFileName = DEBUG_FILE_NAME_BASE + "/" + captureSz +
+                                            "_jpeg.jpg";
+                                    dumpFile(jpegFileName, jpegBmap);
+                                    String fullSizeJpegFileName = DEBUG_FILE_NAME_BASE + "/" +
+                                            captureSz + "_full_jpeg.jpg";
+                                    dumpFile(fullSizeJpegFileName, compressedJpegData);
+                                    String yuvFileName = DEBUG_FILE_NAME_BASE + "/" + captureSz +
+                                            "_yuv.jpg";
+                                    dumpFile(yuvFileName, yuvBmap);
+                                    String fullSizeYuvFileName = DEBUG_FILE_NAME_BASE + "/" +
+                                            captureSz + "_full_yuv.jpg";
+                                    int[] fullYUVColors = convertPixelYuvToRgba(yuvImage.getWidth(),
+                                            yuvImage.getHeight(), 0, 0, yuvImage);
+                                    Bitmap fullYUVBmap = Bitmap.createBitmap(fullYUVColors,
+                                            yuvImage.getWidth(), yuvImage.getHeight(),
+                                            Bitmap.Config.ARGB_8888);
+                                    dumpFile(fullSizeYuvFileName, fullYUVBmap);
+                                }
+                                fail("YUV and JPEG image at capture size " + captureSz +
+                                        " for the same frame are not similar, center patches " +
+                                        "have difference metric of " + difference);
+                            }
+
+                            // Stop capture, delete the streams.
+                            stopCapture(/*fast*/false);
+                        } finally {
+                            closeImageReader(jpegReader);
+                            jpegReader = null;
+                            closeImageReader(yuvReader);
+                            yuvReader = null;
+                        }
+                    }
+                }
+
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
+     * Find the difference between two bitmaps using average of per-pixel differences.
+     *
+     * @param a first {@link Bitmap}.
+     * @param b second {@link Bitmap}.
+     * @return the difference.
+     */
+    private static double findDifferenceMetric(Bitmap a, Bitmap b) {
+        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
+            throw new IllegalArgumentException("Bitmap dimensions for arguments do not match a=" +
+                    a.getWidth() + "x" + a.getHeight() + ", b=" + b.getWidth() + "x" +
+                    b.getHeight());
+        }
+        // TODO: Optimize this in renderscript to avoid copy.
+        int[] aPixels = new int[a.getHeight() * a.getWidth()];
+        int[] bPixels = new int[aPixels.length];
+        a.getPixels(aPixels, /*offset*/0, /*stride*/a.getWidth(), /*x*/0, /*y*/0, a.getWidth(),
+                a.getHeight());
+        b.getPixels(bPixels, /*offset*/0, /*stride*/b.getWidth(), /*x*/0, /*y*/0, b.getWidth(),
+                b.getHeight());
+        double diff = 0;
+        for (int i = 0; i < aPixels.length; i++) {
+            int aPix = aPixels[i];
+            int bPix = bPixels[i];
+
+            diff += Math.abs(Color.red(aPix) - Color.red(bPix)); // red
+            diff += Math.abs(Color.green(aPix) - Color.green(bPix)); // green
+            diff += Math.abs(Color.blue(aPix) - Color.blue(bPix)); // blue
+        }
+        diff /= (aPixels.length * 3);
+        return diff;
+    }
+
+    /**
+     * Convert a rectangular patch in a YUV image to an ARGB color array.
+     *
+     * @param w width of the patch.
+     * @param h height of the patch.
+     * @param wOffset offset of the left side of the patch.
+     * @param hOffset offset of the top of the patch.
+     * @param yuvImage a YUV image to select a patch from.
+     * @return the image patch converted to RGB as an ARGB color array.
+     */
+    private static int[] convertPixelYuvToRgba(int w, int h, int wOffset, int hOffset,
+                                               Image yuvImage) {
+        final int CHANNELS = 3; // yuv
+        final float COLOR_RANGE = 255f;
+
+        assertTrue("Invalid argument to convertPixelYuvToRgba",
+                w > 0 && h > 0 && wOffset >= 0 && hOffset >= 0);
+        assertNotNull(yuvImage);
+        assertTrue("YUV image must have format YUV_420_888",
+                yuvImage.getFormat() == ImageFormat.YUV_420_888);
+
+        int height = yuvImage.getHeight();
+        int width = yuvImage.getWidth();
+
+        Rect imageBounds = new Rect(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
+        Rect crop = new Rect(/*left*/wOffset, /*top*/hOffset, /*right*/wOffset + w,
+                /*bottom*/hOffset + h);
+        assertTrue("Output rectangle" + crop + " must lie within image bounds " + imageBounds,
+                imageBounds.contains(crop));
+        Image.Plane[] planes = yuvImage.getPlanes();
+
+        Image.Plane yPlane = planes[0];
+        Image.Plane cbPlane = planes[1];
+        Image.Plane crPlane = planes[2];
+
+        ByteBuffer yBuf = yPlane.getBuffer();
+        int yPixStride = yPlane.getPixelStride();
+        int yRowStride = yPlane.getRowStride();
+        ByteBuffer cbBuf = cbPlane.getBuffer();
+        int cbPixStride = cbPlane.getPixelStride();
+        int cbRowStride = cbPlane.getRowStride();
+        ByteBuffer crBuf = crPlane.getBuffer();
+        int crPixStride = crPlane.getPixelStride();
+        int crRowStride = crPlane.getRowStride();
+
+        int[] output = new int[w * h];
+
+        // TODO: Optimize this with renderscript intrinsics
+        byte[] yRow = new byte[yPixStride * w];
+        byte[] cbRow = new byte[cbPixStride * w / 2];
+        byte[] crRow = new byte[crPixStride * w / 2];
+        yBuf.mark();
+        cbBuf.mark();
+        crBuf.mark();
+        int initialYPos = yBuf.position();
+        int initialCbPos = cbBuf.position();
+        int initialCrPos = crBuf.position();
+        int outputPos = 0;
+        for (int i = hOffset; i < hOffset + h; i++) {
+            yBuf.position(initialYPos + i * yRowStride + wOffset * yPixStride);
+            yBuf.get(yRow);
+            if ((i & 1) == (hOffset & 1)) {
+                cbBuf.position(initialCbPos + (i / 2) * cbRowStride + wOffset * cbPixStride / 2);
+                cbBuf.get(cbRow);
+                crBuf.position(initialCrPos + (i / 2) * crRowStride + wOffset * crPixStride / 2);
+                crBuf.get(crRow);
+            }
+            for (int j = 0, yPix = 0, crPix = 0, cbPix = 0; j < w; j++, yPix += yPixStride) {
+                float y = yRow[yPix] & 0xFF;
+                float cb = cbRow[cbPix] & 0xFF;
+                float cr = crRow[crPix] & 0xFF;
+
+                // convert YUV -> RGB (from JFIF's "Conversion to and from RGB" section)
+                int r = (int) Math.max(0.0f, Math.min(COLOR_RANGE, y + 1.402f * (cr - 128)));
+                int g = (int) Math.max(0.0f,
+                        Math.min(COLOR_RANGE, y - 0.34414f * (cb - 128) - 0.71414f * (cr - 128)));
+                int b = (int) Math.max(0.0f, Math.min(COLOR_RANGE, y + 1.772f * (cb - 128)));
+
+                // Convert to ARGB pixel color (use opaque alpha)
+                output[outputPos++] = Color.rgb(r, g, b);
+
+                if ((j & 1) == 1) {
+                    crPix += crPixStride;
+                    cbPix += cbPixStride;
+                }
+            }
+        }
+        yBuf.rewind();
+        cbBuf.rewind();
+        crBuf.rewind();
+
+        return output;
+    }
 
     /**
      * Test capture a given format stream with yuv stream simultaneously.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
index 004c7da..30cc58e 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -28,7 +28,6 @@
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.CaptureFailure;
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.cts.CameraTestUtils;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 import android.media.CamcorderProfile;
@@ -42,6 +41,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import static junit.framework.Assert.assertTrue;
 import static org.mockito.Mockito.*;
 
 /**
@@ -50,11 +50,14 @@
 public class RobustnessTest extends Camera2AndroidTestCase {
     private static final String TAG = "RobustnessTest";
 
-    private static final int FAILED_CONFIGURE_TIMEOUT = 5000; //ms
+    private static final int CONFIGURE_TIMEOUT = 5000; //ms
+    private static final int CAPTURE_TIMEOUT = 1000; //ms
 
     /**
-     * Test that a {@link CameraCaptureSession} configured with a {@link Surface} with invalid
-     * dimensions fails gracefully.
+     * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing
+     * a dimension other than one of the supported output dimensions.  The buffers produced into
+     * this surface are expected have the dimensions of the closest possible buffer size in the
+     * available stream configurations for a surface with this format.
      */
     public void testBadSurfaceDimensions() throws Exception {
         for (String id : mCameraIds) {
@@ -62,9 +65,21 @@
                 Log.i(TAG, "Testing Camera " + id);
                 openDevice(id);
 
-                // Setup Surface with unconfigured dimensions.
-                SurfaceTexture surfaceTexture = new SurfaceTexture(0);
-                Surface surface = new Surface(surfaceTexture);
+                // Find some size not supported by the camera
+                Size weirdSize = new Size(643, 577);
+                int count = 0;
+                while(mOrderedPreviewSizes.contains(weirdSize)) {
+                    // Really, they can't all be supported...
+                    weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
+                    count++;
+                    assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100);
+                }
+
+                // Setup imageReader with invalid dimension
+                ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
+                        weirdSize.getHeight(), ImageFormat.YUV_420_888, 3);
+
+                Surface surface = imageReader.getSurface();
                 List<Surface> surfaces = new ArrayList<>();
                 surfaces.add(surface);
 
@@ -78,13 +93,34 @@
                 // Check that correct session callback is hit.
                 CameraCaptureSession.StateCallback sessionListener =
                         mock(CameraCaptureSession.StateCallback.class);
-                mCamera.createCaptureSession(surfaces, sessionListener, mHandler);
-                verify(sessionListener, timeout(FAILED_CONFIGURE_TIMEOUT).atLeastOnce()).
-                        onConfigureFailed(any(CameraCaptureSession.class));
-                verify(sessionListener, never()).onConfigured(any(CameraCaptureSession.class));
+                CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera,
+                        surfaces, sessionListener, mHandler);
+
+                verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
+                        onConfigured(any(CameraCaptureSession.class));
+                verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
+                        onReady(any(CameraCaptureSession.class));
+                verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
                 verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
-                verify(sessionListener, never()).onReady(any(CameraCaptureSession.class));
                 verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
+
+                CameraCaptureSession.CaptureCallback captureListener =
+                        mock(CameraCaptureSession.CaptureCallback.class);
+                session.capture(request.build(), captureListener, mHandler);
+
+                verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
+                        onCaptureCompleted(any(CameraCaptureSession.class),
+                                any(CaptureRequest.class), any(TotalCaptureResult.class));
+                verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
+                        any(CaptureRequest.class), any(CaptureFailure.class));
+
+                Image image = imageReader.acquireLatestImage();
+                int imageWidth = image.getWidth();
+                int imageHeight = image.getHeight();
+                Size actualSize = new Size(imageWidth, imageHeight);
+
+                assertTrue("Camera does not contain outputted image resolution " + actualSize,
+                        mOrderedPreviewSizes.contains(actualSize));
             } finally {
                 closeDevice(id);
             }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index cbb0a3d..1f6b3cf 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -22,7 +22,9 @@
 import android.media.MediaCodecInfo.CodecProfileLevel;
 import static android.media.MediaCodecInfo.CodecProfileLevel.*;
 import static android.media.MediaFormat.MIMETYPE_VIDEO_AVC;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_H263;
 import static android.media.MediaFormat.MIMETYPE_VIDEO_HEVC;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_MPEG4;
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.media.MediaPlayer;
@@ -76,6 +78,39 @@
         }
     }
 
+    // Android device implementations with H.263 encoders, MUST support Level 45.
+    public void testH263EncoderProfileAndLevel() throws Exception {
+        if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_H263)) {
+            return; // skip
+        }
+
+        assertTrue(
+                "H.263 must support Level 45",
+                hasEncoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level45));
+    }
+
+    // Android device implementations with H.263 decoders, MUST support Level 30.
+    public void testH263DecoderProfileAndLevel() throws Exception {
+        if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_H263)) {
+            return; // skip
+        }
+
+        assertTrue(
+                "H.263 must support Level 30",
+                hasDecoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level30));
+    }
+
+    // Android device implementations with MPEG-4 decoders, MUST support Simple Profile Level 3.
+    public void testMpeg4DecoderProfileAndLevel() throws Exception {
+        if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_MPEG4)) {
+            return; // skip
+        }
+
+        assertTrue(
+                "MPEG-4 must support Simple Profile Level 3",
+                hasDecoder(MIMETYPE_VIDEO_MPEG4, MPEG4ProfileSimple, MPEG4Level3));
+    }
+
     // Android device implementations, when supporting H.265 codec MUST support the Main Profile
     // Level 3 Main tier.
     // Android Television Devices MUST support the Main Profile Level 4.1 Main tier.
@@ -279,7 +314,18 @@
             try {
                 CodecCapabilities caps = info.getCapabilitiesForType(mime);
                 for (CodecProfileLevel pl : caps.profileLevels) {
-                    if (pl.profile == profile && pl.level >= level) {
+                    if (pl.profile != profile) {
+                        continue;
+                    }
+
+                    // H.263 levels are not completely ordered:
+                    // Level45 support only implies Level10 support
+                    if (mime.equalsIgnoreCase(MIMETYPE_VIDEO_H263)) {
+                        if (pl.level != level && pl.level == H263Level45 && level > H263Level10) {
+                            continue;
+                        }
+                    }
+                    if (pl.level >= level) {
                         return true;
                     }
                 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 4030636..e04517d 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -50,9 +50,10 @@
             mAllCodecs.getCodecInfos();
 
     class CodecType {
-        CodecType(String type, boolean isEncoder) {
+        CodecType(String type, boolean isEncoder, MediaFormat sampleFormat) {
             mMimeTypeName = type;
             mIsEncoder = isEncoder;
+            mSampleFormat = sampleFormat;
         }
 
         boolean equals(CodecType codecType) {
@@ -60,10 +61,35 @@
                     mIsEncoder == codecType.mIsEncoder;
         }
 
-        String mMimeTypeName;
-        boolean mIsEncoder;
+        boolean canBeFound() {
+            return codecCanBeFound(mIsEncoder, mSampleFormat);
+        }
+
+        @Override
+        public String toString() {
+            return mMimeTypeName + (mIsEncoder ? " encoder" : " decoder") + " for " + mSampleFormat;
+        }
+
+        private String mMimeTypeName;
+        private boolean mIsEncoder;
+        private MediaFormat mSampleFormat;
     };
 
+    class AudioCodec extends CodecType {
+        AudioCodec(String mime, boolean isEncoder, int sampleRate) {
+            super(mime, isEncoder, MediaFormat.createAudioFormat(
+                    mime, sampleRate, 1 /* channelCount */));
+        }
+    }
+
+    class VideoCodec extends CodecType {
+        VideoCodec(String mime, boolean isEncoder) {
+            // implicit assumption that QVGA video is always valid
+            super(mime, isEncoder, MediaFormat.createVideoFormat(
+                    mime, 176 /* width */, 144 /* height */));
+        }
+    }
+
     public static void testMediaCodecXmlFileExist() {
         File file = new File(MEDIA_CODEC_XML_FILE);
         assertTrue("/etc/media_codecs.xml does not exist", file.exists());
@@ -241,6 +267,9 @@
         List<CodecType> requiredList = getRequiredCodecTypes();
         List<CodecType> supportedList = getSupportedCodecTypes();
         assertTrue(areRequiredCodecTypesSupported(requiredList, supportedList));
+        for (CodecType type : requiredList) {
+            assertTrue("cannot find " + type, type.canBeFound());
+        }
     }
 
     private boolean hasCamera() {
@@ -268,80 +297,8 @@
                 && !pm.hasSystemFeature(pm.FEATURE_TELEVISION);
     }
 
-    // H263 baseline profile must be supported
-    public void testIsH263BaselineProfileSupported() {
-        if (!hasCamera()) {
-            Log.d(TAG, "not required without camera");
-            return;
-        }
-
-        int profile = CodecProfileLevel.H263ProfileBaseline;
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_H263, false, profile));
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_H263, true, profile));
-    }
-
-    // AVC baseline profile must be supported
-    public void testIsAVCBaselineProfileSupported() {
-        int profile = CodecProfileLevel.AVCProfileBaseline;
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_AVC, false, profile));
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_AVC, true, profile));
-    }
-
-    // HEVC main profile must be supported
-    public void testIsHEVCMainProfileSupported() {
-        int profile = CodecProfileLevel.HEVCProfileMain;
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_HEVC, false, profile));
-    }
-
-    // MPEG4 simple profile must be supported
-    public void testIsM4VSimpleProfileSupported() {
-        if (!hasCamera()) {
-            Log.d(TAG, "not required without camera");
-            return;
-        }
-
-        int profile = CodecProfileLevel.MPEG4ProfileSimple;
-        assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_MPEG4, false, profile));
-
-        // FIXME: no support for M4v simple profile video encoder
-        // assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_MPEG4, true, profile));
-    }
-
-    /*
-     * Find whether the given codec is supported
-     */
-    private boolean checkProfileSupported(
-            String mime, boolean isEncoder, int profile) {
-        return profileIsListed(mime, isEncoder, profile) &&
-                codecCanBeFound(mime, isEncoder);
-    }
-
-    private boolean profileIsListed(
-        String mime, boolean isEncoder, int profile) {
-
-        for (MediaCodecInfo info : mRegularInfos) {
-            if (isEncoder != info.isEncoder()) {
-                continue;
-            }
-
-            for (String type : info.getSupportedTypes()) {
-                if (type.equalsIgnoreCase(mime)) {
-                    CodecCapabilities cap = info.getCapabilitiesForType(type);
-                    for (CodecProfileLevel pl : cap.profileLevels) {
-                        if (pl.profile == profile) {
-                            return true;
-                        }
-                    }
-                }
-            }
-        }
-        return false;
-    }
-
     // Find whether the given codec can be found using MediaCodecList.find methods.
-    private boolean codecCanBeFound(String mime, boolean isEncoder) {
-        // implicit assumption that QVGA video is always valid.
-        MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
+    private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) {
         String codecName = isEncoder
                 ? mRegularCodecs.findEncoderForFormat(format)
                 : mRegularCodecs.findDecoderForFormat(format);
@@ -380,7 +337,7 @@
             assertTrue("Unexpected number of supported types", types.length > 0);
             boolean isEncoder = info.isEncoder();
             for (int j = 0; j < types.length; ++j) {
-                supportedList.add(new CodecType(types[j], isEncoder));
+                supportedList.add(new CodecType(types[j], isEncoder, null /* sampleFormat */));
             }
         }
         return supportedList;
@@ -393,39 +350,51 @@
     private List<CodecType> getRequiredCodecTypes() {
         List<CodecType> list = new ArrayList<CodecType>(16);
 
-        // Mandatory audio codecs
+        // Mandatory audio decoders
 
         // flac decoder is not omx-based yet
-        // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false));  // flac decoder
-        list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_MPEG, false));     // mp3 decoder
-        list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_VORBIS, false));   // vorbis decoder
-        list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AAC, false));      // aac decoder
-        list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_RAW, false));      // raw/pcm decoder
+        // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false, 8000));
+        // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false, 48000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_MPEG, false, 8000));  // mp3
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_MPEG, false, 48000)); // mp3
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_VORBIS, false, 8000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_VORBIS, false, 48000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, false, 8000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, false, 48000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_RAW, false, 8000));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_RAW, false, 44100));
+        list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_OPUS, false, 48000));
+
+        // Mandatory audio encoders (for non-watch devices with camera)
+
         if (hasMicrophone() && !isWatch()) {
-            list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AAC, true));       // aac encoder
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, true, 16000));
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, true, 48000));
             // flac encoder is not required
-            // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, true));   // flac encoder
-        }
-        if (isHandheld()) {
-            list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_NB, false));   // amrnb decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_NB, true));    // amrnb encoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_WB, false));   // amrwb decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_WB, true));    // amrwb encoder
+            // list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_FLAC, true));  // encoder
         }
 
-        // Mandatory video codecs
+        // Mandatory audio encoders for handheld devices
+        if (isHandheld()) {
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_NB, false, 8000));  // decoder
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_NB, true,  8000));  // encoder
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_WB, false, 16000)); // decoder
+            list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_WB, true,  16000)); // encoder
+        }
+
+        // Mandatory video codecs (for non-watch devices)
 
         if (!isWatch()) {
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_AVC, false));    // avc decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_AVC, true));     // avc encoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP8, false));    // vp8 decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP8, true));     // vp8 encoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP9, false));    // vp9 decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_HEVC, false));   // hevc decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_MPEG4, false));  // m4v decoder
-            list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_H263, false));   // h263 decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_AVC, false));   // avc decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_AVC, true));    // avc encoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false));   // vp8 decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true));    // vp8 encoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false));   // vp9 decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false));  // hevc decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
+            list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false));  // h263 decoder
             if (hasCamera()) {
-                list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_H263, true));    // h263 encoder
+                list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, true)); // h263 encoder
             }
         }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
index a498eac..32fbfb5 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
@@ -109,6 +109,7 @@
         String[] supported = getSupportedVideos();
         if (supported.length == 0) {
             MediaUtils.skipTest("no codec found");
+            return;
         }
 
         Random random = new Random(seed);
diff --git a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java b/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
index 49fc59c..e9bfb43 100644
--- a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
+++ b/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
@@ -130,6 +130,7 @@
 
         // Check the response is an echo reply.
         byte[] response = new byte[bytesRead];
+        responseBuffer.flip();
         responseBuffer.get(response, 0, bytesRead);
         assertEquals((byte) 0x81, response[0]);
 
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 6069ee6..4c92da7 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -28,7 +28,7 @@
 public class BuildVersionTest extends TestCase {
 
     private static final String LOG_TAG = "BuildVersionTest";
-    private static final Set<String> EXPECTED_RELEASES = new HashSet<String>(Arrays.asList("5.0"));
+    private static final Set<String> EXPECTED_RELEASES = new HashSet<String>(Arrays.asList("5.0.1"));
     private static final int EXPECTED_SDK = 21;
     private static final String EXPECTED_BUILD_VARIANT = "user";
     private static final String EXPECTED_TAG = "release-keys";
diff --git a/tests/tests/security/src/android/security/cts/CertificateData.java b/tests/tests/security/src/android/security/cts/CertificateData.java
index da098f3..de7c15e 100644
--- a/tests/tests/security/src/android/security/cts/CertificateData.java
+++ b/tests/tests/security/src/android/security/cts/CertificateData.java
@@ -28,9 +28,11 @@
       "91:C6:D6:EE:3E:8A:C8:63:84:E5:48:C2:99:29:5C:75:6C:81:7B:81",
       "4A:65:D5:F4:1D:EF:39:B8:B8:90:4A:4A:D3:64:81:33:CF:C7:A1:D1",
       "16:32:47:8D:89:F9:21:3A:92:00:85:63:F5:A4:A7:D3:12:40:8A:D6",
+      "D1:CB:CA:5D:B2:D5:2A:7F:69:3B:67:4D:E5:F0:5A:1D:0C:95:7D:F0",
       "4D:23:78:EC:91:95:39:B5:00:7F:75:8F:03:3B:21:1E:C5:4D:8B:CF",
       "E7:B4:F6:9D:61:EC:90:69:DB:7E:90:A7:40:1A:3C:F4:7D:4F:E8:EE",
       "DD:E1:D2:A9:01:80:2E:1D:87:5E:84:B3:80:7E:4B:B1:FD:99:41:34",
+      "69:69:56:2E:40:80:F4:24:A1:E7:19:9F:14:BA:F3:EE:58:AB:6A:BB",
       "92:5A:8F:8D:2C:6D:04:E0:66:5F:59:6A:FF:22:D8:63:E8:25:6F:3F",
       "75:E0:AB:B6:13:85:12:27:1C:04:F8:5F:DD:DE:38:E4:B7:24:2E:FE",
       "40:9D:4B:D9:17:B5:5C:27:B6:9B:64:CB:98:22:44:0D:CD:09:B8:89",
@@ -49,6 +51,7 @@
       "27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4",
       "AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A",
       "8D:17:84:D5:37:F3:03:7D:EC:70:FE:57:8B:51:9A:99:E6:10:D7:B0",
+      "1F:24:C6:30:CD:A4:18:EF:20:69:FF:AD:4F:DD:5F:46:3A:1B:69:AA",
       "AE:50:83:ED:7C:F4:5C:BC:8F:61:C6:21:FE:68:5D:79:42:21:15:6E",
       "DA:FA:F7:FA:66:84:EC:06:8F:14:50:BD:C7:C2:81:A5:BC:A9:64:57",
       "74:F8:A3:C3:EF:E7:B3:90:06:4B:83:90:3C:21:64:60:20:E5:DF:CE",
@@ -56,6 +59,7 @@
       "3E:2B:F7:F2:03:1B:96:F3:8C:E6:C4:D8:A8:5D:3E:2D:58:47:6A:0F",
       "A3:F1:33:3F:E2:42:BF:CF:C5:D1:4E:8F:39:42:98:40:68:10:D1:A0",
       "5F:43:E5:B1:BF:F8:78:8C:AC:1C:C7:CA:4A:9A:C6:22:2B:CC:34:C6",
+      "2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E",
       "A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36",
       "59:22:A1:E1:5A:EA:16:35:21:F8:98:39:6A:46:46:B0:44:1B:0F:A9",
       "D4:DE:20:D0:5E:66:FC:53:FE:1A:50:88:2C:78:DB:28:52:CA:E4:74",
@@ -155,6 +159,7 @@
       "87:82:C6:C3:04:35:3B:CF:D2:96:92:D2:59:3E:7D:44:D9:34:FF:11",
       "59:0D:2D:7D:88:4F:40:2E:61:7E:A5:62:32:17:65:CF:17:D8:94:E9",
       "AE:C5:FB:3F:C8:E1:BF:C4:E5:4F:03:07:5A:9A:E8:00:B7:F7:B6:FA",
+      "AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4",
       "5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74",
       "2A:C8:D5:8B:57:CE:BF:2F:49:AF:F2:FC:76:8F:51:14:62:90:7A:41",
       "F1:7F:6F:B6:31:DC:99:E3:A3:C8:7F:FE:1C:F1:81:10:88:D9:60:33",
diff --git a/tests/tests/uirendering/res/layout/blue_padded_layout.xml b/tests/tests/uirendering/res/layout/blue_padded_layout.xml
index 1cd1b21..68c9cd1 100644
--- a/tests/tests/uirendering/res/layout/blue_padded_layout.xml
+++ b/tests/tests/uirendering/res/layout/blue_padded_layout.xml
@@ -14,6 +14,7 @@
        limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/test_root"
         android:layout_width="200px"
         android:layout_height="200px"
         android:clipChildren="false">
diff --git a/tests/tests/uirendering/res/layout/blue_padded_square.xml b/tests/tests/uirendering/res/layout/blue_padded_square.xml
index 0f254d4..71f4b0c 100644
--- a/tests/tests/uirendering/res/layout/blue_padded_square.xml
+++ b/tests/tests/uirendering/res/layout/blue_padded_square.xml
@@ -14,6 +14,7 @@
        limitations under the License.
   -->
 <View xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="100px"
-        android:layout_height="100px"
-        android:background="@drawable/blue_padded_square"/>
+    android:id="@+id/test_root"
+    android:layout_width="100px"
+    android:layout_height="100px"
+    android:background="@drawable/blue_padded_square"/>
diff --git a/tests/tests/uirendering/res/layout/simple_rect_layout.xml b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
index e64c4e9..b570df8 100644
--- a/tests/tests/uirendering/res/layout/simple_rect_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
@@ -13,11 +13,11 @@
        See the License for the specific language governing permissions and
        limitations under the License.
   -->
-
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
+    android:id="@+id/test_root"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
     <View android:layout_width="100px"
         android:layout_height="100px"
diff --git a/tests/tests/uirendering/res/layout/simple_red_layout.xml b/tests/tests/uirendering/res/layout/simple_red_layout.xml
index 1ae3e38..2d2d189 100644
--- a/tests/tests/uirendering/res/layout/simple_red_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_red_layout.xml
@@ -14,6 +14,7 @@
        limitations under the License.
   -->
 <View xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:id="@+id/test_root"
+    android:layout_width="180px"
+    android:layout_height="180px"
     android:background="#f00" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 978dc0b..36be5f0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -41,9 +41,11 @@
             for (int x = 0 ; x < width ; x++) {
                 int index = indexFromXAndY(x, y, stride, offset);
                 if (ideal[index] != given[index]) {
-                    Log.d(TAG, "Failure on position x = " + x + " y = " + y);
-                    Log.d(TAG, "Expected color : " + Integer.toHexString(ideal[index]) +
-                            " given color : " + Integer.toHexString(given[index]));
+                    if (count < 50) {
+                        Log.d(TAG, "Failure on position x = " + x + " y = " + y);
+                        Log.d(TAG, "Expected color : " + Integer.toHexString(ideal[index]) +
+                                " given color : " + Integer.toHexString(given[index]));
+                    }
                     count++;
                 }
             }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
index ab809f4..0bdcc9b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
@@ -38,30 +38,33 @@
 
 
     public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
-        boolean res = true;
+        int failCount = 0;
         int[] differenceMap = new int[bitmap.length];
         for (int y = 0 ; y < height ; y++) {
             for (int x = 0 ; x < width ; x++) {
                 int index = indexFromXAndY(x, y, stride, offset);
                 int expectedColor = getExpectedColor(x, y);
                 if (!verifyPixel(bitmap[index], expectedColor)) {
-                    Log.d(TAG, "Expected : " + Integer.toHexString(expectedColor)
-                            + " received : " + Integer.toHexString(bitmap[index])
-                            + " at position (" + x + "," + y + ")");
-                    res = false;
+                    if (failCount < 50) {
+                        Log.d(TAG, "Expected : " + Integer.toHexString(expectedColor)
+                                + " received : " + Integer.toHexString(bitmap[index])
+                                + " at position (" + x + "," + y + ")");
+                    }
+                    failCount++;
                     differenceMap[index] = FAIL_COLOR;
                 } else {
                     differenceMap[index] = PASS_COLOR;
                 }
             }
         }
-        if (!res) {
+        boolean success = failCount == 0;
+        if (!success) {
             mDifferenceBitmap = Bitmap.createBitmap(ActivityTestBase.TEST_WIDTH,
                     ActivityTestBase.TEST_HEIGHT, Bitmap.Config.ARGB_8888);
             mDifferenceBitmap.setPixels(differenceMap, offset, stride, 0, 0,
                     ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
         }
-        return res;
+        return success;
     }
 
     protected boolean verifyPixel(int color, int expectedColor) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index 0ba0f69..4667ee9 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -15,32 +15,26 @@
  */
 package android.uirendering.cts.testclasses;
 
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
+import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import com.android.cts.uirendering.R;
 
 import android.test.suitebuilder.annotation.SmallTest;
-import android.uirendering.cts.bitmapcomparers.BitmapComparer;
-import android.uirendering.cts.bitmapcomparers.ExactComparer;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
-
-/**
- * Created to see how custom views made with XML and programatic code will work.
- */
 public class LayoutTests extends ActivityTestBase {
-    private BitmapComparer mBitmapComparer;
-
-    public LayoutTests() {
-        mBitmapComparer = new ExactComparer();
-    }
-
     @SmallTest
     public void testSimpleRedLayout() {
-        createTest().addLayout(R.layout.simple_red_layout, null).runWithComparer(mBitmapComparer);
+        createTest().addLayout(R.layout.simple_red_layout, null, false).runWithVerifier(
+                new ColorVerifier(Color.RED));
     }
 
     @SmallTest
     public void testSimpleRectLayout() {
-        createTest().addLayout(R.layout.simple_rect_layout, null).runWithComparer(mBitmapComparer);
+        createTest().addLayout(R.layout.simple_rect_layout, null, false).runWithVerifier(
+                new RectVerifier(Color.WHITE, Color.BLUE, new Rect(0, 0, 100, 100)));
     }
 }
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index 1acdc20..da2db48 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -62,7 +62,7 @@
     };
 
     // TODO: attempt to reduce
-    static final int TOLERANCE = 10;
+    static final int TOLERANCE = 16;
     static BitmapVerifier makeClipVerifier(Rect blueBoundsRect) {
         return new RectVerifier(Color.WHITE, Color.BLUE, blueBoundsRect, TOLERANCE);
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 278b03b..386c015 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -38,7 +38,7 @@
  */
 public abstract class ActivityTestBase extends
         ActivityInstrumentationTestCase2<DrawActivity> {
-    public static final String TAG_NAME = "ActivityTestBase";
+    public static final String TAG = "ActivityTestBase";
     public static final boolean DEBUG = false;
     public static final boolean USE_RS = false;
     public static final int TEST_WIDTH = 180;
@@ -97,7 +97,7 @@
 
             for (TestCase testCase : testCases) {
                 if (!testCase.wasTestRan) {
-                    Log.w(TAG_NAME, getName() + " not all of the tests were ran");
+                    Log.w(TAG, getName() + " not all of the tests ran");
                     break;
                 }
             }
@@ -220,6 +220,11 @@
          * every test case is tested against it.
          */
         public void runWithComparer(BitmapComparer bitmapComparer) {
+            if (getActivity().getOnWatch()) {
+                Log.d(TAG, getName() + "skipped");
+                return;
+            }
+
             if (mTestCases.size() == 0) {
                 throw new IllegalStateException("Need at least one test to run");
             }
@@ -238,6 +243,11 @@
          * the verifier given.
          */
         public void runWithVerifier(BitmapVerifier bitmapVerifier) {
+            if (getActivity().getOnWatch()) {
+                Log.d(TAG, getName() + "skipped");
+                return;
+            }
+
             if (mTestCases.size() == 0) {
                 throw new IllegalStateException("Need at least one test to run");
             }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 4d4a012..166b6ff 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -17,15 +17,16 @@
 
 import android.annotation.Nullable;
 import android.app.Activity;
-import android.content.Context;
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.webkit.WebView;
 
+import com.android.cts.uirendering.R;
+
 /**
  * A generic activity that uses a view specified by the user.
  */
@@ -36,16 +37,17 @@
 
     private Handler mHandler;
     private View mView;
+    private boolean mOnWatch;
 
     public void onCreate(Bundle bundle){
         super.onCreate(bundle);
         mHandler = new RenderSpecHandler();
+        int uiMode = getResources().getConfiguration().uiMode;
+        mOnWatch = (uiMode & Configuration.UI_MODE_TYPE_WATCH) == Configuration.UI_MODE_TYPE_WATCH;
     }
 
-    @Override
-    public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
-        mView = parent;
-        return super.onCreateView(parent, name, context, attrs);
+    public boolean getOnWatch() {
+        return mOnWatch;
     }
 
     public void enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient, String webViewUrl,
@@ -85,6 +87,10 @@
             switch (message.what) {
                 case LAYOUT_MSG: {
                     setContentView(message.arg1);
+                    mView = findViewById(R.id.test_root);
+                    if (mView == null) {
+                        throw new IllegalStateException("test_root failed to inflate");
+                    }
                 } break;
 
                 case CANVAS_MSG: {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index 41e255b..8dd98b0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -99,9 +99,25 @@
         saveFile(className, testName, SINGULAR_FILE_NAME, bitmap);
     }
 
+    private static void logIfBitmapSolidColor(String bitmapName, Bitmap bitmap) {
+        int firstColor = bitmap.getPixel(0, 0);
+        for (int x = 0; x < bitmap.getWidth(); x++) {
+            for (int y = 0; y < bitmap.getHeight(); y++) {
+                if (bitmap.getPixel(x, y) != firstColor) {
+                    return;
+                }
+            }
+        }
+
+        Log.w(TAG, String.format("%s entire bitmap color is %x", bitmapName, firstColor));
+    }
+
     private static void saveFile(String className, String testName, String fileName, Bitmap bitmap) {
-        Log.d(TAG, "Saving file : " + testName + "_" + fileName + " in directory : " + className);
-        File file = new File(CAPTURE_SUB_DIRECTORY + className, testName + "_" + fileName);
+        String bitmapName = testName + "_" + fileName;
+        Log.d(TAG, "Saving file : " + bitmapName + " in directory : " + className);
+        logIfBitmapSolidColor(bitmapName, bitmap);
+
+        File file = new File(CAPTURE_SUB_DIRECTORY + className, bitmapName);
         FileOutputStream fileStream = null;
         try {
             fileStream = new FileOutputStream(file);
diff --git a/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java b/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
index fb44334..e8f0cab 100644
--- a/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
@@ -144,7 +144,7 @@
 
     public void testGuessFileName() {
         String url = "ftp://example.url/test";
-        assertEquals("test.jpeg", URLUtil.guessFileName(url, null, "image/jpeg"));
+        assertEquals("test.jpg", URLUtil.guessFileName(url, null, "image/jpeg"));
 
         assertEquals("test.bin", URLUtil.guessFileName(url, null, "application/octet-stream"));
     }
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
index c8211f6..5259736 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -404,8 +404,8 @@
         // exceptional
         try {
             tableLayout.addView(null);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
         }
     }
 
@@ -445,8 +445,8 @@
 
         try {
             tableLayout.addView(null, -1);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
         }
     }
 
@@ -477,8 +477,8 @@
 
         try {
             tableLayout.addView(null, new TableLayout.LayoutParams(200, 300));
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
         }
 
         try {
@@ -540,8 +540,8 @@
 
         try {
             tableLayout.addView(null, -1, new TableLayout.LayoutParams(200, 300));
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException e) {
+            fail("Should throw IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
         }
 
         try {
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index 42724e5..7e8a19e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "5.0_r1.93";
+    public static final String CTS_BUILD_VERSION = "5.0_r1.94";
 
     /**
      * {@inheritDoc}