Merge "Camera2: Test creating multiple sessions" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 9021921..db777b5 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -172,6 +172,7 @@
     CtsTextTestCases \
     CtsTextureViewTestCases \
     CtsThemeTestCases \
+    CtsTransitionTestCases \
     CtsTvTestCases \
     CtsUiAutomationTestCases \
     CtsUiRenderingTestCases \
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index 03f8ff9..5475a59 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -369,6 +369,28 @@
     rgb.reshape(w*h*3)[:] = flt.reshape(w*h*3)[:]
     return rgb.astype(numpy.float32) / 255.0
 
+def load_rgb_image(fname):
+    """Load a standard image file (JPG, PNG, etc.).
+
+    Args:
+        fname: The path of the file to load.
+
+    Returns:
+        RGB float-3 image array, with pixel values in [0.0, 1.0].
+    """
+    img = Image.open(fname)
+    w = img.size[0]
+    h = img.size[1]
+    a = numpy.array(img)
+    if len(a.shape) == 3 and a.shape[2] == 3:
+        # RGB
+        return a.reshape(h,w,3) / 255.0
+    elif len(a.shape) == 2 or len(a.shape) == 3 and a.shape[2] == 1:
+        # Greyscale; convert to RGB
+        return a.reshape(h*w).repeat(3).reshape(h,w,3) / 255.0
+    else:
+        raise its.error.Error('Unsupported image type')
+
 def load_yuv420_to_rgb_image(yuv_fname,
                              w, h,
                              ccm_yuv_to_rgb=DEFAULT_YUV_TO_RGB_CCM,
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 98e8acd..ac9466d 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -971,6 +971,17 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.camera.any" />
         </activity>
 
+        <activity android:name=".camera.flashlight.CameraFlashlightActivity"
+                  android:label="@string/camera_flashlight_test"
+                  android:configChanges="keyboardHidden|orientation|screenSize">
+            <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" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.camera.flash" />
+        </activity>
+
         <activity android:name=".usb.UsbAccessoryTestActivity"
                 android:label="@string/usb_accessory_test"
                 android:configChanges="keyboardHidden|orientation|screenSize">
@@ -1438,6 +1449,17 @@
                     android:value="android.software.live_tv" />
         </activity>
 
+        <activity android:name=".tv.TimeShiftTestActivity"
+                android:label="@string/tv_time_shift_test">
+            <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_tv" />
+            <meta-data android:name="test_required_features"
+                    android:value="android.software.live_tv" />
+        </activity>
+
         <activity android:name=".screenpinning.ScreenPinningTestActivity"
             android:label="@string/screen_pinning_test">
             <intent-filter>
@@ -1449,12 +1471,6 @@
                        android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
         </activity>
 
-        <activity android:name=".tv.MockTvInputSettingsActivity">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-            </intent-filter>
-        </activity>
-
         <activity android:name=".tv.MockTvInputSetupActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/apps/CtsVerifier/res/layout/camera_flashlight.xml b/apps/CtsVerifier/res/layout/camera_flashlight.xml
new file mode 100644
index 0000000..2d4378c
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/camera_flashlight.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="bottom"
+    android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/flash_instruction_text"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="2"
+            android:gravity="center"
+            android:text="@string/camera_flashlight_start_text" />
+
+        <Button
+            android:id="@+id/flash_instruction_button"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="100dp"
+            android:layout_marginRight="100dp"
+            android:text="@string/camera_flashlight_start_button" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:layout_marginLeft="50dp"
+            android:layout_marginRight="50dp"
+            android:layout_marginBottom="50dp"
+            android:orientation="horizontal">
+
+            <Button
+                android:id="@+id/flash_on_button"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:text="@string/camera_flashlight_on_button" />
+
+            <Button
+                android:id="@+id/flash_off_button"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:text="@string/camera_flashlight_off_button" />
+
+        </LinearLayout>
+
+    <include layout="@layout/pass_fail_buttons"/>
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 7e67e9f..ad41891 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -842,6 +842,25 @@
     <string name="its_test_passed">All Camera ITS tests passed.  Pass button enabled!</string>
     <string name="its_test_failed">Some Camera ITS tests failed.</string>
 
+    <!-- Strings for the Camera Flashlight test activity -->
+    <string name="camera_flashlight_test">Camera Flashlight</string>
+    <string name="camera_flashlight_info">
+        This test checks the flashlight functionality. It will turn on and off the flashlight of
+        each camera device that has a flash unit. Follow the instructions on screen and observe the
+        flashlight status changing.
+    </string>
+    <string name="camera_flashlight_start_button">Start</string>
+    <string name="camera_flashlight_next_button">Next</string>
+    <string name="camera_flashlight_done_button">Done</string>
+    <string name="camera_flashlight_on_button">On</string>
+    <string name="camera_flashlight_off_button">Off</string>
+    <string name="camera_flashlight_start_text">Press Start to start flashlight test.</string>
+    <string name="camera_flashlight_question_text">Is Camera %1$s flashlight on or off?</string>
+    <string name="camera_flashlight_next_text">Ok. Press next.</string>
+    <string name="camera_flashlight_failed_text">Test failed. Press Done or Fail button.</string>
+    <string name="camera_flashlight_passed_text">All tests passed. Press Done or Pass button.
+    </string>
+
     <!-- Strings for StreamingVideoActivity -->
     <string name="streaming_video">Streaming Video Quality Verifier</string>
     <string name="streaming_video_info">This is a test for assessing the quality of streaming videos.  Play each stream and verify that the video is smooth and in sync with the audio, and that there are no quality problems.</string>
@@ -1597,6 +1616,41 @@
     The Spanish audio track should be selected.
     </string>
 
+    <string name="tv_time_shift_test">TV app time shift test</string>
+    <string name="tv_time_shift_test_info">
+    This test verifies that the TV app invokes proper time shift APIs in the framwork.
+    </string>
+    <string name="tv_time_shift_test_pause_resume">
+    Press the \"Launch TV app\" button. Verify that the playback control is available.
+    Pause the playback and then resume it.
+    </string>
+    <string name="tv_time_shift_test_verify_resume_after_pause">
+    The playback should be resumed after pause.
+    </string>
+    <string name="tv_time_shift_test_verify_position_tracking">
+    The playback position tracking should be activated.
+    </string>
+    <string name="tv_time_shift_test_speed_rate">
+    Press the \"Launch TV app\" button. Verify that the playback control is available.
+    Rewind the playback and in a few seconds fast-forward it.
+    </string>
+    <string name="tv_time_shift_test_verify_rewind">
+    The playback should be rewinded.
+    </string>
+    <string name="tv_time_shift_test_verify_fast_forward">
+    The playback should be fast-forwarded.
+    </string>
+    <string name="tv_time_shift_test_seek">
+    Press the \"Launch TV app\" button. Verify that the playback control is available.
+    Seek to previous and then seek to next.
+    </string>
+    <string name="tv_time_shift_test_verify_seek_to_previous">
+    The playback position should be moved to the previous position.
+    </string>
+    <string name="tv_time_shift_test_verify_seek_to_next">
+    The playback position should be moved to the next position.
+    </string>
+
     <string name="overlay_view_text">Overlay View Dummy Text</string>
     <string name="fake_rating">Fake</string>
 
diff --git a/apps/CtsVerifier/res/xml/mock_tv_input_service.xml b/apps/CtsVerifier/res/xml/mock_tv_input_service.xml
index 1a2cf86..d9cb867 100644
--- a/apps/CtsVerifier/res/xml/mock_tv_input_service.xml
+++ b/apps/CtsVerifier/res/xml/mock_tv_input_service.xml
@@ -15,5 +15,4 @@
 -->
 
 <tv-input xmlns:android="http://schemas.android.com/apk/res/android"
-    android:setupActivity="com.android.cts.verifier.tv.MockTvInputSetupActivity"
-    android:settingsActivity="com.android.cts.verifier.tv.MockTvInputSettingsActivity" />
+    android:setupActivity="com.android.cts.verifier.tv.MockTvInputSetupActivity" />
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/flashlight/CameraFlashlightActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/flashlight/CameraFlashlightActivity.java
new file mode 100644
index 0000000..4d37b3ee
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/flashlight/CameraFlashlightActivity.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2015 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.flashlight;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import android.content.Context;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraCharacteristics;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import java.util.HashSet;
+import java.util.HashMap;
+
+/**
+ * This test checks the flashlight functionality by turning on and off the flashlight. After it
+ * turns on or off the flashlight, it asks for user input to verify the flashlight status. The
+ * test will pass when the user input is correct for all camera devices with a flash unit.
+ */
+public class CameraFlashlightActivity extends PassFailButtons.Activity {
+
+    private static final String TAG = "CameraFlashlight";
+
+    private CameraManager mCameraManager;
+    private TestState mTestState;
+    private final HashSet<String> mPendingCameraIds = new HashSet<>();
+    private String mCurrentCameraId;
+
+    private Button mInstructionButton;
+    private Button mOnButton;
+    private Button mOffButton;
+    private TextView mInstructionTextView;
+    private final HashSet<View> mAllButtons = new HashSet<>();
+    // TestState -> enabled buttons
+    private final HashMap<TestState, HashSet<View>> mStateButtonsMap = new HashMap<>();
+
+    private enum TestState {
+        NOT_STARTED,
+        TESTING_ON,
+        WAITING_ON_CALLBACK_ON,
+        RESPONDED_ON_CORRECTLY,
+        WAITING_ON_CALLBACK_OFF,
+        TESTING_OFF,
+        RESPONDED_OFF_CORRECTLY,
+        ALL_PASSED,
+        FAILED
+    }
+
+    private final View.OnClickListener mInstructionButtonListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            switch (mTestState) {
+                case NOT_STARTED:
+                    // Start testing turning on the first camera's flashlight.
+                    // Fall through.
+                case RESPONDED_OFF_CORRECTLY:
+                    // Current camera passed. Start testing turning on next camera's flashlight.
+                    if (mPendingCameraIds.size() == 0) {
+                        // Passed
+                        mTestState = TestState.ALL_PASSED;
+                        updateButtonsAndInstructionLocked();
+                        return;
+                    }
+
+                    mCurrentCameraId = (String)mPendingCameraIds.toArray()[0];
+                    mPendingCameraIds.remove(mCurrentCameraId);
+
+                    try {
+                        mCameraManager.setTorchMode(mCurrentCameraId, true);
+                        mTestState = TestState.WAITING_ON_CALLBACK_ON;
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        mTestState = TestState.FAILED;
+                    }
+                    break;
+
+                case RESPONDED_ON_CORRECTLY:
+                    // Flashlight is on and user responded correctly.
+                    // Turning off the flashlight.
+                    try {
+                        mCameraManager.setTorchMode(mCurrentCameraId, false);
+                        mTestState = TestState.WAITING_ON_CALLBACK_OFF;
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        mTestState = TestState.FAILED;
+                    }
+                    break;
+
+                case FAILED:
+                    // The test failed, report failure.
+                    if (mCurrentCameraId != null) {
+                        try {
+                            mCameraManager.setTorchMode(mCurrentCameraId, false);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            Log.e(TAG, "Test failed but cannot turn off the torch");
+                        }
+                    }
+                    setTestResultAndFinish(false);
+                    break;
+
+                case ALL_PASSED:
+                    // The test passed, report pass.
+                    setTestResultAndFinish(true);
+                    break;
+            }
+
+            updateButtonsAndInstructionLocked();
+        }
+    };
+
+    private final View.OnClickListener mOnButtonListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            // Check if user responded correctly.
+            if (mTestState == TestState.TESTING_ON) {
+                mTestState = TestState.RESPONDED_ON_CORRECTLY;
+            } else {
+                mTestState = TestState.FAILED;
+            }
+            updateButtonsAndInstructionLocked();
+        }
+    };
+
+    private final View.OnClickListener mOffButtonListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            // Check if user responded correctly.
+            if (mTestState == TestState.TESTING_OFF) {
+                mTestState = TestState.RESPONDED_OFF_CORRECTLY;
+            } else {
+                mTestState = TestState.FAILED;
+            }
+            updateButtonsAndInstructionLocked();
+        }
+    };
+
+    private final CameraManager.TorchCallback mTorchCallback = new CameraManager.TorchCallback() {
+        @Override
+        public void onTorchModeChanged(String cameraId, boolean enabled) {
+            if (!cameraId.equals(mCurrentCameraId)) {
+                return;
+            }
+
+            // Move to next state after receiving the expected callback.
+            if (mTestState == TestState.WAITING_ON_CALLBACK_ON && enabled) {
+                mTestState = TestState.TESTING_ON;
+            } else if (mTestState == TestState.WAITING_ON_CALLBACK_OFF && !enabled) {
+                mTestState = TestState.TESTING_OFF;
+            }
+            updateButtonsAndInstructionLocked();
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        // initialize state -> buttons map
+        for (TestState state : TestState.values()) {
+            mStateButtonsMap.put(state, new HashSet<View>());
+        }
+
+        mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
+
+        try {
+            String[] cameraIds = mCameraManager.getCameraIdList();
+            for (String id : cameraIds) {
+                CameraCharacteristics info = mCameraManager.getCameraCharacteristics(id);
+                if (info.get(CameraCharacteristics.FLASH_INFO_AVAILABLE).booleanValue() ==
+                        true) {
+                    mPendingCameraIds.add(id);
+                }
+            }
+            mCameraManager.registerTorchCallback(mTorchCallback, new Handler());
+        } catch (Exception e) {
+            e.printStackTrace();
+            mTestState = TestState.FAILED;
+            updateButtonsAndInstructionLocked();
+            return;
+        }
+
+        // Setup the UI.
+        setContentView(R.layout.camera_flashlight);
+        setPassFailButtonClickListeners();
+        setInfoResources(R.string.camera_flashlight_test, R.string.camera_flashlight_info, -1);
+
+        mInstructionTextView = (TextView) findViewById(R.id.flash_instruction_text);
+
+        // Get the buttons and attach the listener.
+        mInstructionButton = (Button) findViewById(R.id.flash_instruction_button);
+        mInstructionButton.setOnClickListener(mInstructionButtonListener);
+        mStateButtonsMap.get(TestState.NOT_STARTED).add(mInstructionButton);
+        mStateButtonsMap.get(TestState.RESPONDED_ON_CORRECTLY).add(mInstructionButton);
+        mStateButtonsMap.get(TestState.RESPONDED_OFF_CORRECTLY).add(mInstructionButton);
+        mStateButtonsMap.get(TestState.ALL_PASSED).add(mInstructionButton);
+        mStateButtonsMap.get(TestState.FAILED).add(mInstructionButton);
+        mAllButtons.add(mInstructionButton);
+
+        mOnButton = (Button) findViewById(R.id.flash_on_button);
+        mOnButton.setOnClickListener(mOnButtonListener);
+        mStateButtonsMap.get(TestState.TESTING_ON).add(mOnButton);
+        mStateButtonsMap.get(TestState.TESTING_OFF).add(mOnButton);
+        mAllButtons.add(mOnButton);
+
+        mOffButton = (Button) findViewById(R.id.flash_off_button);
+        mOffButton.setOnClickListener(mOffButtonListener);
+        mStateButtonsMap.get(TestState.TESTING_ON).add(mOffButton);
+        mStateButtonsMap.get(TestState.TESTING_OFF).add(mOffButton);
+        mAllButtons.add(mOffButton);
+
+        View passButton = getPassButton();
+        mStateButtonsMap.get(TestState.ALL_PASSED).add(passButton);
+        mAllButtons.add(passButton);
+
+        mTestState = TestState.NOT_STARTED;
+        updateButtonsAndInstructionLocked();
+    }
+
+
+    private void updateButtonsAndInstructionLocked() {
+        for (View v : mAllButtons) {
+            v.setEnabled(false);
+        }
+
+        // Only enable the buttons for this state.
+        HashSet<View> views = mStateButtonsMap.get(mTestState);
+        for (View v : views) {
+            v.setEnabled(true);
+        }
+
+        switch (mTestState) {
+            case TESTING_ON:
+            case TESTING_OFF:
+                mInstructionTextView.setText(String.format(
+                        getString(R.string.camera_flashlight_question_text), mCurrentCameraId));
+                break;
+            case RESPONDED_ON_CORRECTLY:
+            case RESPONDED_OFF_CORRECTLY:
+                mInstructionTextView.setText(R.string.camera_flashlight_next_text);
+                mInstructionButton.setText(R.string.camera_flashlight_next_button);
+                break;
+            case FAILED:
+                mInstructionTextView.setText(R.string.camera_flashlight_failed_text);
+                mInstructionButton.setText(R.string.camera_flashlight_done_button);
+                break;
+            case ALL_PASSED:
+                mInstructionTextView.setText(R.string.camera_flashlight_passed_text);
+                mInstructionButton.setText(R.string.camera_flashlight_done_button);
+                break;
+            default:
+                break;
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/DetermineFovActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/DetermineFovActivity.java
index 8b989e1..959e98f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/DetermineFovActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/fov/DetermineFovActivity.java
@@ -145,7 +145,7 @@
         mTargetDistanceCm = getTargetDistance();
         mReportedFovDegrees = PhotoCaptureActivity.getReportedFovDegrees();
 
-        mFovDegrees = mReportedFovDegrees > 80 ? 60 : mReportedFovDegrees;
+        mFovDegrees = mReportedFovDegrees > 120 ? 60 : mReportedFovDegrees;
         mFovMaxDegrees = mFovDegrees + FOV_ADJUSTMENT_RANGE / 2;
         mFovMinDegrees = mFovDegrees - FOV_ADJUSTMENT_RANGE / 2;
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
index 57d0c8f..9abfa9a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
@@ -151,6 +151,19 @@
                         cfgArray.put(obj);
                     }
                 }
+                sizes = map.getHighResolutionOutputSizes(fmts[fi]);
+                if (sizes != null) {
+                    for (int si = 0; si < Array.getLength(sizes); si++) {
+                        JSONObject obj = new JSONObject();
+                        obj.put("format", fmts[fi]);
+                        obj.put("width",sizes[si].getWidth());
+                        obj.put("height", sizes[si].getHeight());
+                        obj.put("input", false);
+                        obj.put("minFrameDuration",
+                                map.getOutputMinFrameDuration(fmts[fi],sizes[si]));
+                        cfgArray.put(obj);
+                    }
+                }
             }
         }
         mapObj.put("availableStreamConfigurations", cfgArray);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 85b8a18..5b034fe 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -1077,10 +1077,10 @@
                                     "Zero stream configs available for requested format: %s",
                                     sformat));
                         }
-                        width = sizes[0].getWidth();
+                        width = ItsUtils.getMaxSize(sizes).getWidth();
                     }
                     if (height <= 0) {
-                        height = sizes[0].getHeight();
+                        height = ItsUtils.getMaxSize(sizes).getHeight();
                     }
 
                     outputSizes[i] = new Size(width, height);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
index fddee4d..6fd050b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsUtils.java
@@ -128,10 +128,24 @@
         if (configMap == null) {
             throw new ItsException("Failed to get stream config");
         }
-        return configMap.getOutputSizes(format);
+        Size[] normalSizes = configMap.getOutputSizes(format);
+        Size[] slowSizes = configMap.getHighResolutionOutputSizes(format);
+        Size[] allSizes = null;
+        if (normalSizes != null && slowSizes != null) {
+            allSizes = new Size[normalSizes.length + slowSizes.length];
+            System.arraycopy(normalSizes, 0, allSizes, 0,
+                    normalSizes.length);
+            System.arraycopy(slowSizes, 0, allSizes, normalSizes.length,
+                    slowSizes.length);
+        } else if (normalSizes != null) {
+            allSizes = normalSizes;
+        } else if (slowSizes != null) {
+            allSizes = slowSizes;
+        }
+        return allSizes;
     }
 
-    private static Size getMaxSize(Size[] sizes) {
+    public static Size getMaxSize(Size[] sizes) {
         if (sizes == null || sizes.length == 0) {
             throw new IllegalArgumentException("sizes was empty");
         }
@@ -252,4 +266,3 @@
         }
     }
 }
-
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
index e7d1d79..f875684 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputService.java
@@ -16,9 +16,9 @@
 
 package com.android.cts.verifier.tv;
 
-import com.android.cts.verifier.R;
-
+import android.annotation.SuppressLint;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -27,20 +27,29 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Rect;
+import android.media.PlaybackParams;
 import android.media.tv.TvContentRating;
+import android.media.tv.TvContract;
 import android.media.tv.TvInputManager;
 import android.media.tv.TvInputService;
 import android.media.tv.TvTrackInfo;
 import android.net.Uri;
 import android.os.Bundle;
-import android.view.Surface;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
 import android.view.LayoutInflater;
+import android.view.Surface;
 import android.view.View;
 import android.widget.TextView;
 
+import com.android.cts.verifier.R;
+
 import java.util.ArrayList;
 import java.util.List;
 
+@SuppressLint("NewApi")
 public class MockTvInputService extends TvInputService {
     private static final String TAG = "MockTvInputService";
 
@@ -48,6 +57,7 @@
     private static final String SELECT_TRACK_TYPE = "type";
     private static final String SELECT_TRACK_ID = "id";
     private static final String CAPTION_ENABLED = "enabled";
+    private static final String PAUSE_CALLED = "pause_called";
 
     private static Object sLock = new Object();
     private static Callback sTuneCallback = null;
@@ -56,6 +66,14 @@
     private static Callback sUnblockContentCallback = null;
     private static Callback sSelectTrackCallback = null;
     private static Callback sSetCaptionEnabledCallback = null;
+    // Callbacks for time shift.
+    private static Callback sResumeAfterPauseCallback = null;
+    private static Callback sPositionTrackingCallback = null;
+    private static Callback sRewindCallback = null;
+    private static Callback sFastForwardCallback = null;
+    private static Callback sSeekToPreviousCallback = null;
+    private static Callback sSeekToNextCallback = null;
+
     private static TvContentRating sRating = null;
 
     static final TvTrackInfo sEngAudioTrack =
@@ -142,6 +160,47 @@
         }
     }
 
+    static void expectResumeAfterPause(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sResumeAfterPauseCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectPositionTracking(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sPositionTrackingCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectRewind(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sRewindCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectFastForward(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sFastForwardCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectSeekToPrevious(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sSeekToPreviousCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static void expectSeekToNext(View postTarget, Runnable successCallback) {
+        synchronized (sLock) {
+            sSeekToNextCallback = new Callback(postTarget, successCallback);
+        }
+    }
+
+    static String getInputId(Context context) {
+        return TvContract.buildInputId(new ComponentName(context,
+                        MockTvInputService.class.getName()));
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -165,10 +224,45 @@
     }
 
     private static class MockSessionImpl extends Session {
+        private static final int MSG_SEEK = 1000;
+        private static final int SEEK_DELAY_MS = 300;
+
         private final Context mContext;
         private Surface mSurface = null;
         private List<TvTrackInfo> mTracks = new ArrayList<>();
 
+        private long mRecordStartTimeMs;
+        private long mPausedTimeMs;
+        // The time in milliseconds when the current position is lastly updated.
+        private long mLastCurrentPositionUpdateTimeMs;
+        // The current playback position.
+        private long mCurrentPositionMs;
+        // The current playback speed rate.
+        private float mSpeed;
+
+        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_SEEK) {
+                    // Actually, this input doesn't play any videos, it just shows the image.
+                    // So we should simulate the playback here by changing the current playback
+                    // position periodically in order to test the time shift.
+                    // If the playback is paused, the current playback position doesn't need to be
+                    // changed.
+                    if (mPausedTimeMs == 0) {
+                        long currentTimeMs = System.currentTimeMillis();
+                        mCurrentPositionMs += (long) ((currentTimeMs
+                                - mLastCurrentPositionUpdateTimeMs) * mSpeed);
+                        mCurrentPositionMs = Math.max(mRecordStartTimeMs,
+                                Math.min(mCurrentPositionMs, currentTimeMs));
+                        mLastCurrentPositionUpdateTimeMs = currentTimeMs;
+                    }
+                    sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS);
+                }
+                super.handleMessage(msg);
+            }
+        };
+
         private MockSessionImpl(Context context) {
             super(context);
             mContext = context;
@@ -256,6 +350,12 @@
             notifyTracksChanged(mTracks);
             notifyTrackSelected(TvTrackInfo.TYPE_AUDIO, sEngAudioTrack.getId());
             notifyTrackSelected(TvTrackInfo.TYPE_SUBTITLE, null);
+            notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE);
+            mRecordStartTimeMs = mCurrentPositionMs = mLastCurrentPositionUpdateTimeMs
+                    = System.currentTimeMillis();
+            mPausedTimeMs = 0;
+            mHandler.sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS);
+            mSpeed = 1;
             return true;
         }
 
@@ -298,6 +398,88 @@
                 }
             }
         }
+
+        @Override
+        public long onTimeShiftGetCurrentPosition() {
+            synchronized (sLock) {
+                if (sPositionTrackingCallback != null) {
+                    sPositionTrackingCallback.post();
+                    sPositionTrackingCallback = null;
+                }
+            }
+            Log.d(TAG, "currentPositionMs=" + mCurrentPositionMs);
+            return mCurrentPositionMs;
+        }
+
+        @Override
+        public long onTimeShiftGetStartPosition() {
+            return mRecordStartTimeMs;
+        }
+
+        @Override
+        public void onTimeShiftPause() {
+            synchronized (sLock) {
+                if (sResumeAfterPauseCallback != null) {
+                    sResumeAfterPauseCallback.mBundle.putBoolean(PAUSE_CALLED, true);
+                }
+            }
+            mCurrentPositionMs = mPausedTimeMs = mLastCurrentPositionUpdateTimeMs
+                    = System.currentTimeMillis();
+        }
+
+        @Override
+        public void onTimeShiftResume() {
+            synchronized (sLock) {
+                if (sResumeAfterPauseCallback != null
+                        && sResumeAfterPauseCallback.mBundle.getBoolean(PAUSE_CALLED)) {
+                    sResumeAfterPauseCallback.post();
+                    sResumeAfterPauseCallback = null;
+                }
+            }
+            mSpeed = 1;
+            mPausedTimeMs = 0;
+            mLastCurrentPositionUpdateTimeMs = System.currentTimeMillis();
+        }
+
+        @Override
+        public void onTimeShiftSeekTo(long timeMs) {
+            synchronized (sLock) {
+                if (mCurrentPositionMs > timeMs) {
+                    if (sSeekToPreviousCallback != null) {
+                        sSeekToPreviousCallback.post();
+                        sSeekToPreviousCallback = null;
+                    }
+                } else if (mCurrentPositionMs < timeMs) {
+                    if (sSeekToNextCallback != null) {
+                        sSeekToNextCallback.post();
+                        sSeekToNextCallback = null;
+                    }
+                }
+            }
+            mLastCurrentPositionUpdateTimeMs = System.currentTimeMillis();
+            mCurrentPositionMs = Math.max(mRecordStartTimeMs,
+                    Math.min(timeMs, mLastCurrentPositionUpdateTimeMs));
+        }
+
+        @Override
+        public void onTimeShiftSetPlaybackParams(PlaybackParams params) {
+            synchronized(sLock) {
+                if (params != null) {
+                    if (params.getSpeed() > 1) {
+                        if (sFastForwardCallback != null) {
+                            sFastForwardCallback.post();
+                            sFastForwardCallback = null;
+                        }
+                    } else if (params.getSpeed() < 1) {
+                        if (sRewindCallback != null) {
+                            sRewindCallback.post();
+                            sRewindCallback = null;
+                        }
+                    }
+                }
+            }
+            mSpeed = params.getSpeed();
+        }
     }
 
     private static class Callback {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java
index 66af4c6..a912cc6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MultipleTracksTestActivity.java
@@ -17,7 +17,7 @@
 package com.android.cts.verifier.tv;
 
 import com.android.cts.verifier.R;
-
+import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.database.Cursor;
 import android.media.tv.TvContentRating;
@@ -36,6 +36,7 @@
 /**
  * Tests for verifying TV app behavior on multiple tracks and subtitle.
  */
+@SuppressLint("NewApi")
 public class MultipleTracksTestActivity extends TvAppVerifierActivity
         implements View.OnClickListener {
     private static final String TAG = "MultipleTracksTestActivity";
@@ -113,7 +114,8 @@
         }
         if (mTvAppIntent == null) {
             String[] projection = { TvContract.Channels._ID };
-            try (Cursor cursor = getContentResolver().query(TvContract.Channels.CONTENT_URI,
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
                     projection, null, null, null)) {
                 if (cursor != null && cursor.moveToNext()) {
                     mTvAppIntent = new Intent(Intent.ACTION_VIEW,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java
index 284b485..c99da46 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/ParentalControlTestActivity.java
@@ -17,7 +17,7 @@
 package com.android.cts.verifier.tv;
 
 import com.android.cts.verifier.R;
-
+import android.annotation.SuppressLint;
 import android.content.Intent;
 import android.database.Cursor;
 import android.media.tv.TvContentRating;
@@ -35,6 +35,7 @@
 /**
  * Tests for verifying TV app behavior on parental control.
  */
+@SuppressLint("NewApi")
 public class ParentalControlTestActivity extends TvAppVerifierActivity
         implements View.OnClickListener {
     private static final String TAG = "ParentalControlTestActivity";
@@ -110,7 +111,8 @@
         }
         if (mTvAppIntent == null) {
             String[] projection = { TvContract.Channels._ID };
-            try (Cursor cursor = getContentResolver().query(TvContract.Channels.CONTENT_URI,
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
                     projection, null, null, null)) {
                 if (cursor != null && cursor.moveToNext()) {
                     mTvAppIntent = new Intent(Intent.ACTION_VIEW,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TimeShiftTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TimeShiftTestActivity.java
new file mode 100644
index 0000000..5e4036c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TimeShiftTestActivity.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2015 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.tv;
+
+import android.content.Intent;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for verifying TV app behavior on time shift.
+ */
+public class TimeShiftTestActivity extends TvAppVerifierActivity
+        implements View.OnClickListener {
+    private static final long TIMEOUT_MS = TimeUnit.MINUTES.toMillis(5);
+    private static final boolean NOT_PASSED = false;
+    private static final boolean PASSED = true;
+
+    private View mPauseResumeItem;
+    private View mVerifyResumeAfterPauseItem;
+    private View mVerifyPositionTrackingItem;
+
+    private View mSetPlaybackParamsItem;
+    private View mVerifyRewindItem;
+    private View mVerifyFastForwardItem;
+
+    private View mSeekToItem;
+    private View mVerifySeekToPreviousItem;
+    private View mVerifySeekToNextItem;
+
+    private Intent mTvAppIntent = null;
+
+    @Override
+    public void onClick(View v) {
+        final View postTarget = getPostTarget();
+
+        if (containsButton(mPauseResumeItem, v)) {
+            mVerifyResumeAfterPauseItem.setTag(NOT_PASSED);
+            mVerifyPositionTrackingItem.setTag(NOT_PASSED);
+
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mVerifyResumeAfterPauseItem, false);
+                    setPassState(mVerifyPositionTrackingItem, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.expectResumeAfterPause(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mPauseResumeItem, true);
+                    setPassState(mVerifyResumeAfterPauseItem, true);
+                    mVerifyResumeAfterPauseItem.setTag(PASSED);
+                    if (isPassedState(mVerifyResumeAfterPauseItem)
+                            && isPassedState(mVerifyPositionTrackingItem)) {
+                        setButtonEnabled(mSetPlaybackParamsItem, true);
+                    }
+                }
+            });
+            MockTvInputService.expectPositionTracking(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mPauseResumeItem, true);
+                    setPassState(mVerifyPositionTrackingItem, true);
+                    mVerifyPositionTrackingItem.setTag(PASSED);
+                    if (isPassedState(mVerifyResumeAfterPauseItem)
+                            && isPassedState(mVerifyPositionTrackingItem)) {
+                        setButtonEnabled(mSetPlaybackParamsItem, true);
+                    }
+                }
+            });
+        } else if (containsButton(mSetPlaybackParamsItem, v)) {
+            mVerifyRewindItem.setTag(NOT_PASSED);
+            mVerifyFastForwardItem.setTag(NOT_PASSED);
+
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mVerifyRewindItem, false);
+                    setPassState(mVerifyFastForwardItem, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.expectRewind(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mSetPlaybackParamsItem, true);
+                    setPassState(mVerifyRewindItem, true);
+                    mVerifyRewindItem.setTag(PASSED);
+                    if (isPassedState(mVerifyRewindItem) && isPassedState(mVerifyFastForwardItem)) {
+                        setButtonEnabled(mSeekToItem, true);
+                    }
+                }
+            });
+            MockTvInputService.expectFastForward(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mSetPlaybackParamsItem, true);
+                    setPassState(mVerifyFastForwardItem, true);
+                    mVerifyFastForwardItem.setTag(PASSED);
+                    if (isPassedState(mVerifyRewindItem) && isPassedState(mVerifyFastForwardItem)) {
+                        setButtonEnabled(mSeekToItem, true);
+                    }
+                }
+            });
+        } else if (containsButton(mSeekToItem, v)) {
+            mVerifySeekToPreviousItem.setTag(NOT_PASSED);
+            mVerifySeekToNextItem.setTag(NOT_PASSED);
+
+            final Runnable failCallback = new Runnable() {
+                @Override
+                public void run() {
+                    setPassState(mVerifySeekToPreviousItem, false);
+                    setPassState(mVerifySeekToNextItem, false);
+                }
+            };
+            postTarget.postDelayed(failCallback, TIMEOUT_MS);
+            MockTvInputService.expectSeekToPrevious(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mSeekToItem, true);
+                    setPassState(mVerifySeekToPreviousItem, true);
+                    mVerifySeekToPreviousItem.setTag(PASSED);
+                    if (isPassedState(mVerifySeekToPreviousItem)
+                            && isPassedState(mVerifySeekToNextItem)) {
+                        getPassButton().setEnabled(true);
+                    }
+                }
+            });
+            MockTvInputService.expectSeekToNext(postTarget, new Runnable() {
+                @Override
+                public void run() {
+                    postTarget.removeCallbacks(failCallback);
+                    setPassState(mSeekToItem, true);
+                    setPassState(mVerifySeekToNextItem, true);
+                    mVerifySeekToNextItem.setTag(PASSED);
+                    if (isPassedState(mVerifySeekToPreviousItem)
+                            && isPassedState(mVerifySeekToNextItem)) {
+                        getPassButton().setEnabled(true);
+                    }
+                }
+            });
+        }
+        if (mTvAppIntent == null) {
+            String[] projection = { TvContract.Channels._ID };
+            try (Cursor cursor = getContentResolver().query(
+                    TvContract.buildChannelsUriForInput(MockTvInputService.getInputId(this)),
+                    projection, null, null, null)) {
+                if (cursor != null && cursor.moveToNext()) {
+                    mTvAppIntent = new Intent(Intent.ACTION_VIEW,
+                            TvContract.buildChannelUri(cursor.getLong(0)));
+                }
+            }
+            if (mTvAppIntent == null) {
+                Toast.makeText(this, R.string.tv_channel_not_found, Toast.LENGTH_SHORT).show();
+                return;
+            }
+        }
+        startActivity(mTvAppIntent);
+    }
+
+    @Override
+    protected void createTestItems() {
+        mPauseResumeItem = createUserItem(
+                R.string.tv_time_shift_test_pause_resume,
+                R.string.tv_launch_tv_app, this);
+        setButtonEnabled(mPauseResumeItem, true);
+        mVerifyResumeAfterPauseItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_resume_after_pause);
+        mVerifyPositionTrackingItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_position_tracking);
+        mSetPlaybackParamsItem = createUserItem(
+                R.string.tv_time_shift_test_speed_rate,
+                R.string.tv_launch_tv_app, this);
+        mVerifyRewindItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_rewind);
+        mVerifyFastForwardItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_fast_forward);
+        mSeekToItem = createUserItem(
+                R.string.tv_time_shift_test_seek,
+                R.string.tv_launch_tv_app, this);
+        mVerifySeekToPreviousItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_seek_to_previous);
+        mVerifySeekToNextItem = createAutoItem(
+                R.string.tv_time_shift_test_verify_seek_to_next);
+    }
+
+    @Override
+    protected void setInfoResources() {
+        setInfoResources(R.string.tv_time_shift_test,
+                R.string.tv_time_shift_test_info, -1);
+    }
+
+    private boolean isPassedState(View view) {
+        return ((Boolean) view.getTag()) == PASSED;
+    }
+}
diff --git a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
index d0a3a37..efb53d5 100644
--- a/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
+++ b/common/host-side/xml-plan-generator/src/com/android/compatibility/common/xmlgenerator/XmlPlanGenerator.java
@@ -22,9 +22,9 @@
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
-import vogar.Expectation;
 import vogar.ExpectationStore;
 import vogar.ModeId;
+import vogar.Result;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -161,7 +161,7 @@
     }
 
     public static boolean isKnownFailure(ExpectationStore store, String fullname) {
-        return store != null && store.get(fullname) != Expectation.SUCCESS;
+        return store != null && store.get(fullname).getResult() != Result.SUCCESS;
     }
 
     public static void main(String[] args) throws Exception {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
index e4f5134b..dcb5bbc 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/BaseDeviceOwnerTest.java
@@ -19,6 +19,9 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Process;
 import android.test.AndroidTestCase;
 
 /**
@@ -32,6 +35,14 @@
 public class BaseDeviceOwnerTest extends AndroidTestCase {
 
     public static class BasicAdminReceiver extends DeviceAdminReceiver {
+        @Override
+        public String onChoosePrivateKeyAlias(Context context, Intent intent, int uid, Uri uri,
+                String suggestedAlias) {
+            if (uid != Process.myUid() || uri == null) {
+                return null;
+            }
+            return uri.getQueryParameter("alias");
+        }
     }
 
     public static final String PACKAGE_NAME = BaseDeviceOwnerTest.class.getPackage().getName();
@@ -44,11 +55,15 @@
 
         mDevicePolicyManager = (DevicePolicyManager)
                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        assertTrue(mDevicePolicyManager.isAdminActive(getWho()));
-        assertTrue(mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+        assertDeviceOwner(mDevicePolicyManager);
     }
 
-    public static ComponentName getWho() {
+    static void assertDeviceOwner(DevicePolicyManager dpm) {
+        assertTrue(dpm.isAdminActive(getWho()));
+        assertTrue(dpm.isDeviceOwnerApp(PACKAGE_NAME));
+    }
+
+    protected static ComponentName getWho() {
         return new ComponentName(PACKAGE_NAME, BasicAdminReceiver.class.getName());
     }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
index 23d108f..a608794 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -15,11 +15,21 @@
  */
 package com.android.cts.deviceowner;
 
+import static com.android.cts.deviceowner.BaseDeviceOwnerTest.getWho;
 import static com.android.cts.deviceowner.FakeKeys.FAKE_RSA_1;
 
+import android.app.Activity;
 import android.app.admin.DevicePolicyManager;
+import android.net.Uri;
+import android.os.Handler;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+import android.security.KeyChainException;
+import android.test.ActivityInstrumentationTestCase2;
 
 import java.io.ByteArrayInputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.Certificate;
@@ -28,12 +38,31 @@
 import java.security.PrivateKey;
 import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
-public class KeyManagementTest extends BaseDeviceOwnerTest {
+import android.content.ComponentName;
+import android.content.Context;
+
+public class KeyManagementTest extends
+        ActivityInstrumentationTestCase2<ExampleIntentReceivingActivity1> {
+
+    private static final int KEYCHAIN_TIMEOUT_MS = 8000;
+    private DevicePolicyManager mDevicePolicyManager;
+
+    public KeyManagementTest() {
+        super(ExampleIntentReceivingActivity1.class);
+    }
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        // Confirm our DeviceOwner is set up
+        mDevicePolicyManager = (DevicePolicyManager)
+                getActivity().getSystemService(Context.DEVICE_POLICY_SERVICE);
+        BaseDeviceOwnerTest.assertDeviceOwner(mDevicePolicyManager);
+
         // Enable credential storage by setting a nonempty password.
         assertTrue(mDevicePolicyManager.resetPassword("test", 0));
     }
@@ -49,27 +78,32 @@
     }
 
     public void testCanInstallValidRsaKeypair()
-            throws CertificateException, NoSuchAlgorithmException, InvalidKeySpecException {
+            throws CertificateException, NoSuchAlgorithmException, InvalidKeySpecException,
+                    KeyChainException, InterruptedException, UnsupportedEncodingException {
         final String alias = "com.android.test.valid-rsa-key-1";
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey , "RSA");
         final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
         assertTrue(mDevicePolicyManager.installKeyPair(getWho(), privKey, cert, alias));
+
+        assertEquals(alias, new KeyChainAliasFuture(alias).get());
+        final PrivateKey retrievedKey = KeyChain.getPrivateKey(getActivity(), alias);
+        assertEquals(retrievedKey.getAlgorithm(), "RSA");
     }
 
-    public void testNullKeyParamsFailGracefully()
+    public void testNullKeyParamsFailPredictably()
             throws CertificateException, NoSuchAlgorithmException, InvalidKeySpecException {
         final String alias = "com.android.test.null-key-1";
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey, "RSA");
         final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
         try {
-            assertFalse(mDevicePolicyManager.installKeyPair(getWho(), null, cert, alias));
-        } catch (NullPointerException accept) {
-            // Accept either false return value or NPE
+            mDevicePolicyManager.installKeyPair(getWho(), null, cert, alias);
+            fail("Exception should have been thrown for null PrivateKey");
+        } catch (NullPointerException expected) {
         }
         try {
-            assertFalse(mDevicePolicyManager.installKeyPair(getWho(), privKey, null, alias));
-        } catch (NullPointerException accept) {
-            // Accept either false return value or NPE
+            mDevicePolicyManager.installKeyPair(getWho(), privKey, null, alias);
+            fail("Exception should have been thrown for null Certificate");
+        } catch (NullPointerException expected) {
         }
     }
 
@@ -79,21 +113,46 @@
         final PrivateKey privKey = getPrivateKey(FAKE_RSA_1.privateKey, "RSA");
         final Certificate cert = getCertificate(FAKE_RSA_1.caCertificate);
         try {
-            assertFalse(mDevicePolicyManager.installKeyPair(null, privKey, cert, alias));
+            mDevicePolicyManager.installKeyPair(null, privKey, cert, alias);
             fail("Exception should have been thrown for null ComponentName");
-        } catch (SecurityException | NullPointerException expected) {
+        } catch (SecurityException expected) {
         }
     }
 
-    PrivateKey getPrivateKey(final byte[] key, String type)
+    private static PrivateKey getPrivateKey(final byte[] key, String type)
             throws NoSuchAlgorithmException, InvalidKeySpecException {
         return KeyFactory.getInstance(type).generatePrivate(
                 new PKCS8EncodedKeySpec(key));
     }
 
-    Certificate getCertificate(byte[] cert) throws CertificateException {
+    private static Certificate getCertificate(byte[] cert) throws CertificateException {
         return CertificateFactory.getInstance("X.509").generateCertificate(
                 new ByteArrayInputStream(cert));
     }
 
+    private class KeyChainAliasFuture implements KeyChainAliasCallback {
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private String mChosenAlias = null;
+
+        @Override
+        public void alias(final String chosenAlias) {
+            mChosenAlias = chosenAlias;
+            mLatch.countDown();
+        }
+
+        public KeyChainAliasFuture(String alias) throws UnsupportedEncodingException {
+            /* Pass the alias as a GET to an imaginary server instead of explicitly asking for it,
+             * to make sure the DPC actually has to do some work to grant the cert.
+             */
+            final Uri uri =
+                    Uri.parse("https://example.org/?alias=" + URLEncoder.encode(alias, "UTF-8"));
+            KeyChain.choosePrivateKeyAlias(getActivity(), this,
+                    null /* keyTypes */, null /* issuers */, uri, null /* alias */);
+        }
+
+        public String get() throws InterruptedException {
+            assertTrue("Chooser timeout", mLatch.await(KEYCHAIN_TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            return mChosenAlias;
+        }
+    };
 }
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index 4517ea2..5f645b6 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -26,6 +26,8 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
 
+LOCAL_STATIC_JAVA_LIBRARIES = android-support-v4 ctstestrunner
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
index a21b8c2..5ded006 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
@@ -23,7 +23,7 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.cts.launchertests"
                      android:label="Launcher Apps CTS Tests"/>
 </manifest>
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 3d44ecd..3bd21d9 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -38,8 +38,8 @@
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.test.InstrumentationTestCase;
-import android.test.InstrumentationTestRunner;
+import android.support.test.InstrumentationRegistry;
+import android.test.AndroidTestCase;
 import android.util.Pair;
 
 import java.util.concurrent.Semaphore;
@@ -49,7 +49,7 @@
 /**
  * Tests for LauncherApps service
  */
-public class LauncherAppsTests extends InstrumentationTestCase {
+public class LauncherAppsTests extends AndroidTestCase {
 
     public static final String SIMPLE_APP_PACKAGE = "com.android.cts.launcherapps.simpleapp";
 
@@ -69,7 +69,7 @@
 
     private LauncherApps mLauncherApps;
     private UserHandle mUser;
-    private InstrumentationTestRunner mInstrumentation;
+    private Instrumentation mInstrumentation;
     private Messenger mService;
     private Connection mConnection;
     private Result mResult;
@@ -78,8 +78,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mInstrumentation = (InstrumentationTestRunner) getInstrumentation();
-        Bundle arguments = mInstrumentation.getArguments();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        Bundle arguments = InstrumentationRegistry.getArguments();
         UserManager userManager = (UserManager) mInstrumentation.getContext().getSystemService(
                 Context.USER_SERVICE);
         mUser = getUserHandleArgument(userManager, "testUser", arguments);
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
index 82f6d6d..31e4ad4 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/AndroidManifest.xml
@@ -22,6 +22,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+    <uses-permission android:name="android.permission.CAMERA" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/device_admin.xml
index 8f39ed0..c3d5c98 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/device_admin.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/device_admin.xml
@@ -15,5 +15,6 @@
 <device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
     <uses-policies>
         <wipe-data />
+        <disable-camera />
     </uses-policies>
 </device-admin>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml
index a6aff49..0ec3d1e 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/res/xml/primary_device_admin.xml
@@ -16,5 +16,6 @@
     <uses-policies>
          <reset-password />
          <limit-password />
+         <disable-camera />
     </uses-policies>
 </device-admin>
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraPolicyTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraPolicyTest.java
new file mode 100644
index 0000000..25e0b94
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraPolicyTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 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.managedprofile;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.hardware.camera2.CameraManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.test.AndroidTestCase;
+
+
+public class CameraPolicyTest extends AndroidTestCase {
+
+    protected static final String MANAGED_PROFILE_PKG = "com.android.cts.managedprofile";
+
+    private static final String PRIMARY_ADMIN_RECEIVER_TEST_CLASS =
+            MANAGED_PROFILE_PKG + ".PrimaryUserDeviceAdmin";
+
+    private static final String MANAGED_PROFILE_ADMIN_RECEIVER_TEST_CLASS =
+            MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
+
+    private DevicePolicyManager mDevicePolicyManager;
+
+    private CameraManager mCameraManager;
+
+    private ComponentName mPrimaryAdminComponent;
+
+    private ComponentName mManagedProfileAdminComponent;
+
+    private HandlerThread mBackgroundThread;
+
+    /**
+     * A {@link Handler} for running tasks in the background.
+     */
+    private Handler mBackgroundHandler;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mDevicePolicyManager = (DevicePolicyManager) getContext()
+                .getSystemService(Context.DEVICE_POLICY_SERVICE);
+        mCameraManager = (CameraManager) getContext().getSystemService(Context.CAMERA_SERVICE);
+        mPrimaryAdminComponent = new ComponentName(MANAGED_PROFILE_PKG,
+                PRIMARY_ADMIN_RECEIVER_TEST_CLASS);
+        mManagedProfileAdminComponent = new ComponentName(MANAGED_PROFILE_PKG,
+                MANAGED_PROFILE_ADMIN_RECEIVER_TEST_CLASS);
+        startBackgroundThread();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        stopBackgroundThread();
+        super.tearDown();
+    }
+
+    public void testDisableCameraInManagedProfile() throws Exception {
+        mDevicePolicyManager.setCameraDisabled(mManagedProfileAdminComponent, true);
+        assertTrue(mDevicePolicyManager.getCameraDisabled(mManagedProfileAdminComponent));
+        assertTrue(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(false);
+    }
+
+    public void testEnableCameraInManagedProfile() throws Exception {
+        mDevicePolicyManager.setCameraDisabled(mManagedProfileAdminComponent, false);
+        assertFalse(mDevicePolicyManager.getCameraDisabled(mManagedProfileAdminComponent));
+        assertFalse(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(true);
+    }
+
+    public void testDisableCameraInPrimaryProfile() throws Exception {
+        mDevicePolicyManager.setCameraDisabled(mPrimaryAdminComponent, true);
+        assertTrue(mDevicePolicyManager.getCameraDisabled(mPrimaryAdminComponent));
+        assertTrue(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(false);
+    }
+
+    public void testEnableCameraInPrimaryProfile() throws Exception {
+        mDevicePolicyManager.setCameraDisabled(mPrimaryAdminComponent, false);
+        assertFalse(mDevicePolicyManager.getCameraDisabled(mPrimaryAdminComponent));
+        assertFalse(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(true);
+    }
+
+    public void testIsCameraEnabledInPrimaryProfile() throws Exception {
+        assertFalse(mDevicePolicyManager.getCameraDisabled(mPrimaryAdminComponent));
+        assertFalse(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(true);
+    }
+
+    public void testIsCameraEnabledInManagedProfile() throws Exception {
+        assertFalse(mDevicePolicyManager.getCameraDisabled(mManagedProfileAdminComponent));
+        assertFalse(mDevicePolicyManager.getCameraDisabled(null));
+        checkCanOpenCamera(true);
+    }
+
+    private void checkCanOpenCamera(boolean canOpen) {
+        boolean successToOpen = CameraUtils
+                .blockUntilOpenCamera(mCameraManager, mBackgroundHandler);
+        assertEquals(canOpen, successToOpen);
+    }
+
+    /**
+     * Starts a background thread and its {@link Handler}.
+     */
+    private void startBackgroundThread() {
+        mBackgroundThread = new HandlerThread("CameraBackground");
+        mBackgroundThread.start();
+        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
+    }
+
+    /**
+     * Stops the background thread and its {@link Handler}.
+     */
+    private void stopBackgroundThread() {
+        mBackgroundThread.quitSafely();
+        try {
+            mBackgroundThread.join();
+            mBackgroundThread = null;
+            mBackgroundHandler = null;
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraUtils.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraUtils.java
new file mode 100644
index 0000000..516e244
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CameraUtils.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.managedprofile;
+
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * A util class to help open camera in a blocking way.
+ */
+class CameraUtils {
+
+    private static final String TAG = "CameraUtils";
+
+    /**
+     * @return true if success to open camera, false otherwise.
+     */
+    public static boolean blockUntilOpenCamera(CameraManager cameraManager, Handler handler) {
+        try {
+            String[] cameraIdList = cameraManager.getCameraIdList();
+            if (cameraIdList == null || cameraIdList.length == 0) {
+                return false;
+            }
+            String cameraId = cameraIdList[0];
+            CameraCallback callback = new CameraCallback();
+            cameraManager.openCamera(cameraId, callback, handler);
+            return callback.waitForResult();
+        } catch (Exception ex) {
+            // No matter what is going wrong, it means fail to open camera.
+            ex.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * {@link CameraDevice.StateCallback} is called when {@link CameraDevice} changes its state.
+     */
+    private static class CameraCallback extends CameraDevice.StateCallback {
+
+        private static final int OPEN_TIMEOUT_SECONDS = 5;
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+
+        private AtomicBoolean mResult = new AtomicBoolean(false);
+
+        @Override
+        public void onOpened(CameraDevice cameraDevice) {
+            Log.d(TAG, "open camera successfully");
+            mResult.set(true);
+            if (cameraDevice != null) {
+                cameraDevice.close();
+            }
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onDisconnected(CameraDevice cameraDevice) {
+            Log.d(TAG, "disconnect camera");
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onError(CameraDevice cameraDevice, int error) {
+            Log.e(TAG, "Fail to open camera, error code = " + error);
+            mLatch.countDown();
+        }
+
+        public boolean waitForResult() throws InterruptedException {
+            mLatch.await(OPEN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+            return mResult.get();
+        }
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java
index 2faf158..1cc2ee2 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/PermissionsTest.java
@@ -30,6 +30,8 @@
 public class PermissionsTest extends BaseManagedProfileTest {
 
     private static final String SIMPLE_APP_PACKAGE_NAME = "com.android.cts.launcherapps.simpleapp";
+    private static final String SIMPLE_PRE_M_APP_PACKAGE_NAME =
+            "com.android.cts.launcherapps.simplepremapp";
     private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS";
 
     @Override
@@ -47,8 +49,8 @@
         mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
-        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME),
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED);
         assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
                 PackageManager.PERMISSION_DENIED);
@@ -56,8 +58,8 @@
         mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
-        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME),
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
         // Should stay denied
         assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
@@ -66,8 +68,8 @@
         mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
                 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
-        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME),
                 DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
         assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
                 PackageManager.PERMISSION_GRANTED);
@@ -75,8 +77,8 @@
         mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
                 SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME,
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
-        assertTrue(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
-                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME) ==
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_APP_PACKAGE_NAME, PERMISSION_NAME),
                 DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
         // Should stay granted
         assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_APP_PACKAGE_NAME),
@@ -97,4 +99,29 @@
         assertEquals(mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT),
                 DevicePolicyManager.PERMISSION_POLICY_PROMPT);
     }
+
+    public void testPermissionGrantStatePreMApp() {
+        // These tests are to make sure that pre-M apps are not granted runtime permissions
+        // by a profile owner
+        PackageManager pm = mContext.getPackageManager();
+        assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED));
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME),
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        // Install time permissions should always be granted
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_PRE_M_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_GRANTED);
+
+        mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME,
+                DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+        assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT,
+                SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME),
+                DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT);
+        // Install time permissions should always be granted
+        assertEquals(pm.checkPermission(PERMISSION_NAME, SIMPLE_PRE_M_APP_PACKAGE_NAME),
+                PackageManager.PERMISSION_GRANTED);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
new file mode 100644
index 0000000..7460552
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 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.
+
+# This app is meant for testing device policy permission APIs on legacy apps (pre-M)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsSimplePreMApp
+
+LOCAL_SDK_VERSION := 21
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/SimplePreMApp/AndroidManifest.xml
new file mode 100644
index 0000000..85962a1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.launcherapps.simplepremapp">
+
+    <uses-sdk android:targetSdkVersion="21"/>
+
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
+
+    <application>
+        <activity android:name=".SimpleActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+
+</manifest>
+
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/src/com/android/cts/launcherapps/simplepremapp/SimpleActivity.java b/hostsidetests/devicepolicy/app/SimplePreMApp/src/com/android/cts/launcherapps/simplepremapp/SimpleActivity.java
new file mode 100644
index 0000000..0dba719
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/src/com/android/cts/launcherapps/simplepremapp/SimpleActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 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.launcherapps.simplepremapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.Override;
+
+/**
+ * A simple activity to install for various users to test LauncherApps.
+ */
+public class SimpleActivity extends Activity {
+
+    private static final String TAG = "SimpleActivity";
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Log.i(TAG, "Created for user " + android.os.Process.myUserHandle());
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 255c49e..3f0805c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -31,6 +31,7 @@
     private static final String MANAGED_PROFILE_APK = "CtsManagedProfileApp.apk";
 
     private static final String SIMPLE_APP_APK = "CtsSimpleApp.apk";
+    private static final String SIMPLE_PRE_M_APP_APK = "CtsSimplePreMApp.apk";
 
     private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
     private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
@@ -45,6 +46,7 @@
             MANAGED_PROFILE_PKG + ".BaseManagedProfileTest$BasicAdminReceiver";
 
     private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
+    private static final String FEATURE_CAMERA = "android.hardware.camera";
     private int mUserId;
 
     @Override
@@ -257,6 +259,52 @@
                 "testGetRemoteDevice", mUserId));
     }
 
+    public void testCameraPolicy() throws Exception {
+        boolean hasCamera = hasDeviceFeature(FEATURE_CAMERA);
+        if (!mHasFeature || !hasCamera) {
+            return;
+        }
+        try {
+            setDeviceAdmin(MANAGED_PROFILE_PKG + "/.PrimaryUserDeviceAdmin");
+
+            // Disable managed profile camera.
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testDisableCameraInManagedProfile",
+                    mUserId));
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testIsCameraEnabledInPrimaryProfile",
+                    0));
+
+            // Enable managed profile camera.
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testEnableCameraInManagedProfile",
+                    mUserId));
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testIsCameraEnabledInPrimaryProfile",
+                    0));
+
+            // Disable primary profile camera.
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testDisableCameraInPrimaryProfile",
+                    0));
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testIsCameraEnabledInManagedProfile",
+                    mUserId));
+
+            // Enable primary profile camera.
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testEnableCameraInPrimaryProfile",
+                    0));
+            assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CameraPolicyTest",
+                    "testIsCameraEnabledInManagedProfile",
+                    mUserId));
+        } finally {
+            final String adminHelperClass = ".PrimaryUserAdminHelper";
+            assertTrue("Clear device admin failed", runDeviceTestsAsUser(MANAGED_PROFILE_PKG,
+                    adminHelperClass, "testClearDeviceAdmin", 0 /* user 0 */));
+        }
+    }
+
     public void testManagedContacts() throws Exception {
         if (!mHasFeature) {
             return;
@@ -417,11 +465,20 @@
         if (!mHasFeature) {
             return;
         }
-        installApp(SIMPLE_APP_APK);
+        installAppAsUser(SIMPLE_APP_APK, mUserId);
         assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PermissionsTest",
                 "testPermissionGrantState", mUserId));
     }
 
+    public void testPermissionGrantPreMApp() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAppAsUser(SIMPLE_PRE_M_APP_APK, mUserId);
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".PermissionsTest",
+                "testPermissionGrantStatePreMApp", mUserId));
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
diff --git a/libs/testserver/src/android/webkit/cts/CtsTestServer.java b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
index e39e435..de88f3b 100644
--- a/libs/testserver/src/android/webkit/cts/CtsTestServer.java
+++ b/libs/testserver/src/android/webkit/cts/CtsTestServer.java
@@ -229,12 +229,30 @@
             // request for shutdown and having the server's one thread
             // sequentially call accept() and close().
             URL url = new URL(mServerUri + SHUTDOWN_PREFIX);
-            URLConnection connection = openConnection(url);
-            connection.connect();
+            if (url.getProtocol().equalsIgnoreCase("http")) {
+                // Use Socket instead of HttpURLConnection when the server is in cleartext HTTP mode
+                // to avoid the request being blocked by NetworkSecurityPolicy.
+                Socket socket = null;
+                try {
+                    socket = new Socket(url.getHost(), url.getPort());
+                    socket.getOutputStream().write(
+                        ("GET " + SHUTDOWN_PREFIX + " HTTP/1.0\r\n\r\n").getBytes("US-ASCII"));
+                    socket.getOutputStream().flush();
+                } finally {
+                    if (socket != null) {
+                        try {
+                            socket.close();
+                        } catch (Exception ignored) {}
+                    }
+                }
+            } else {
+                URLConnection connection = openConnection(url);
+                connection.connect();
 
-            // Read the input from the stream to send the request.
-            InputStream is = connection.getInputStream();
-            is.close();
+                // Read the input from the stream to send the request.
+                InputStream is = connection.getInputStream();
+                is.close();
+            }
 
             // Block until the server thread is done shutting down.
             mServerThread.join();
@@ -1014,7 +1032,7 @@
                         conn.receiveRequestEntity( (HttpEntityEnclosingRequest) request);
                     }
 
-                    mExecutorService.submit(new HandleResponseTask(conn, request));
+                    mExecutorService.execute(new HandleResponseTask(conn, request));
                 } catch (IOException e) {
                     // normal during shutdown, ignore
                     Log.w(TAG, e);
@@ -1045,7 +1063,7 @@
             return path.equals(SHUTDOWN_PREFIX);
         }
 
-        private class HandleResponseTask implements Callable<Void> {
+        private class HandleResponseTask implements Runnable {
 
             private DefaultHttpServerConnection mConnection;
 
@@ -1058,12 +1076,15 @@
             }
 
             @Override
-            public Void call() throws Exception {
-                HttpResponse response = mServer.getResponse(mRequest);
-                mConnection.sendResponseHeader(response);
-                mConnection.sendResponseEntity(response);
-                mConnection.close();
-                return null;
+            public void run() {
+                try {
+                    HttpResponse response = mServer.getResponse(mRequest);
+                    mConnection.sendResponseHeader(response);
+                    mConnection.sendResponseEntity(response);
+                    mConnection.close();
+                } catch (Exception e) {
+                    Log.e(TAG, "Error handling request:", e);
+                }
             }
         }
     }
diff --git a/libs/vogar-expect/src/vogar/Expectation.java b/libs/vogar-expect/src/vogar/Expectation.java
index f065f42..ddbc233f 100644
--- a/libs/vogar-expect/src/vogar/Expectation.java
+++ b/libs/vogar-expect/src/vogar/Expectation.java
@@ -16,7 +16,6 @@
 
 package vogar;
 
-import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
 import java.util.regex.Pattern;
@@ -37,14 +36,6 @@
  */
 public final class Expectation {
 
-    /** The pattern to use when no expected output is specified */
-    public static final Pattern MATCH_ALL_PATTERN
-            = Pattern.compile(".*", Pattern.MULTILINE | Pattern.DOTALL);
-
-    /** The expectation of a general successful run. */
-    public static final Expectation SUCCESS = new Expectation(Result.SUCCESS, MATCH_ALL_PATTERN,
-            Collections.<String>emptySet(), "", -1);
-
     /** Justification for this expectation */
     private final String description;
 
diff --git a/libs/vogar-expect/src/vogar/ExpectationStore.java b/libs/vogar-expect/src/vogar/ExpectationStore.java
index cfa20e9..090322d 100644
--- a/libs/vogar-expect/src/vogar/ExpectationStore.java
+++ b/libs/vogar-expect/src/vogar/ExpectationStore.java
@@ -26,6 +26,7 @@
 import java.io.File;
 import java.io.FileReader;
 import java.io.IOException;
+import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -50,7 +51,17 @@
  * expectation, the outcome expectation will be returned.
  */
 public final class ExpectationStore {
+
+    /** The pattern to use when no expected output is specified */
+    private static final Pattern MATCH_ALL_PATTERN
+            = Pattern.compile(".*", Pattern.MULTILINE | Pattern.DOTALL);
+
+    /** The expectation of a general successful run. */
+    private static final Expectation SUCCESS = new Expectation(Result.SUCCESS, MATCH_ALL_PATTERN,
+            Collections.<String>emptySet(), "", -1);
+
     private static final int PATTERN_FLAGS = Pattern.MULTILINE | Pattern.DOTALL;
+
     private final Map<String, Expectation> outcomes = new LinkedHashMap<String, Expectation>();
     private final Map<String, Expectation> failures = new LinkedHashMap<String, Expectation>();
 
@@ -62,7 +73,7 @@
      */
     public Expectation get(String name) {
         Expectation byName = getByNameOrPackage(name);
-        return byName != null ? byName : Expectation.SUCCESS;
+        return byName != null ? byName : SUCCESS;
     }
 
     /**
@@ -87,7 +98,7 @@
         }
 
         Expectation byName = getByNameOrPackage(outcome.getName());
-        return byName != null ? byName : Expectation.SUCCESS;
+        return byName != null ? byName : SUCCESS;
     }
 
     private Expectation getByNameOrPackage(String name) {
@@ -141,8 +152,8 @@
 
     private void readExpectation(JsonReader reader, ModeId mode) throws IOException {
         boolean isFailure = false;
-        Result result = Result.SUCCESS;
-        Pattern pattern = Expectation.MATCH_ALL_PATTERN;
+        Result result = Result.EXEC_FAILED;
+        Pattern pattern = MATCH_ALL_PATTERN;
         Set<String> names = new LinkedHashSet<String>();
         Set<String> tags = new LinkedHashSet<String>();
         Set<ModeId> modes = null;
@@ -159,6 +170,12 @@
             } else if (name.equals("names")) {
                 readStrings(reader, names);
             } else if (name.equals("failure")) {
+                // isFailure is somewhat arbitrarily keyed on the existence of a "failure"
+                // element instead of looking at the "result" field. There are only about 5
+                // expectations in our entire expectation store that have this tag.
+                //
+                // TODO: Get rid of it and the "failures" map and just use the outcomes
+                // map for everything. Both uses seem useless.
                 isFailure = true;
                 names.add(reader.nextString());
             } else if (name.equals("pattern")) {
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index ecb7050..86fe4af 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -151,13 +151,6 @@
   bug: 17144778
 },
 {
-  description: "Roboto font tests are not yet known good on all devices",
-  names: [
-    "android.uirendering.cts.testclasses.FontRenderingTests"
-  ],
-  bug: 17109280
-},
-{
   description: "android.keystore tests will replace these tests",
   names: [
     "com.android.org.conscrypt.MacTest#test_getInstance_OpenSSL_ENGINE",
@@ -179,5 +172,12 @@
     "android.hardware.camera2.cts.ImageReaderTest#testAllOutputYUVResolutions"
   ],
   bug: 18689511
+},
+{
+  description: "The new prepare performance test is not yet passing on all devices",
+  names: [
+    "android.hardware.camera2.cts.SurfaceViewPreviewTest#testPreparePerformance"
+  ],
+  bug: 17989532
 }
 ]
diff --git a/tests/netsecpolicy/Android.mk b/tests/netsecpolicy/Android.mk
new file mode 100644
index 0000000..137672e
--- /dev/null
+++ b/tests/netsecpolicy/Android.mk
@@ -0,0 +1,17 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
new file mode 100644
index 0000000..1af3b49
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, \
+    ../usescleartexttraffic-shared/src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficFalse
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml b/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
new file mode 100644
index 0000000..013821e
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.netsecpolicy.usescleartext.false.cts">
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <application android:usesCleartextTraffic="false">
+    </application>
+</manifest>
diff --git a/tests/netsecpolicy/usescleartexttraffic-shared/src/Dummy.java b/tests/netsecpolicy/usescleartexttraffic-shared/src/Dummy.java
new file mode 100644
index 0000000..2705a5f
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-shared/src/Dummy.java
@@ -0,0 +1,2 @@
+public class Dummy {
+}
diff --git a/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
new file mode 100644
index 0000000..5effc57
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, \
+    ../usescleartexttraffic-shared/src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficTrue
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml b/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
new file mode 100644
index 0000000..f50295e
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.netsecpolicy.usescleartext.true.cts">
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-library android:name="org.apache.http.legacy"/>
+
+    <application android:usesCleartextTraffic="true">
+    </application>
+</manifest>
diff --git a/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
new file mode 100644
index 0000000..685a16f
--- /dev/null
+++ b/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, \
+    ../usescleartexttraffic-shared/src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficUnspecified
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java b/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
similarity index 60%
copy from apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
copy to tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
index 4231db7..7e735c7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
+++ b/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
@@ -1,5 +1,7 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 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.
@@ -12,12 +14,11 @@
  * 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.tv;
-
-import android.preference.PreferenceActivity;
-
-public class MockTvInputSettingsActivity extends PreferenceActivity {
-
-}
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="android.netsecpolicy.usescleartext.unspecified.cts">
+     <uses-permission android:name="android.permission.INTERNET"/>
+    <application>
+    </application>
+</manifest>
diff --git a/tests/tests/accessibility/AndroidManifest.xml b/tests/tests/accessibility/AndroidManifest.xml
index 319fb49..b3bcbc8 100644
--- a/tests/tests/accessibility/AndroidManifest.xml
+++ b/tests/tests/accessibility/AndroidManifest.xml
@@ -17,18 +17,19 @@
  -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="android.view.cts.accessibility">
+          package="android.view.cts.accessibility">
 
-  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
-  <application android:theme="@android:style/Theme.Holo.NoActionBar" >
-      <uses-library android:name="android.test.runner"/>
-  </application>
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
 
-  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
-                   android:targetPackage="android.view.cts.accessibility"
-                   android:label="Tests for the accessibility APIs.">
+    <application android:theme="@android:style/Theme.Holo.NoActionBar" >
+        <uses-library android:name="android.test.runner"/>
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.view.cts.accessibility"
+                     android:label="Tests for the accessibility APIs.">
         <meta-data android:name="listener"
-            android:value="com.android.cts.runner.CtsTestRunListener" />
+                   android:value="com.android.cts.runner.CtsTestRunListener" />
     </instrumentation>
 
 </manifest>
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java b/tests/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
new file mode 100644
index 0000000..53eb215
--- /dev/null
+++ b/tests/tests/accessibility/src/android/view/accessibility/cts/CaptioningManagerTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2015 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.view.accessibility.cts;
+
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+import android.test.InstrumentationTestCase;
+import android.view.accessibility.CaptioningManager;
+import android.view.accessibility.CaptioningManager.CaptionStyle;
+import android.view.accessibility.CaptioningManager.CaptioningChangeListener;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+
+/**
+ * Tests whether the CaptioningManager APIs are functional.
+ */
+public class CaptioningManagerTest extends InstrumentationTestCase {
+    private CaptioningManager mManager;
+    private UiAutomation mUiAutomation;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mManager = getInstrumentation().getTargetContext().getSystemService(
+                CaptioningManager.class);
+
+        assertNotNull("Obtained captioning manager", mManager);
+
+        mUiAutomation = getInstrumentation().getUiAutomation();
+    }
+
+    /**
+     * Tests whether a client can observe changes in caption properties.
+     */
+    public void testChangeListener() {
+        putSecureSetting("accessibility_captioning_enabled","0");
+        putSecureSetting("accessibility_captioning_preset", "1");
+        putSecureSetting("accessibility_captioning_locale", "en_US");
+        putSecureSetting("accessibility_captioning_font_scale", "1.0");
+
+        MockCaptioningChangeListener listener = new MockCaptioningChangeListener();
+        mManager.addCaptioningChangeListener(listener);
+
+        putSecureSetting("accessibility_captioning_enabled", "1");
+        assertTrue("Observed enabled change", listener.wasEnabledChangedCalled);
+
+        putSecureSetting("accessibility_captioning_preset", "-1");
+        assertTrue("Observed user style change", listener.wasUserStyleChangedCalled);
+
+        putSecureSetting("accessibility_captioning_locale", "ja_JP");
+        assertTrue("Observed locale change", listener.wasLocaleChangedCalled);
+
+        putSecureSetting("accessibility_captioning_font_scale", "2.0");
+        assertTrue("Observed font scale change", listener.wasFontScaleChangedCalled);
+
+        mManager.removeCaptioningChangeListener(listener);
+
+        listener.reset();
+
+        putSecureSetting("accessibility_captioning_enabled","0");
+        assertFalse("Did not observe enabled change", listener.wasEnabledChangedCalled);
+
+        try {
+            mManager.removeCaptioningChangeListener(listener);
+        } catch (Exception e) {
+            throw new AssertionError("Fails silently when removing listener twice", e);
+        }
+    }
+
+    public void testProperties() {
+        putSecureSetting("accessibility_captioning_font_scale", "2.0");
+        putSecureSetting("accessibility_captioning_locale", "ja_JP");
+        putSecureSetting("accessibility_captioning_enabled", "1");
+
+        assertEquals("Test runner set font scale to 2.0", 2.0f, mManager.getFontScale());
+        assertEquals("Test runner set locale to Japanese", Locale.JAPAN, mManager.getLocale());
+        assertEquals("Test runner set enabled to true", true, mManager.isEnabled());
+    }
+
+    public void testUserStyle() {
+        putSecureSetting("accessibility_captioning_preset", "-1");
+        putSecureSetting("accessibility_captioning_foreground_color", "511");
+        putSecureSetting("accessibility_captioning_background_color", "511");
+        putSecureSetting("accessibility_captioning_window_color", "511");
+        putSecureSetting("accessibility_captioning_edge_color", "511");
+        putSecureSetting("accessibility_captioning_edge_type", "-1");
+        deleteSecureSetting("accessibility_captioning_typeface");
+
+        CaptionStyle userStyle = mManager.getUserStyle();
+        assertNotNull("Default user style is not null", userStyle);
+        assertFalse("Default user style has no edge type", userStyle.hasEdgeType());
+        assertFalse("Default user style has no edge color", userStyle.hasEdgeColor());
+        assertFalse("Default user style has no foreground color", userStyle.hasForegroundColor());
+        assertFalse("Default user style has no background color", userStyle.hasBackgroundColor());
+        assertFalse("Default user style has no window color", userStyle.hasWindowColor());
+        assertNull("Default user style has no typeface", userStyle.getTypeface());
+    }
+
+    private void deleteSecureSetting(String name) {
+        execShellCommand("settings delete secure " + name);
+    }
+
+    private void putSecureSetting(String name, String value) {
+        execShellCommand("settings put secure " + name + " " + value);
+    }
+
+    private void execShellCommand(String cmd) {
+        ParcelFileDescriptor pfd = mUiAutomation.executeShellCommand(cmd);
+        InputStream is = new FileInputStream(pfd.getFileDescriptor());
+        try {
+            final byte[] buffer = new byte[8192];
+            while ((is.read(buffer)) != -1);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to exec: " + cmd);
+        }
+    }
+
+    private static class MockCaptioningChangeListener extends CaptioningChangeListener {
+        boolean wasEnabledChangedCalled = false;
+        boolean wasUserStyleChangedCalled = false;
+        boolean wasLocaleChangedCalled = false;
+        boolean wasFontScaleChangedCalled = false;
+
+        @Override
+        public void onEnabledChanged(boolean enabled) {
+            super.onEnabledChanged(enabled);
+            wasEnabledChangedCalled = true;
+        }
+
+        @Override
+        public void onUserStyleChanged(CaptionStyle userStyle) {
+            super.onUserStyleChanged(userStyle);
+            wasUserStyleChangedCalled = true;
+        }
+
+        @Override
+        public void onLocaleChanged(Locale locale) {
+            super.onLocaleChanged(locale);
+            wasLocaleChangedCalled = true;
+        }
+
+        @Override
+        public void onFontScaleChanged(float fontScale) {
+            super.onFontScaleChanged(fontScale);
+            wasFontScaleChangedCalled = true;
+        }
+
+        public void reset() {
+            wasEnabledChangedCalled = false;
+            wasUserStyleChangedCalled = false;
+            wasLocaleChangedCalled = false;
+            wasFontScaleChangedCalled = false;
+        }
+    }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index 0e84fb9..4350191 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -1452,27 +1452,14 @@
     }
 
     /**
-     * Tests the setting of lastAuthenticatedTime on accountAuthenticated being
-     * successful.
-     */
-    public void testLastAuthenticatedTimeAfterAccountAuthenticated() throws IOException,
-            AuthenticatorException, OperationCanceledException {
-        long accountAddTime = addAccountAndReturnAccountAddedTime(ACCOUNT, ACCOUNT_PASSWORD);
-        mockAuthenticator.callAccountAuthenticated();
-        long accountAuthenticatedTime = getLastAuthenticatedTime(ACCOUNT);
-        assertTrue(accountAuthenticatedTime > accountAddTime);
-    }
-
-    /**
-     * Tests the setting of lastAuthenticatedTime on setPassword being
-     * successful.
+     * LastAuthenticatedTime on setPassword should not be disturbed.
      */
     public void testLastAuthenticatedTimeAfterSetPassword() throws IOException,
             AuthenticatorException, OperationCanceledException {
         long accountAddTime = addAccountAndReturnAccountAddedTime(ACCOUNT, ACCOUNT_PASSWORD);
         mockAuthenticator.callSetPassword();
         long setPasswordTime = getLastAuthenticatedTime(ACCOUNT);
-        assertTrue(setPasswordTime > accountAddTime);
+        assertTrue(setPasswordTime == accountAddTime);
     }
 
     /**
@@ -1947,7 +1934,14 @@
 
     private long addAccountAndReturnAccountAddedTime(Account account, String password)
             throws OperationCanceledException, AuthenticatorException, IOException {
-        addAccountExplicitly(account, password, null /* userData */);
+        addAccount(am,
+                ACCOUNT_TYPE,
+                AUTH_TOKEN_TYPE,
+                REQUIRED_FEATURES,
+                OPTIONS_BUNDLE,
+                mActivity,
+                null /* callback */,
+                null /* handler */);
         return getLastAuthenticatedTime(account);
     }
 
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
index faebd53..c1b08de 100644
--- a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
+++ b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
@@ -151,6 +151,8 @@
         this.mAuthTokenType = authTokenType;
         this.mRequiredFeatures = requiredFeatures;
         this.mOptionsAddAccount = options;
+        AccountManager am = AccountManager.get(mContext);
+        am.addAccountExplicitly(AccountManagerTest.ACCOUNT, "fakePassword", null);
         return createResultBundle();
     }
 
diff --git a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
index a68d860..2c87b78 100644
--- a/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
+++ b/tests/tests/app/src/android/app/cts/DownloadManagerTest.java
@@ -96,6 +96,82 @@
         }
     }
 
+    public void testDownloadManagerSupportsHttp() throws Exception {
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            long id = mDownloadManager.enqueue(new Request(getGoodUrl()));
+
+            assertEquals(1, getTotalNumberDownloads());
+
+            assertDownloadQueryableById(id);
+
+            receiver.waitForDownloadComplete(SHORT_TIMEOUT, id);
+
+            assertDownloadQueryableByStatus(DownloadManager.STATUS_SUCCESSFUL);
+
+            assertRemoveDownload(id, 0);
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    public void testDownloadManagerSupportsHttpWithExternalWebServer() throws Exception {
+        // As a result of testDownloadManagerSupportsHttpsWithExternalWebServer relying on an
+        // external resource https://www.example.com this test uses http://www.example.com to help
+        // disambiguate errors from testDownloadManagerSupportsHttpsWithExternalWebServer.
+
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            long id = mDownloadManager.enqueue(new Request(Uri.parse("http://www.example.com")));
+
+            assertEquals(1, getTotalNumberDownloads());
+
+            assertDownloadQueryableById(id);
+
+            receiver.waitForDownloadComplete(SHORT_TIMEOUT, id);
+
+            assertDownloadQueryableByStatus(DownloadManager.STATUS_SUCCESSFUL);
+
+            assertRemoveDownload(id, 0);
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    public void testDownloadManagerSupportsHttpsWithExternalWebServer() throws Exception {
+        // For HTTPS, DownloadManager trusts only SSL server certs issued by CAs trusted by the
+        // system. Unfortunately, this means that it cannot trust the mock web server's SSL cert.
+        // Until this is resolved (e.g., by making it possible to specify additional CA certs to
+        // trust for a particular download), this test relies on https://www.example.com being
+        // operational and reachable from the Android under test.
+
+        final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
+        try {
+            IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+            mContext.registerReceiver(receiver, intentFilter);
+
+            long id = mDownloadManager.enqueue(new Request(Uri.parse("https://www.example.com")));
+
+            assertEquals(1, getTotalNumberDownloads());
+
+            assertDownloadQueryableById(id);
+
+            receiver.waitForDownloadComplete(SHORT_TIMEOUT, id);
+
+            assertDownloadQueryableByStatus(DownloadManager.STATUS_SUCCESSFUL);
+
+            assertRemoveDownload(id, 0);
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
     public void testMinimumDownload() throws Exception {
         final DownloadCompleteReceiver receiver = new DownloadCompleteReceiver();
         try {
diff --git a/tests/tests/content/res/values-v23/strings.xml b/tests/tests/content/res/values-v23/strings.xml
new file mode 100644
index 0000000..4ed1aaa
--- /dev/null
+++ b/tests/tests/content/res/values-v23/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+   <string name="version_cur">v23cur</string>
+</resources>
diff --git a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
index 8d96d91..80e0253 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PaintTest.java
@@ -809,7 +809,6 @@
     }
 
     public void testReset() {
-
         Paint p  = new Paint();
         ColorFilter c = new ColorFilter();
         MaskFilter m  = new MaskFilter();
@@ -845,7 +844,6 @@
         assertEquals(null, p.getShader());
         assertEquals(null, p.getTypeface());
         assertEquals(null, p.getXfermode());
-
     }
 
     public void testSetLinearText() {
@@ -930,6 +928,20 @@
         assertMeasureText(text, textChars, textSpan, 4, 7, widths[4] + widths[5] + widths[6]);
     }
 
+    public void testMeasureTextContext() {
+       Paint p = new Paint();
+       // Arabic LAM, which is different width depending on context
+       String shortString = "\u0644";
+       String longString = "\u0644\u0644\u0644";
+       char[] longChars = longString.toCharArray();
+       SpannedString longSpanned = new SpannedString(longString);
+       float width = p.measureText(shortString);
+       // Verify that measurement of substring is consistent no matter what surrounds it.
+       assertMeasureText(longString, longChars, longSpanned, 0, 1, width);
+       assertMeasureText(longString, longChars, longSpanned, 1, 2, width);
+       assertMeasureText(longString, longChars, longSpanned, 2, 3, width);
+    }
+
     public void testMeasureTextWithLongText() {
         // This test is not compatible with 4.0.3
         if ("4.0.3".equals(Build.VERSION.RELEASE)) {
@@ -1184,6 +1196,51 @@
         }
     }
 
+    public void testGetRunAdvance_nonzeroIndex() {
+        Paint p = new Paint();
+        final String text = "Android powers hundreds of millions of mobile " +
+                "devices in more than 190 countries around the world. It's" +
+                "the largest installed base of any mobile platform and" +
+                "growing fast—every day another million users power up their" +
+                "Android devices for the first time and start looking for" +
+                "apps, games, and other digital content.";
+        // Test offset index does not affect width.
+        final float widthAndroidFirst = p.getRunAdvance(
+                text, 0, 7, 0, text.length(), false, 7);
+        final float widthAndroidSecond = p.getRunAdvance(
+                text, 215, 222, 0, text.length(), false, 222);
+        assertTrue(Math.abs(widthAndroidFirst - widthAndroidSecond) < 1);
+    }
+
+    public void testGetRunAdvance_glyphDependingContext() {
+        Paint p = new Paint();
+        // Test the context change the character shape.
+        // First character should be isolated form because the context ends at index 1.
+        final float isolatedFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 1, true, 1);
+        // First character should be initial form because the context ends at index 2.
+        final float initialFormWidth = p.getRunAdvance("\u0644\u0644", 0, 1, 0, 2, true, 1);
+        assertTrue(isolatedFormWidth > initialFormWidth);
+    }
+
+    public void testGetRunAdvance_arabic() {
+        Paint p = new Paint();
+        // Test total width is equals to sum of each character's width.
+        // "What is Unicode?" in Arabic.
+        final String text =
+                "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
+                "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
+                "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
+                "\u062F\u061F";
+        final float totalWidth = p.getRunAdvance(
+                text, 0, text.length(), 0, text.length(), true, text.length());
+        float sumOfCharactersWidth = 0;
+        for (int i = 0; i < text.length(); i++) {
+            sumOfCharactersWidth += p.getRunAdvance(
+                    text, i, i + 1, 0, text.length(), true, i + 1);
+        }
+        assertTrue(Math.abs(totalWidth - sumOfCharactersWidth) < 1);
+    }
+
     public void testGetOffsetForAdvance() {
         Paint p = new Paint();
         {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index 457c688..88e7acb 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -164,21 +164,6 @@
 
     }
 
-    public void testGetDither() {
-        InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
-        BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
-
-        assertTrue(bitmapDrawable.getPaint().isDither());
-
-        bitmapDrawable.setDither(false);
-        assertFalse(bitmapDrawable.isDither());
-        assertEquals(bitmapDrawable.isDither(), bitmapDrawable.getPaint().isDither());
-
-        bitmapDrawable.setDither(true);
-        assertTrue(bitmapDrawable.isDither());
-        assertEquals(bitmapDrawable.isDither(), bitmapDrawable.getPaint().isDither());
-    }
-
     public void testAccessTileMode() {
         InputStream source = mContext.getResources().openRawResource(R.raw.testimage);
         BitmapDrawable bitmapDrawable = new BitmapDrawable(source);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
index 0d3c22f..79d2a1d 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableContainerTest.java
@@ -184,25 +184,6 @@
         assertTrue(dr.hasSetDitherCalled());
     }
 
-    public void testGetDither() {
-        assertConstantStateNotSet();
-        assertNull(mDrawableContainer.getCurrent());
-
-        mDrawableContainer.setConstantState(mDrawableContainerState);
-
-        MockDrawable dr = new MockDrawable();
-        addAndSelectDrawable(dr);
-
-
-        mDrawableContainer.setDither(true);
-        assertTrue(mDrawableContainer.isDither());
-
-        mDrawableContainer.setDither(false);
-        assertFalse(mDrawableContainer.isDither());
-
-        dr.reset();
-    }
-
     public void testSetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
         assertConstantStateNotSet();
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
index 608805a..a91353f 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTest.java
@@ -546,13 +546,6 @@
         mockDrawable.setDither(false);
     }
 
-    public void testGetDither() {
-        MockDrawable mockDrawable = new MockDrawable();
-
-        // isDither simply returns false for Drawable superclass
-        assertFalse((mockDrawable.isDither()));
-    }
-
     public void testSetHotspotBounds() {
         MockDrawable mockDrawable = new MockDrawable();
 
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index 9d9f52f..eeda22c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -189,16 +189,6 @@
         gradientDrawable.setDither(false);
     }
 
-    public void testGetDither() {
-        GradientDrawable gradientDrawable = new GradientDrawable();
-
-        gradientDrawable.setDither(true);
-        assertTrue(gradientDrawable.isDither());
-
-        gradientDrawable.setDither(false);
-        assertFalse(gradientDrawable.isDither());
-    }
-
     public void testSetColorFilter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         ColorFilter cf = new ColorFilter();
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index f24d6e2..a2f9ddf 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -502,19 +502,6 @@
         assertTrue(mockDrawable2.hasCalledSetDither());
     }
 
-    public void testGetDither() {
-        MockDrawable mockDrawable1 = new MockDrawable();
-        MockDrawable mockDrawable2 = new MockDrawable();
-        Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
-        LayerDrawable layerDrawable = new LayerDrawable(array);
-
-        layerDrawable.setDither(true);
-        assertTrue(layerDrawable.isDither());
-
-        layerDrawable.setDither(false);
-        assertFalse(layerDrawable.isDither());
-    }
-
     public void testSetHotspotBounds() {
         Rect bounds = new Rect(10, 15, 100, 150);
         MockDrawable mockDrawable1 = new MockDrawable();
@@ -1467,11 +1454,6 @@
             mCalledSetDither = true;
         }
 
-        @Override
-        public boolean isDither() {
-            return mDither;
-        }
-
         public boolean hasCalledSetDither() {
             return mCalledSetDither;
         }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
index 2c7209b..720397c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
@@ -197,16 +197,6 @@
         assertTrue(mNinePatchDrawable.getPaint().isDither());
     }
 
-    public void testGetDither() {
-        mNinePatchDrawable.setDither(false);
-        assertFalse(mNinePatchDrawable.isDither());
-        assertEquals(mNinePatchDrawable.isDither(), mNinePatchDrawable.getPaint().isDither());
-
-        mNinePatchDrawable.setDither(true);
-        assertTrue(mNinePatchDrawable.isDither());
-        assertEquals(mNinePatchDrawable.isDither(), mNinePatchDrawable.getPaint().isDither());
-    }
-
     public void testSetFilterBitmap() {
         mNinePatchDrawable.setFilterBitmap(false);
         assertFalse(mNinePatchDrawable.getPaint().isFilterBitmap());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 186010b..5b3234e 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -332,18 +332,6 @@
         assertFalse(shapeDrawable.getPaint().isDither());
     }
 
-    public void testGetDither() {
-        ShapeDrawable shapeDrawable = new ShapeDrawable();
-
-        shapeDrawable.setDither(true);
-        assertTrue(shapeDrawable.isDither());
-        assertEquals(shapeDrawable.isDither(), shapeDrawable.getPaint().isDither());
-
-        shapeDrawable.setDither(false);
-        assertFalse(shapeDrawable.isDither());
-        assertEquals(shapeDrawable.isDither(), shapeDrawable.getPaint().isDither());
-    }
-
     public void testMutate() {
         // How to load a ShapeDrawable from resources.
     }
diff --git a/tests/tests/hardware/AndroidManifest.xml b/tests/tests/hardware/AndroidManifest.xml
index 7b15b61..1d1e3a8 100644
--- a/tests/tests/hardware/AndroidManifest.xml
+++ b/tests/tests/hardware/AndroidManifest.xml
@@ -71,6 +71,8 @@
             android:process=":camera2ActivityProcess">
         </activity>
 
+        <activity android:name="android.hardware.input.cts.InputCtsActivity"
+            android:label="InputCtsActivity" />
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/hardware/res/raw/gamepad_press_a.json b/tests/tests/hardware/res/raw/gamepad_press_a.json
new file mode 100644
index 0000000..ff3ca4f
--- /dev/null
+++ b/tests/tests/hardware/res/raw/gamepad_press_a.json
@@ -0,0 +1,39 @@
+{
+    "id": 1,
+    "command": "register",
+    "name": "Odie (Test)",
+    "vid": 0x18d1,
+    "pid": 0x2c40,
+    "descriptor": [0x05, 0x01, 0x09, 0x05, 0xa1, 0x01, 0x85, 0x01, 0x05, 0x09, 0x0a, 0x01, 0x00,
+        0x0a, 0x02, 0x00, 0x0a, 0x04, 0x00, 0x0a, 0x05, 0x00, 0x0a, 0x07, 0x00, 0x0a, 0x08, 0x00,
+        0x0a, 0x0e, 0x00, 0x0a, 0x0f, 0x00, 0x0a, 0x0d, 0x00, 0x05, 0x0c, 0x0a, 0x24, 0x02, 0x0a,
+        0x23, 0x02, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x0b, 0x81, 0x02, 0x75, 0x01, 0x95,
+        0x01, 0x81, 0x03, 0x05, 0x01, 0x75, 0x04, 0x95, 0x01, 0x25, 0x07, 0x46, 0x3b, 0x01, 0x66,
+        0x14, 0x00, 0x09, 0x39, 0x81, 0x42, 0x66, 0x00, 0x00, 0x09, 0x01, 0xa1, 0x00, 0x09, 0x30,
+        0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x05, 0x02, 0x09, 0xc5, 0x09, 0xc4, 0x15, 0x00, 0x26,
+        0xff, 0x00, 0x35, 0x00, 0x46, 0xff, 0x00, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0x85,
+        0x02, 0x05, 0x08, 0x0a, 0x01, 0x00, 0x0a, 0x02, 0x00, 0x0a, 0x03, 0x00, 0x0a, 0x04, 0x00,
+        0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x04, 0x91, 0x02, 0x75, 0x04, 0x95, 0x01, 0x91,
+        0x03, 0xc0, 0x05, 0x0c, 0x09, 0x01, 0xa1, 0x01, 0x85, 0x03, 0x05, 0x01, 0x09, 0x06, 0xa1,
+        0x02, 0x05, 0x06, 0x09, 0x20, 0x15, 0x00, 0x26, 0xff, 0x00, 0x75, 0x08, 0x95, 0x01, 0x81,
+        0x02, 0x06, 0xbc, 0xff, 0x0a, 0xad, 0xbd, 0x75, 0x08, 0x95, 0x06, 0x81, 0x02, 0xc0, 0xc0],
+    "report": [0x01, 0x00, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
+
+{
+    "id": 1,
+    "command": "report",
+    "report": [0x01, 0x01, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
+
+{
+    "id": 1,
+    "command": "delay",
+    "duration": 10
+}
+
+{
+    "id": 1,
+    "command": "report",
+    "report": [0x01, 0x00, 0x80, 0x90, 0x80, 0x7f, 0x73, 0x00, 0x00]
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java b/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
index 936883e..1881774 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
@@ -19,6 +19,7 @@
 import android.app.Activity;
 import android.os.Bundle;
 import android.os.ConditionVariable;
+import android.os.SystemClock;
 import android.util.Log;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
@@ -57,7 +58,7 @@
         int waitTimeMs = timeOutMs;
         boolean changeSucceeded = false;
         while (!changeSucceeded && waitTimeMs > 0) {
-            long startTimeMs = System.currentTimeMillis();
+            long startTimeMs = SystemClock.elapsedRealtime();
             changeSucceeded = surfaceChangedDone.block(waitTimeMs);
             if (!changeSucceeded) {
                 Log.e(TAG, "Wait for surface change timed out after " + timeOutMs + " ms");
@@ -72,7 +73,7 @@
                 // again.
                 changeSucceeded = false;
             }
-            waitTimeMs -= (System.currentTimeMillis() - startTimeMs);
+            waitTimeMs -= (SystemClock.elapsedRealtime() - startTimeMs);
         }
 
         // Couldn't get expected surface size change.
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 afd71f5..ed8f7b7 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -739,6 +739,15 @@
         BlockingSessionCallback sessionListener = new BlockingSessionCallback(listener);
         camera.createReprocessableCaptureSession(inputConfiguration, outputSurfaces,
                 sessionListener, handler);
+
+        Integer[] sessionStates = {BlockingSessionCallback.SESSION_READY,
+                                   BlockingSessionCallback.SESSION_CONFIGURE_FAILED};
+        int state = sessionListener.getStateWaiter().waitForAnyOfStates(
+                Arrays.asList(sessionStates), SESSION_CONFIGURE_TIMEOUT_MS);
+
+        assertTrue("Creating a reprocessable session failed.",
+                state == BlockingSessionCallback.SESSION_READY);
+
         CameraCaptureSession session =
                 sessionListener.waitAndGetSession(SESSION_CONFIGURE_TIMEOUT_MS);
         assertTrue("Camera session should be a reprocessable session", session.isReprocessable());
@@ -938,6 +947,44 @@
         Size[] availableSizes = configMap.getOutputSizes(format);
         assertArrayNotEmpty(availableSizes, "availableSizes should not be empty for format: "
                 + format);
+        Size[] highResAvailableSizes = configMap.getHighResolutionOutputSizes(format);
+        if (highResAvailableSizes != null && highResAvailableSizes.length > 0) {
+            Size[] allSizes = new Size[availableSizes.length + highResAvailableSizes.length];
+            System.arraycopy(availableSizes, 0, allSizes, 0,
+                    availableSizes.length);
+            System.arraycopy(highResAvailableSizes, 0, allSizes, availableSizes.length,
+                    highResAvailableSizes.length);
+            availableSizes = allSizes;
+        }
+        if (VERBOSE) Log.v(TAG, "Supported sizes are: " + Arrays.deepToString(availableSizes));
+        return availableSizes;
+    }
+
+    /**
+     * Get the available output sizes for the given class.
+     *
+     */
+    public static Size[] getSupportedSizeForClass(Class klass, String cameraId,
+            CameraManager cameraManager) throws CameraAccessException {
+        CameraCharacteristics properties = cameraManager.getCameraCharacteristics(cameraId);
+        assertNotNull("Can't get camera characteristics!", properties);
+        if (VERBOSE) {
+            Log.v(TAG, "get camera characteristics for camera: " + cameraId);
+        }
+        StreamConfigurationMap configMap =
+                properties.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+        Size[] availableSizes = configMap.getOutputSizes(klass);
+        assertArrayNotEmpty(availableSizes, "availableSizes should not be empty for class: "
+                + klass);
+        Size[] highResAvailableSizes = configMap.getHighResolutionOutputSizes(ImageFormat.PRIVATE);
+        if (highResAvailableSizes != null && highResAvailableSizes.length > 0) {
+            Size[] allSizes = new Size[availableSizes.length + highResAvailableSizes.length];
+            System.arraycopy(availableSizes, 0, allSizes, 0,
+                    availableSizes.length);
+            System.arraycopy(highResAvailableSizes, 0, allSizes, availableSizes.length,
+                    highResAvailableSizes.length);
+            availableSizes = allSizes;
+        }
         if (VERBOSE) Log.v(TAG, "Supported sizes are: " + Arrays.deepToString(availableSizes));
         return availableSizes;
     }
@@ -961,10 +1008,9 @@
      */
     static public List<Size> getSupportedPreviewSizes(String cameraId,
             CameraManager cameraManager, Size bound) throws CameraAccessException {
-        CameraCharacteristics props = cameraManager.getCameraCharacteristics(cameraId);
-        StreamConfigurationMap config =
-                props.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-        Size[] rawSizes = config.getOutputSizes(android.view.SurfaceHolder.class);
+
+        Size[] rawSizes = getSupportedSizeForClass(android.view.SurfaceHolder.class, cameraId,
+                cameraManager);
         assertArrayNotEmpty(rawSizes,
                 "Available sizes for SurfaceHolder class should not be empty");
         if (VERBOSE) {
@@ -1050,10 +1096,9 @@
      */
     static public List<Size> getSupportedVideoSizes(String cameraId,
             CameraManager cameraManager, Size bound) throws CameraAccessException {
-        CameraCharacteristics props = cameraManager.getCameraCharacteristics(cameraId);
-        StreamConfigurationMap config =
-                props.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-        Size[] rawSizes = config.getOutputSizes(android.media.MediaRecorder.class);
+
+        Size[] rawSizes = getSupportedSizeForClass(android.media.MediaRecorder.class,
+                cameraId, cameraManager);
         assertArrayNotEmpty(rawSizes,
                 "Available sizes for MediaRecorder class should not be empty");
         if (VERBOSE) {
@@ -1668,7 +1713,9 @@
         // Validate capture result vs. request
         Size resultThumbnailSize = captureResult.get(CaptureResult.JPEG_THUMBNAIL_SIZE);
         int orientationTested = expectedExifData.jpegOrientation;
-        if ((orientationTested == 90 || orientationTested == 270)) {
+        // Legacy shim always doesn't rotate thumbnail size
+        if ((orientationTested == 90 || orientationTested == 270) &&
+                staticInfo.isHardwareLevelLimitedOrBetter()) {
             int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                     /*defaultValue*/-1);
             if (exifOrientation == ExifInterface.ORIENTATION_UNDEFINED) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
index 8184226..0da0ce7 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
@@ -115,19 +115,7 @@
                     continue;
                 }
 
-                Size[] targetCaptureSizes =
-                        mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
-                                StaticMetadata.StreamDirection.Output);
-
-                assertTrue("No capture sizes available for RAW format!",
-                        targetCaptureSizes.length != 0);
-                Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-                Size activeArraySize = new Size(activeArray.width(), activeArray.height());
-                assertTrue("Missing ActiveArraySize", activeArray.width() > 0 &&
-                        activeArray.height() > 0);
-                // TODO: Allow PixelArraySize also.
-                assertArrayContains("Available sizes for RAW format must include ActiveArraySize",
-                        targetCaptureSizes, activeArraySize);
+                Size activeArraySize = mStaticInfo.getRawDimensChecked();
 
                 // Create capture image reader
                 CameraTestUtils.SimpleImageReaderListener captureListener
@@ -202,19 +190,7 @@
                     continue;
                 }
 
-                Size[] targetCaptureSizes =
-                        mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
-                                StaticMetadata.StreamDirection.Output);
-
-                assertTrue("No capture sizes available for RAW format!",
-                        targetCaptureSizes.length != 0);
-                Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-                Size activeArraySize = new Size(activeArray.width(), activeArray.height());
-                assertTrue("Missing ActiveArraySize", activeArray.width() > 0 &&
-                        activeArray.height() > 0);
-                // TODO: Allow PixelArraySize also.
-                assertArrayContains("Available sizes for RAW format must include ActiveArraySize",
-                        targetCaptureSizes, activeArraySize);
+                Size activeArraySize = mStaticInfo.getRawDimensChecked();
 
                 Size[] targetPreviewSizes =
                         mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
@@ -322,19 +298,7 @@
                     continue;
                 }
 
-                Size[] targetCaptureSizes =
-                        mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
-                                StaticMetadata.StreamDirection.Output);
-
-                assertTrue("No capture sizes available for RAW format!",
-                        targetCaptureSizes.length != 0);
-                Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-                Size activeArraySize = new Size(activeArray.width(), activeArray.height());
-                assertTrue("Active array has invalid size!", activeArray.width() > 0 &&
-                        activeArray.height() > 0);
-                // TODO: Allow PixelArraySize also.
-                assertArrayContains("Available sizes for RAW format must include ActiveArraySize",
-                        targetCaptureSizes, activeArraySize);
+                Size activeArraySize = mStaticInfo.getRawDimensChecked();
 
                 // Get largest jpeg size
                 Size[] targetJpegSizes =
@@ -369,8 +333,8 @@
                         Bitmap.Config.ARGB_8888);
 
                 Size rawBitmapSize = new Size(rawBitmap.getWidth(), rawBitmap.getHeight());
-                assertTrue("Raw bitmap size must be equal to active array size.",
-                        rawBitmapSize.equals(activeArraySize));
+                assertTrue("Raw bitmap size must be equal to either pre-correction active array" +
+                        " size or pixel array size.", rawBitmapSize.equals(activeArraySize));
 
                 byte[] rawPlane = new byte[raw.getPlanes()[0].getRowStride() * raw.getHeight()];
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index aa1c3fc..99f7091 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -373,7 +373,7 @@
     /**
      * Test values for static metadata used by the BURST capability.
      */
-    public void testStaticBurstCharacteristics() {
+    public void testStaticBurstCharacteristics() throws Exception {
         int counter = 0;
         final float SIZE_ERROR_MARGIN = 0.03f;
         for (CameraCharacteristics c : mCharacteristics) {
@@ -395,7 +395,18 @@
             // Ensure that max YUV size matches max JPEG size
             Size maxYuvSize = CameraTestUtils.getMaxSize(
                     config.getOutputSizes(ImageFormat.YUV_420_888));
-            Size maxJpegSize = CameraTestUtils.getMaxSize(config.getOutputSizes(ImageFormat.JPEG));
+            Size maxFastYuvSize = maxYuvSize;
+
+            Size[] slowYuvSizes = config.getHighResolutionOutputSizes(ImageFormat.YUV_420_888);
+            assertTrue("Null slow YUV size array not allowed with BURST_CAPTURE capability!",
+                    slowYuvSizes != null);
+            if (slowYuvSizes.length > 0) {
+                Size maxSlowYuvSize = CameraTestUtils.getMaxSize(slowYuvSizes);
+                maxYuvSize = CameraTestUtils.getMaxSize(new Size[]{maxYuvSize, maxSlowYuvSize});
+            }
+
+            Size maxJpegSize = CameraTestUtils.getMaxSize(CameraTestUtils.getSupportedSizeForFormat(
+                    ImageFormat.JPEG, mIds[counter], mCameraManager));
 
             boolean haveMaxYuv = maxYuvSize != null ?
                 (maxJpegSize.getWidth() <= maxYuvSize.getWidth() &&
@@ -413,19 +424,29 @@
             boolean haveAwbLock = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE);
 
-            // Ensure that YUV output is fast enough - needs to be at least 20 fps
+            // Ensure that max YUV output is fast enough - needs to be at least 10 fps
 
             long maxYuvRate =
                 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
-            final long MIN_DURATION_BOUND_NS = 50000000; // 50 ms, 20 fps
+            final long MIN_MAXSIZE_DURATION_BOUND_NS = 100000000; // 100 ms, 10 fps
+            boolean haveMaxYuvRate = maxYuvRate <= MIN_MAXSIZE_DURATION_BOUND_NS;
 
-            boolean haveMaxYuvRate = maxYuvRate <= MIN_DURATION_BOUND_NS;
+            // Ensure that some >=8MP YUV output is fast enough - needs to be at least 20 fps
+
+            long maxFastYuvRate =
+                    config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxFastYuvSize);
+            final long MIN_8MP_DURATION_BOUND_NS = 200000000; // 50 ms, 20 fps
+            boolean haveFastYuvRate = maxFastYuvRate <= MIN_8MP_DURATION_BOUND_NS;
+
+            final int SIZE_8MP_BOUND = 8000000;
+            boolean havefast8MPYuv = (maxFastYuvSize.getWidth() * maxFastYuvSize.getHeight()) >
+                    SIZE_8MP_BOUND;
 
             // Ensure that there's an FPS range that's fast enough to capture at above
-            // minFrameDuration, for full-auto bursts
+            // minFrameDuration, for full-auto bursts at the fast resolutions
             Range[] fpsRanges = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
-            float minYuvFps = 1.f / maxYuvRate;
+            float minYuvFps = 1.f / maxFastYuvRate;
 
             boolean haveFastAeTargetFps = false;
             for (Range<Integer> r : fpsRanges) {
@@ -454,11 +475,18 @@
                                 mIds[counter]),
                         haveMaxYuv);
                 assertTrue(
-                        String.format("BURST-capable camera device %s YUV frame rate is too slow" +
+                        String.format("BURST-capable camera device %s max-resolution " +
+                                "YUV frame rate is too slow" +
                                 "(%d ns min frame duration reported, less than %d ns expected)",
-                                mIds[counter], maxYuvRate, MIN_DURATION_BOUND_NS),
+                                mIds[counter], maxYuvRate, MIN_MAXSIZE_DURATION_BOUND_NS),
                         haveMaxYuvRate);
                 assertTrue(
+                        String.format("BURST-capable camera device %s >= 8MP YUV output " +
+                                "frame rate is too slow" +
+                                "(%d ns min frame duration reported, less than %d ns expected)",
+                                mIds[counter], maxYuvRate, MIN_8MP_DURATION_BOUND_NS),
+                        haveFastYuvRate);
+                assertTrue(
                         String.format("BURST-capable camera device %s does not list an AE target " +
                                 " FPS range with min FPS >= %f, for full-AUTO bursts",
                                 mIds[counter], minYuvFps),
@@ -553,6 +581,7 @@
                     // Verify camera can output the reprocess input formats and sizes.
                     Size[] inputSizes = configs.getInputSizes(input);
                     Size[] outputSizes = configs.getOutputSizes(input);
+                    Size[] highResOutputSizes = configs.getHighResolutionOutputSizes(input);
                     assertTrue("no input size supported for format " + input,
                             inputSizes.length > 0);
                     assertTrue("no output size supported for format " + input,
@@ -560,7 +589,9 @@
 
                     for (Size inputSize : inputSizes) {
                         assertTrue("Camera must be able to output the supported reprocessing " +
-                            "input size", arrayContains(outputSizes, inputSize));
+                                "input size",
+                                arrayContains(outputSizes, inputSize) ||
+                                arrayContains(highResOutputSizes, inputSize));
                     }
                 }
             }
@@ -570,7 +601,7 @@
     /**
      * Cross-check StreamConfigurationMap output
      */
-    public void testStreamConfigurationMap() {
+    public void testStreamConfigurationMap() throws Exception {
         int counter = 0;
         for (CameraCharacteristics c : mCharacteristics) {
             Log.i(TAG, "testStreamConfigurationMap: Testing camera ID " + mIds[counter]);
@@ -618,6 +649,13 @@
                         config.isOutputSupportedFor(format));
                 List<Size> supportedSizes = CameraTestUtils.getAscendingOrderSizes(
                         Arrays.asList(config.getOutputSizes(format)), /*ascending*/true);
+                if (arrayContains(actualCapabilities,
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
+                    supportedSizes.addAll(
+                        Arrays.asList(config.getHighResolutionOutputSizes(format)));
+                    supportedSizes = CameraTestUtils.getAscendingOrderSizes(
+                        supportedSizes, /*ascending*/true);
+                }
                 assertTrue("Supported format " + format + " has no sizes listed",
                         supportedSizes.size() > 0);
                 for (int i = 0; i < supportedSizes.size(); i++) {
@@ -718,7 +756,8 @@
             SurfaceTexture st = new SurfaceTexture(1);
             Surface surf = new Surface(st);
 
-            Size[] opaqueSizes = config.getOutputSizes(SurfaceTexture.class);
+            Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class,
+                    mIds[counter], mCameraManager);
             assertTrue("Opaque format has no sizes listed",
                     opaqueSizes.length > 0);
             for (Size size : opaqueSizes) {
@@ -762,7 +801,8 @@
      * Test high speed capability and cross-check the high speed sizes and fps ranges from
      * the StreamConfigurationMap.
      */
-    public void testConstrainedHighSpeedCapability() {
+    public void testConstrainedHighSpeedCapability() throws Exception {
+        int counter = 0;
         for (CameraCharacteristics c : mCharacteristics) {
             int[] capabilities = CameraTestUtils.getValueNotNull(
                     c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
@@ -773,7 +813,8 @@
                                 c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                 List<Size> highSpeedSizes = Arrays.asList(config.getHighSpeedVideoSizes());
                 assertTrue("High speed sizes shouldn't be empty", highSpeedSizes.size() > 0);
-                Size[] allSizes = config.getOutputSizes(ImageFormat.PRIVATE);
+                Size[] allSizes = CameraTestUtils.getSupportedSizeForFormat(ImageFormat.PRIVATE,
+                        mIds[counter], mCameraManager);
                 assertTrue("Normal size for PRIVATE format shouldn't be null or empty",
                         allSizes != null && allSizes.length > 0);
                 for (Size size: highSpeedSizes) {
@@ -833,6 +874,7 @@
                     }
                 }
             }
+            counter++;
         }
     }
 
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 3d5ceaa..a078ad4 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -17,7 +17,7 @@
 package android.hardware.camera2.cts;
 
 import static android.hardware.camera2.cts.CameraTestUtils.*;
-import static android.hardware.camera2.cts.RobustnessTest.MaxOutputSizes.*;
+import static android.hardware.camera2.cts.RobustnessTest.MaxStreamSizes.*;
 
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
@@ -27,16 +27,20 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 import android.media.CamcorderProfile;
 import android.media.Image;
 import android.media.ImageReader;
+import android.media.ImageWriter;
 import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
 
+import com.android.ex.camera2.blocking.BlockingSessionCallback;
+
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
@@ -144,7 +148,7 @@
          * Each row of the table is a set of (format, max resolution) pairs, using the below consts
          */
 
-        // Enum values are defined in MaxOutputSizes
+        // Enum values are defined in MaxStreamSizes
         final int[][] LEGACY_COMBINATIONS = {
             {PRIV, MAXIMUM}, // Simple preview, GPU video processing, or no-preview video recording
             {JPEG, MAXIMUM}, // No-viewfinder still image capture
@@ -191,9 +195,164 @@
         final int[][][] TABLES =
             { LEGACY_COMBINATIONS, LIMITED_COMBINATIONS, BURST_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS };
 
-        // Sanity check the tables
+        sanityCheckConfigurationTables(TABLES);
+
+        for (String id : mCameraIds) {
+            openDevice(id);
+
+            // Find the concrete max sizes for each format/resolution combination
+            MaxStreamSizes maxSizes = new MaxStreamSizes(mStaticInfo, id);
+
+            String streamConfigurationMapString =
+                    mStaticInfo.getCharacteristics().get(
+                            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).toString();
+            if (VERBOSE) {
+                Log.v(TAG, "StreamConfigurationMap: " + streamConfigurationMapString);
+            }
+
+            // Always run legacy-level tests
+
+            for (int[] config : LEGACY_COMBINATIONS) {
+                testOutputCombination(id, config, maxSizes);
+            }
+
+            // Then run higher-level tests if applicable
+
+            if (!mStaticInfo.isHardwareLevelLegacy()) {
+
+                // If not legacy, at least limited, so run limited-level tests
+
+                for (int[] config : LIMITED_COMBINATIONS) {
+                    testOutputCombination(id, config, maxSizes);
+                }
+
+                // Check for BURST_CAPTURE, FULL and RAW and run those if appropriate
+
+                if (mStaticInfo.isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
+                    for (int[] config : BURST_COMBINATIONS) {
+                        testOutputCombination(id, config, maxSizes);
+                    }
+                }
+
+                if (mStaticInfo.isHardwareLevelFull()) {
+                    for (int[] config : FULL_COMBINATIONS) {
+                        testOutputCombination(id, config, maxSizes);
+                    }
+                }
+
+                if (mStaticInfo.isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
+                    for (int[] config : RAW_COMBINATIONS) {
+                        testOutputCombination(id, config, maxSizes);
+                    }
+                }
+            }
+
+            closeDevice(id);
+        }
+    }
+
+    /**
+     * Test for making sure the required reprocess input/output combinations for each hardware
+     * level and capability work as expected.
+     */
+    public void testMandatoryReprocessConfigurations() throws Exception {
+
+        /**
+         * For each stream combination, verify that
+         *    1. A reprocessable session can be created using the stream combination.
+         *    2. Reprocess capture requests targeting YUV and JPEG outputs are successful.
+         */
+        final int[][] LIMITED_COMBINATIONS = {
+            // Input        Outputs
+            {PRIV, MAXIMUM, JPEG, MAXIMUM},
+            {YUV , MAXIMUM, JPEG, MAXIMUM},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM},
+            {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM},
+            {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV,  MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+        };
+
+        final int[][] FULL_COMBINATIONS = {
+            // Input        Outputs
+            {YUV , MAXIMUM, PRIV, PREVIEW},
+            {YUV , MAXIMUM, YUV , PREVIEW},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , RECORD},
+            {YUV , MAXIMUM, PRIV, PREVIEW, YUV , RECORD},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , MAXIMUM},
+            {PRIV, MAXIMUM, YUV , PREVIEW, YUV , MAXIMUM},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , RECORD , JPEG, RECORD},
+            {YUV , MAXIMUM, PRIV, PREVIEW, YUV , RECORD , JPEG, RECORD},
+            {PRIV, MAXIMUM, YUV , PREVIEW, PRIV, PREVIEW, YUV , MAXIMUM},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+            {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, JPEG, MAXIMUM},
+        };
+
+        final int[][] RAW_COMBINATIONS = {
+            // Input        Outputs
+            {PRIV, MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM, YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM, PRIV, PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {YUV , MAXIMUM, YUV , PREVIEW, YUV , PREVIEW, RAW , MAXIMUM},
+            {PRIV, MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {YUV , MAXIMUM, PRIV, PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {PRIV, MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+            {YUV , MAXIMUM, YUV , PREVIEW, JPEG, MAXIMUM, RAW , MAXIMUM},
+        };
+
+        final int[][][] TABLES =
+                { LIMITED_COMBINATIONS, FULL_COMBINATIONS, RAW_COMBINATIONS };
+
+        sanityCheckConfigurationTables(TABLES);
+
+        for (String id : mCameraIds) {
+            CameraCharacteristics cc = mCameraManager.getCameraCharacteristics(id);
+            StaticMetadata staticInfo = new StaticMetadata(cc);
+            MaxStreamSizes maxSizes = new MaxStreamSizes(staticInfo, id);
+
+            // Skip the test for legacy devices.
+            if (staticInfo.isHardwareLevelLegacy()) {
+                continue;
+            }
+
+            openDevice(id);
+
+            try {
+                for (int[] config : LIMITED_COMBINATIONS) {
+                    testReprocessStreamCombination(id, config, maxSizes, staticInfo);
+                }
+
+                // Check FULL devices
+                if (staticInfo.isHardwareLevelFull()) {
+                    for (int[] config : FULL_COMBINATIONS) {
+                        testReprocessStreamCombination(id, config, maxSizes, staticInfo);
+                    }
+                }
+
+                // Check devices with RAW capability.
+                if (staticInfo.isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
+                    for (int[] config : RAW_COMBINATIONS) {
+                        testReprocessStreamCombination(id, config, maxSizes, staticInfo);
+                    }
+                }
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
+     * Sanity check the configuration tables.
+     */
+    private void sanityCheckConfigurationTables(final int[][][] tables) throws Exception {
         int tableIdx = 0;
-        for (int[][] table : TABLES) {
+        for (int[][] table : tables) {
             int rowIdx = 0;
             for (int[] row : table) {
                 assertTrue(String.format("Odd number of entries for table %d row %d: %s ",
@@ -214,73 +373,14 @@
             }
             tableIdx++;
         }
-
-        for (String id : mCameraIds) {
-
-            // Find the concrete max sizes for each format/resolution combination
-
-            CameraCharacteristics cc = mCameraManager.getCameraCharacteristics(id);
-
-            MaxOutputSizes maxSizes = new MaxOutputSizes(cc, id);
-
-            final StaticMetadata staticInfo = new StaticMetadata(cc);
-            String streamConfigurationMapString =
-                    cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).toString();
-            if (VERBOSE) {
-                Log.v(TAG, "StreamConfigurationMap: " + streamConfigurationMapString);
-            }
-
-            openDevice(id);
-
-            // Always run legacy-level tests
-
-            for (int[] config : LEGACY_COMBINATIONS) {
-                testOutputCombination(id, config, maxSizes);
-            }
-
-            // Then run higher-level tests if applicable
-
-            if (!staticInfo.isHardwareLevelLegacy()) {
-
-                // If not legacy, at least limited, so run limited-level tests
-
-                for (int[] config : LIMITED_COMBINATIONS) {
-                    testOutputCombination(id, config, maxSizes);
-                }
-
-                // Check for BURST_CAPTURE, FULL and RAW and run those if appropriate
-
-                if (staticInfo.isCapabilitySupported(
-                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
-                    for (int[] config : BURST_COMBINATIONS) {
-                        testOutputCombination(id, config, maxSizes);
-                    }
-                }
-
-                if (staticInfo.isHardwareLevelFull()) {
-                    for (int[] config : FULL_COMBINATIONS) {
-                        testOutputCombination(id, config, maxSizes);
-                    }
-                }
-
-                if (staticInfo.isCapabilitySupported(
-                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
-                    for (int[] config : RAW_COMBINATIONS) {
-                        testOutputCombination(id, config, maxSizes);
-                    }
-                }
-            }
-
-            closeDevice(id);
-        }
     }
 
     /**
      * Simple holder for resolutions to use for different camera outputs and size limits.
      */
-    static class MaxOutputSizes {
+    static class MaxStreamSizes {
         // Format shorthands
-        static final int PRIV = -1;
+        static final int PRIV = ImageFormat.PRIVATE;
         static final int JPEG = ImageFormat.JPEG;
         static final int YUV  = ImageFormat.YUV_420_888;
         static final int RAW  = ImageFormat.RAW_SENSOR;
@@ -292,15 +392,15 @@
         static final int VGA = 3;
         static final int RESOLUTION_COUNT = 4;
 
-        public MaxOutputSizes(CameraCharacteristics cc, String cameraId) {
-            StreamConfigurationMap configs =
-                    cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
-            Size[] privSizes = configs.getOutputSizes(SurfaceTexture.class);
-            Size[] yuvSizes = configs.getOutputSizes(ImageFormat.YUV_420_888);
-            Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG);
-            Size[] rawSizes = configs.getOutputSizes(ImageFormat.RAW_SENSOR);
+        public MaxStreamSizes(StaticMetadata sm, String cameraId) {
+            Size[] privSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.PRIVATE,
+                    StaticMetadata.StreamDirection.Output);
+            Size[] yuvSizes = sm.getAvailableSizesForFormatChecked(ImageFormat.YUV_420_888,
+                    StaticMetadata.StreamDirection.Output);
+            Size[] jpegSizes = sm.getJpegOutputSizesChecked();
+            Size[] rawSizes = sm.getRawOutputSizesChecked();
 
-            maxRawSize = (rawSizes != null) ? CameraTestUtils.getMaxSize(rawSizes) : null;
+            maxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null;
 
             maxPrivSizes[PREVIEW] = getMaxSize(privSizes, PREVIEW_SIZE_BOUND);
             maxYuvSizes[PREVIEW]  = getMaxSize(yuvSizes, PREVIEW_SIZE_BOUND);
@@ -314,6 +414,15 @@
             maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
             maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
 
+            StreamConfigurationMap configs = sm.getCharacteristics().get(
+                    CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+            Size[] privInputSizes = configs.getInputSizes(ImageFormat.PRIVATE);
+            maxInputPrivSize = privInputSizes != null ?
+                    CameraTestUtils.getMaxSize(privInputSizes) : null;
+            Size[] yuvInputSizes = configs.getInputSizes(ImageFormat.YUV_420_888);
+            maxInputYuvSize = yuvInputSizes != null ?
+                    CameraTestUtils.getMaxSize(yuvInputSizes) : null;
+
             // Must always be supported, add unconditionally
             final Size vgaSize = new Size(640, 480);
             maxPrivSizes[VGA] = vgaSize;
@@ -325,118 +434,253 @@
         public final Size[] maxJpegSizes = new Size[RESOLUTION_COUNT];
         public final Size[] maxYuvSizes = new Size[RESOLUTION_COUNT];
         public final Size maxRawSize;
+        // TODO: support non maximum reprocess input.
+        public final Size maxInputPrivSize;
+        public final Size maxInputYuvSize;
 
         static public String configToString(int[] config) {
             StringBuilder b = new StringBuilder("{ ");
             for (int i = 0; i < config.length; i += 2) {
                 int format = config[i];
                 int sizeLimit = config[i + 1];
-                switch (format) {
-                    case PRIV:
-                        b.append("[PRIV, ");
-                        break;
-                    case JPEG:
-                        b.append("[JPEG, ");
-                        break;
-                    case YUV:
-                        b.append("[YUV, ");
-                        break;
-                    case RAW:
-                        b.append("[RAW, ");
-                        break;
-                    default:
-                        b.append("[UNK, ");
-                        break;
-                }
-                switch (sizeLimit) {
-                    case PREVIEW:
-                        b.append("PREVIEW] ");
-                        break;
-                    case RECORD:
-                        b.append("RECORD] ");
-                        break;
-                    case MAXIMUM:
-                        b.append("MAXIMUM] ");
-                        break;
-                    case VGA:
-                        b.append("VGA] ");
-                        break;
-                    default:
-                        b.append("UNK] ");
-                        break;
-                }
+
+                appendFormatSize(b, format, sizeLimit);
+                b.append(" ");
             }
             b.append("}");
             return b.toString();
         }
+
+        static public String reprocessConfigToString(int[] reprocessConfig) {
+            // reprocessConfig[0..1] is the input configuration
+            StringBuilder b = new StringBuilder("Input: ");
+            appendFormatSize(b, reprocessConfig[0], reprocessConfig[1]);
+
+            // reprocessConfig[0..1] is also output configuration to be captured as reprocess input.
+            b.append(", Outputs: { ");
+            for (int i = 0; i < reprocessConfig.length; i += 2) {
+                int format = reprocessConfig[i];
+                int sizeLimit = reprocessConfig[i + 1];
+
+                appendFormatSize(b, format, sizeLimit);
+                b.append(" ");
+            }
+            b.append("}");
+            return b.toString();
+        }
+
+        static private void appendFormatSize(StringBuilder b, int format, int Size) {
+            switch (format) {
+                case PRIV:
+                    b.append("[PRIV, ");
+                    break;
+                case JPEG:
+                    b.append("[JPEG, ");
+                    break;
+                case YUV:
+                    b.append("[YUV, ");
+                    break;
+                case RAW:
+                    b.append("[RAW, ");
+                    break;
+                default:
+                    b.append("[UNK, ");
+                    break;
+            }
+
+            switch (Size) {
+                case PREVIEW:
+                    b.append("PREVIEW]");
+                    break;
+                case RECORD:
+                    b.append("RECORD]");
+                    break;
+                case MAXIMUM:
+                    b.append("MAXIMUM]");
+                    break;
+                case VGA:
+                    b.append("VGA]");
+                    break;
+                default:
+                    b.append("UNK]");
+                    break;
+            }
+        }
     }
 
-    private void testOutputCombination(String cameraId, int[] config, MaxOutputSizes maxSizes)
+    /**
+     * Return an InputConfiguration for a given reprocess configuration.
+     */
+    private InputConfiguration getInputConfig(int[] reprocessConfig, MaxStreamSizes maxSizes) {
+        int format;
+        Size size;
+
+        if (reprocessConfig[1] != MAXIMUM) {
+            throw new IllegalArgumentException("Test only supports MAXIMUM input");
+        }
+
+        switch (reprocessConfig[0]) {
+            case PRIV:
+                format = ImageFormat.PRIVATE;
+                size = maxSizes.maxInputPrivSize;
+                break;
+            case YUV:
+                format = ImageFormat.YUV_420_888;
+                size = maxSizes.maxInputYuvSize;
+                break;
+            default:
+                throw new IllegalArgumentException("Input format not supported: " +
+                        reprocessConfig[0]);
+        }
+
+        return new InputConfiguration(size.getWidth(), size.getHeight(), format);
+    }
+
+    private void testReprocessStreamCombination(String cameraId, int[] reprocessConfig,
+            MaxStreamSizes maxSizes, StaticMetadata staticInfo) throws Exception {
+
+        Log.i(TAG, String.format("Testing Camera %s, reprocess config: %s", cameraId,
+                MaxStreamSizes.reprocessConfigToString(reprocessConfig)));
+
+        final int TIMEOUT_FOR_RESULT_MS = 3000;
+        final int NUM_REPROCESS_CAPTURES = 3;
+
+        List<SurfaceTexture> privTargets = new ArrayList<>();
+        List<ImageReader> jpegTargets = new ArrayList<>();
+        List<ImageReader> yuvTargets = new ArrayList<>();
+        List<ImageReader> rawTargets = new ArrayList<>();
+        List<Surface> outputSurfaces = new ArrayList<>();
+        ImageReader inputReader = null;
+        ImageWriter inputWriter = null;
+        SimpleImageReaderListener inputReaderListener = new SimpleImageReaderListener();
+        SimpleCaptureCallback inputCaptureListener = new SimpleCaptureCallback();
+        SimpleCaptureCallback reprocessOutputCaptureListener = new SimpleCaptureCallback();
+
+        boolean supportYuvReprocess = staticInfo.isCapabilitySupported(
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING);
+        boolean supportOpaqueReprocess = staticInfo.isCapabilitySupported(
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
+
+        // Skip the configuration if the format is not supported for reprocessing.
+        if ((reprocessConfig[0] == YUV && !supportYuvReprocess) ||
+                (reprocessConfig[0] == PRIV && !supportOpaqueReprocess)) {
+            return;
+        }
+
+        try {
+            // reprocessConfig[0:1] is input
+            InputConfiguration inputConfig = getInputConfig(
+                    Arrays.copyOfRange(reprocessConfig, 0, 2), maxSizes);
+
+
+            inputReader = ImageReader.newInstance(inputConfig.getWidth(), inputConfig.getHeight(),
+                    inputConfig.getFormat(), NUM_REPROCESS_CAPTURES);
+            inputReader.setOnImageAvailableListener(inputReaderListener, mHandler);
+            outputSurfaces.add(inputReader.getSurface());
+
+            // reprocessConfig[2..] are additional outputs
+            setupConfigurationTargets(
+                    Arrays.copyOfRange(reprocessConfig, 2, reprocessConfig.length),
+                    maxSizes, privTargets, jpegTargets, yuvTargets, rawTargets, outputSurfaces,
+                    NUM_REPROCESS_CAPTURES);
+
+            // Verify we can create a reprocessable session with the input and all outputs.
+            BlockingSessionCallback sessionListener = new BlockingSessionCallback();
+            CameraCaptureSession session = configureReprocessableCameraSession(mCamera,
+                    inputConfig, outputSurfaces, sessionListener, mHandler);
+            inputWriter = ImageWriter.newInstance(session.getInputSurface(),
+                    NUM_REPROCESS_CAPTURES);
+
+            // Prepare a request for reprocess input
+            CaptureRequest.Builder builder = mCamera.createCaptureRequest(
+                    CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG);
+            builder.addTarget(inputReader.getSurface());
+
+            for (int i = 0; i < NUM_REPROCESS_CAPTURES; i++) {
+                session.capture(builder.build(), inputCaptureListener, mHandler);
+            }
+
+            List<CaptureRequest> reprocessRequests = new ArrayList<>();
+            int numReprocessOutputs = 0;
+
+            for (int i = 0; i < NUM_REPROCESS_CAPTURES; i++) {
+                TotalCaptureResult result = inputCaptureListener.getTotalCaptureResult(
+                        TIMEOUT_FOR_RESULT_MS);
+                builder =  mCamera.createReprocessCaptureRequest(result);
+                inputWriter.queueInputImage(inputReaderListener.getImage(TIMEOUT_FOR_RESULT_MS));
+
+                // Test mandatory YUV and JPEG reprocess outputs.
+                for (ImageReader reader : jpegTargets) {
+                    builder.addTarget(reader.getSurface());
+                    numReprocessOutputs++;
+                }
+
+                for (ImageReader reader : yuvTargets) {
+                    builder.addTarget(reader.getSurface());
+                    numReprocessOutputs++;
+                }
+
+                reprocessRequests.add(builder.build());
+            }
+
+            session.captureBurst(reprocessRequests, reprocessOutputCaptureListener, mHandler);
+
+            for (int i = 0; i < numReprocessOutputs; i++) {
+                TotalCaptureResult result = reprocessOutputCaptureListener.getTotalCaptureResult(
+                        TIMEOUT_FOR_RESULT_MS);
+            }
+        } catch (Throwable e) {
+            mCollector.addMessage(String.format("Reprocess stream combination %s failed due to: %s",
+                    MaxStreamSizes.reprocessConfigToString(reprocessConfig), e.getMessage()));
+        } finally {
+            inputReaderListener.drain();
+            reprocessOutputCaptureListener.drain();
+
+            for (SurfaceTexture target : privTargets) {
+                target.release();
+            }
+
+            for (ImageReader target : jpegTargets) {
+                target.close();
+            }
+
+            for (ImageReader target : yuvTargets) {
+                target.close();
+            }
+
+            for (ImageReader target : rawTargets) {
+                target.close();
+            }
+
+            if (inputReader != null) {
+                inputReader.close();
+            }
+
+            if (inputWriter != null) {
+                inputWriter.close();
+            }
+        }
+    }
+
+    private void testOutputCombination(String cameraId, int[] config, MaxStreamSizes maxSizes)
             throws Exception {
 
         Log.i(TAG, String.format("Testing Camera %s, config %s",
-                        cameraId, MaxOutputSizes.configToString(config)));
+                        cameraId, MaxStreamSizes.configToString(config)));
 
         // Timeout is relaxed by 500ms for LEGACY devices to reduce false positive rate in CTS
         final int TIMEOUT_FOR_RESULT_MS = (mStaticInfo.isHardwareLevelLegacy()) ? 1500 : 1000;
         final int MIN_RESULT_COUNT = 3;
 
-        ImageDropperListener imageDropperListener = new ImageDropperListener();
         // Set up outputs
-        List<Object> outputTargets = new ArrayList<>();
-        List<Surface> outputSurfaces = new ArrayList<>();
+        List<Surface> outputSurfaces = new ArrayList<Surface>();
         List<SurfaceTexture> privTargets = new ArrayList<SurfaceTexture>();
         List<ImageReader> jpegTargets = new ArrayList<ImageReader>();
         List<ImageReader> yuvTargets = new ArrayList<ImageReader>();
         List<ImageReader> rawTargets = new ArrayList<ImageReader>();
-        for (int i = 0; i < config.length; i += 2) {
-            int format = config[i];
-            int sizeLimit = config[i + 1];
 
-            switch (format) {
-                case PRIV: {
-                    Size targetSize = maxSizes.maxPrivSizes[sizeLimit];
-                    SurfaceTexture target = new SurfaceTexture(/*random int*/1);
-                    target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight());
-                    outputTargets.add(target);
-                    outputSurfaces.add(new Surface(target));
-                    privTargets.add(target);
-                    break;
-                }
-                case JPEG: {
-                    Size targetSize = maxSizes.maxJpegSizes[sizeLimit];
-                    ImageReader target = ImageReader.newInstance(
-                        targetSize.getWidth(), targetSize.getHeight(), JPEG, MIN_RESULT_COUNT);
-                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
-                    outputTargets.add(target);
-                    outputSurfaces.add(target.getSurface());
-                    jpegTargets.add(target);
-                    break;
-                }
-                case YUV: {
-                    Size targetSize = maxSizes.maxYuvSizes[sizeLimit];
-                    ImageReader target = ImageReader.newInstance(
-                        targetSize.getWidth(), targetSize.getHeight(), YUV, MIN_RESULT_COUNT);
-                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
-                    outputTargets.add(target);
-                    outputSurfaces.add(target.getSurface());
-                    yuvTargets.add(target);
-                    break;
-                }
-                case RAW: {
-                    Size targetSize = maxSizes.maxRawSize;
-                    ImageReader target = ImageReader.newInstance(
-                        targetSize.getWidth(), targetSize.getHeight(), RAW, MIN_RESULT_COUNT);
-                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
-                    outputTargets.add(target);
-                    outputSurfaces.add(target.getSurface());
-                    rawTargets.add(target);
-                    break;
-                }
-                default:
-                    fail("Unknown output format " + format);
-            }
-        }
+        setupConfigurationTargets(config, maxSizes, privTargets, jpegTargets, yuvTargets,
+                rawTargets, outputSurfaces, MIN_RESULT_COUNT);
 
         boolean haveSession = false;
         try {
@@ -469,17 +713,17 @@
 
         } catch (Throwable e) {
             mCollector.addMessage(String.format("Output combination %s failed due to: %s",
-                    MaxOutputSizes.configToString(config), e.getMessage()));
+                    MaxStreamSizes.configToString(config), e.getMessage()));
         }
         if (haveSession) {
             try {
                 Log.i(TAG, String.format("Done with camera %s, config %s, closing session",
-                                cameraId, MaxOutputSizes.configToString(config)));
+                                cameraId, MaxStreamSizes.configToString(config)));
                 stopCapture(/*fast*/false);
             } catch (Throwable e) {
                 mCollector.addMessage(
                     String.format("Closing down for output combination %s failed due to: %s",
-                            MaxOutputSizes.configToString(config), e.getMessage()));
+                            MaxStreamSizes.configToString(config), e.getMessage()));
             }
         }
 
@@ -497,6 +741,59 @@
         }
     }
 
+    private void setupConfigurationTargets(int[] outputConfigs, MaxStreamSizes maxSizes,
+            List<SurfaceTexture> privTargets, List<ImageReader> jpegTargets,
+            List<ImageReader> yuvTargets, List<ImageReader> rawTargets,
+            List<Surface> outputSurfaces, int numBuffers) {
+
+        ImageDropperListener imageDropperListener = new ImageDropperListener();
+
+        for (int i = 0; i < outputConfigs.length; i += 2) {
+            int format = outputConfigs[i];
+            int sizeLimit = outputConfigs[i + 1];
+
+            switch (format) {
+                case PRIV: {
+                    Size targetSize = maxSizes.maxPrivSizes[sizeLimit];
+                    SurfaceTexture target = new SurfaceTexture(/*random int*/1);
+                    target.setDefaultBufferSize(targetSize.getWidth(), targetSize.getHeight());
+                    outputSurfaces.add(new Surface(target));
+                    privTargets.add(target);
+                    break;
+                }
+                case JPEG: {
+                    Size targetSize = maxSizes.maxJpegSizes[sizeLimit];
+                    ImageReader target = ImageReader.newInstance(
+                        targetSize.getWidth(), targetSize.getHeight(), JPEG, numBuffers);
+                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                    outputSurfaces.add(target.getSurface());
+                    jpegTargets.add(target);
+                    break;
+                }
+                case YUV: {
+                    Size targetSize = maxSizes.maxYuvSizes[sizeLimit];
+                    ImageReader target = ImageReader.newInstance(
+                        targetSize.getWidth(), targetSize.getHeight(), YUV, numBuffers);
+                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                    outputSurfaces.add(target.getSurface());
+                    yuvTargets.add(target);
+                    break;
+                }
+                case RAW: {
+                    Size targetSize = maxSizes.maxRawSize;
+                    ImageReader target = ImageReader.newInstance(
+                        targetSize.getWidth(), targetSize.getHeight(), RAW, numBuffers);
+                    target.setOnImageAvailableListener(imageDropperListener, mHandler);
+                    outputSurfaces.add(target.getSurface());
+                    rawTargets.add(target);
+                    break;
+                }
+                default:
+                    fail("Unknown output format " + format);
+            }
+        }
+    }
+
     private static Size getMaxRecordingSize(String cameraId) {
         int id = Integer.valueOf(cameraId);
 
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
index 0dba61e..0bc74b3 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -86,10 +86,6 @@
                 mCollector.expectTrue("Full device must contain BURST_CAPTURE capability",
                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE));
 
-                // Max resolution fps must be >= 20.
-                mCollector.expectTrue("Full device must support at least 20fps for max resolution",
-                        getFpsForMaxSize(id) >= MIN_FPS_FOR_FULL_DEVICE);
-
                 // Need support per frame control
                 mCollector.expectTrue("Full device must support per frame control",
                         mStaticInfo.isPerFrameControlSupported());
@@ -102,7 +98,7 @@
             }
 
             // Max jpeg resolution must be very close to  sensor resolution
-            Size[] jpegSizes = configs.getOutputSizes(ImageFormat.JPEG);
+            Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
             Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
             mCollector.expectSizesAreSimilar(
                     "Active array size and max JPEG size should be similar",
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
index 62403cf..ee4ddd9 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -18,7 +18,6 @@
 
 import static android.hardware.camera2.cts.CameraTestUtils.*;
 import static android.hardware.camera2.cts.helpers.AssertHelpers.assertArrayContains;
-import static junit.framework.Assert.assertNotNull;
 
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -106,7 +105,7 @@
     public void testTakePicture() throws Exception{
         for (String id : mCameraIds) {
             try {
-                Log.i(TAG, "Testing touch for focus for Camera " + id);
+                Log.i(TAG, "Testing basic take picture for Camera " + id);
                 openDevice(id);
 
                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null);
@@ -336,6 +335,21 @@
         }
     }
 
+    public void testAePrecaptureTriggerCancelJpegCapture() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing AE precapture cancel for jpeg capture for Camera " + id);
+                openDevice(id);
+
+                takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
+                        /*addAeTriggerCancel*/true);
+            } finally {
+                closeDevice();
+                closeImageReader();
+            }
+        }
+    }
+
     /**
      * Start preview,take a picture and test preview is still running after snapshot
      */
@@ -393,6 +407,29 @@
     private void takePictureTestByCamera(
             MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
             MeteringRectangle[] afRegions) throws Exception {
+        takePictureTestByCamera(aeRegions, awbRegions, afRegions,
+                /*addAeTriggerCancel*/false);
+    }
+
+    /**
+     * Take a picture for a given set of 3A regions for a particular camera.
+     * <p>
+     * Before take a still capture, it triggers an auto focus and lock it first,
+     * then wait for AWB to converge and lock it, then trigger a precapture
+     * metering sequence and wait for AE converged. After capture is received, the
+     * capture result and image are validated. If {@code addAeTriggerCancel} is true,
+     * a precapture trigger cancel will be inserted between two adjacent triggers, which
+     * should effective cancel the first trigger.
+     * </p>
+     *
+     * @param aeRegions AE regions for this capture
+     * @param awbRegions AWB regions for this capture
+     * @param afRegions AF regions for this capture
+     * @param addAeTriggerCancel If a AE precapture trigger cancel is sent after the trigger.
+     */
+    private void takePictureTestByCamera(
+            MeteringRectangle[] aeRegions, MeteringRectangle[] awbRegions,
+            MeteringRectangle[] afRegions, boolean addAeTriggerCancel) throws Exception {
 
         boolean hasFocuser = mStaticInfo.hasFocuser();
 
@@ -498,6 +535,22 @@
         previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                 CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
         mSession.capture(previewRequest.build(), resultListener, mHandler);
+        if (addAeTriggerCancel) {
+            // Cancel the current precapture trigger, then send another trigger.
+            // The camera device should behave as if the first trigger is not sent.
+            // Wait one request to make the trigger start doing something before cancel.
+            waitForNumResults(resultListener, /*numResultsWait*/ 1);
+            previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL);
+            mSession.capture(previewRequest.build(), resultListener, mHandler);
+            waitForResultValue(resultListener, CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER,
+                    CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER_CANCEL,
+                    NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+            // Issue another trigger
+            previewRequest.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
+                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
+            mSession.capture(previewRequest.build(), resultListener, mHandler);
+        }
         waitForAeStable(resultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
 
         // Validate the next result immediately for region and mode.
@@ -610,16 +663,7 @@
      */
     private void rawCaptureTestByCamera() throws Exception {
         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
-        Size[] rawSizes = mStaticInfo.getRawOutputSizesChecked();
-
-        assertTrue("No capture sizes available for RAW format!",
-                rawSizes.length != 0);
-        Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-        Size size = new Size(activeArray.width(), activeArray.height());
-        assertTrue("Missing ActiveArraySize", activeArray.width() > 0 &&
-                activeArray.height() > 0);
-        assertArrayContains("Available sizes for RAW format must include ActiveArraySize",
-                rawSizes, size);
+        Size size = mStaticInfo.getRawDimensChecked();
 
         // Prepare raw capture and start preview.
         CaptureRequest.Builder previewBuilder =
@@ -658,20 +702,12 @@
     private void fullRawCaptureTestByCamera() throws Exception {
         Size maxPreviewSz = mOrderedPreviewSizes.get(0);
         Size maxStillSz = mOrderedStillSizes.get(0);
-        Size[] rawSizes = mStaticInfo.getRawOutputSizesChecked();
 
         SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
         SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
         SimpleImageReaderListener rawListener = new SimpleImageReaderListener();
 
-        assertTrue("No capture sizes available for RAW format!",
-                rawSizes.length != 0);
-        Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-        Size size = new Size(activeArray.width(), activeArray.height());
-        assertTrue("Missing ActiveArraySize", activeArray.width() > 0 &&
-                activeArray.height() > 0);
-        assertArrayContains("Available sizes for RAW format must include ActiveArraySize",
-                rawSizes, size);
+        Size size = mStaticInfo.getRawDimensChecked();
 
         if (VERBOSE) {
             Log.v(TAG, "Testing multi capture with size " + size.toString()
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 3890b33..e26cf7a 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -41,6 +41,8 @@
 import java.util.List;
 import java.util.Set;
 
+import static android.hardware.camera2.cts.helpers.AssertHelpers.*;
+
 /**
  * Helpers to get common static info out of the camera.
  *
@@ -743,6 +745,26 @@
     }
 
     /**
+     * Get and check pre-correction active array size.
+     */
+    public Rect getPreCorrectedActiveArraySizeChecked() {
+        Key<Rect> key = CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE;
+        Rect activeArray = getValueFromKeyNonNull(key);
+
+        if (activeArray == null) {
+            return new Rect(0, 0, 0, 0);
+        }
+
+        Size pixelArraySize = getPixelArraySizeChecked();
+        checkTrueForKey(key, "values left/top are invalid", activeArray.left >= 0 && activeArray.top >= 0);
+        checkTrueForKey(key, "values width/height are invalid",
+                activeArray.width() <= pixelArraySize.getWidth() &&
+                activeArray.height() <= pixelArraySize.getHeight());
+
+        return activeArray;
+    }
+
+    /**
      * Get and check active array size.
      */
     public Rect getActiveArraySizeChecked() {
@@ -763,6 +785,29 @@
     }
 
     /**
+     * Get the dimensions to use for RAW16 buffers.
+     */
+    public Size getRawDimensChecked() throws Exception {
+        Size[] targetCaptureSizes = getAvailableSizesForFormatChecked(ImageFormat.RAW_SENSOR,
+                        StaticMetadata.StreamDirection.Output);
+        Assert.assertTrue("No capture sizes available for RAW format!",
+                targetCaptureSizes.length != 0);
+        Rect activeArray = getPreCorrectedActiveArraySizeChecked();
+        Size preCorrectionActiveArraySize =
+                new Size(activeArray.width(), activeArray.height());
+        Size pixelArraySize = getPixelArraySizeChecked();
+        Assert.assertTrue("Missing pre-correction active array size", activeArray.width() > 0 &&
+                activeArray.height() > 0);
+        Assert.assertTrue("Missing pixel array size", pixelArraySize.getWidth() > 0 &&
+                pixelArraySize.getHeight() > 0);
+        Size[] allowedArraySizes = new Size[] { preCorrectionActiveArraySize,
+                pixelArraySize };
+        return assertArrayContainsAnyOf("Available sizes for RAW format" +
+                " must include either the pre-corrected active array size, or the full " +
+                "pixel array size", targetCaptureSizes, allowedArraySizes);
+    }
+
+    /**
      * Get the sensitivity value and clamp to the range if needed.
      *
      * @param sensitivity Input sensitivity value to check.
@@ -1168,7 +1213,7 @@
      *
      * @return Empty size array if jpeg output is not supported
      */
-    public Size[] getJpegOutputSizeChecked() {
+    public Size[] getJpegOutputSizesChecked() {
         return getAvailableSizesForFormatChecked(ImageFormat.JPEG,
                 StreamDirection.Output);
     }
@@ -1236,6 +1281,22 @@
      * @return The sizes of the given format, empty array if no available size is found.
      */
     public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction) {
+        return getAvailableSizesForFormatChecked(format, direction,
+                /*fastSizes*/true, /*slowSizes*/true);
+    }
+
+    /**
+     * Get available sizes for given format and direction, and whether to limit to slow or fast
+     * resolutions.
+     *
+     * @param format The format for the requested size array.
+     * @param direction The stream direction, input or output.
+     * @param fastSizes whether to include getOutputSizes() sizes (generally faster)
+     * @param slowSizes whether to include getHighResolutionOutputSizes() sizes (generally slower)
+     * @return The sizes of the given format, empty array if no available size is found.
+     */
+    public Size[] getAvailableSizesForFormatChecked(int format, StreamDirection direction,
+            boolean fastSizes, boolean slowSizes) {
         Key<StreamConfigurationMap> key =
                 CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
         StreamConfigurationMap config = getValueFromKeyNonNull(key);
@@ -1244,11 +1305,27 @@
             return new Size[0];
         }
 
-        Size[] sizes;
+        Size[] sizes = null;
 
         switch (direction) {
             case Output:
-                sizes = config.getOutputSizes(format);
+                Size[] fastSizeList = null;
+                Size[] slowSizeList = null;
+                if (fastSizes) {
+                    fastSizeList = config.getOutputSizes(format);
+                }
+                if (slowSizes) {
+                    slowSizeList = config.getHighResolutionOutputSizes(format);
+                }
+                if (fastSizeList != null && slowSizeList != null) {
+                    sizes = new Size[slowSizeList.length + fastSizeList.length];
+                    System.arraycopy(fastSizeList, 0, sizes, 0, fastSizeList.length);
+                    System.arraycopy(slowSizeList, 0, sizes, fastSizeList.length, slowSizeList.length);
+                } else if (fastSizeList != null) {
+                    sizes = fastSizeList;
+                } else if (slowSizeList != null) {
+                    sizes = slowSizeList;
+                }
                 break;
             case Input:
                 sizes = config.getInputSizes(format);
@@ -1369,7 +1446,8 @@
             return minDurationMap;
         }
 
-        for (android.util.Size size : config.getOutputSizes(format)) {
+        for (android.util.Size size : getAvailableSizesForFormatChecked(format,
+                StreamDirection.Output)) {
             long minFrameDuration = config.getOutputMinFrameDuration(format, size);
 
             if (minFrameDuration != 0) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
index 019bd21..ec9caaf 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
@@ -37,6 +37,7 @@
 import android.os.ConditionVariable;
 import android.os.Environment;
 import android.os.Looper;
+import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.MoreAsserts;
 import android.test.UiThreadTest;
@@ -1975,7 +1976,7 @@
         // This method tests if the actual fps is between minimum and maximum.
         // It also tests if the frame interval is too long.
         public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
-            long arrivalTime = System.currentTimeMillis();
+            long arrivalTime = SystemClock.elapsedRealtime();
             camera.addCallbackBuffer(data);
             if (firstFrameArrivalTime == 0) firstFrameArrivalTime = arrivalTime;
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
index 7c4deb9..a90725f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
@@ -43,7 +43,7 @@
     private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<TestSensorEvent>();
 
     private final long mMaximumSynchronizationErrorNs;
-    private final long mReportLatencyNs;
+    private final long mExpectedSyncLatencyNs;
 
     /**
      * Constructs an instance of {@link EventTimestampSynchronizationVerification}.
@@ -53,9 +53,9 @@
      */
     public EventTimestampSynchronizationVerification(
             long maximumSynchronizationErrorNs,
-            long reportLatencyNs) {
+            long expectedSyncLatencyNs) {
         mMaximumSynchronizationErrorNs = maximumSynchronizationErrorNs;
-        mReportLatencyNs = reportLatencyNs;
+        mExpectedSyncLatencyNs = expectedSyncLatencyNs;
     }
 
     /**
@@ -73,10 +73,12 @@
         if (fifoMaxEventCount > 0 && maximumExpectedSamplingPeriodUs != Integer.MAX_VALUE) {
             long fifoBasedReportLatencyUs =
                     fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
-            reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs);
+            reportLatencyUs = Math.min(reportLatencyUs, fifoBasedReportLatencyUs) +
+                (long)(2.5 * maximumExpectedSamplingPeriodUs);
         }
-        long reportLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs);
-        return new EventTimestampSynchronizationVerification(DEFAULT_THRESHOLD_NS, reportLatencyNs);
+        long expectedSyncLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs);
+        return new EventTimestampSynchronizationVerification(DEFAULT_THRESHOLD_NS,
+                                                              expectedSyncLatencyNs);
     }
 
     @Override
@@ -84,7 +86,6 @@
         StringBuilder errorMessageBuilder =
                 new StringBuilder(" event timestamp synchronization failures: ");
         List<IndexedEvent> failures = verifyTimestampSynchronization(errorMessageBuilder);
-
         int failuresCount = failures.size();
         stats.addValue(SensorStats.EVENT_TIME_SYNCHRONIZATION_COUNT_KEY, failuresCount);
         stats.addValue(
@@ -104,7 +105,7 @@
     public EventTimestampSynchronizationVerification clone() {
         return new EventTimestampSynchronizationVerification(
                 mMaximumSynchronizationErrorNs,
-                mReportLatencyNs);
+                mExpectedSyncLatencyNs);
     }
 
     /**
@@ -133,7 +134,7 @@
             long receivedTimestampNs = event.receivedTimestamp;
             long upperThresholdNs = receivedTimestampNs;
             long lowerThresholdNs = receivedTimestampNs - mMaximumSynchronizationErrorNs
-                    - mReportLatencyNs;
+                    - mExpectedSyncLatencyNs;
 
             if (eventTimestampNs < lowerThresholdNs || eventTimestampNs > upperThresholdNs) {
                 if (failures.size() < TRUNCATE_MESSAGE_LENGTH) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java b/tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java
similarity index 67%
copy from apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
copy to tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java
index 4231db7..accdcaf 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/InputCallback.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright 2015 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.
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.cts.verifier.tv;
+package android.hardware.input.cts;
 
-import android.preference.PreferenceActivity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
 
-public class MockTvInputSettingsActivity extends PreferenceActivity {
-
+public interface InputCallback {
+    public void onKeyEvent(KeyEvent ev);
+    public void onMotionEvent(MotionEvent ev);
 }
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
new file mode 100644
index 0000000..b16cadb
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/InputCtsActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2015 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.hardware.input.cts;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InputCtsActivity extends Activity {
+    private InputCallback mInputCallback;
+
+    @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchTouchEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchTrackballEvent(MotionEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onMotionEvent(ev);
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent ev) {
+        if (mInputCallback != null) {
+            mInputCallback.onKeyEvent(ev);
+        }
+        return true;
+    }
+
+    public void setInputCallback(InputCallback callback) {
+        mInputCallback = callback;
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java
new file mode 100644
index 0000000..92fba12
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/GamepadTestCase.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 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.hardware.input.cts.tests;
+
+import android.util.Log;
+import android.view.KeyEvent;
+
+import java.io.Writer;
+import java.util.List;
+
+import com.android.cts.hardware.R;
+
+public class GamepadTestCase extends InputTestCase {
+    private static final String TAG = "GamepadTests";
+
+    public void testButtonA() throws Exception {
+        sendHidCommands(R.raw.gamepad_press_a);
+        assertReceivedKeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BUTTON_A);
+        assertReceivedKeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BUTTON_A);
+        assertNoMoreEvents();
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
new file mode 100644
index 0000000..fba5f51
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2015 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.hardware.input.cts.tests;
+
+import android.app.UiAutomation;
+import android.hardware.input.cts.InputCtsActivity;
+import android.hardware.input.cts.InputCallback;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.List;
+import java.util.UUID;
+
+public class InputTestCase extends ActivityInstrumentationTestCase2<InputCtsActivity> {
+    private static final String TAG = "InputTestCase";
+    private static final String HID_EXECUTABLE = "hid";
+    private static final int SHELL_UID = 2000;
+    private static final String[] KEY_ACTIONS = {"DOWN", "UP", "MULTIPLE"};
+
+    private File mFifo;
+    private Writer mWriter;
+
+    private BlockingQueue<KeyEvent> mKeys;
+    private BlockingQueue<MotionEvent> mMotions;
+    private InputListener mInputListener;
+
+    public InputTestCase() {
+        super(InputCtsActivity.class);
+        mKeys = new LinkedBlockingQueue<KeyEvent>();
+        mMotions = new LinkedBlockingQueue<MotionEvent>();
+        mInputListener = new InputListener();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mFifo = setupFifo();
+        clearKeys();
+        clearMotions();
+        getActivity().setInputCallback(mInputListener);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (mFifo != null) {
+            mFifo.delete();
+            mFifo = null;
+        }
+        closeQuietly(mWriter);
+        mWriter = null;
+        super.tearDown();
+    }
+
+    /**
+     * Sends the HID commands designated by the given resource id.
+     * The commands must be in the format expected by the `hid` shell command.
+     *
+     * @param id The resource id from which to load the HID commands. This must be a "raw"
+     * resource.
+     */
+    public void sendHidCommands(int id) {
+        try {
+            Writer w = getWriter();
+            w.write(getEvents(id));
+            w.flush();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Asserts that the application received a {@link android.view.KeyEvent} with the given action
+     * and keycode.
+     *
+     * If other KeyEvents are received by the application prior to the expected KeyEvent, or no
+     * KeyEvents are received within a reasonable amount of time, then this will throw an
+     * AssertionFailedError.
+     *
+     * @param action The action to expect on the next KeyEvent
+     * (e.g. {@link android.view.KeyEvent#ACTION_DOWN}).
+     * @param keyCode The expected key code of the next KeyEvent.
+     */
+    public void assertReceivedKeyEvent(int action, int keyCode) {
+        KeyEvent k = waitForKey();
+        if (k == null) {
+            fail("Timed out waiting for " + KeyEvent.keyCodeToString(keyCode)
+                    + " with action " + KEY_ACTIONS[action]);
+            return;
+        }
+        assertEquals(action, k.getAction());
+        assertEquals(keyCode, k.getKeyCode());
+    }
+
+    /**
+     * Asserts that no more events have been received by the application.
+     *
+     * If any more events have been received by the application, this throws an
+     * AssertionFailedError.
+     */
+    public void assertNoMoreEvents() {
+        KeyEvent key;
+        MotionEvent motion;
+        if ((key = mKeys.poll()) != null) {
+            fail("Extraneous key events generated: " + key);
+        }
+        if ((motion = mMotions.poll()) != null) {
+            fail("Extraneous motion events generated: " + motion);
+        }
+    }
+
+    private KeyEvent waitForKey() {
+        try {
+            return mKeys.poll(1, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            return null;
+        }
+    }
+
+    private void clearKeys() {
+        mKeys.clear();
+    }
+
+    private void clearMotions() {
+        mMotions.clear();
+    }
+
+    private File setupFifo() throws ErrnoException {
+        File dir = getActivity().getCacheDir();
+        String filename = dir.getAbsolutePath() + File.separator +  UUID.randomUUID().toString();
+        Os.mkfifo(filename, 0666);
+        File f = new File(filename);
+        return f;
+    }
+
+    private Writer getWriter() throws IOException {
+        if (mWriter == null) {
+            UiAutomation ui = getInstrumentation().getUiAutomation();
+            ui.executeShellCommand("hid " + mFifo.getAbsolutePath());
+            mWriter = new FileWriter(mFifo);
+        }
+        return mWriter;
+    }
+
+    private String getEvents(int id) throws IOException {
+        InputStream is =
+            getInstrumentation().getTargetContext().getResources().openRawResource(id);
+        return readFully(is);
+    }
+
+
+    private static void closeQuietly(AutoCloseable closeable) {
+        if (closeable != null) {
+            try {
+                closeable.close();
+            } catch (RuntimeException rethrown) {
+                throw rethrown;
+            } catch (Exception ignored) { }
+        }
+    }
+
+    private static String readFully(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int read = 0;
+        byte[] buffer = new byte[1024];
+        while ((read = is.read(buffer)) >= 0) {
+            baos.write(buffer, 0, read);
+        }
+        return baos.toString();
+    }
+
+    private class InputListener implements InputCallback {
+        public void onKeyEvent(KeyEvent ev) {
+            boolean done = false;
+            do {
+                try {
+                    mKeys.put(new KeyEvent(ev));
+                    done = true;
+                } catch (InterruptedException ignore) { }
+            } while (!done);
+        }
+
+        public void onMotionEvent(MotionEvent ev) {
+            boolean done = false;
+            do {
+                try {
+                    mMotions.put(MotionEvent.obtain(ev));
+                    done = true;
+                } catch (InterruptedException ignore) { }
+            } while (!done);
+        }
+    }
+}
diff --git a/tests/tests/keystore/Android.mk b/tests/tests/keystore/Android.mk
index 0f2cd03..eaf5389 100644
--- a/tests/tests/keystore/Android.mk
+++ b/tests/tests/keystore/Android.mk
@@ -16,7 +16,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_TAGS := tests
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner core-tests-support
 
diff --git a/tests/tests/keystore/assets/nist_cavp_aes_kat.zip b/tests/tests/keystore/assets/nist_cavp_aes_kat.zip
new file mode 100644
index 0000000..90083c8
--- /dev/null
+++ b/tests/tests/keystore/assets/nist_cavp_aes_kat.zip
Binary files differ
diff --git a/tests/tests/keystore/res/raw/ec_key1_cert.der b/tests/tests/keystore/res/raw/ec_key1_cert.der
new file mode 100644
index 0000000..77293bb
--- /dev/null
+++ b/tests/tests/keystore/res/raw/ec_key1_cert.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/ec_key1_pkcs8.der b/tests/tests/keystore/res/raw/ec_key1_pkcs8.der
new file mode 100644
index 0000000..0400ad6
--- /dev/null
+++ b/tests/tests/keystore/res/raw/ec_key1_pkcs8.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/rsa_key1_cert.der b/tests/tests/keystore/res/raw/rsa_key1_cert.der
new file mode 100644
index 0000000..09e5a30
--- /dev/null
+++ b/tests/tests/keystore/res/raw/rsa_key1_cert.der
Binary files differ
diff --git a/tests/tests/keystore/res/raw/rsa_key1_pkcs8.der b/tests/tests/keystore/res/raw/rsa_key1_pkcs8.der
new file mode 100644
index 0000000..b398ab1
--- /dev/null
+++ b/tests/tests/keystore/res/raw/rsa_key1_pkcs8.der
Binary files differ
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java b/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java
new file mode 100644
index 0000000..520b54d
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2015 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.keystore.cts;
+
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.KeyStore;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+public class AESCipherNistCavpKatTest extends AndroidTestCase {
+
+    private static final String TAG = AESCipherNistCavpKatTest.class.getSimpleName();
+
+    public void testSomething() throws Exception {
+        try (ZipInputStream zipIn = new ZipInputStream(
+                getContext().getResources().getAssets().open("nist_cavp_aes_kat.zip"))) {
+            ZipEntry zipEntry;
+            while ((zipEntry = zipIn.getNextEntry()) != null) {
+                String entryName = zipEntry.getName();
+                if (!entryName.endsWith(".rsp")) {
+                    continue;
+                }
+
+                if (zipEntry.getSize() > 1024 * 1024) {
+                    fail("Entry " + entryName + " too large: " + zipEntry.getSize() + " bytes");
+                }
+                byte[] entryContents = new byte[(int) zipEntry.getSize()];
+                readFully(zipIn, entryContents);
+                runTestsForKatFile(entryName, entryContents);
+            }
+        }
+    }
+
+    private void runTestsForKatFile(String fileName, byte[] contents) throws Exception {
+        if ((!fileName.endsWith(".rsp")) || (fileName.length() < 10)) {
+            Log.i(TAG, "Ignoring " + fileName + " -- not a KAT file");
+            return;
+        }
+        String mode = fileName.substring(0, 3);
+        if ("CFB".equals(mode)) {
+            mode = fileName.substring(0, 4);
+        }
+        try {
+            Cipher.getInstance("AES/" + mode + "/NoPadding", "AndroidKeyStoreBCWorkaround");
+        } catch (NoSuchAlgorithmException e) {
+            if (("CBC".equals(mode)) || ("ECB".equals(mode))) {
+                fail("Supported mode is apparently not supported: " + mode);
+            }
+            Log.i(TAG, "Skipping " + fileName
+                    + " -- transformation not supported by AndroidKeyStore");
+            return;
+        }
+
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(
+                    new ByteArrayInputStream(contents), "ISO-8859-1"));
+            String line;
+            int lineNumber = 0;
+            String section = null; // ENCRYPT or DECRYPT
+
+            boolean insideTestDefinition = false;
+            int testNumber = 0;
+            TestVector testVector = null;
+
+            while ((line = in.readLine()) != null) {
+                lineNumber++;
+                line = line.trim();
+                if (line.startsWith("#")) {
+                    // Ignore comment lines
+                    continue;
+                }
+
+                if (!insideTestDefinition) {
+                    // Outside of a test definition
+                    if (line.length() == 0) {
+                        // Ignore empty lines
+                        continue;
+                    }
+                    if ((line.startsWith("[")) && (line.endsWith("]"))) {
+                        section = line.substring(1, line.length() - 1);
+                        if ((!"DECRYPT".equals(section)) && (!"ENCRYPT".equals(section))) {
+                            throw new IOException(lineNumber + ": Unexpected section: " + section);
+                        }
+                        continue;
+                    }
+
+                    // Check whether this is a NAME = VALUE line
+                    int delimiterIndex = line.indexOf('=');
+                    if (delimiterIndex == -1) {
+                        throw new IOException(lineNumber + ": Unexpected line outside of test"
+                                + " definition: " + line);
+                    }
+                    String name = line.substring(0, delimiterIndex).trim();
+                    String value = line.substring(delimiterIndex + 1).trim();
+
+                    if ("COUNT".equals(name)) {
+                        testNumber = Integer.parseInt(value);
+                        insideTestDefinition = true;
+                        testVector = new TestVector();
+                    } else {
+                        throw new IOException(lineNumber + ": Unexpected line outside of test"
+                                + " definition: " + line);
+                    }
+                } else {
+                    // Inside of a test definition
+                    if (line.length() == 0) {
+                        // End of test definition
+                        boolean encrypt;
+                        if ("ENCRYPT".equals(section)) {
+                            encrypt = true;
+                        } else if ("DECRYPT".equals(section)) {
+                            encrypt = false;
+                        } else {
+                            throw new IOException("Unexpected test operation: " + section);
+                        }
+                        Log.d(TAG, "Running test #" + testNumber + ": AES/" + mode + " from " + fileName);
+                        runKatTest(mode, encrypt, testVector);
+                        insideTestDefinition = false;
+                        testVector = null;
+                    } else {
+                        // Check whether this is a NAME = VALUE line
+                        int delimiterIndex = line.indexOf('=');
+                        if (delimiterIndex == -1) {
+                            throw new IOException(lineNumber + ": Unexpected line inside test"
+                                    + " definition: " + line);
+                        }
+                        String name = line.substring(0, delimiterIndex).trim();
+                        String value = line.substring(delimiterIndex + 1).trim();
+
+                        if ("KEY".equals(name)) {
+                            testVector.key = HexEncoding.decode(value);
+                        } else if ("IV".equals(name)) {
+                            testVector.iv = HexEncoding.decode(value);
+                        } else if ("PLAINTEXT".equals(name)) {
+                            testVector.plaintext = HexEncoding.decode(value);
+                        } else if ("CIPHERTEXT".equals(name)) {
+                            testVector.ciphertext = HexEncoding.decode(value);
+                        } else {
+                            throw new IOException(lineNumber + ": Unexpected line inside test"
+                                    + " definition: " + line);
+                        }
+                    }
+                }
+            }
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (Exception ignored) {}
+            }
+        }
+    }
+
+    private void runKatTest(String mode, boolean encrypt, TestVector testVector) throws Exception {
+        String keyAlias = AESCipherNistCavpKatTest.class.getName();
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+        keyStore.setEntry(keyAlias,
+                new KeyStore.SecretKeyEntry(new SecretKeySpec(testVector.key, "AES")),
+                new KeyProtection.Builder(
+                        KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+                        .setBlockModes(mode)
+                        .setEncryptionPaddings("NoPadding")
+                        .setRandomizedEncryptionRequired(false)
+                        .build());
+        try {
+            SecretKey key = (SecretKey) keyStore.getKey(keyAlias, null);
+            assertNotNull(key);
+            Cipher cipher = Cipher.getInstance("AES/" + mode + "/NoPadding");
+
+            int opmode = (encrypt) ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE;
+            if (testVector.iv != null) {
+                cipher.init(opmode, key, new IvParameterSpec(testVector.iv));
+            } else {
+                cipher.init(opmode, key);
+            }
+
+            byte[] input = (encrypt) ? testVector.plaintext : testVector.ciphertext;
+            byte[] actualOutput = cipher.doFinal(input);
+            byte[] expectedOutput = (encrypt) ? testVector.ciphertext : testVector.plaintext;
+            if (!Arrays.equals(expectedOutput, actualOutput)) {
+                fail("Expected: " + HexEncoding.encode(expectedOutput)
+                        + ", actual: " + HexEncoding.encode(actualOutput));
+            }
+        } finally {
+            keyStore.deleteEntry(keyAlias);
+        }
+    }
+
+    private static void readFully(InputStream in, byte[] buf) throws IOException {
+        int offset = 0;
+        int remaining = buf.length;
+        while (remaining > 0) {
+            int chunkSize = in.read(buf, offset, remaining);
+            if (chunkSize == -1) {
+                throw new EOFException("Premature EOF. Remainig: " + remaining);
+            }
+            offset += chunkSize;
+            remaining -= chunkSize;
+        }
+    }
+
+    private static class TestVector {
+        public byte[] key;
+        public byte[] iv;
+        public byte[] plaintext;
+        public byte[] ciphertext;
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java
new file mode 100644
index 0000000..2330209
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/ECDSASignatureTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 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.keystore.cts;
+
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+
+import junit.framework.TestCase;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.Signature;
+
+public class ECDSASignatureTest extends TestCase {
+
+    public void testNONEwithECDSATruncatesInputToFieldSize() throws Exception {
+        assertNONEwithECDSATruncatesInputToFieldSize(224);
+        assertNONEwithECDSATruncatesInputToFieldSize(256);
+        assertNONEwithECDSATruncatesInputToFieldSize(384);
+        assertNONEwithECDSATruncatesInputToFieldSize(521);
+    }
+
+    private void assertNONEwithECDSATruncatesInputToFieldSize(int keySizeBits) throws Exception {
+        byte[] message = new byte[(keySizeBits * 3) / 8];
+        for (int i = 0; i < message.length; i++) {
+            message[i] = (byte) (i + 1);
+        }
+        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+        generator.initialize(new KeyGenParameterSpec.Builder(
+                "test1",
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_NONE)
+                .setKeySize(keySizeBits)
+                .build());
+        KeyPair keyPair = generator.generateKeyPair();
+
+        Signature signature = Signature.getInstance("NONEwithECDSA");
+        signature.initSign(keyPair.getPrivate());
+        assertSame(Security.getProvider(SignatureTest.EXPECTED_PROVIDER_NAME),
+                signature.getProvider());
+        signature.update(message);
+        byte[] sigBytes = signature.sign();
+
+        signature = Signature.getInstance(signature.getAlgorithm(), signature.getProvider());
+        signature.initVerify(keyPair.getPublic());
+
+        // Verify the full-length message
+        signature.update(message);
+        assertTrue(signature.verify(sigBytes));
+
+        // Verify the message truncated to field size
+        signature.update(message, 0, (keySizeBits + 7) / 8);
+        assertTrue(signature.verify(sigBytes));
+
+        // Verify message truncated to one byte shorter than field size -- this should fail
+        signature.update(message, 0, (keySizeBits / 8) - 1);
+        assertFalse(signature.verify(sigBytes));
+    }
+
+    public void testNONEwithECDSASupportsMessagesShorterThanFieldSize() throws Exception {
+        assertNONEwithECDSASupportsMessagesShorterThanFieldSize(224);
+        assertNONEwithECDSASupportsMessagesShorterThanFieldSize(256);
+        assertNONEwithECDSASupportsMessagesShorterThanFieldSize(384);
+        assertNONEwithECDSASupportsMessagesShorterThanFieldSize(521);
+    }
+
+    private void assertNONEwithECDSASupportsMessagesShorterThanFieldSize(
+            int keySizeBits) throws Exception {
+        byte[] message = new byte[(keySizeBits * 3 / 4) / 8];
+        for (int i = 0; i < message.length; i++) {
+            message[i] = (byte) (i + 1);
+        }
+        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+        generator.initialize(new KeyGenParameterSpec.Builder(
+                "test1",
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_NONE)
+                .setKeySize(keySizeBits)
+                .build());
+        KeyPair keyPair = generator.generateKeyPair();
+
+        Signature signature = Signature.getInstance("NONEwithECDSA");
+        signature.initSign(keyPair.getPrivate());
+        assertSame(Security.getProvider(SignatureTest.EXPECTED_PROVIDER_NAME),
+                signature.getProvider());
+        signature.update(message);
+        byte[] sigBytes = signature.sign();
+
+        signature = Signature.getInstance(signature.getAlgorithm(), signature.getProvider());
+        signature.initVerify(keyPair.getPublic());
+
+        // Verify the message
+        signature.update(message);
+        assertTrue(signature.verify(sigBytes));
+
+        // Assert that the message is left-padded with zero bits
+        byte[] fullLengthMessage = new byte[keySizeBits / 8];
+        System.arraycopy(message, 0,
+                fullLengthMessage, fullLengthMessage.length - message.length,
+                message.length);
+        signature.update(fullLengthMessage);
+        assertTrue(signature.verify(sigBytes));
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyPairGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
similarity index 94%
rename from tests/tests/keystore/src/android/keystore/cts/AndroidKeyPairGeneratorTest.java
rename to tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
index 5ed169b..db7f539 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyPairGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
@@ -64,7 +64,7 @@
 import libcore.javax.net.ssl.TestKeyManager;
 import libcore.javax.net.ssl.TestSSLContext;
 
-public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
+public class KeyPairGeneratorTest extends AndroidTestCase {
     private KeyStore mKeyStore;
 
     private CountingSecureRandom mRng;
@@ -91,6 +91,8 @@
     @SuppressWarnings("deprecation")
     private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
 
+    private static final long DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
+
     private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
     private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
     private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
@@ -556,8 +558,6 @@
                 .setCertificateSubject(certSubject)
                 .setCertificateNotBefore(certNotBefore)
                 .setCertificateNotAfter(certNotAfter)
-                .setUserAuthenticationRequired(true)
-                .setUserAuthenticationValidityDurationSeconds(600)
                 .build());
         KeyPair keyPair = generator.generateKeyPair();
         assertGeneratedKeyPairAndSelfSignedCertificate(
@@ -588,8 +588,8 @@
                 KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512);
         MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings()));
         MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getEncryptionPaddings()));
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(600, keyInfo.getUserAuthenticationValidityDurationSeconds());
+        assertFalse(keyInfo.isUserAuthenticationRequired());
+        assertEquals(-1, keyInfo.getUserAuthenticationValidityDurationSeconds());
     }
 
     public void testGenerate_RSA_ModernSpec_AsCustomAsPossible() throws Exception {
@@ -622,8 +622,6 @@
                 .setCertificateSubject(certSubject)
                 .setCertificateNotBefore(certNotBefore)
                 .setCertificateNotAfter(certNotAfter)
-                .setUserAuthenticationRequired(true)
-                .setUserAuthenticationValidityDurationSeconds(600)
                 .build());
         KeyPair keyPair = generator.generateKeyPair();
         assertGeneratedKeyPairAndSelfSignedCertificate(
@@ -659,8 +657,8 @@
         MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getEncryptionPaddings()),
                 KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
                 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(600, keyInfo.getUserAuthenticationValidityDurationSeconds());
+        assertFalse(keyInfo.isUserAuthenticationRequired());
+        assertEquals(-1, keyInfo.getUserAuthenticationValidityDurationSeconds());
     }
 
     public void testGenerate_EC_ModernSpec_UsableForTLSPeerAuth() throws Exception {
@@ -721,13 +719,19 @@
         assertKeyPairAndCertificateUsableForTLSPeerAuthentication(TEST_ALIAS_1);
     }
 
-    public void testGenerate_EC_ModernSpec_PerOpAuthRequired() throws Exception {
+    // TODO: Test fingerprint-authorized and secure lock screen-authorized keys. These can't
+    // currently be tested here because CTS does not require that secure lock screen is set up and
+    // that at least one fingerprint is enrolled.
+
+    public void testGenerate_EC_ModernSpec_KeyNotYetValid() throws Exception {
         KeyPairGenerator generator = getEcGenerator();
+        Date validityStart = new Date(System.currentTimeMillis() + DAY_IN_MILLIS);
         generator.initialize(new KeyGenParameterSpec.Builder(
                 TEST_ALIAS_1,
                 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setDigests(KeyProperties.DIGEST_NONE)
-                .setUserAuthenticationRequired(true)
+                .setKeySize(256)
+                .setDigests(KeyProperties.DIGEST_SHA256)
+                .setKeyValidityStart(validityStart)
                 .build());
         KeyPair keyPair = generator.generateKeyPair();
         assertGeneratedKeyPairAndSelfSignedCertificate(
@@ -740,79 +744,32 @@
                 DEFAULT_CERT_NOT_BEFORE,
                 DEFAULT_CERT_NOT_AFTER);
         KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(-1, keyInfo.getUserAuthenticationValidityDurationSeconds());
+        assertEquals(validityStart, keyInfo.getKeyValidityStart());
     }
 
-    public void testGenerate_RSA_ModernSpec_PerOpAuthRequired() throws Exception {
+    public void testGenerate_RSA_ModernSpec_KeyExpiredForOrigination() throws Exception {
         KeyPairGenerator generator = getRsaGenerator();
+        Date originationEnd = new Date(System.currentTimeMillis() - DAY_IN_MILLIS);
         generator.initialize(new KeyGenParameterSpec.Builder(
                 TEST_ALIAS_1,
                 KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setDigests(KeyProperties.DIGEST_NONE)
-                .setUserAuthenticationRequired(true)
+                .setKeySize(1024)
+                .setDigests(KeyProperties.DIGEST_SHA256)
+                .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+                .setKeyValidityForOriginationEnd(originationEnd)
                 .build());
         KeyPair keyPair = generator.generateKeyPair();
         assertGeneratedKeyPairAndSelfSignedCertificate(
                 keyPair,
                 TEST_ALIAS_1,
                 "RSA",
-                2048,
+                1024,
                 DEFAULT_CERT_SUBJECT,
                 DEFAULT_CERT_SERIAL_NUMBER,
                 DEFAULT_CERT_NOT_BEFORE,
                 DEFAULT_CERT_NOT_AFTER);
         KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(-1, keyInfo.getUserAuthenticationValidityDurationSeconds());
-    }
-
-    public void testGenerate_EC_ModernSpec_TimeoutBasedAuthRequired() throws Exception {
-        KeyPairGenerator generator = getEcGenerator();
-        generator.initialize(new KeyGenParameterSpec.Builder(
-                TEST_ALIAS_1,
-                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setDigests(KeyProperties.DIGEST_NONE)
-                .setUserAuthenticationRequired(true)
-                .setUserAuthenticationValidityDurationSeconds(60)
-                .build());
-        KeyPair keyPair = generator.generateKeyPair();
-        assertGeneratedKeyPairAndSelfSignedCertificate(
-                keyPair,
-                TEST_ALIAS_1,
-                "EC",
-                256,
-                DEFAULT_CERT_SUBJECT,
-                DEFAULT_CERT_SERIAL_NUMBER,
-                DEFAULT_CERT_NOT_BEFORE,
-                DEFAULT_CERT_NOT_AFTER);
-        KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(60, keyInfo.getUserAuthenticationValidityDurationSeconds());
-    }
-
-    public void testGenerate_RSA_ModernSpec_TimeoutBasedAuthRequired() throws Exception {
-        KeyPairGenerator generator = getRsaGenerator();
-        generator.initialize(new KeyGenParameterSpec.Builder(
-                TEST_ALIAS_1,
-                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setDigests(KeyProperties.DIGEST_NONE)
-                .setUserAuthenticationRequired(true)
-                .setUserAuthenticationValidityDurationSeconds(60)
-                .build());
-        KeyPair keyPair = generator.generateKeyPair();
-        assertGeneratedKeyPairAndSelfSignedCertificate(
-                keyPair,
-                TEST_ALIAS_1,
-                "RSA",
-                2048,
-                DEFAULT_CERT_SUBJECT,
-                DEFAULT_CERT_SERIAL_NUMBER,
-                DEFAULT_CERT_NOT_BEFORE,
-                DEFAULT_CERT_NOT_AFTER);
-        KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
-        assertTrue(keyInfo.isUserAuthenticationRequired());
-        assertEquals(60, keyInfo.getUserAuthenticationValidityDurationSeconds());
+        assertEquals(originationEnd, keyInfo.getKeyValidityForOriginationEnd());
     }
 
     public void testGenerate_EC_ModernSpec_SupportedSizes() throws Exception {
diff --git a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
new file mode 100644
index 0000000..9e8678b
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
@@ -0,0 +1,980 @@
+/*
+ * Copyright 2015 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.keystore.cts;
+
+import com.android.cts.keystore.R;
+
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.Provider.Service;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+
+public class SignatureTest extends AndroidTestCase {
+    static final String EXPECTED_PROVIDER_NAME = "AndroidKeyStoreBCWorkaround";
+
+    private static final String[] EXPECTED_SIGNATURE_ALGORITHMS = {
+        "NONEwithRSA",
+        "MD5withRSA",
+        "SHA1withRSA",
+        "SHA224withRSA",
+        "SHA256withRSA",
+        "SHA384withRSA",
+        "SHA512withRSA",
+        "SHA1withRSA/PSS",
+        "SHA224withRSA/PSS",
+        "SHA256withRSA/PSS",
+        "SHA384withRSA/PSS",
+        "SHA512withRSA/PSS",
+        "NONEwithECDSA",
+        "SHA1withECDSA",
+        "SHA224withECDSA",
+        "SHA256withECDSA",
+        "SHA384withECDSA",
+        "SHA512withECDSA"
+    };
+
+    private static final Map<String, String> SIG_ALG_TO_CANONICAL_NAME_CASE_INSENSITIVE =
+            new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
+    static {
+        // For an unknown legacy reason, libcore's ProviderTest#test_Provider_getServices insists
+        // that a Service with algorithm "ECDSA" be exposed, despite the RI not exposing any such
+        // services. Thus, our provider has to expose the "ECDSA" service whose actual proper
+        // name is SHA1withECDSA.
+        SIG_ALG_TO_CANONICAL_NAME_CASE_INSENSITIVE.put("ECDSA", "SHA1withECDSA");
+    }
+
+    private static final byte[] SHORT_MSG_KAT_MESSAGE =
+            HexEncoding.decode("ec174729c4f5c570ba0de4c424cdcbf0362a7718039464");
+    private static final byte[] LONG_MSG_KAT_SEED = SHORT_MSG_KAT_MESSAGE;
+    private static final int LONG_MSG_KAT_SIZE_BYTES = 3 * 1024 * 1024 + 123;
+
+    private static final Map<String, byte[]> SHORT_MSG_KAT_SIGNATURES =
+            new TreeMap<String, byte[]>(String.CASE_INSENSITIVE_ORDER);
+    static {
+        // From RI
+        SHORT_MSG_KAT_SIGNATURES.put("NONEwithECDSA", HexEncoding.decode(
+                "304402201ea57c2fb571991639d103bfec658ee7f359b60664e400a5834cfc20d28b588902202433f5"
+                + "eb07d2b03bf8d238ea256ea399d0913a6cfcae2c3b00e2efd50aebc967"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA1withECDSA", HexEncoding.decode(
+                "30440220742d71a013564ab196789322b9231ac5ff26460c2d6b1ab8ccb45eec254cc8ba0220780a86"
+                + "5ddc2334fae23d563e3142b04660c2ab1b875c4ff8c557a1d1accc43e1"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA224withECDSA", HexEncoding.decode(
+                "304502200f74966078b34317daa69e487c3163dbb4e0391cd74191cc3e95b33fc60966e3022100ebdc"
+                + "be19c516d550609f73fb37557a406e397bc1725a1baba50cdfc3537bd377"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA256withECDSA", HexEncoding.decode(
+                "304402204443b560d888beeae729155b0d9410fef2ec78607d9166af6144346fba8ce45d02205b0727"
+                + "bfa630050f1395c8bcf46c614c14eb15f2a6abbd3bc7c0e83b41819281"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA384withECDSA", HexEncoding.decode(
+                "3045022025ade03446ce95aa525a51aedd16baf12a2b8b9c1f4c87224c38e48c84cbbbf8022100ad21"
+                + "8424c3671bc1513e1da7e7186dbc6bf67bec434c95863a48e79f53684971"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA512withECDSA", HexEncoding.decode(
+                "3045022100969e8fed2dc4ddcdf341368e057efe4e3a00eda66bbb127dec31bb0144c5334602201087"
+                + "2b7f9ab9c06a07053e0641e6adc18a87a1d7807550a19e872e78e5c7f0dd"));
+
+        // From RI
+        SHORT_MSG_KAT_SIGNATURES.put("NONEwithRSA", HexEncoding.decode(
+                "257d0704e514ead29a5c45576adb2d5a7d7738e6a83b5d6463a5306788015d14580fee340e78e00d39"
+                + "f56ae616083ac929e5daf9eeab40b908eb05d0cd1036d9e92799587df0d4c5304c9b27f913e1c891"
+                + "919eff0df3b5d9c0d8cc4cd843795840799cc0353192c3868b3f8cad96d04bb566ca53e1146aa2a3"
+                + "4b890ce917680bbdea1dee417a89630224d2ee79d66d38c7c77e50b45e1dd1b8b63eb98ecd60426b"
+                + "c9fb30917e78ae4dd7cbfa9475f9be53bf45e7032add52681553679252f4f74de77831c95ea69f30"
+                + "2f0fd28867de058728455e3537680c86a001236e70c7680c78b4dc98942d233b968635a0debccb41"
+                + "fbc17ece7172631f5ab6d578d70eb0"));
+        SHORT_MSG_KAT_SIGNATURES.put("MD5withRSA", HexEncoding.decode(
+                "1e1edefc9a6a4e61fcef0d4b202cc2b53ab9043b1a0b21117d122d4c5399182998ec66608e1ab13513"
+                + "08fbb23f92d5d970f7fb1a0691f8d1e682ff4f5e394ef2dfcbdc2de5c2c33372aec9a0c7fba982c5"
+                + "c0f1a5f65677d9294d54a2e613cc0e5feb919135e883827da0e1c222bf31336afa63a837c57c0b70"
+                + "70ceb8a24492a42afa6750cc9fe3a9586aa15507a65410db973a4b26734624d323dc700928717789"
+                + "fb1f970d57326eef49e012fcebcfbbfd18fb4d6feff03587d0f2b0a556fe467437a44a2283ea5027"
+                + "6efda4fd427365687960e0c289c5853a7b300ff081511a2f52899e6f6a569b30e07adfd52e9d9d7e"
+                + "ab33999da0da1dd16d4e88bd980fcd"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA1withRSA", HexEncoding.decode(
+                "280977b4ee18cbe27d3e452c9b90174f5d81dd518018ce52ff1cd1e8d4d0626afca85be14a43fa3b76"
+                + "a80e818b4bc10abc62180fa15619d78be98ccd8fa642ea05355aa84f2924e041c2b594b1cf31d42b"
+                + "f11c78dd3cbb6cc2cbfe151792985e6e5cf73c2e600a38f31e26e84c3e4a434f67a625fefe712d17"
+                + "b34125ea91d333cfe1c4ac914b6c411b08e64700885325e07510c4f49ef3648252736f17d3ae7705"
+                + "0054ceb07ab04b5ecaa5fc4556328bad4f97eba37f9bf079506e0eb136c9eadf9e466ccb18d65b4d"
+                + "ef2ba3ca5c2f33354a2040dfb646423f96ba43d1d8f3dcf91c0c2c14e7958159d2ac3ebc0b6b87e6"
+                + "6efbdda046ce8a766fecc3f905d6ff"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA224withRSA", HexEncoding.decode(
+                "490af9e685ef44da9528d9271d00e09a3e688012bf3f63fd924a06cb4db747a28cdf924c2d51620165"
+                + "33985abf4b91d64c17ff7e2b4f0de5a28375dddf556cd9e5dcebd112f766f07cb867e8d5710ce79a"
+                + "1c3d5244cbd16618b0fedc2b9015d51a98d453747fb320b97995ea9579adbc8bf6042b2f4252cef1"
+                + "787207fefaf4b9c7212fe0ff8b22ae12ffc888f0a1e6923455577e82b58608dabc2acba05be693ff"
+                + "ae7da263d6c83cb13d59a083f177578d11030f8974bdb301f6135ecd5ec18dd68dc453c5963e94b6"
+                + "2d89bcda0ff63ac7394030f79b59139e1d51573f0d4a1e85d22502c9b0d29412f7eb277fb42fa4db"
+                + "18875baffa7719b700e4830edbcd6f"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA256withRSA", HexEncoding.decode(
+                "1f1adcd6edbf4c50777c932db6e99a577853fbc9c71c692e921291c5aa73eb0155e30c8d4f3aff828f"
+                + "2040c84e10b1ba729ccc23899650451022fcd3574df5454b01112adec5f01565b578bbc7c32810c9"
+                + "407106054ad8f4f640b589ddef264d028ad906536d61c8053ef0dba8e10ca2e30a9dd6ccc9a9ec3e"
+                + "76c10d36029820865b2d01095987af4a29369ffc6f70fa7e1de2b8e28f41894df4225cf966454096"
+                + "7fb7ecff443948c8a0ee6a1be51e0f8e8887ff512dbdc4fc81636e69ae698000ce3899c2ec999b68"
+                + "691adfb53092380264b27d91bd64561fee9d2e622919cf6b472fd764dc2065ae6a67df2c7b5ec855"
+                + "099bdb6bb104ee41fa129c9da99745"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA384withRSA", HexEncoding.decode(
+                "3b5e8baa62803569642fa8c3255249709c9f1d69bd31f7b531d5071c07cd9bac29273097666d96b2e3"
+                + "2db13529b6414be5aee0c8a90c3f3b2a5c815f37fac16a3527fa45903f847416ed218eee2fef5b87"
+                + "5f0c97576f58b3467e83497c1cdeea44d0ea151e9c4d27b85eef75d612b1fc16731859738e95bdf1"
+                + "2f2098ebd501d8493c66585e8545fb13d736f7dbbb530fb06f6f157cd10c332ca498b379336efdaf"
+                + "a8f940552da2dbb047c33e87f699068eaadd6d47c92a299f35483ba3ae09f7e52a205f202c1af997"
+                + "c9bdc40f423b3767292c7fcea3eaf338a76f9db07a53d7f8d084bf1ceac38ec0509e442b1283cd8f"
+                + "013c4c7a9189fe4ef9ab00c80cb470"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA512withRSA", HexEncoding.decode(
+                "23eb7577d2ffefed10780c2a26f79f64abe08203e900db2333413f30bbc81f800857857c8b0e02c3e8"
+                + "8fe3cf5514130d6216ef7c4a86b1012594c7cb07a293159b92bf40291224386a84e607e0a8389c8a"
+                + "a0c45cc553037517c52f61fe0ea51dba184e890db7d9517760724c038018330c0a9450c280430e6f"
+                + "9e4cdd4545c3f6684485cd6e27203735ff4be76420071920b18c54d98c0e3eb7ae7d1f01f5171ace"
+                + "87885c6185f66d947d51a441a756bc953458f7d3a1714226899562478ebf91ab18d8e7556a966661"
+                + "31de37bc2e399b366877f53c1d88f93c989aeb64a43f0f6cbc2a29587230f7e3e90ea18868d79584"
+                + "3e62b49f5df78e355b437ec2f882f9"));
+
+        // From Bouncy Castle
+        SHORT_MSG_KAT_SIGNATURES.put("SHA1withRSA/PSS", HexEncoding.decode(
+                "17e483781695067a25bc7cb204429a8754af36032038460e1938c28cd058025b14d2cffe5d3da39e76"
+                + "6542014e5419f1d4c4d7d8e3ebcd2221dde04d24bbbad657f6782b7a0fada3c3ea595bc21054b0ab"
+                + "d1eb1ada86276ed31dbcce58be7407cbbb924d595fbf44f2bb6e3eab92296076e291439107e67912"
+                + "b4fac3a27ff84af7cd2db1385a8340b2e49c7c2ec96a6b657a1641da80799cb88734cca35a2b3a2c"
+                + "4af832a34ac8d3134ccc8b61150dc1b64391888a3a84bdb5184b48e8509e8ba726ba8847e4ca0640"
+                + "ce615e3adf5248ce08adb6484f6f29caf6c65308ec6351d97369ae005a7c762f76f0ddc0becc3e45"
+                + "529aa9c8391473e392c9a60c2d0834"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA224withRSA/PSS", HexEncoding.decode(
+                "3b7641a49e7766ed879f2b0e33ceb3d935678a7deffbd855a97abf00a65c981814ac54a71150b2ffea"
+                + "d5db83aa96d0939267b3c5e2fcf958e9c6fdf7d90908e6139f7f330a16dc625d8268ffd324659f6c"
+                + "e36798ef3b71a92f1d2237e3ce1e281aacc1d5370ae63c9b75e7134ad15cca1410746bf259ac4519"
+                + "c407877503900ec8f3b71edce727e9d0275c9cd48385f89ce76ed17a2bf246578f183bb6577d6942"
+                + "2056c7d9145528fc8ca036926a9fafe819f37c1a4a0a69b17f3d4b0a116106f94a5d2a5f8ce6981c"
+                + "d6e5c2f858dcb0823e725fffe6be14ca882c81fa993bebda549fcf983eb7f8a87eccd545951dcdc9"
+                + "d8055ae4f4067de997cfd89952c905"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA256withRSA/PSS", HexEncoding.decode(
+                "6f0f744fa8e813b4c7caa0c395c1aa8aee0d61e621b4daae305c759b5b5972311ad691f8867821efba"
+                + "d57995cc8ff38f33393293e94e1c484e94de4816b0fd986f5710a02d80e62461cc6f87f1f3742268"
+                + "c28a54870f290d136aa629cbe00a1bf243fab1674c04cd5910a786b2ac5e71d9c6f4c41daa4c584d"
+                + "46ba7ee768d2d2559be587a7b2009f3b7497d556a0da8a8ae80ce91152c81ffba62720d36b699d1f"
+                + "157137ff7ee7239fc4baf611d01582346e201900f7a4f2617cdf574653e124fb895c6cb76d4ed5a8"
+                + "aca97d1e408e8011eba649d5617bae8b27c1b946dcff7b29151d8632ad128f22907e8b83b9149e16"
+                + "fbb9e9b87600a2f90c1fd6dc164c52"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA384withRSA/PSS", HexEncoding.decode(
+                "8e57992362ad4b0487a707b2f8811d953f5aaf800978859981e7dcddad6f9f411fb162859115577c53"
+                + "7a3524e26bf069508185848d6e29e7da1f9660a49771533e43853e02232314afd2928a1ff1824345"
+                + "a5a90309a59d213ff6a4d04520f95a976342e6ac529ec6a6821157f4fee3bdae30d836d3ab44386d"
+                + "3914e6aacd6a6a63e1d63b4d9bfb93b343b6c1f28d60042ffbe1e46fb692a381456e84b3328dbcae"
+                + "ed6fc577cb1c5f86a38c5c34d439eeee7e798edc9f2bcd4fc217b1630e45b8df67def2c2cdb9fea0"
+                + "5d67aa6cce6e9a72e9a114e2e620a54c05755e32685ffc7e50487c3cd00888c09492fad8c461c338"
+                + "e7d099b275deaf184b7d6689385f7c"));
+        SHORT_MSG_KAT_SIGNATURES.put("SHA512withRSA/PSS", HexEncoding.decode(
+                "7a40f9f2797beda0702df0520c7138269295a0f0328aab4eba123ebf178ea4abc745ed42d3b175dc70"
+                + "c8dcc98f46f2234b392dbb3e939f30888715c4fbb47fbb5bb7c0557c140c579f48226710e5b3da0d"
+                + "9511337cde5626df586b4004100dd45490e5f8ae23307b5d1054c97e9ef58f9c385ca55b6db4f58d"
+                + "2e19bc8ca9d8c2b4922fb3325b6fb61fc40a359e9196aa9388845b136d2790d71410e20371dcf0a7"
+                + "0425ee1854c5c3d7de976b28de0ee9b1048ed99b2a957edc97466cc4c87e36224fd323605228f61a"
+                + "1aad30253b0698f9a358491138027d325d46bdfdf72171c57a2dab0a9cddaad8e170b8275c172e42"
+                + "33b29ed81c0f4de9fe9f0670106aad"));
+    }
+
+    private static final Map<String, byte[]> LONG_MSG_KAT_SIGNATURES =
+            new TreeMap<String, byte[]>(String.CASE_INSENSITIVE_ORDER);
+    static {
+        // From RI
+        LONG_MSG_KAT_SIGNATURES.put("NONEwithECDSA", HexEncoding.decode(
+                "304502206e4039608a66ce118821eeca3e2af7f530f51d1ce8089685a13f49010e3cd58b02210083a5"
+                + "fe62a171f1b1d775fad712128a223d6b63336e0248783652474221cb3193"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA1withECDSA", HexEncoding.decode(
+                "3044022075f09bb5c87d883c088ca2ad263bbe1754ab614f727465bc43695d3521eaccf80220460e4e"
+                + "32421e6f4398cd9b7fbb31a1d1f2961f26b9783620f6413f0e6f7efb84"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA224withECDSA", HexEncoding.decode(
+                "3045022100d6b24250b7d3cbd329913705f4990cfd1000f338f7332a44f07d7731bd8e1ff602200565"
+                + "0951e14d0d21c4344a449843ef65ac3a3f831dc7f304c0fa068c996f7d34"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA256withECDSA", HexEncoding.decode(
+                "30440220501946a2c373e8da19b36e3c7718e3f2f2f16395d5026ac4fbbc7b2d53f9f21a0220347d7a"
+                + "46685282f308bacd5fb25ae92b351228ea39082784789696580f27eed1"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA384withECDSA", HexEncoding.decode(
+                "30450220576836de4ab94a869e867b2360a71dc5a0b3351ea1c896b163206db7c3507dc2022100c1a6"
+                + "719052a175e023bca7f3b9bb7a379fc6b51864cb28a195076d2f3c79ed2e"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA512withECDSA", HexEncoding.decode(
+                "304402204ca46bac4e43e8694d1af38854c96024a4e9bcc55c6904c1f8fea0d1927f69f7022054662e"
+                + "84b4d16b9f7e8164f4896212dec3c7c1e7fd108f69b0dff5bc15399eeb"));
+
+        // From RI
+        LONG_MSG_KAT_SIGNATURES.put("MD5withRSA", HexEncoding.decode(
+                "7040f3e0d95f4d22719d26e5e684dbcd5ed52ab4a7c5aa51b938b2c060c79eb600f9c9771c2fcda7e3"
+                + "55e7c7b5e2ba9fe9a2a3621881c0fe51702781ffcde6ce7013218c04bb05988346c2bed99afb97a8"
+                + "113fb50697adf93791c9129e938040f91178e35d6f323cfa515ea6d2112e8cce1302201b51333794"
+                + "4a5c425cecc8181842ace89163d84784599ea688060ad0d61ac92b673feabe01ae5e6b85d8b5e8f0"
+                + "519aea3c29781e82df9153404d027d75df8370658898ed348acf4e13fd8f79c8a545881fbbf585e1"
+                + "c666be3805e808819e2cc730379f35a207f9e0e646c7ab6d598c75b1901f0c5ca7099e34f7f01579"
+                + "3b57dfb5c2a32e8423bfed6215f9d0"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA1withRSA", HexEncoding.decode(
+                "187d7689206c9dd03861009c6cb62c7752fd2bbc354f0bea4e76059fe582744c80027175112a3df4b6"
+                + "3b4a5626ed3051192e3c9b6d906497472f6df81171064b59114ff5d7c60f66943549634461cfadd8"
+                + "a033cba2b8781fb7936ea1ca0043da119856a21e533afa999f095cf87604bb33a14e8f82fab01998"
+                + "9ef3133e8069708670645ddd5cdc86bbe19fbf672b409fb6d7cae2f913814cd3dc8d5ae8e4037ccf"
+                + "4a3ef97db8c8a08516716258c4b767607c51dfb289d90af014d3cfc64dbadb2135ed59728b78fda0"
+                + "823fe7e68e84280c283d21ab660364a9bf035afa9a7262bade87057a63aa1d7e2c09bb9dd037bcbd"
+                + "7b98356793bc32be81623833c6ab62"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA224withRSA", HexEncoding.decode(
+                "31ff68ddfafcf3ff6e651c93649bf9cc06f4138493317606d8676a8676f9d9f3a1d5e418358f79d143"
+                + "a922a3cfc5e1ad6765dc829b556c9019a6d9389144cc6a7571011c024c0514891970508dac5f0d26"
+                + "f26b536cf3e4511b5e72cd9f60590b387d8a351a9f28839a1c5be5272cb75a9062aa313f3d095074"
+                + "6d0a21d4f8c9a94d3bb4715c3ef0207cf1335653161a8f78972329f3ec2fa5cfe05318221cb1f535"
+                + "8151dde5410f6c36f32287a2d5e76bf36134d7103fc6810a1bb8627de37d6b9efde347242d08b0b6"
+                + "2b1d73bacd243ccc8546536080b42a82b7162afeb4151315746a14b64e45226c9f5b35cf1577fc6b"
+                + "f5c882b71deb7f0e375db5c0196446"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA256withRSA", HexEncoding.decode(
+                "529c70877dedf3eb1abda98a2f2b0fc899e1edece70da79f8f8bbceb98de5c85263bef2ef8a7322624"
+                + "5ed2767045ea6965f35cb53e6ac1d6c62e8007a79962507d3e01c77d4e96674344438519adae67d9"
+                + "6357da5c4527969c939fd86f3b8685338c2be4bf6f1f85527b11fcaa4708f925e8bb9b877bda179b"
+                + "d1b45153ef22834cf593ecc5b6eca3deddbe5d05894e4e5707d71bc35ea879ccb6e8ffc32e0cdc5e"
+                + "88a30eef7a608d9ea80b5cefec2aa493a3b1354ad20e88ab1f8bfda3bd9961e10f0736d1bc090d57"
+                + "b93fbce3e6e2fc99e67c7b466188d1615b4150c206472e48a9253b7549cebf6c7cbb558b54e10b73"
+                + "c8b1747c18d1890a24d0a835ee710a"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA384withRSA", HexEncoding.decode(
+                "5dd3553bc594c541937dac9a8ac119407712da7564816bcdc0ca4e14bc6059b9f9bd72e99be8a3df3e"
+                + "0a3c4e8ed643db9ed528b43a396dba470ad3307815bd7c75fa5b08775a378cc4203341379087dcb3"
+                + "62a5e9f5c979744e4498a6aafd1b1a8069caf4ef437f2743754861fcc96d67a0f1dd3397bb65ede3"
+                + "18d2b3628eb2c3ec5db8a3e21fbbe2629f1030641e420963abc4da99e24dd497337c8149a52d97da"
+                + "7176c0767d72e18f8c9a49e6808509837f719fd16ba27b19a2b32bd19b9b14818e0b9be81062be77"
+                + "4fb1b3105a1528170822391915a5cd12b8e79aaab7943c34094da4c4f8d56f52177db953d3bf7846"
+                + "f0e5f22f2311054a1daba4fec6b589"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA512withRSA", HexEncoding.decode(
+                "971d6350337866fbcb48c49446c50cac1995b822cfec8f2a3e2c8206158a2ddfc8fc7b38f5174b3288"
+                + "91489e7b379829bac5e48cd41e9713ea7e2dc9c61cf90d255387d31818d2f161ec5c3a977b4ce121"
+                + "62fb11ede30d1e63c0fbba8a4094e6ad39e64176a033e7130bbed71a67ff1713b45f0bedeb1ee532"
+                + "15690f169452c061cd7d15e71cc754a2f233f5647af8373d2b583e98e4242c0a0581e0ce2b22e15a"
+                + "443b0ff23d516ed39664f8b8ab5ca98a44af500407941fae97f37cb1becbcbff453608cb94a176d9"
+                + "e702947fff80bc8d1e9bcdef2b7bbe681e15327cee50a72649aed0d730df7b3c9c31b165416d9c9f"
+                + "1fcb04edbf96514f5758b9e90ebc0e"));
+
+        // From Bouncy Castle
+        LONG_MSG_KAT_SIGNATURES.put("SHA1withRSA/PSS", HexEncoding.decode(
+                "54a2050b22f6182b65d790da80ea16bfbc34b0c7e564d1a3ce4450e9b7785d9eaa14814dee8699977a"
+                + "e8da5cfb3c55c9a623ca55abcc0ef4b3b515ce31d49a78db442f9db270d35a179baf71057fe8d6d2"
+                + "d3f7e4fd5f5c80e11dc059c72a1a0373f527d88089c230525f895ee19e45f5547572083418c9e542"
+                + "5ff44e407500d1c49159484f38e4b00523c2fa45b7b9b38a2c1ad676b36f02a06db6fca52bd79ba1"
+                + "94d5062f5035a12a1f026ac216789844a5da0caa4d481386a12ca635c06b877515ce3782d9189d87"
+                + "d1ff5ec6ec7c39437071c8db7d1c2702205da4cfb01805ca7fec5595dba2234602ca5347d30538cb"
+                + "4b5286c151609afcca890a6276d5e8"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA224withRSA/PSS", HexEncoding.decode(
+                "7e95c1e4f700ceaf9ce72fd3f9f245ba80f2e1341341c49521779c8a79004f9c534297441330b9df36"
+                + "bb23467eb560e5e5538612cecc27953336a0d4d8044d5a80f6bcef5299830215258c574d271ea6cd"
+                + "7117c2723189385435b0f06951ff3d6a700b23bc7ed3298cfb6aa65e8f540717d57f8b55290a4862"
+                + "034d9f73e8d9cb6ae7fa55a8b4c127535b5690122d6405cb0c9a313808327cfd4fb763eae875acd1"
+                + "b60e1920ecf1116102cc5f7d776ed88e666962f759258d6f5454c29cb99b8f9ccad07d209671b607"
+                + "014d19009e392bfb08247acf7f354458dc51196d84b492798dd829b7300c7591d42c58f21bd2c3d1"
+                + "e5ce0a0d3e0aa8aa4b090b6a619fc6"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA256withRSA/PSS", HexEncoding.decode(
+                "5a8c0ae593a6714207b3ad83398b38b93da18cfda73139ea9f02c88a989368ae6901357194a873dd2e"
+                + "8cd1bb86d1f81fbc8bf725538dc2ad60759f8caab6a98a6baa6014874a92d4b92ed72e73f2721ba2"
+                + "86e545924860d27210b53f9308c4fec622fdfca7dd6d51a5b092184114e9dcf57636cdabaca17b49"
+                + "70cd5e93ce12c30af6d09d6964c5ad173095ea000529620d94a25b4cc977deefd25cc810a7b11cd5"
+                + "e5b71c9276b0bd33c53db01304b359a4a88f3fe8bc3335669f7609b0f6da17e49ad87f38468fa2c6"
+                + "8134ba6df407207559355b6e486a745009931796ab0567c9bd61788073aa00113b324fa25bd32b4d"
+                + "3521e98e0b4905c6dce30d70387a2e"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA384withRSA/PSS", HexEncoding.decode(
+                "7913f13dc399adb07cd96c1bb484f999d047efcd96501c92477d2234a1da94db9c6fd65a8031bd3040"
+                + "82d90ef4a4f388e670795d144ef72a160583d4a2c805415542fa16ffd8760d2f28bdc82f63db0900"
+                + "a3554bc9175dafa1899249abd49591216ba2965a4862d0f59d8b8c8d1042ed7ac43a3a15650d578a"
+                + "2ea53696e462f757b326b7f0f7610fb9934aee7d954a45ca03ef66464a5611433e1224d05f783cd1"
+                + "935eff90015140cb35e15f2bbf491a0d6342ccef57e453f3462412c5ff4dfdc44527ea76c6b05b1d"
+                + "1330869aec1b2f41e7d975eba6b056e7c2f75dd73b1eff6d853b9507f410279b02f9244b656a1aca"
+                + "befcc5e1167df3a49c4a7d8479c30f"));
+        LONG_MSG_KAT_SIGNATURES.put("SHA512withRSA/PSS", HexEncoding.decode(
+                "43ffefe9c96014312679a2e3803eb7c58a2a4ab8bb659c12fec7fb574c82aed673e21ed86ac309cf6c"
+                + "e567e47b7c6c83dcd72e3ee946067c2004689420528174d028e3d32b2b306bcbcb6a9c8e8b83918f"
+                + "7415d792f9d6417769def3316ed61898443d3ffa4dc160e5b5ecf4a11a9dfed6b4a7aa65f0f2c653"
+                + "4f7e514aed73be441609ffca29207b4ced249058543fd6e13a02ef42babe2cdf4aaba66b42e9d47f"
+                + "c79b4ed54fbc28d9d732f2e468d43f0ca1de6fd5312fad2c4e3eaf3e9586bca6a8bab24b4dfab8b3"
+                + "9a4057c8ed27024b61b425036bea5e23689cd9db2450be47ec2c30bb6707740c70a53b3e7a1c7ecf"
+                + "f04e3de1460e60e9be7a42b1ddff0c"));
+    }
+
+    private static final long DAY_IN_MILLIS = 1000 * 60 * 60 * 24;
+
+    public void testAlgorithmList() {
+        // Assert that Android Keystore Provider exposes exactly the expected signature algorithms.
+        // We don't care whether the algorithms are exposed via aliases, as long as the canonical
+        // names of algorithms are accepted.
+        // If the Provider exposes extraneous algorithms, it'll be caught because it'll have to
+        // expose at least one Service for such an algorithm, and this Service's algorithm will
+        // not be in the expected set.
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        Set<Service> services = provider.getServices();
+        Set<String> actualSigAlgsLowerCase = new HashSet<String>();
+        Set<String> expectedSigAlgsLowerCase = new HashSet<String>(
+                Arrays.asList(TestUtils.toLowerCase(EXPECTED_SIGNATURE_ALGORITHMS)));
+        for (Service service : services) {
+            if ("Signature".equalsIgnoreCase(service.getType())) {
+                String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US);
+                if (!expectedSigAlgsLowerCase.contains(algLowerCase)) {
+                    // Unexpected algorithm -- check whether it's an alias for an expected one
+                    String canonicalAlgorithm =
+                            SIG_ALG_TO_CANONICAL_NAME_CASE_INSENSITIVE.get(algLowerCase);
+                    if (canonicalAlgorithm != null) {
+                        // Use the canonical name instead
+                        algLowerCase = canonicalAlgorithm.toLowerCase();
+                    }
+                }
+                actualSigAlgsLowerCase.add(algLowerCase);
+            }
+        }
+
+        TestUtils.assertContentsInAnyOrder(actualSigAlgsLowerCase,
+                expectedSigAlgsLowerCase.toArray(new String[0]));
+    }
+
+    public void testGeneratedSignatureVerifies() throws Exception {
+        Collection<KeyPair> keyPairs = importDefaultKatKeyPairs();
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        assertNotNull(provider);
+        for (String sigAlgorithm : EXPECTED_SIGNATURE_ALGORITHMS) {
+            try {
+                KeyPair keyPair = getKeyPairForSignatureAlgorithm(sigAlgorithm, keyPairs);
+
+                // Generate a signature
+                Signature signature = Signature.getInstance(sigAlgorithm);
+                signature.initSign(keyPair.getPrivate());
+                assertSame(provider, signature.getProvider());
+                byte[] message = "This is a test".getBytes("UTF-8");
+                signature.update(message);
+                byte[] sigBytes = signature.sign();
+
+                // Assert that it verifies using our own Provider
+                assertSignatureVerifiesOneShot(
+                        sigAlgorithm, provider, keyPair.getPublic(), message, sigBytes);
+
+                // Assert that it verifies using whatever Provider is chosen by JCA by
+                // default for this signature algorithm and public key.
+                assertSignatureVerifiesOneShot(
+                        sigAlgorithm, keyPair.getPublic(), message, sigBytes);
+            } catch (Exception e) {
+                throw new RuntimeException(sigAlgorithm + " failed", e);
+            }
+        }
+    }
+
+    public void testSmallMsgKat() throws Exception {
+        Collection<KeyPair> keyPairs = importDefaultKatKeyPairs();
+        byte[] message = SHORT_MSG_KAT_MESSAGE;
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        assertNotNull(provider);
+        for (String algorithm : EXPECTED_SIGNATURE_ALGORITHMS) {
+            try {
+                byte[] goodSigBytes = SHORT_MSG_KAT_SIGNATURES.get(algorithm);
+                assertNotNull(goodSigBytes);
+                KeyPair keyPair = getKeyPairForSignatureAlgorithm(algorithm, keyPairs);
+                // Assert that AndroidKeyStore provider can verify the known good signature.
+                assertSignatureVerifiesOneShot(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigBytes);
+                assertSignatureVerifiesFedOneByteAtATime(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigBytes);
+                assertSignatureVerifiesFedUsingFixedSizeChunks(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigBytes, 3);
+
+                byte[] messageWithBitFlip = message.clone();
+                messageWithBitFlip[messageWithBitFlip.length / 2] ^= 1;
+                assertSignatureDoesNotVerifyOneShot(
+                        algorithm, provider, keyPair.getPublic(), messageWithBitFlip, goodSigBytes);
+
+                byte[] goodSigWithBitFlip = goodSigBytes.clone();
+                goodSigWithBitFlip[goodSigWithBitFlip.length / 2] ^= 1;
+                assertSignatureDoesNotVerifyOneShot(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigWithBitFlip);
+
+                // Sign the message in one go
+                Signature signature = Signature.getInstance(algorithm);
+                signature.initSign(keyPair.getPrivate());
+                assertSame(provider, signature.getProvider());
+                signature.update(message);
+                byte[] generatedSigBytes = signature.sign();
+                boolean deterministicSignatureScheme =
+                        algorithm.toLowerCase().endsWith("withrsa");
+                if (deterministicSignatureScheme) {
+                    MoreAsserts.assertEquals(goodSigBytes, generatedSigBytes);
+                } else {
+                    if (Math.abs(goodSigBytes.length - generatedSigBytes.length) > 2) {
+                        fail("Generated signature expected to be between "
+                                + (goodSigBytes.length - 2) + " and "
+                                + (goodSigBytes.length + 2) + " bytes long, but was: "
+                                + generatedSigBytes.length + " bytes: "
+                                + HexEncoding.encode(generatedSigBytes));
+                    }
+
+                    // Assert that the signature verifies using our own Provider
+                    assertSignatureVerifiesOneShot(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedOneByteAtATime(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedUsingFixedSizeChunks(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes,
+                            3);
+
+                    // Assert that the signature verifies using whatever Provider is chosen by JCA
+                    // by default for this signature algorithm and public key.
+                    assertSignatureVerifiesOneShot(
+                            algorithm, keyPair.getPublic(), message, generatedSigBytes);
+                }
+
+                // Sign the message by feeding it into the Signature one byte at a time
+                signature = Signature.getInstance(signature.getAlgorithm());
+                signature.initSign(keyPair.getPrivate());
+                for (int i = 0; i < message.length; i++) {
+                    signature.update(message[i]);
+                }
+                generatedSigBytes = signature.sign();
+                if (deterministicSignatureScheme) {
+                    MoreAsserts.assertEquals(goodSigBytes, generatedSigBytes);
+                } else {
+                    if (Math.abs(goodSigBytes.length - generatedSigBytes.length) > 2) {
+                        fail("Generated signature expected to be between "
+                                + (goodSigBytes.length - 2) + " and "
+                                + (goodSigBytes.length + 2) + " bytes long, but was: "
+                                + generatedSigBytes.length + " bytes: "
+                                + HexEncoding.encode(generatedSigBytes));
+                    }
+                    // Assert that the signature verifies using our own Provider
+                    assertSignatureVerifiesOneShot(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedOneByteAtATime(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedUsingFixedSizeChunks(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes,
+                            3);
+
+                    // Assert that the signature verifies using whatever Provider is chosen by JCA
+                    // by default for this signature algorithm and public key.
+                    assertSignatureVerifiesOneShot(
+                            algorithm, keyPair.getPublic(), message, generatedSigBytes);
+                }
+            } catch (Throwable e) {
+                throw new RuntimeException("Failed for " + algorithm, e);
+            }
+        }
+    }
+
+    private static byte[] generateLargeKatMsg(byte[] seed, int msgSizeBytes) throws Exception {
+        byte[] result = new byte[msgSizeBytes];
+        MessageDigest digest = MessageDigest.getInstance("SHA-512");
+        int resultOffset = 0;
+        int resultRemaining = msgSizeBytes;
+        while (resultRemaining > 0) {
+            seed = digest.digest(seed);
+            int chunkSize = Math.min(seed.length, resultRemaining);
+            System.arraycopy(seed, 0, result, resultOffset, chunkSize);
+            resultOffset += chunkSize;
+            resultRemaining -= chunkSize;
+        }
+        return result;
+    }
+
+    public void testLongMsgKat() throws Exception {
+        Collection<KeyPair> keyPairs = importDefaultKatKeyPairs();
+        byte[] message = generateLargeKatMsg(LONG_MSG_KAT_SEED, LONG_MSG_KAT_SIZE_BYTES);
+
+        Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
+        assertNotNull(provider);
+        for (String algorithm : EXPECTED_SIGNATURE_ALGORITHMS) {
+            KeyPair keyPair = getKeyPairForSignatureAlgorithm(algorithm, keyPairs);
+
+            try {
+                if (algorithm.toLowerCase(Locale.US).startsWith("nonewithrsa")) {
+                    // This algorithm cannot accept large messages
+                    Signature signature = Signature.getInstance(algorithm);
+                    signature.initSign(keyPair.getPrivate());
+                    assertSame(provider, signature.getProvider());
+                    try {
+                        signature.update(message);
+                        signature.sign();
+                        fail();
+                    } catch (SignatureException expected) {}
+
+                    // Bogus signature generated using SHA-256 digest -- shouldn't because the
+                    // message is too long (and should not be digested/hashed) and because the
+                    // signature uses the wrong digest/hash.
+                    byte[] sigBytes = SHORT_MSG_KAT_SIGNATURES.get(
+                            "SHA256" + algorithm.substring("NONE".length()));
+                    assertNotNull(sigBytes);
+                    signature = Signature.getInstance(algorithm);
+                    signature.initVerify(keyPair.getPublic());
+                    try {
+                        signature.update(message);
+                        signature.verify(sigBytes);
+                        fail();
+                    } catch (SignatureException expected) {}
+                    continue;
+                }
+
+                byte[] goodSigBytes = LONG_MSG_KAT_SIGNATURES.get(algorithm);
+                assertNotNull(goodSigBytes);
+
+                // Assert that AndroidKeyStore provider can verify the known good signature.
+                assertSignatureVerifiesOneShot(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigBytes);
+                assertSignatureVerifiesFedUsingFixedSizeChunks(
+                        algorithm, provider, keyPair.getPublic(), message, goodSigBytes, 718871);
+
+                // Sign the message in one go
+                Signature signature = Signature.getInstance(algorithm);
+                signature.initSign(keyPair.getPrivate());
+                assertSame(provider, signature.getProvider());
+                signature.update(message);
+                byte[] generatedSigBytes = signature.sign();
+                boolean deterministicSignatureScheme =
+                        algorithm.toLowerCase().endsWith("withrsa");
+                if (deterministicSignatureScheme) {
+                    MoreAsserts.assertEquals(goodSigBytes, generatedSigBytes);
+                } else {
+                    if (Math.abs(goodSigBytes.length - generatedSigBytes.length) > 2) {
+                        fail("Generated signature expected to be between "
+                                + (goodSigBytes.length - 2) + " and "
+                                + (goodSigBytes.length + 2) + " bytes long, but was: "
+                                + generatedSigBytes.length + " bytes: "
+                                + HexEncoding.encode(generatedSigBytes));
+                    }
+
+                    // Assert that the signature verifies using our own Provider
+                    assertSignatureVerifiesOneShot(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedUsingFixedSizeChunks(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes,
+                            718871);
+
+                    // Assert that the signature verifies using whatever Provider is chosen by JCA
+                    // by default for this signature algorithm and public key.
+                    assertSignatureVerifiesOneShot(
+                            algorithm, keyPair.getPublic(), message, generatedSigBytes);
+                }
+
+                // Sign the message by feeding it into the Signature one byte at a time
+                signature = Signature.getInstance(signature.getAlgorithm());
+                generatedSigBytes = generateSignatureFedUsingFixedSizeChunks(
+                        algorithm, provider, keyPair.getPrivate(), message, 444307);
+                signature.initSign(keyPair.getPrivate());
+                if (deterministicSignatureScheme) {
+                    MoreAsserts.assertEquals(goodSigBytes, generatedSigBytes);
+                } else {
+                    if (Math.abs(goodSigBytes.length - generatedSigBytes.length) > 2) {
+                        fail("Generated signature expected to be between "
+                                + (goodSigBytes.length - 2) + " and "
+                                + (goodSigBytes.length + 2) + " bytes long, but was: "
+                                + generatedSigBytes.length + " bytes: "
+                                + HexEncoding.encode(generatedSigBytes));
+                    }
+                    // Assert that the signature verifies using our own Provider
+                    assertSignatureVerifiesOneShot(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes);
+                    assertSignatureVerifiesFedUsingFixedSizeChunks(
+                            algorithm, provider, keyPair.getPublic(), message, generatedSigBytes,
+                            718871);
+
+                    // Assert that the signature verifies using whatever Provider is chosen by JCA
+                    // by default for this signature algorithm and public key.
+                    assertSignatureVerifiesOneShot(
+                            algorithm, keyPair.getPublic(), message, generatedSigBytes);
+                }
+            } catch (Throwable e) {
+                throw new RuntimeException("Failed for " + algorithm, e);
+            }
+        }
+    }
+
+    public void testInitVerifySucceedsDespiteMissingAuthorizations() throws Exception {
+        KeyProtection spec = new KeyProtection.Builder(0).build();
+        assertInitVerifySucceeds("SHA256withECDSA", spec);
+        assertInitVerifySucceeds("SHA256withRSA", spec);
+        assertInitVerifySucceeds("SHA256withRSA/PSS", spec);
+    }
+
+    public void testInitSignFailsWhenNotAuthorizedToSign() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_NONE);
+        int badPurposes = KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT
+                | KeyProperties.PURPOSE_VERIFY;
+
+        assertInitSignSucceeds("SHA256withECDSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA256withECDSA",
+                TestUtils.buildUpon(good, badPurposes).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+        assertInitSignSucceeds("SHA256withRSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA256withRSA",
+                TestUtils.buildUpon(good, badPurposes).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+        assertInitSignSucceeds("SHA256withRSA/PSS", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA256withRSA/PSS",
+                TestUtils.buildUpon(good, badPurposes).build());
+    }
+
+    public void testInitSignFailsWhenDigestNotAuthorized() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_SHA384);
+        String badDigest = KeyProperties.DIGEST_SHA256;
+
+        assertInitSignSucceeds("SHA384withECDSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA384withECDSA",
+                TestUtils.buildUpon(good).setDigests(badDigest).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+        assertInitSignSucceeds("SHA384withRSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA384withRSA",
+                TestUtils.buildUpon(good).setDigests(badDigest).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+        assertInitSignSucceeds("SHA384withRSA/PSS", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA384withRSA/PSS",
+                TestUtils.buildUpon(good).setDigests(badDigest).build());
+    }
+
+    public void testInitSignFailsWhenPaddingNotAuthorized() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_SHA512);
+
+        // Does not apply to ECDSA because it doesn't any signature padding schemes
+        // assertInitSignThrowsInvalidKeyException("SHA256withECDSA", builder.build());
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+        assertInitSignSucceeds("SHA512withRSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA512withRSA",
+                TestUtils.buildUpon(good)
+                        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS)
+                        .build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+        assertInitSignSucceeds("SHA512withRSA/PSS", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA512withRSA/PSS",
+                TestUtils.buildUpon(good)
+                        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
+                        .build());
+    }
+
+    public void testInitSignFailsWhenKeyNotYetValid() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_SHA224);
+        Date badStartDate = new Date(System.currentTimeMillis() + DAY_IN_MILLIS);
+        assertInitSignSucceeds("SHA224withECDSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withECDSA",
+                TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+        assertInitSignSucceeds("SHA224withRSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withRSA",
+                TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+        assertInitSignSucceeds("SHA224withRSA/PSS", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withRSA/PSS",
+                TestUtils.buildUpon(good).setKeyValidityStart(badStartDate).build());
+    }
+
+    public void testInitSignFailsWhenKeyNoLongerValid() throws Exception {
+        KeyProtection.Builder good = new KeyProtection.Builder(
+                KeyProperties.PURPOSE_SIGN)
+                .setDigests(KeyProperties.DIGEST_SHA224);
+        Date badEndDate = new Date(System.currentTimeMillis() - DAY_IN_MILLIS);
+        assertInitSignSucceeds("SHA224withECDSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withECDSA",
+                TestUtils.buildUpon(good).setKeyValidityForOriginationEnd(badEndDate).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1);
+        assertInitSignSucceeds("SHA224withRSA", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withRSA",
+                TestUtils.buildUpon(good).setKeyValidityForOriginationEnd(badEndDate).build());
+
+        good.setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PSS);
+        assertInitSignSucceeds("SHA224withRSA/PSS", good.build());
+        assertInitSignThrowsInvalidKeyException("SHA224withRSA/PSS",
+                TestUtils.buildUpon(good).setKeyValidityForOriginationEnd(badEndDate).build());
+    }
+
+    private void assertInitVerifySucceeds(
+            String signatureAlgorithm,
+            KeyProtection keyProtection) throws Exception {
+        int[] resIds = getDefaultKeyAndCertResIds(signatureAlgorithm);
+        assertInitVerifySucceeds(
+                signatureAlgorithm,
+                resIds[0],
+                resIds[1],
+                keyProtection);
+    }
+
+    private void assertInitVerifySucceeds(
+            String signatureAlgorithm,
+            int privateKeyResId,
+            int certResId,
+            KeyProtection keyProtection) throws Exception {
+        PublicKey publicKey = TestUtils.importIntoAndroidKeyStore(
+                "test1",
+                TestUtils.getRawResPrivateKey(getContext(), privateKeyResId),
+                TestUtils.getRawResX509Certificate(getContext(), certResId),
+                keyProtection)
+                .getPublic();
+        Signature signature = Signature.getInstance(signatureAlgorithm);
+        signature.initVerify(publicKey);
+    }
+
+    private void assertInitSignSucceeds(
+            String signatureAlgorithm,
+            KeyProtection keyProtection) throws Exception {
+        int[] resIds = getDefaultKeyAndCertResIds(signatureAlgorithm);
+        assertInitSignSucceeds(
+                signatureAlgorithm,
+                resIds[0],
+                resIds[1],
+                keyProtection);
+    }
+
+    private void assertInitSignSucceeds(
+            String signatureAlgorithm,
+            int privateKeyResId,
+            int certResId,
+            KeyProtection keyProtection) throws Exception {
+        PrivateKey privateKey = TestUtils.importIntoAndroidKeyStore(
+                "test1",
+                TestUtils.getRawResPrivateKey(getContext(), privateKeyResId),
+                TestUtils.getRawResX509Certificate(getContext(), certResId),
+                keyProtection)
+                .getPrivate();
+        Signature signature = Signature.getInstance(signatureAlgorithm);
+        signature.initSign(privateKey);
+    }
+
+    private void assertInitSignThrowsInvalidKeyException(
+            String signatureAlgorithm,
+            KeyProtection keyProtection) throws Exception {
+        assertInitSignThrowsInvalidKeyException(null, signatureAlgorithm, keyProtection);
+    }
+
+    private void assertInitSignThrowsInvalidKeyException(
+            String message,
+            String signatureAlgorithm,
+            KeyProtection keyProtection) throws Exception {
+        int[] resIds = getDefaultKeyAndCertResIds(signatureAlgorithm);
+        assertInitSignThrowsInvalidKeyException(
+                message,
+                signatureAlgorithm,
+                resIds[0],
+                resIds[1],
+                keyProtection);
+    }
+
+    private void assertInitSignThrowsInvalidKeyException(
+            String message,
+            String signatureAlgorithm,
+            int privateKeyResId,
+            int certResId,
+            KeyProtection keyProtection) throws Exception {
+        PrivateKey privateKey = TestUtils.importIntoAndroidKeyStore(
+                "test1",
+                TestUtils.getRawResPrivateKey(getContext(), privateKeyResId),
+                TestUtils.getRawResX509Certificate(getContext(), certResId),
+                keyProtection)
+                .getPrivate();
+        Signature signature = Signature.getInstance(signatureAlgorithm);
+        try {
+            signature.initSign(privateKey);
+            fail(message);
+        } catch (InvalidKeyException expected) {}
+    }
+
+    static int[] getDefaultKeyAndCertResIds(String signatureAlgorithm) {
+        String sigAlgLowerCase = signatureAlgorithm.toLowerCase();
+        if (sigAlgLowerCase.contains("ecdsa")) {
+            return new int[] {R.raw.ec_key1_pkcs8, R.raw.ec_key1_cert};
+        } else if (sigAlgLowerCase.contains("rsa")) {
+            return new int[] {R.raw.rsa_key1_pkcs8, R.raw.rsa_key1_cert};
+        } else {
+            throw new IllegalArgumentException(
+                    "Unknown signature algorithm: " + signatureAlgorithm);
+        }
+    }
+
+    private static String getKeyAlgorithmForSignatureAlgorithm(String signatureAlgorithm) {
+        String algLowerCase = signatureAlgorithm.toLowerCase();
+        if (algLowerCase.contains("withecdsa")) {
+            return KeyProperties.KEY_ALGORITHM_EC;
+        } else if (algLowerCase.contains("withrsa")) {
+            return KeyProperties.KEY_ALGORITHM_RSA;
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported signature algorithm: " + signatureAlgorithm);
+        }
+    }
+
+    private static KeyPair getKeyPairForSignatureAlgorithm(String signatureAlgorithm,
+            Iterable<KeyPair> keyPairs) {
+        return TestUtils.getKeyPairForKeyAlgorithm(
+                getKeyAlgorithmForSignatureAlgorithm(signatureAlgorithm), keyPairs);
+    }
+
+    private Collection<KeyPair> importDefaultKatKeyPairs() throws Exception {
+        return Arrays.asList(
+                TestUtils.importIntoAndroidKeyStore(
+                        "testRsa",
+                        TestUtils.getRawResPrivateKey(getContext(), R.raw.rsa_key1_pkcs8),
+                        TestUtils.getRawResX509Certificate(getContext(), R.raw.rsa_key1_cert),
+                        new KeyProtection.Builder(
+                                KeyProperties.PURPOSE_SIGN)
+                                .setDigests(KeyProperties.DIGEST_NONE)
+                                .setSignaturePaddings(
+                                        KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
+                                        KeyProperties.SIGNATURE_PADDING_RSA_PSS)
+                                .build()),
+                TestUtils.importIntoAndroidKeyStore(
+                        "testEc",
+                        TestUtils.getRawResPrivateKey(getContext(), R.raw.ec_key1_pkcs8),
+                        TestUtils.getRawResX509Certificate(getContext(), R.raw.ec_key1_cert),
+                        new KeyProtection.Builder(
+                                KeyProperties.PURPOSE_SIGN)
+                                .setDigests(KeyProperties.DIGEST_NONE)
+                                .build())
+                );
+    }
+
+    private void assertSignatureVerifiesOneShot(
+            String algorithm,
+            PublicKey publicKey,
+            byte[] message,
+            byte[] signature) throws Exception {
+        assertSignatureVerifiesOneShot(algorithm, null, publicKey, message, signature);
+    }
+
+    private void assertSignatureVerifiesOneShot(
+            String algorithm,
+            Provider provider,
+            PublicKey publicKey,
+            byte[] message,
+            byte[] signature) throws Exception {
+        Signature sig = (provider != null)
+                ? Signature.getInstance(algorithm, provider) : Signature.getInstance(algorithm);
+        sig.initVerify(publicKey);
+        sig.update(message);
+        if (!sig.verify(signature)) {
+            fail("Signature did not verify. algorithm: " + algorithm
+                    + ", provider: " + sig.getProvider().getName()
+                    + ", signature (" + signature.length + " bytes): "
+                    + HexEncoding.encode(signature));
+        }
+    }
+
+    private void assertSignatureDoesNotVerifyOneShot(
+            String algorithm,
+            Provider provider,
+            PublicKey publicKey,
+            byte[] message,
+            byte[] signature) throws Exception {
+        Signature sig = (provider != null)
+                ? Signature.getInstance(algorithm, provider) : Signature.getInstance(algorithm);
+        sig.initVerify(publicKey);
+        sig.update(message);
+        if (sig.verify(signature)) {
+            fail("Signature verified unexpectedly. algorithm: " + algorithm
+                    + ", provider: " + sig.getProvider().getName()
+                    + ", signature (" + signature.length + " bytes): "
+                    + HexEncoding.encode(signature));
+        }
+    }
+
+    private void assertSignatureVerifiesFedOneByteAtATime(
+            String algorithm,
+            Provider provider,
+            PublicKey publicKey,
+            byte[] message,
+            byte[] signature) throws Exception {
+        Signature sig = (provider != null)
+                ? Signature.getInstance(algorithm, provider) : Signature.getInstance(algorithm);
+        sig.initVerify(publicKey);
+        for (int i = 0; i < message.length; i++) {
+            sig.update(message[i]);
+        }
+        if (!sig.verify(signature)) {
+            fail("Signature did not verify. algorithm: " + algorithm
+                    + ", provider: " + sig.getProvider().getName()
+                    + ", signature (" + signature.length + " bytes): "
+                    + HexEncoding.encode(signature));
+        }
+    }
+
+    private byte[] generateSignatureFedUsingFixedSizeChunks(
+            String algorithm,
+            Provider expectedProvider,
+            PrivateKey privateKey,
+            byte[] message,
+            int chunkSizeBytes) throws Exception {
+        Signature signature = Signature.getInstance(algorithm);
+        signature.initSign(privateKey);
+        assertSame(expectedProvider, signature.getProvider());
+        int messageRemaining = message.length;
+        int messageOffset = 0;
+        while (messageRemaining > 0) {
+            int actualChunkSizeBytes =  Math.min(chunkSizeBytes, messageRemaining);
+            signature.update(message, messageOffset, actualChunkSizeBytes);
+            messageOffset += actualChunkSizeBytes;
+            messageRemaining -= actualChunkSizeBytes;
+        }
+        return signature.sign();
+    }
+    private void assertSignatureVerifiesFedUsingFixedSizeChunks(
+            String algorithm,
+            Provider provider,
+            PublicKey publicKey,
+            byte[] message,
+            byte[] signature,
+            int chunkSizeBytes) throws Exception {
+        Signature sig = (provider != null)
+                ? Signature.getInstance(algorithm, provider) : Signature.getInstance(algorithm);
+        sig.initVerify(publicKey);
+        int messageRemaining = message.length;
+        int messageOffset = 0;
+        while (messageRemaining > 0) {
+            int actualChunkSizeBytes =  Math.min(chunkSizeBytes, messageRemaining);
+            sig.update(message, messageOffset, actualChunkSizeBytes);
+            messageOffset += actualChunkSizeBytes;
+            messageRemaining -= actualChunkSizeBytes;
+        }
+        if (!sig.verify(signature)) {
+            fail("Signature did not verify. algorithm: " + algorithm
+                    + ", provider: " + sig.getProvider().getName()
+                    + ", signature (" + signature.length + " bytes): "
+                    + HexEncoding.encode(signature));
+        }
+    }
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index cbcbc45..02fbd1e 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -16,14 +16,21 @@
 
 package android.keystore.cts;
 
+import android.content.Context;
+import android.security.keystore.KeyGenParameterSpec;
 import android.security.keystore.KeyInfo;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.KeyProtection;
 import android.test.MoreAsserts;
-
 import junit.framework.Assert;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.security.Key;
 import java.security.KeyFactory;
 import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
@@ -32,6 +39,7 @@
 import java.security.PublicKey;
 import java.security.UnrecoverableEntryException;
 import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.interfaces.ECKey;
 import java.security.interfaces.ECPrivateKey;
@@ -42,6 +50,12 @@
 import java.security.spec.ECParameterSpec;
 import java.security.spec.EllipticCurve;
 import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import javax.crypto.SecretKey;
 import javax.crypto.SecretKeyFactory;
@@ -231,4 +245,225 @@
             throw new IllegalArgumentException("Unexpected key type: " + key.getClass());
         }
     }
+
+    static <T> void assertContentsInAnyOrder(Iterable<T> actual, T... expected) {
+        assertContentsInAnyOrder(null, actual, expected);
+    }
+
+    static <T> void assertContentsInAnyOrder(String message, Iterable<T> actual, T... expected) {
+        Map<T, Integer> actualFreq = getFrequencyTable(actual);
+        Map<T, Integer> expectedFreq = getFrequencyTable(expected);
+        if (actualFreq.equals(expectedFreq)) {
+            return;
+        }
+
+        Map<T, Integer> extraneousFreq = new HashMap<T, Integer>();
+        for (Map.Entry<T, Integer> actualEntry : actualFreq.entrySet()) {
+            int actualCount = actualEntry.getValue();
+            Integer expectedCount = expectedFreq.get(actualEntry.getKey());
+            int diff = actualCount - ((expectedCount != null) ? expectedCount : 0);
+            if (diff > 0) {
+                extraneousFreq.put(actualEntry.getKey(), diff);
+            }
+        }
+
+        Map<T, Integer> missingFreq = new HashMap<T, Integer>();
+        for (Map.Entry<T, Integer> expectedEntry : expectedFreq.entrySet()) {
+            int expectedCount = expectedEntry.getValue();
+            Integer actualCount = actualFreq.get(expectedEntry.getKey());
+            int diff = expectedCount - ((actualCount != null) ? actualCount : 0);
+            if (diff > 0) {
+                missingFreq.put(expectedEntry.getKey(), diff);
+            }
+        }
+
+        List<T> extraneous = frequencyTableToValues(extraneousFreq);
+        List<T> missing = frequencyTableToValues(missingFreq);
+        StringBuilder result = new StringBuilder();
+        String delimiter = "";
+        if (message != null) {
+            result.append(message).append(".");
+            delimiter = " ";
+        }
+        if (!missing.isEmpty()) {
+            result.append(delimiter).append("missing: " + missing);
+            delimiter = ", ";
+        }
+        if (!extraneous.isEmpty()) {
+            result.append(delimiter).append("extraneous: " + extraneous);
+        }
+        fail(result.toString());
+    }
+
+    private static <T> Map<T, Integer> getFrequencyTable(Iterable<T> values) {
+        Map<T, Integer> result = new HashMap<T, Integer>();
+        for (T value : values) {
+            Integer count = result.get(value);
+            if (count == null) {
+                count = 1;
+            } else {
+                count++;
+            }
+            result.put(value, count);
+        }
+        return result;
+    }
+
+    private static <T> Map<T, Integer> getFrequencyTable(T... values) {
+        Map<T, Integer> result = new HashMap<T, Integer>();
+        for (T value : values) {
+            Integer count = result.get(value);
+            if (count == null) {
+                count = 1;
+            } else {
+                count++;
+            }
+            result.put(value, count);
+        }
+        return result;
+    }
+
+    @SuppressWarnings("rawtypes")
+    private static <T> List<T> frequencyTableToValues(Map<T, Integer> table) {
+        if (table.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        List<T> result = new ArrayList<T>();
+        boolean comparableValues = true;
+        for (Map.Entry<T, Integer> entry : table.entrySet()) {
+            T value = entry.getKey();
+            if (!(value instanceof Comparable)) {
+                comparableValues = false;
+            }
+            int frequency = entry.getValue();
+            for (int i = 0; i < frequency; i++) {
+                result.add(value);
+            }
+        }
+
+        if (comparableValues) {
+            sortAssumingComparable(result);
+        }
+        return result;
+    }
+
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    private static void sortAssumingComparable(List<?> values) {
+        Collections.sort((List<Comparable>)values);
+    }
+
+    static String[] toLowerCase(String... values) {
+        if (values == null) {
+            return null;
+        }
+        String[] result = new String[values.length];
+        for (int i = 0; i < values.length; i++) {
+            String value = values[i];
+            result[i] = (value != null) ? value.toLowerCase() : null;
+        }
+        return result;
+    }
+
+    static Certificate generateSelfSignedCert(String keyAlgorithm) throws Exception {
+        KeyPairGenerator generator =
+                KeyPairGenerator.getInstance(keyAlgorithm, "AndroidKeyStore");
+        generator.initialize(new KeyGenParameterSpec.Builder(
+                "test1",
+                KeyProperties.PURPOSE_SIGN)
+                .build());
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+        return keyStore.getCertificate("test1");
+    }
+
+    static PrivateKey getRawResPrivateKey(Context context, int resId) throws Exception {
+        byte[] pkcs8EncodedForm;
+        try (InputStream in = context.getResources().openRawResource(resId)) {
+            pkcs8EncodedForm = drain(in);
+        }
+        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pkcs8EncodedForm);
+
+        try {
+            return KeyFactory.getInstance("EC").generatePrivate(privateKeySpec);
+        } catch (InvalidKeySpecException e) {
+            try {
+                return KeyFactory.getInstance("RSA").generatePrivate(privateKeySpec);
+            } catch (InvalidKeySpecException e2) {
+                throw new InvalidKeySpecException("The key is neither EC nor RSA", e);
+            }
+        }
+    }
+
+    static X509Certificate getRawResX509Certificate(Context context, int resId) throws Exception {
+        try (InputStream in = context.getResources().openRawResource(resId)) {
+            return (X509Certificate) CertificateFactory.getInstance("X.509")
+                    .generateCertificate(in);
+        }
+    }
+
+    static KeyPair importIntoAndroidKeyStore(
+            String alias,
+            PrivateKey privateKey,
+            Certificate certificate,
+            KeyProtection keyProtection) throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+        keyStore.load(null);
+        keyStore.setEntry(alias,
+                new KeyStore.PrivateKeyEntry(privateKey, new Certificate[] {certificate}),
+                keyProtection);
+        return new KeyPair(
+                keyStore.getCertificate(alias).getPublicKey(),
+                (PrivateKey) keyStore.getKey(alias, null));
+    }
+
+    static byte[] drain(InputStream in) throws IOException {
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+        byte[] buffer = new byte[16 * 1024];
+        int chunkSize;
+        while ((chunkSize = in.read(buffer)) != -1) {
+            result.write(buffer, 0, chunkSize);
+        }
+        return result.toByteArray();
+    }
+
+    static KeyProtection.Builder buildUpon(
+            KeyProtection.Builder builder) {
+        return buildUponInternal(builder, null);
+    }
+
+    static KeyProtection.Builder buildUpon(
+            KeyProtection.Builder builder, int newPurposes) {
+        return buildUponInternal(builder, newPurposes);
+    }
+
+    private static KeyProtection.Builder buildUponInternal(
+            KeyProtection.Builder builder, Integer newPurposes) {
+        KeyProtection spec = builder.build();
+        int purposes = (newPurposes == null) ? spec.getPurposes() : newPurposes;
+        KeyProtection.Builder result = new KeyProtection.Builder(purposes);
+        result.setBlockModes(spec.getBlockModes());
+        if (spec.isDigestsSpecified()) {
+            result.setDigests(spec.getDigests());
+        }
+        result.setEncryptionPaddings(spec.getEncryptionPaddings());
+        result.setSignaturePaddings(spec.getSignaturePaddings());
+        result.setKeyValidityStart(spec.getKeyValidityStart());
+        result.setKeyValidityForOriginationEnd(spec.getKeyValidityForOriginationEnd());
+        result.setKeyValidityForConsumptionEnd(spec.getKeyValidityForConsumptionEnd());
+        result.setRandomizedEncryptionRequired(spec.isRandomizedEncryptionRequired());
+        result.setUserAuthenticationRequired(spec.isUserAuthenticationRequired());
+        result.setUserAuthenticationValidityDurationSeconds(
+                spec.getUserAuthenticationValidityDurationSeconds());
+        return result;
+    }
+
+    static KeyPair getKeyPairForKeyAlgorithm(String keyAlgorithm, Iterable<KeyPair> keyPairs) {
+        for (KeyPair keyPair : keyPairs) {
+            if (keyAlgorithm.equalsIgnoreCase(keyPair.getPublic().getAlgorithm())) {
+                return keyPair;
+            }
+        }
+        throw new IllegalArgumentException("No KeyPair for key algorithm " + keyAlgorithm);
+    }
 }
diff --git a/tests/tests/media/res/raw/gb18030_5.mp3 b/tests/tests/media/res/raw/gb18030_5.mp3
deleted file mode 100644
index 70f76ce..0000000
--- a/tests/tests/media/res/raw/gb18030_5.mp3
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index 4b42690..af7cfaa 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -390,8 +390,6 @@
                     new String[] {"电视原声带", "格斗天王(限量精装版)(预购版)", null, "11.Open Arms.( cn808.net )", null} ),
             new MediaScanEntry(R.raw.gb18030_4,
                     new String[] {"莫扎特", "黄金古典", "柏林爱乐乐团", "第25号交响曲", "莫扎特"} ),
-            new MediaScanEntry(R.raw.gb18030_5,
-                    new String[] {"光良", "童话", "光良", "02.童话", "鍏夎壇"} ),
             new MediaScanEntry(R.raw.gb18030_6,
                     new String[] {"张韶涵", "潘朵拉", "張韶涵", "隐形的翅膀", "王雅君"} ),
             new MediaScanEntry(R.raw.gb18030_7, // this is actually utf-8
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index 6f9e2a2..41d8d89 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -503,7 +503,7 @@
                     // sync.getTolerance() is MediaSync's tolerance of the playback rate, whereas
                     // PLAYBACK_RATE_TOLERANCE_PERCENT / 100 is our test's tolerance.
                     // We need to add both to get an upperbound for allowable error.
-                    mediaDurationUs * (sync.getTolerance() + PLAYBACK_RATE_TOLERANCE_PERCENT / 100)
+                    mediaDurationUs * (sync.getTolerance() + PLAYBACK_RATE_TOLERANCE_PERCENT / 100.)
                             + TIME_MEASUREMENT_TOLERANCE_US);
         }
 
diff --git a/tests/tests/net/Android.mk b/tests/tests/net/Android.mk
index a35e145..6524871 100644
--- a/tests/tests/net/Android.mk
+++ b/tests/tests/net/Android.mk
@@ -26,7 +26,8 @@
 
 LOCAL_JAVA_LIBRARIES := voip-common conscrypt org.apache.http.legacy
 
-LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni
+LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativedns_jni \
+                              libnativemultinetwork_jni
 
 # include CtsTestServer as a temporary hack to free net.cts from cts.stub.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/tests/net/jni/Android.mk b/tests/tests/net/jni/Android.mk
index 75982de..ca82b30 100644
--- a/tests/tests/net/jni/Android.mk
+++ b/tests/tests/net/jni/Android.mk
@@ -28,3 +28,12 @@
 LOCAL_SHARED_LIBRARIES := libnativehelper liblog
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libnativemultinetwork_jni
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := NativeMultinetworkJni.c
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+LOCAL_SHARED_LIBRARIES := libandroid libnativehelper liblog
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/net/jni/NativeMultinetworkJni.c b/tests/tests/net/jni/NativeMultinetworkJni.c
new file mode 100644
index 0000000..9a5ab9c
--- /dev/null
+++ b/tests/tests/net/jni/NativeMultinetworkJni.c
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+
+#define LOG_TAG "MultinetworkApiTest"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <jni.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <android/multinetwork.h>
+
+#define UNUSED(X) ((void) X)
+
+static const char kHostname[] = "connectivitycheck.android.com";
+
+
+JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runGetaddrinfoCheck(
+        JNIEnv* env, jclass class, jlong nethandle) {
+    UNUSED(env);
+    UNUSED(class);
+    net_handle_t handle = (net_handle_t) nethandle;
+    struct addrinfo *res = NULL;
+
+    errno = 0;
+    int rval = android_getaddrinfofornetwork(handle, kHostname, NULL, NULL, &res);
+    const int saved_errno = errno;
+    freeaddrinfo(res);
+
+    ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d",
+          handle, kHostname, rval, saved_errno);
+    return rval == 0 ? 0 : -saved_errno;
+}
+
+JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetprocnetwork(
+        JNIEnv* env, jclass class, jlong nethandle) {
+    UNUSED(env);
+    UNUSED(class);
+    net_handle_t handle = (net_handle_t) nethandle;
+
+    errno = 0;
+    int rval = android_setprocnetwork(handle);
+    const int saved_errno = errno;
+    ALOGD("android_setprocnetwork(%llu) returned rval=%d errno=%d",
+          handle, rval, saved_errno);
+    return rval == 0 ? 0 : -saved_errno;
+}
+
+JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runSetsocknetwork(
+        JNIEnv* env, jclass class, jlong nethandle) {
+    UNUSED(env);
+    UNUSED(class);
+    net_handle_t handle = (net_handle_t) nethandle;
+
+    errno = 0;
+    int fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+    if (fd < 0) {
+        ALOGD("socket() failed, errno=%d", errno);
+        return -errno;
+    }
+
+    errno = 0;
+    int rval = android_setsocknetwork(handle, fd);
+    const int saved_errno = errno;
+    ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d",
+          handle, fd, rval, saved_errno);
+    close(fd);
+    return rval == 0 ? 0 : -saved_errno;
+}
+
+static const int kSockaddrStrLen = INET6_ADDRSTRLEN + strlen("[]:65535");
+
+void sockaddr_ntop(const struct sockaddr *sa, socklen_t salen, char *dst, const size_t size) {
+    char addrstr[INET6_ADDRSTRLEN];
+    char portstr[sizeof("65535")];
+    char buf[sizeof(addrstr) + sizeof(portstr) + sizeof("[]:")];
+    int ret = getnameinfo(sa, salen,
+                          addrstr, sizeof(addrstr),
+                          portstr, sizeof(portstr),
+                          NI_NUMERICHOST | NI_NUMERICSERV);
+    if (ret == 0) {
+        snprintf(buf, sizeof(buf),
+                 (sa->sa_family == AF_INET6) ? "[%s]:%s" : "%s:%s",
+                 addrstr, portstr);
+    } else {
+        sprintf(buf, "???");
+    }
+
+    strlcpy(dst, buf, (strlen(buf) < size - 1) ? strlen(buf) : size - 1);
+}
+
+JNIEXPORT jint Java_android_net_cts_MultinetworkApiTest_runDatagramCheck(
+        JNIEnv* env, jclass class, jlong nethandle) {
+    UNUSED(env);
+    UNUSED(class);
+    const struct addrinfo kHints = {
+        .ai_flags = AI_ADDRCONFIG,
+        .ai_family = AF_UNSPEC,
+        .ai_socktype = SOCK_DGRAM,
+        .ai_protocol = IPPROTO_UDP,
+    };
+    struct addrinfo *res = NULL;
+    net_handle_t handle = (net_handle_t) nethandle;
+
+    // Quoth Ian Swett:
+    //     "QUIC always uses 80 and 443, but only 443 is used for secure(HTTPS) traffic."
+    int rval = android_getaddrinfofornetwork(handle, kHostname, "80", &kHints, &res);
+    if (rval != 0) {
+        ALOGD("android_getaddrinfofornetwork(%llu, %s) returned rval=%d errno=%d",
+              handle, kHostname, rval, errno);
+        freeaddrinfo(res);
+        return -errno;
+    }
+
+    // Rely upon getaddrinfo sorting the best destination to the front.
+    int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+    if (fd < 0) {
+        ALOGD("socket(%d, %d, %d) failed, errno=%d",
+              res->ai_family, res->ai_socktype, res->ai_protocol, errno);
+        freeaddrinfo(res);
+        return -errno;
+    }
+
+    rval = android_setsocknetwork(handle, fd);
+    ALOGD("android_setprocnetwork(%llu, %d) returned rval=%d errno=%d",
+          handle, fd, rval, errno);
+    if (rval != 0) {
+        close(fd);
+        freeaddrinfo(res);
+        return -errno;
+    }
+
+    char addrstr[kSockaddrStrLen];
+    sockaddr_ntop(res->ai_addr, res->ai_addrlen, addrstr, sizeof(addrstr));
+    ALOGD("Attempting connect() to %s...", addrstr);
+
+    rval = connect(fd, res->ai_addr, res->ai_addrlen);
+    if (rval != 0) {
+        close(fd);
+        freeaddrinfo(res);
+        return -errno;
+    }
+    freeaddrinfo(res);
+
+    struct sockaddr_storage src_addr;
+    socklen_t src_addrlen = sizeof(src_addr);
+    if (getsockname(fd, (struct sockaddr *)&src_addr, &src_addrlen) != 0) {
+        close(fd);
+        return -errno;
+    }
+    sockaddr_ntop((const struct sockaddr *)&src_addr, sizeof(src_addr), addrstr, sizeof(addrstr));
+    ALOGD("... from %s", addrstr);
+
+    // Don't let reads or writes block indefinitely.
+    const struct timeval timeo = { 5, 0 };  // 5 seconds
+    setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
+    setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeo, sizeof(timeo));
+
+    uint8_t quic_packet[] = {
+        0x0c,                    // public flags: 64bit conn ID, 8bit sequence number
+        0, 0, 0, 0, 0, 0, 0, 0,  // 64bit connection ID
+        0x01,                    // sequence number
+        0x00,                    // private flags
+        0x07,                    // type: regular frame type "PING"
+    };
+
+    arc4random_buf(quic_packet + 1, 8);  // random connection ID
+
+    ssize_t sent = send(fd, quic_packet, sizeof(quic_packet), 0);
+    if (sent < (ssize_t)sizeof(quic_packet)) {
+        ALOGD("send(QUIC packet) returned sent=%zd, errno=%d", sent, errno);
+        close(fd);
+        return -errno;
+    }
+
+    uint8_t response[1500];
+    ssize_t rcvd = recv(fd, response, sizeof(response), 0);
+    if (rcvd < sent) {
+        ALOGD("recv() returned rcvd=%zd, errno=%d", rcvd, errno);
+        close(fd);
+        return -errno;
+    }
+
+    int conn_id_cmp = memcmp(quic_packet + 1, response + 1, 8);
+    if (conn_id_cmp != 0) {
+        ALOGD("sent and received connection IDs do not match");
+        close(fd);
+        return -EPROTO;
+    }
+
+    // TODO: log, and compare to the IP address encoded in the
+    // response, since this should be a public reset packet.
+
+    close(fd);
+    return 0;
+}
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
new file mode 100644
index 0000000..51ee50e
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/MultinetworkApiTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2015 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 android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkUtils;
+import android.system.ErrnoException;
+import android.system.OsConstants;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+
+
+public class MultinetworkApiTest extends AndroidTestCase {
+
+    static {
+        System.loadLibrary("nativemultinetwork_jni");
+    }
+
+    private static final String TAG = "MultinetworkNativeApiTest";
+
+    /**
+     * @return 0 on success
+     */
+    private static native int runGetaddrinfoCheck(long networkHandle);
+    private static native int runSetprocnetwork(long networkHandle);
+    private static native int runSetsocknetwork(long networkHandle);
+    private static native int runDatagramCheck(long networkHandle);
+
+    private ConnectivityManager mCM;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+    }
+
+    private Network[] getTestableNetworks() {
+        final ArrayList<Network> testableNetworks = new ArrayList<Network>();
+        for (Network network : mCM.getAllNetworks()) {
+            final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
+            if (nc != null
+                    && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+                    && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+                testableNetworks.add(network);
+            }
+        }
+
+        assertTrue(
+                "This test requires that at least one network be connected. " +
+                "Please ensure that the device is connected to a network.",
+                testableNetworks.size() >= 1);
+        return testableNetworks.toArray(new Network[0]);
+    }
+
+    public void testGetaddrinfo() throws ErrnoException {
+        for (Network network : getTestableNetworks()) {
+            int errno = runGetaddrinfoCheck(network.getNetworkHandle());
+            if (errno != 0) {
+                throw new ErrnoException(
+                        "getaddrinfo on " + mCM.getNetworkInfo(network), -errno);
+            }
+        }
+    }
+
+    public void testSetprocnetwork() throws ErrnoException {
+        // Hopefully no prior test in this process space has set a default network.
+        assertNull(mCM.getProcessDefaultNetwork());
+        assertEquals(0, NetworkUtils.getBoundNetworkForProcess());
+
+        for (Network network : getTestableNetworks()) {
+            mCM.setProcessDefaultNetwork(null);
+            assertNull(mCM.getProcessDefaultNetwork());
+
+            int errno = runSetprocnetwork(network.getNetworkHandle());
+            if (errno != 0) {
+                throw new ErrnoException(
+                        "setprocnetwork on " + mCM.getNetworkInfo(network), -errno);
+            }
+            Network processDefault = mCM.getProcessDefaultNetwork();
+            assertNotNull(processDefault);
+            assertEquals(network, processDefault);
+            // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::,
+            // and ensure that the source address is in fact on this network as
+            // determined by mCM.getLinkProperties(network).
+
+            mCM.setProcessDefaultNetwork(null);
+        }
+
+        for (Network network : getTestableNetworks()) {
+            NetworkUtils.bindProcessToNetwork(0);
+            assertNull(mCM.getBoundNetworkForProcess());
+
+            int errno = runSetprocnetwork(network.getNetworkHandle());
+            if (errno != 0) {
+                throw new ErrnoException(
+                        "setprocnetwork on " + mCM.getNetworkInfo(network), -errno);
+            }
+            assertEquals(network, new Network(mCM.getBoundNetworkForProcess()));
+            // TODO: open DatagramSockets, connect them to 192.0.2.1 and 2001:db8::,
+            // and ensure that the source address is in fact on this network as
+            // determined by mCM.getLinkProperties(network).
+
+            NetworkUtils.bindProcessToNetwork(0);
+        }
+    }
+
+    public void testSetsocknetwork() throws ErrnoException {
+        for (Network network : getTestableNetworks()) {
+            int errno = runSetsocknetwork(network.getNetworkHandle());
+            if (errno != 0) {
+                throw new ErrnoException(
+                        "setsocknetwork on " + mCM.getNetworkInfo(network), -errno);
+            }
+        }
+    }
+
+    public void testNativeDatagramTransmission() throws ErrnoException {
+        for (Network network : getTestableNetworks()) {
+            int errno = runDatagramCheck(network.getNetworkHandle());
+            if (errno != 0) {
+                throw new ErrnoException(
+                        "DatagramCheck on " + mCM.getNetworkInfo(network), -errno);
+            }
+        }
+    }
+
+    public void testNoSuchNetwork() {
+        final Network eNoNet = new Network(54321);
+        assertNull(mCM.getNetworkInfo(eNoNet));
+
+        final long eNoNetHandle = eNoNet.getNetworkHandle();
+        assertEquals(-OsConstants.ENONET, runSetsocknetwork(eNoNetHandle));
+        assertEquals(-OsConstants.ENONET, runSetprocnetwork(eNoNetHandle));
+        // TODO: correct test permissions so this call is not silently re-mapped
+        // to query on the default network.
+        // assertEquals(-OsConstants.ENONET, runGetaddrinfoCheck(eNoNetHandle));
+    }
+}
diff --git a/tests/tests/net/src/android/net/cts/MultinetworkTest.java b/tests/tests/net/src/android/net/cts/MultinetworkSysctlTest.java
similarity index 96%
rename from tests/tests/net/src/android/net/cts/MultinetworkTest.java
rename to tests/tests/net/src/android/net/cts/MultinetworkSysctlTest.java
index 256c030..c091a13 100644
--- a/tests/tests/net/src/android/net/cts/MultinetworkTest.java
+++ b/tests/tests/net/src/android/net/cts/MultinetworkSysctlTest.java
@@ -27,9 +27,9 @@
 import java.io.IOException;
 
 /**
- * Tests for multinetwork functionality.
+ * Tests for multinetwork sysctl functionality.
  */
-public class MultinetworkTest extends AndroidTestCase {
+public class MultinetworkSysctlTest extends AndroidTestCase {
 
     // Global sysctls. Must be present and set to 1.
     private static final String[] GLOBAL_SYSCTLS = {
diff --git a/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java b/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
index 7d9189f..2e5306d 100644
--- a/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
+++ b/tests/tests/net/src/android/net/http/cts/ApacheHttpClientTest.java
@@ -21,56 +21,27 @@
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.DefaultHttpClient;
 
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.State;
 import android.net.Uri;
-import android.net.wifi.WifiManager;
 import android.test.AndroidTestCase;
-import android.util.Log;
 import android.webkit.cts.CtsTestServer;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 public class ApacheHttpClientTest extends AndroidTestCase {
 
-    private static final String TAG = ApacheHttpClientTest.class.getSimpleName();
-
     private static final int NUM_DOWNLOADS = 20;
 
     private static final int SMALL_DOWNLOAD_SIZE = 100 * 1024;
 
     private CtsTestServer mWebServer;
 
-    private WifiManager mWifiManager;
-
-    private ConnectivityManager mConnectivityManager;
-
-    private boolean mHasTelephony;
-
-    private boolean mHasWifi;
-
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mWebServer = new CtsTestServer(mContext);
-        mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        mConnectivityManager = (ConnectivityManager)
-                mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-
-        PackageManager packageManager = mContext.getPackageManager();
-        mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
     }
 
     @Override
@@ -79,25 +50,8 @@
         mWebServer.shutdown();
     }
 
-    public void testExecute_withMobile() throws Exception {
-        if (mHasTelephony) {
-            disconnectWifiToConnectToMobile();
-        }
-
+    public void testExecute() throws Exception {
         downloadMultipleFiles();
-
-        if (mHasWifi) {
-            connectToWifi();
-        }
-    }
-
-    public void testExecute_withWifi() throws Exception {
-        if (mHasWifi) {
-            if (!mWifiManager.isWifiEnabled()) {
-                connectToWifi();
-            }
-            downloadMultipleFiles();
-        }
     }
 
     private void downloadMultipleFiles() throws ClientProtocolException, IOException {
@@ -134,77 +88,6 @@
                 numBytes += bytesRead;
             }
         }
-        assertEquals(message, SMALL_DOWNLOAD_SIZE, numBytes);
-    }
-
-    private void connectToWifi() throws InterruptedException {
-        if (!mWifiManager.isWifiEnabled()) {
-            ConnectivityActionReceiver receiver =
-                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI, State.CONNECTED);
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-            mContext.registerReceiver(receiver, filter);
-
-            assertTrue(mWifiManager.setWifiEnabled(true));
-            assertTrue("Wifi must be configured to connect to an access point for this test.",
-                    receiver.waitForStateChange());
-
-            mContext.unregisterReceiver(receiver);
-        }
-    }
-
-    private void disconnectWifiToConnectToMobile() throws InterruptedException {
-        if (mHasWifi && mWifiManager.isWifiEnabled()) {
-            ConnectivityActionReceiver connectMobileReceiver =
-                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_MOBILE,
-                            State.CONNECTED);
-            ConnectivityActionReceiver disconnectWifiReceiver =
-                    new ConnectivityActionReceiver(ConnectivityManager.TYPE_WIFI,
-                            State.DISCONNECTED);
-            IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
-            mContext.registerReceiver(connectMobileReceiver, filter);
-            mContext.registerReceiver(disconnectWifiReceiver, filter);
-
-            assertTrue(mWifiManager.setWifiEnabled(false));
-            assertTrue(disconnectWifiReceiver.waitForStateChange());
-            assertTrue(connectMobileReceiver.waitForStateChange());
-
-            mContext.unregisterReceiver(connectMobileReceiver);
-            mContext.unregisterReceiver(disconnectWifiReceiver);
-        }
-    }
-
-    /** Receiver that captures the last connectivity change's network type and state. */
-    private class ConnectivityActionReceiver extends BroadcastReceiver {
-
-        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
-        private final int mNetworkType;
-
-        private final State mExpectedState;
-
-        ConnectivityActionReceiver(int networkType, State expectedState) {
-            mNetworkType = networkType;
-            mExpectedState = expectedState;
-        }
-
-        public void onReceive(Context context, Intent intent) {
-            NetworkInfo networkInfo = intent.getExtras()
-                    .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
-            int networkType = networkInfo.getType();
-            State networkState = networkInfo.getState();
-            Log.i(TAG, "Network type: " + networkType + " State: " + networkInfo.getState());
-            if (networkType == mNetworkType && networkInfo.getState() == mExpectedState) {
-                mReceiveLatch.countDown();
-            }
-        }
-
-        public boolean waitForStateChange() throws InterruptedException {
-            return mReceiveLatch.await(30, TimeUnit.SECONDS) || hasExpectedState();
-        }
-
-        private boolean hasExpectedState() {
-            return mExpectedState == mConnectivityManager.getNetworkInfo(mNetworkType).getState();
-        }
+        assertEquals(message, expectedNumBytes, numBytes);
     }
 }
diff --git a/tests/tests/netsecpolicy/Android.mk b/tests/tests/netsecpolicy/Android.mk
new file mode 100644
index 0000000..137672e
--- /dev/null
+++ b/tests/tests/netsecpolicy/Android.mk
@@ -0,0 +1,17 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/netsecpolicy/src/android/security/NetworkSecurityPolicyTestBase.java b/tests/tests/netsecpolicy/src/android/security/NetworkSecurityPolicyTestBase.java
new file mode 100644
index 0000000..0ab07ae
--- /dev/null
+++ b/tests/tests/netsecpolicy/src/android/security/NetworkSecurityPolicyTestBase.java
@@ -0,0 +1,380 @@
+package android.security;
+
+import android.app.DownloadManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.database.Cursor;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.net.http.AndroidHttpClient;
+import android.test.AndroidTestCase;
+import android.webkit.cts.CtsTestServer;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.UnknownServiceException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+abstract class NetworkSecurityPolicyTestBase extends AndroidTestCase {
+    private CtsTestServer mHttpOnlyWebServer;
+
+    private final boolean mCleartextTrafficExpectedToBePermitted;
+
+    NetworkSecurityPolicyTestBase(boolean cleartextTrafficExpectedToBePermitted) {
+        mCleartextTrafficExpectedToBePermitted = cleartextTrafficExpectedToBePermitted;
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mHttpOnlyWebServer = new CtsTestServer(mContext, false);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            mHttpOnlyWebServer.shutdown();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    public void testNetworkSecurityPolicy() {
+        assertEquals(mCleartextTrafficExpectedToBePermitted,
+                NetworkSecurityPolicy.getInstance().isCleartextTrafficPermitted());
+    }
+
+    public void testApplicationInfoFlag() {
+        ApplicationInfo appInfo = getContext().getApplicationInfo();
+        int expectedValue = (mCleartextTrafficExpectedToBePermitted)
+                ? ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC : 0;
+        assertEquals(expectedValue, appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC);
+    }
+
+    public void testDefaultHttpURLConnection() throws Exception {
+        if (mCleartextTrafficExpectedToBePermitted) {
+            assertCleartextHttpURLConnectionSucceeds();
+        } else {
+            assertCleartextHttpURLConnectionBlocked();
+        }
+    }
+
+    private void assertCleartextHttpURLConnectionSucceeds() throws Exception {
+        URL url = new URL(mHttpOnlyWebServer.getUserAgentUrl());
+        HttpURLConnection conn = null;
+        try {
+            mHttpOnlyWebServer.resetRequestState();
+            conn = (HttpURLConnection) url.openConnection();
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(5000);
+            assertEquals(200, conn.getResponseCode());
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
+        }
+        Uri uri = Uri.parse(url.toString()).buildUpon().scheme(null).authority(null).build();
+        assertTrue(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    private void assertCleartextHttpURLConnectionBlocked() throws Exception {
+        URL url = new URL(mHttpOnlyWebServer.getUserAgentUrl());
+        HttpURLConnection conn = null;
+        try {
+            mHttpOnlyWebServer.resetRequestState();
+            conn = (HttpURLConnection) url.openConnection();
+            conn.setConnectTimeout(5000);
+            conn.setReadTimeout(5000);
+            conn.getResponseCode();
+            fail();
+        } catch (UnknownServiceException e) {
+            if ((e.getMessage() == null) || (!e.getMessage().toLowerCase().contains("cleartext"))) {
+                fail("Exception with which request failed does not mention cleartext: " + e);
+            }
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
+        }
+        Uri uri = Uri.parse(url.toString()).buildUpon().scheme(null).authority(null).build();
+        assertFalse(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    public void testAndroidHttpClient() throws Exception {
+        if (mCleartextTrafficExpectedToBePermitted) {
+            assertAndroidHttpClientCleartextRequestSucceeds();
+        } else {
+            assertAndroidHttpClientCleartextRequestBlocked();
+        }
+    }
+
+    private void assertAndroidHttpClientCleartextRequestSucceeds() throws Exception {
+        URL url = new URL(mHttpOnlyWebServer.getUserAgentUrl());
+        AndroidHttpClient httpClient = AndroidHttpClient.newInstance(null);
+        try {
+            HttpResponse response = httpClient.execute(new HttpGet(url.toString()));
+            assertEquals(200, response.getStatusLine().getStatusCode());
+        } finally {
+            httpClient.close();
+        }
+        Uri uri = Uri.parse(url.toString()).buildUpon().scheme(null).authority(null).build();
+        assertTrue(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    private void assertAndroidHttpClientCleartextRequestBlocked() throws Exception {
+        URL url = new URL(mHttpOnlyWebServer.getUserAgentUrl());
+        AndroidHttpClient httpClient = AndroidHttpClient.newInstance(null);
+        try {
+            HttpResponse response = httpClient.execute(new HttpGet(url.toString()));
+            fail();
+        } catch (IOException e) {
+            if ((e.getMessage() == null) || (!e.getMessage().toLowerCase().contains("cleartext"))) {
+                fail("Exception with which request failed does not mention cleartext: " + e);
+            }
+        } finally {
+            httpClient.close();
+        }
+        Uri uri = Uri.parse(url.toString()).buildUpon().scheme(null).authority(null).build();
+        assertFalse(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    public void testMediaPlayer() throws Exception {
+        if (mCleartextTrafficExpectedToBePermitted) {
+            assertMediaPlayerCleartextRequestSucceeds();
+        } else {
+            assertMediaPlayerCleartextRequestBlocked();
+        }
+    }
+
+    private void assertMediaPlayerCleartextRequestSucceeds() throws Exception {
+        MediaPlayer mediaPlayer = new MediaPlayer();
+        Uri uri = Uri.parse(mHttpOnlyWebServer.getUserAgentUrl());
+        mediaPlayer.setDataSource(getContext(), uri);
+
+        try {
+            mediaPlayer.prepare();
+        } catch (IOException expected) {
+        } finally {
+            try {
+                mediaPlayer.stop();
+            } catch (IllegalStateException ignored) {
+            }
+        }
+        uri = uri.buildUpon().scheme(null).authority(null).build();
+        assertTrue(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    private void assertMediaPlayerCleartextRequestBlocked() throws Exception {
+        MediaPlayer mediaPlayer = new MediaPlayer();
+        Uri uri = Uri.parse(mHttpOnlyWebServer.getUserAgentUrl());
+        mediaPlayer.setDataSource(getContext(), uri);
+
+        try {
+            mediaPlayer.prepare();
+        } catch (IOException expected) {
+        } finally {
+            try {
+                mediaPlayer.stop();
+            } catch (IllegalStateException ignored) {
+            }
+        }
+        uri = uri.buildUpon().scheme(null).authority(null).build();
+        assertFalse(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+    }
+
+    public void testDownloadManager() throws Exception {
+        Uri uri = Uri.parse(mHttpOnlyWebServer.getTestDownloadUrl("netsecpolicy", 0));
+        int[] result = downloadUsingDownloadManager(uri);
+        int status = result[0];
+        int reason = result[1];
+        uri = uri.buildUpon().scheme(null).authority(null).build();
+        if (mCleartextTrafficExpectedToBePermitted) {
+            assertEquals(DownloadManager.STATUS_SUCCESSFUL, status);
+            assertTrue(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+        } else {
+            assertEquals(DownloadManager.STATUS_FAILED, status);
+            assertEquals(400, reason);
+            assertFalse(mHttpOnlyWebServer.wasResourceRequested(uri.toString()));
+        }
+    }
+
+
+    private int[] downloadUsingDownloadManager(Uri uri) throws Exception {
+        DownloadManager downloadManager =
+                (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
+        removeAllDownloads(downloadManager);
+        BroadcastReceiver downloadCompleteReceiver = null;
+        try {
+            final SettableFuture<Intent> downloadCompleteIntentFuture = new SettableFuture<Intent>();
+            downloadCompleteReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    downloadCompleteIntentFuture.set(intent);
+                }
+            };
+            getContext().registerReceiver(
+                    downloadCompleteReceiver,
+                    new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
+
+            Intent downloadCompleteIntent;
+
+            long downloadId = downloadManager.enqueue(new DownloadManager.Request(uri));
+            downloadCompleteIntent = downloadCompleteIntentFuture.get(5, TimeUnit.SECONDS);
+
+            assertEquals(downloadId,
+                    downloadCompleteIntent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1));
+            Cursor c = downloadManager.query(
+                    new DownloadManager.Query().setFilterById(downloadId));
+            try {
+                if (!c.moveToNext()) {
+                    fail("Download not found");
+                    return null;
+                }
+                int status = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
+                int reason = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_REASON));
+                return new int[] {status, reason};
+            } finally {
+                c.close();
+            }
+        } finally {
+            if (downloadCompleteReceiver != null) {
+                getContext().unregisterReceiver(downloadCompleteReceiver);
+            }
+            removeAllDownloads(downloadManager);
+        }
+    }
+
+    private static void removeAllDownloads(DownloadManager downloadManager) {
+        Cursor cursor = null;
+        try {
+            DownloadManager.Query query = new DownloadManager.Query();
+            cursor = downloadManager.query(query);
+            if (cursor.getCount() == 0) {
+                return;
+            }
+            long[] removeIds = new long[cursor.getCount()];
+            int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_ID);
+            for (int i = 0; cursor.moveToNext(); i++) {
+                removeIds[i] = cursor.getLong(columnIndex);
+            }
+            assertEquals(removeIds.length, downloadManager.remove(removeIds));
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+    }
+
+    private static class SettableFuture<T> implements Future<T> {
+
+        private final Object mLock = new Object();
+        private boolean mDone;
+        private boolean mCancelled;
+        private T mValue;
+        private Throwable mException;
+
+        public void set(T value) {
+            synchronized (mLock) {
+                if (!mDone) {
+                    mValue = value;
+                    mDone = true;
+                    mLock.notifyAll();
+                }
+            }
+        }
+
+        public void setException(Throwable exception) {
+            synchronized (mLock) {
+                if (!mDone) {
+                    mException = exception;
+                    mDone = true;
+                    mLock.notifyAll();
+                }
+            }
+        }
+
+        @Override
+        public boolean cancel(boolean mayInterruptIfRunning) {
+            synchronized (mLock) {
+                if (mDone) {
+                    return false;
+                }
+                mCancelled = true;
+                mDone = true;
+                mLock.notifyAll();
+                return true;
+            }
+        }
+
+        @Override
+        public T get() throws InterruptedException, ExecutionException {
+            synchronized (mLock) {
+                while (!mDone) {
+                    mLock.wait();
+                }
+                return getValue();
+            }
+        }
+
+        @Override
+        public T get(long timeout, TimeUnit timeUnit)
+                throws InterruptedException, ExecutionException, TimeoutException {
+            synchronized (mLock) {
+                if (mDone) {
+                    return getValue();
+                }
+                long timeoutMillis = timeUnit.toMillis(timeout);
+                long deadlineTimeMillis = System.currentTimeMillis() + timeoutMillis;
+
+                while (!mDone) {
+                    long millisTillDeadline = deadlineTimeMillis - System.currentTimeMillis();
+                    if ((millisTillDeadline <= 0) || (millisTillDeadline > timeoutMillis)) {
+                        throw new TimeoutException();
+                    }
+                    mLock.wait(millisTillDeadline);
+                }
+                return getValue();
+            }
+        }
+
+        private T getValue() throws ExecutionException {
+            synchronized (mLock) {
+                if (!mDone) {
+                    throw new IllegalStateException("Not yet done");
+                }
+                if (mCancelled) {
+                    throw new CancellationException();
+                }
+                if (mException != null) {
+                    throw new ExecutionException(mException);
+                }
+                return mValue;
+            }
+        }
+
+        @Override
+        public boolean isCancelled() {
+            synchronized (mLock) {
+                return mCancelled;
+            }
+        }
+
+        @Override
+        public boolean isDone() {
+            synchronized (mLock) {
+                return mDone;
+            }
+        }
+    }
+}
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
new file mode 100644
index 0000000..0441f2b
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
+    ctstestserver \
+    org.apache.http.legacy
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src ../src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficFalseTestCases
+
+LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficFalse
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
new file mode 100644
index 0000000..49385f8
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.netsecpolicy.usescleartext.false">
+
+  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.netsecpolicy.usescleartext.false.cts"
+                   android:label="Tests for NetworkSecurityPolicy cleartext traffic policy when it is set to denied.">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-false/src/android/security/NetworkSecurityPolicyCleartextDeniedTest.java b/tests/tests/netsecpolicy/usescleartexttraffic-false/src/android/security/NetworkSecurityPolicyCleartextDeniedTest.java
new file mode 100644
index 0000000..f5d9770
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-false/src/android/security/NetworkSecurityPolicyCleartextDeniedTest.java
@@ -0,0 +1,9 @@
+package android.security;
+
+public class NetworkSecurityPolicyCleartextDeniedTest extends NetworkSecurityPolicyTestBase {
+
+    public NetworkSecurityPolicyCleartextDeniedTest() {
+        super(false // expect cleartext traffic to be blocked
+                );
+    }
+}
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
new file mode 100644
index 0000000..5a4a41d
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
+    ctstestserver \
+    org.apache.http.legacy
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src ../src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficTrueTestCases
+
+LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficTrue
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
new file mode 100644
index 0000000..be698f2
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.netsecpolicy.usescleartext.true">
+
+  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.netsecpolicy.usescleartext.true.cts"
+                   android:label="Tests for NetworkSecurityPolicy cleartext traffic policy when it is set to permitted.">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-true/src/android/security/NetworkSecurityPolicyCleartextPermittedTest.java b/tests/tests/netsecpolicy/usescleartexttraffic-true/src/android/security/NetworkSecurityPolicyCleartextPermittedTest.java
new file mode 100644
index 0000000..83c1049
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-true/src/android/security/NetworkSecurityPolicyCleartextPermittedTest.java
@@ -0,0 +1,9 @@
+package android.security;
+
+public class NetworkSecurityPolicyCleartextPermittedTest extends NetworkSecurityPolicyTestBase {
+
+    public NetworkSecurityPolicyCleartextPermittedTest() {
+        super(true // expect cleartext traffic to be permitted
+                );
+    }
+}
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
new file mode 100644
index 0000000..faa3c23
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
+    ctstestserver \
+    org.apache.http.legacy
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src ../src)
+
+LOCAL_PACKAGE_NAME := CtsNetSecPolicyUsesCleartextTrafficUnspecifiedTestCases
+
+LOCAL_INSTRUMENTATION_FOR := CtsNetSecPolicyUsesCleartextTrafficUnspecified
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
new file mode 100644
index 0000000..7bd8742
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.cts.netsecpolicy.usescleartext.unspecified">
+
+  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+  <application>
+      <uses-library android:name="android.test.runner"/>
+  </application>
+
+  <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                   android:targetPackage="android.netsecpolicy.usescleartext.unspecified.cts"
+                   android:label="Tests for NetworkSecurityPolicy cleartext traffic policy when it is not specified.">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
diff --git a/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/src/android/security/NetworkSecurityPolicyCleartextUnspecifiedTest.java b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/src/android/security/NetworkSecurityPolicyCleartextUnspecifiedTest.java
new file mode 100644
index 0000000..5690f31
--- /dev/null
+++ b/tests/tests/netsecpolicy/usescleartexttraffic-unspecified/src/android/security/NetworkSecurityPolicyCleartextUnspecifiedTest.java
@@ -0,0 +1,9 @@
+package android.security;
+
+public class NetworkSecurityPolicyCleartextUnspecifiedTest extends NetworkSecurityPolicyTestBase {
+
+    public NetworkSecurityPolicyCleartextUnspecifiedTest() {
+        super(true // expect cleartext traffic to be permitted
+                );
+    }
+}
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 9dfb86e..f4b140e 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -31,6 +31,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
         src/android/os/cts/IParcelFileDescriptorPeer.aidl \
         src/android/os/cts/IEmptyService.aidl \
+        src/android/os/cts/ISeccompIsolatedService.aidl \
         src/android/os/cts/ISecondary.aidl
 
 LOCAL_PACKAGE_NAME := CtsOsTestCases
diff --git a/tests/tests/os/AndroidManifest.xml b/tests/tests/os/AndroidManifest.xml
index f225903..deb7045 100644
--- a/tests/tests/os/AndroidManifest.xml
+++ b/tests/tests/os/AndroidManifest.xml
@@ -120,6 +120,10 @@
             </intent-filter>
         </service>
 
+        <service android:name="android.os.cts.SeccompTest$IsolatedService"
+                android:isolatedProcess="true">
+        </service>
+
         <service android:name="android.os.cts.MessengerService"
                 android:process=":messengerService">
         </service>
diff --git a/tests/tests/os/jni/Android.mk b/tests/tests/os/jni/Android.mk
index fab1ec2..24a0651 100644
--- a/tests/tests/os/jni/Android.mk
+++ b/tests/tests/os/jni/Android.mk
@@ -47,7 +47,9 @@
 endif
 
 ifeq ($(ARCH_SUPPORTS_SECCOMP),1)
-	LOCAL_SRC_FILES += seccomp-tests/tests/seccomp_bpf_tests.c
+	LOCAL_SRC_FILES += seccomp-tests/tests/seccomp_bpf_tests.c \
+			seccomp_sample_program.cpp
+
 	# This define controls the behavior of OSFeatures.needsSeccompSupport().
 	LOCAL_CFLAGS += -DARCH_SUPPORTS_SECCOMP
 endif
diff --git a/tests/tests/os/jni/android_os_cts_SeccompTest.cpp b/tests/tests/os/jni/android_os_cts_SeccompTest.cpp
index cd1543d..528696b 100644
--- a/tests/tests/os/jni/android_os_cts_SeccompTest.cpp
+++ b/tests/tests/os/jni/android_os_cts_SeccompTest.cpp
@@ -17,7 +17,15 @@
 #include <android/log.h>
 #include <jni.h>
 #include <string.h>
+#include <time.h>
 
+#if defined(ARCH_SUPPORTS_SECCOMP)
+#include <linux/filter.h>
+#include <linux/seccomp.h>
+#include <sys/syscall.h>
+#endif
+
+#include "seccomp_sample_program.h"
 #include "seccomp-tests/tests/test_harness.h"
 
 // Forward declare from seccomp_bpf_tests.c.
@@ -46,9 +54,33 @@
     return false;
 }
 
+jboolean android_security_cts_SeccompBpfTest_installTestFilter(JNIEnv*, jclass) {
+#if !defined(ARCH_SUPPORTS_SECCOMP)
+  return false;
+#else
+  struct sock_fprog prog = GetTestSeccompFilterProgram();
+
+  if (prog.len == 0)
+    return false;
+
+  int rv = syscall(__NR_seccomp, SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, &prog);
+  return rv == 0;
+#endif
+}
+
+jint android_security_cts_SeccompBpfTest_getClockBootTime(JNIEnv*, jclass) {
+  struct timespec ts;
+  int rv = clock_gettime(CLOCK_BOOTTIME, &ts);
+  return rv;
+}
+
 static JNINativeMethod methods[] = {
     { "runKernelUnitTest", "(Ljava/lang/String;)Z",
         (void*)android_security_cts_SeccompBpfTest_runKernelUnitTest },
+    { "installTestFilter", "()Z",
+        (void*)android_security_cts_SeccompBpfTest_installTestFilter },
+    { "getClockBootTime", "()I",
+        (void*)android_security_cts_SeccompBpfTest_getClockBootTime },
 };
 
 int register_android_os_cts_SeccompTest(JNIEnv* env) {
diff --git a/tests/tests/os/jni/seccomp_sample_program.cpp b/tests/tests/os/jni/seccomp_sample_program.cpp
new file mode 100644
index 0000000..e291e8a
--- /dev/null
+++ b/tests/tests/os/jni/seccomp_sample_program.cpp
@@ -0,0 +1,1458 @@
+/*
+ * Copyright (C) 2015 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 <linux/filter.h>
+
+// This file defines a sample seccomp-bpf policy. It is taken from the
+// Chromium renderer process policy applied to isolatedProcess services.
+//
+// In the future, this policy should be further restricted to just the set
+// of system calls that an isolatedProcess should be allowed to make.
+
+#if defined(__arm__)
+struct sock_filter kTestSeccompFilter[] = {
+  {0x20, 0, 0, 0x4},
+  {0x15, 1, 0, 0x40000028},
+  {0x6, 0, 0, 0x30006},
+  {0x20, 0, 0, 0x0},
+  {0x35, 0, 90, 0xab},
+  {0x35, 0, 43, 0x108},
+  {0x35, 0, 21, 0x14f},
+  {0x35, 0, 10, 0x168},
+  {0x35, 0, 5, 0x181},
+  {0x35, 0, 2, 0xf0006},
+  {0x35, 0, 58, 0xffff0},
+  {0x35, 57, 55, 0xffff1},
+  {0x35, 0, 43, 0x182},
+  {0x35, 53, 55, 0xf0001},
+  {0x35, 0, 2, 0x16f},
+  {0x35, 0, 53, 0x17e},
+  {0x35, 52, 39, 0x180},
+  {0x35, 38, 51, 0x16e},
+  {0x35, 0, 5, 0x15b},
+  {0x35, 0, 2, 0x160},
+  {0x35, 0, 35, 0x161},
+  {0x35, 45, 47, 0x165},
+  {0x35, 0, 46, 0x15c},
+  {0x35, 45, 32, 0x15d},
+  {0x35, 0, 2, 0x152},
+  {0x35, 0, 30, 0x153},
+  {0x35, 40, 42, 0x15a},
+  {0x35, 41, 39, 0x151},
+  {0x35, 0, 10, 0x121},
+  {0x35, 0, 5, 0x138},
+  {0x35, 0, 2, 0x143},
+  {0x35, 0, 24, 0x147},
+  {0x35, 23, 34, 0x148},
+  {0x35, 0, 22, 0x139},
+  {0x35, 32, 34, 0x142},
+  {0x35, 0, 2, 0x127},
+  {0x35, 0, 30, 0x12a},
+  {0x35, 31, 18, 0x135},
+  {0x35, 30, 28, 0x126},
+  {0x35, 0, 4, 0x10e},
+  {0x35, 0, 2, 0x119},
+  {0x35, 0, 14, 0x11e},
+  {0x35, 137, 26, 0x120},
+  {0x35, 23, 25, 0x118},
+  {0x35, 0, 3, 0x10b},
+  {0x35, 0, 23, 0x10c},
+  {0x35, 9, 0, 0x10d},
+  {0x5, 0, 0, 0x110},
+  {0x35, 7, 20, 0x10a},
+  {0x35, 0, 25, 0xce},
+  {0x35, 0, 12, 0xee},
+  {0x35, 0, 6, 0xf9},
+  {0x35, 0, 2, 0x100},
+  {0x35, 0, 13, 0x101},
+  {0x35, 129, 14, 0x107},
+  {0x35, 1, 0, 0xfa},
+  {0x5, 0, 0, 0x10d},
+  {0x35, 11, 9, 0xfd},
+  {0x35, 0, 2, 0xf0},
+  {0x35, 0, 148, 0xf1},
+  {0x35, 6, 8, 0xf8},
+  {0x35, 7, 0, 0xef},
+  {0x5, 0, 0, 0x106},
+  {0x35, 0, 7, 0xda},
+  {0x35, 0, 3, 0xde},
+  {0x35, 0, 3, 0xe0},
+  {0x35, 2, 0, 0xe1},
+  {0x5, 0, 0, 0x103},
+  {0x35, 1, 0, 0xdc},
+  {0x5, 0, 0, 0x102},
+  {0x35, 209, 172, 0xdd},
+  {0x35, 0, 2, 0xd2},
+  {0x35, 0, 253, 0xd3},
+  {0x35, 252, 253, 0xd4},
+  {0x35, 252, 251, 0xd1},
+  {0x35, 0, 10, 0xb9},
+  {0x35, 0, 5, 0xc1},
+  {0x35, 0, 2, 0xc7},
+  {0x35, 0, 248, 0xcb},
+  {0x35, 247, 246, 0xcd},
+  {0x35, 0, 245, 0xc5},
+  {0x35, 244, 245, 0xc6},
+  {0x35, 0, 2, 0xbb},
+  {0x35, 0, 244, 0xbf},
+  {0x35, 162, 242, 0xc0},
+  {0x35, 241, 240, 0xba},
+  {0x35, 0, 4, 0xb2},
+  {0x35, 0, 2, 0xb5},
+  {0x35, 0, 239, 0xb6},
+  {0x35, 237, 236, 0xb8},
+  {0x35, 236, 237, 0xb4},
+  {0x35, 0, 2, 0xad},
+  {0x35, 0, 234, 0xb0},
+  {0x35, 233, 234, 0xb1},
+  {0x35, 156, 232, 0xac},
+  {0x35, 0, 42, 0x52},
+  {0x35, 0, 21, 0x7e},
+  {0x35, 0, 10, 0x96},
+  {0x35, 0, 5, 0xa4},
+  {0x35, 0, 2, 0xa8},
+  {0x35, 0, 226, 0xa9},
+  {0x35, 224, 226, 0xaa},
+  {0x35, 0, 223, 0xa5},
+  {0x35, 224, 223, 0xa6},
+  {0x35, 0, 2, 0x9e},
+  {0x35, 0, 221, 0x9f},
+  {0x35, 220, 221, 0xa2},
+  {0x35, 220, 219, 0x98},
+  {0x35, 0, 5, 0x8c},
+  {0x35, 0, 2, 0x90},
+  {0x35, 0, 217, 0x91},
+  {0x35, 216, 215, 0x94},
+  {0x35, 0, 214, 0x8d},
+  {0x35, 213, 212, 0x8e},
+  {0x35, 0, 2, 0x85},
+  {0x35, 0, 210, 0x86},
+  {0x35, 209, 211, 0x8a},
+  {0x35, 210, 209, 0x7f},
+  {0x35, 0, 10, 0x64},
+  {0x35, 0, 5, 0x73},
+  {0x35, 0, 2, 0x7a},
+  {0x35, 0, 205, 0x7b},
+  {0x35, 153, 205, 0x7d},
+  {0x35, 0, 204, 0x77},
+  {0x35, 203, 202, 0x79},
+  {0x35, 0, 2, 0x6c},
+  {0x35, 0, 200, 0x6d},
+  {0x35, 199, 200, 0x72},
+  {0x35, 197, 199, 0x6a},
+  {0x35, 0, 4, 0x5b},
+  {0x35, 0, 2, 0x60},
+  {0x35, 0, 195, 0x62},
+  {0x35, 193, 195, 0x63},
+  {0x35, 192, 193, 0x5c},
+  {0x35, 0, 2, 0x54},
+  {0x35, 0, 192, 0x55},
+  {0x35, 191, 189, 0x57},
+  {0x35, 188, 190, 0x53},
+  {0x35, 0, 21, 0x2d},
+  {0x35, 0, 10, 0x3e},
+  {0x35, 0, 5, 0x46},
+  {0x35, 0, 2, 0x4f},
+  {0x35, 0, 185, 0x50},
+  {0x35, 182, 183, 0x51},
+  {0x35, 0, 181, 0x48},
+  {0x35, 181, 182, 0x4e},
+  {0x35, 0, 2, 0x41},
+  {0x35, 0, 180, 0x43},
+  {0x35, 179, 178, 0x44},
+  {0x35, 177, 176, 0x3f},
+  {0x35, 0, 5, 0x33},
+  {0x35, 0, 2, 0x38},
+  {0x35, 0, 175, 0x3c},
+  {0x35, 174, 172, 0x3d},
+  {0x35, 0, 173, 0x36},
+  {0x35, 124, 171, 0x37},
+  {0x35, 0, 2, 0x2f},
+  {0x35, 0, 169, 0x30},
+  {0x35, 168, 169, 0x31},
+  {0x35, 166, 167, 0x2e},
+  {0x35, 0, 10, 0x17},
+  {0x35, 0, 5, 0x21},
+  {0x35, 0, 2, 0x26},
+  {0x35, 0, 162, 0x29},
+  {0x35, 163, 162, 0x2b},
+  {0x35, 0, 160, 0x22},
+  {0x35, 153, 161, 0x25},
+  {0x35, 0, 2, 0x19},
+  {0x35, 0, 159, 0x1d},
+  {0x35, 158, 157, 0x1e},
+  {0x35, 156, 155, 0x18},
+  {0x35, 0, 4, 0xd},
+  {0x35, 0, 2, 0x11},
+  {0x35, 0, 154, 0x13},
+  {0x35, 153, 152, 0x15},
+  {0x35, 150, 152, 0xe},
+  {0x35, 0, 2, 0x3},
+  {0x35, 0, 149, 0x7},
+  {0x35, 147, 149, 0x8},
+  {0x35, 146, 147, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 140, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 143, 144, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 136, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 139, 0, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 132, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 135, 0, 0x6},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 128, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 131, 0, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 124, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 127, 0, 0x0},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 120, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 123, 0, 0x5},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 116, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 119, 120, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 112, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 115, 0xfffffe7f},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 108, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 110, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 103, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 105, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 98, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 100, 0, 0x4},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 93, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 95, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 88, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 90, 0, 0x9},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 83, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 85, 0, 0xa},
+  {0x6, 0, 0, 0x30005},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 77, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x15, 80, 79, 0x4},
+  {0x20, 0, 0, 0x2c},
+  {0x15, 0, 73, 0x0},
+  {0x20, 0, 0, 0x28},
+  {0x45, 77, 76, 0xfffdb7cc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 69, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 72, 0, 0x10},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 65, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 68, 0, 0xf},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 61, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 64, 0, 0x3},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 57, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 60, 0, 0x4},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 53, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 56, 0, 0x53564d41},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 49, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 52, 0, 0x29},
+  {0x6, 0, 0, 0x30004},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 44, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 48, 47, 0xfffffff8},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 40, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 43, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 36, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 39, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 32, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 35, 0, 0x2},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 28, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 31, 0, 0x6},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 24, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 27, 0, 0x7},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 20, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 23, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 16, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 19, 0, 0x0},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 12, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 15, 0, 0x406},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 8, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 0, 12, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 4, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 8, 7, 0xfff1e3fc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 1, 0, 0x0},
+  {0x6, 0, 0, 0x30003},
+  {0x20, 0, 0, 0x10},
+  {0x15, 2, 0, 0x2da4},
+  {0x6, 0, 0, 0x30002},
+  {0x6, 0, 0, 0x50001},
+  {0x6, 0, 0, 0x7fff0000},
+  {0x6, 0, 0, 0x30001},
+};
+#elif defined(__aarch64__)
+// Note: aarch64 is not required to support seccomp-bpf yet, but some Nexus
+// devices do support it. For completeness, this test BPF program is provided.
+struct sock_filter kTestSeccompFilter[] = {
+  {0x20, 0, 0, 0x4},
+  {0x15, 1, 0, 0xc00000b7},
+  {0x6, 0, 0, 0x30006},
+  {0x20, 0, 0, 0x0},
+  {0x35, 0, 51, 0x88},
+  {0x35, 0, 25, 0xba},
+  {0x35, 0, 12, 0xdf},
+  {0x35, 0, 6, 0xea},
+  {0x35, 0, 3, 0x104},
+  {0x35, 0, 1, 0x114},
+  {0x35, 86, 85, 0x116},
+  {0x35, 85, 81, 0x105},
+  {0x35, 0, 84, 0xf2},
+  {0x35, 83, 82, 0xf3},
+  {0x35, 0, 2, 0xe4},
+  {0x35, 0, 77, 0xe6},
+  {0x35, 92, 80, 0xe9},
+  {0x35, 0, 79, 0xe2},
+  {0x35, 78, 97, 0xe3},
+  {0x35, 0, 6, 0xd1},
+  {0x35, 0, 3, 0xd9},
+  {0x35, 0, 1, 0xdd},
+  {0x35, 100, 73, 0xde},
+  {0x35, 69, 73, 0xdc},
+  {0x35, 0, 68, 0xd5},
+  {0x35, 67, 71, 0xd6},
+  {0x35, 0, 2, 0xcc},
+  {0x35, 0, 69, 0xce},
+  {0x35, 68, 64, 0xd0},
+  {0x35, 0, 66, 0xc7},
+  {0x35, 65, 99, 0xc8},
+  {0x35, 0, 12, 0x9e},
+  {0x35, 0, 6, 0xa6},
+  {0x35, 0, 3, 0xa9},
+  {0x35, 0, 1, 0xac},
+  {0x35, 61, 57, 0xb3},
+  {0x35, 60, 56, 0xaa},
+  {0x35, 0, 58, 0xa7},
+  {0x35, 58, 98, 0xa8},
+  {0x35, 0, 2, 0xa1},
+  {0x35, 0, 56, 0xa3},
+  {0x35, 55, 51, 0xa4},
+  {0x35, 0, 50, 0x9f},
+  {0x35, 49, 52, 0xa0},
+  {0x35, 0, 6, 0x94},
+  {0x35, 0, 3, 0x97},
+  {0x35, 0, 1, 0x9c},
+  {0x35, 49, 45, 0x9d},
+  {0x35, 48, 47, 0x99},
+  {0x35, 0, 43, 0x95},
+  {0x35, 42, 45, 0x96},
+  {0x35, 0, 2, 0x8b},
+  {0x35, 0, 40, 0x8e},
+  {0x35, 42, 43, 0x8f},
+  {0x35, 0, 42, 0x89},
+  {0x35, 41, 37, 0x8a},
+  {0x35, 0, 25, 0x4e},
+  {0x35, 0, 12, 0x65},
+  {0x35, 0, 6, 0x80},
+  {0x35, 0, 3, 0x83},
+  {0x35, 0, 1, 0x85},
+  {0x35, 31, 35, 0x86},
+  {0x35, 30, 117, 0x84},
+  {0x35, 0, 29, 0x81},
+  {0x35, 122, 115, 0x82},
+  {0x35, 0, 2, 0x72},
+  {0x35, 0, 30, 0x7c},
+  {0x35, 29, 25, 0x7d},
+  {0x35, 0, 24, 0x66},
+  {0x35, 118, 27, 0x71},
+  {0x35, 0, 6, 0x5b},
+  {0x35, 0, 3, 0x61},
+  {0x35, 0, 1, 0x63},
+  {0x35, 23, 22, 0x64},
+  {0x35, 155, 22, 0x62},
+  {0x35, 0, 20, 0x5c},
+  {0x35, 16, 20, 0x5d},
+  {0x35, 0, 2, 0x58},
+  {0x35, 0, 17, 0x59},
+  {0x35, 13, 17, 0x5a},
+  {0x35, 0, 15, 0x4f},
+  {0x35, 15, 11, 0x51},
+  {0x35, 0, 15, 0x2c},
+  {0x35, 0, 6, 0x3b},
+  {0x35, 0, 3, 0x3e},
+  {0x35, 0, 1, 0x48},
+  {0x35, 10, 6, 0x4a},
+  {0x35, 9, 5, 0x44},
+  {0x35, 0, 4, 0x3c},
+  {0x35, 6, 7, 0x3d},
+  {0x35, 0, 3, 0x34},
+  {0x35, 0, 4, 0x38},
+  {0x35, 4, 0, 0x3a},
+  {0x5, 0, 0, 0x104},
+  {0x35, 0, 2, 0x2d},
+  {0x35, 1, 0, 0x33},
+  {0x5, 0, 0, 0x102},
+  {0x5, 0, 0, 0x102},
+  {0x35, 0, 5, 0x1d},
+  {0x35, 0, 2, 0x21},
+  {0x35, 0, 254, 0x27},
+  {0x35, 253, 254, 0x2b},
+  {0x35, 0, 251, 0x1e},
+  {0x35, 250, 252, 0x20},
+  {0x35, 0, 2, 0x14},
+  {0x35, 0, 248, 0x19},
+  {0x35, 249, 179, 0x1a},
+  {0x35, 0, 248, 0x11},
+  {0x35, 247, 246, 0x13},
+  {0x20, 0, 0, 0x24},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 235, 0xffffffff},
+  {0x20, 0, 0, 0x20},
+  {0x45, 0, 233, 0x80000000},
+  {0x20, 0, 0, 0x20},
+  {0x15, 238, 239, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 228, 0xffffffff},
+  {0x20, 0, 0, 0x20},
+  {0x45, 0, 226, 0x80000000},
+  {0x20, 0, 0, 0x20},
+  {0x45, 233, 231, 0xfffffff8},
+  {0x20, 0, 0, 0x2c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 221, 0xffffffff},
+  {0x20, 0, 0, 0x28},
+  {0x45, 0, 219, 0x80000000},
+  {0x20, 0, 0, 0x28},
+  {0x45, 226, 224, 0xfffdb7cc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 214, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 212, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 217, 219, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 207, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 205, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 210, 0, 0x10},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 200, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 198, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 203, 0, 0xf},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 193, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 191, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 196, 0, 0x3},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 186, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 184, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 189, 0, 0x4},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 179, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 177, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 182, 0, 0x53564d41},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 172, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 170, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 175, 0, 0x29},
+  {0x6, 0, 0, 0x30005},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 164, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 162, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 167, 0, 0x1393},
+  {0x6, 0, 0, 0x30004},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 156, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 154, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 159, 0, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 149, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 147, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 152, 0, 0x6},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 142, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 140, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 145, 0, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 135, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 133, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 138, 0, 0x0},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 128, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 126, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 131, 0, 0x5},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 121, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 119, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 124, 126, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 114, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 112, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 117, 0xfffffe7f},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 107, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 105, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 109, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 99, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 97, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 101, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 91, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 89, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 93, 0, 0x4},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 83, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 81, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 85, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 75, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 73, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 77, 0, 0x9},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 67, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 65, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 69, 0, 0xa},
+  {0x6, 0, 0, 0x30003},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 58, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 56, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 61, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 51, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 49, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 54, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 44, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 42, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 47, 0, 0x2},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 37, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 35, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 40, 0, 0x6},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 30, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 28, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 33, 0, 0x7},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 23, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 21, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 26, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 16, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 14, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 19, 0, 0x0},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 9, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 7, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 12, 0, 0x406},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 4, 0, 0x0},
+  {0x15, 0, 2, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 1, 0, 0x80000000},
+  {0x6, 0, 0, 0x30002},
+  {0x20, 0, 0, 0x18},
+  {0x15, 0, 6, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 4, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 2, 0, 0xffe1e3fc},
+  {0x6, 0, 0, 0x7fff0000},
+  {0x6, 0, 0, 0x50001},
+  {0x6, 0, 0, 0x30001},
+};
+#elif defined(__i386__)
+struct sock_filter kTestSeccompFilter[] = {
+  {0x20, 0, 0, 0x4},
+  {0x15, 1, 0, 0x40000003},
+  {0x6, 0, 0, 0x30007},
+  {0x20, 0, 0, 0x0},
+  {0x45, 0, 1, 0x40000000},
+  {0x6, 0, 0, 0x30006},
+  {0x35, 0, 87, 0x94},
+  {0x35, 0, 43, 0xdd},
+  {0x35, 0, 20, 0x11c},
+  {0x35, 0, 10, 0x13f},
+  {0x35, 0, 5, 0x149},
+  {0x35, 0, 2, 0x163},
+  {0x35, 0, 79, 0x164},
+  {0x35, 78, 73, 0x165},
+  {0x35, 0, 78, 0x14c},
+  {0x35, 71, 76, 0x161},
+  {0x35, 0, 2, 0x141},
+  {0x35, 0, 74, 0x144},
+  {0x35, 73, 68, 0x145},
+  {0x35, 67, 73, 0x140},
+  {0x35, 0, 4, 0x12d},
+  {0x35, 0, 2, 0x136},
+  {0x35, 0, 69, 0x137},
+  {0x35, 68, 63, 0x138},
+  {0x35, 68, 62, 0x134},
+  {0x35, 0, 2, 0x127},
+  {0x35, 0, 66, 0x128},
+  {0x35, 65, 59, 0x12c},
+  {0x35, 63, 64, 0x11d},
+  {0x35, 0, 11, 0xfe},
+  {0x35, 0, 6, 0x10a},
+  {0x35, 0, 3, 0x10e},
+  {0x35, 1, 0, 0x10f},
+  {0x5, 0, 0, 0x135},
+  {0x35, 57, 52, 0x110},
+  {0x35, 0, 56, 0x10c},
+  {0x35, 55, 50, 0x10d},
+  {0x35, 0, 2, 0x102},
+  {0x35, 0, 54, 0x103},
+  {0x35, 135, 52, 0x109},
+  {0x35, 51, 52, 0x101},
+  {0x35, 0, 4, 0xef},
+  {0x35, 0, 2, 0xf1},
+  {0x35, 0, 48, 0xfc},
+  {0x35, 42, 48, 0xfd},
+  {0x35, 153, 46, 0xf0},
+  {0x35, 0, 3, 0xe0},
+  {0x35, 0, 45, 0xe1},
+  {0x35, 0, 43, 0xee},
+  {0x5, 0, 0, 0x12a},
+  {0x35, 41, 252, 0xde},
+  {0x35, 0, 20, 0xb6},
+  {0x35, 0, 10, 0xc7},
+  {0x35, 0, 5, 0xd2},
+  {0x35, 0, 2, 0xd9},
+  {0x35, 0, 36, 0xdb},
+  {0x35, 30, 177, 0xdc},
+  {0x35, 0, 29, 0xd3},
+  {0x35, 28, 34, 0xd4},
+  {0x35, 0, 2, 0xcd},
+  {0x35, 0, 32, 0xce},
+  {0x35, 31, 25, 0xd1},
+  {0x35, 24, 30, 0xcb},
+  {0x35, 0, 4, 0xbf},
+  {0x35, 0, 2, 0xc1},
+  {0x35, 0, 21, 0xc5},
+  {0x35, 20, 26, 0xc6},
+  {0x35, 231, 25, 0xc0},
+  {0x35, 0, 2, 0xb9},
+  {0x35, 0, 17, 0xba},
+  {0x35, 21, 22, 0xbb},
+  {0x35, 21, 15, 0xb8},
+  {0x35, 0, 9, 0xa9},
+  {0x35, 0, 4, 0xb0},
+  {0x35, 0, 2, 0xb2},
+  {0x35, 0, 16, 0xb4},
+  {0x35, 15, 16, 0xb5},
+  {0x35, 15, 14, 0xb1},
+  {0x35, 0, 2, 0xab},
+  {0x35, 0, 13, 0xac},
+  {0x35, 12, 157, 0xad},
+  {0x35, 5, 10, 0xaa},
+  {0x35, 0, 5, 0xa2},
+  {0x35, 0, 2, 0xa5},
+  {0x35, 0, 8, 0xa6},
+  {0x35, 7, 6, 0xa8},
+  {0x35, 0, 6, 0xa4},
+  {0x5, 0, 0, 0x105},
+  {0x35, 0, 2, 0x98},
+  {0x35, 0, 2, 0x9e},
+  {0x35, 1, 2, 0x9f},
+  {0x35, 1, 0, 0x96},
+  {0x5, 0, 0, 0x102},
+  {0x5, 0, 0, 0x100},
+  {0x35, 0, 40, 0x4f},
+  {0x35, 0, 20, 0x6e},
+  {0x35, 0, 10, 0x7d},
+  {0x35, 0, 5, 0x8a},
+  {0x35, 0, 2, 0x8e},
+  {0x35, 0, 250, 0x90},
+  {0x35, 249, 250, 0x91},
+  {0x35, 0, 247, 0x8c},
+  {0x35, 246, 247, 0x8d},
+  {0x35, 0, 2, 0x7f},
+  {0x35, 0, 246, 0x85},
+  {0x35, 245, 243, 0x86},
+  {0x35, 243, 156, 0x7e},
+  {0x35, 0, 4, 0x76},
+  {0x35, 0, 2, 0x79},
+  {0x35, 0, 241, 0x7a},
+  {0x35, 240, 239, 0x7b},
+  {0x35, 238, 239, 0x77},
+  {0x35, 0, 2, 0x72},
+  {0x35, 0, 236, 0x73},
+  {0x35, 234, 236, 0x75},
+  {0x35, 235, 233, 0x6f},
+  {0x35, 0, 9, 0x60},
+  {0x35, 0, 4, 0x66},
+  {0x35, 0, 2, 0x6a},
+  {0x35, 0, 229, 0x6c},
+  {0x35, 230, 229, 0x6d},
+  {0x35, 229, 145, 0x67},
+  {0x35, 0, 2, 0x63},
+  {0x35, 0, 225, 0x64},
+  {0x35, 224, 226, 0x65},
+  {0x35, 225, 224, 0x62},
+  {0x35, 0, 4, 0x57},
+  {0x35, 0, 2, 0x5a},
+  {0x35, 0, 170, 0x5b},
+  {0x35, 219, 220, 0x5c},
+  {0x35, 218, 220, 0x59},
+  {0x35, 0, 2, 0x51},
+  {0x35, 0, 216, 0x52},
+  {0x35, 215, 216, 0x53},
+  {0x35, 215, 216, 0x50},
+  {0x35, 0, 20, 0x29},
+  {0x35, 0, 10, 0x38},
+  {0x35, 0, 5, 0x41},
+  {0x35, 0, 2, 0x46},
+  {0x35, 0, 209, 0x48},
+  {0x35, 209, 210, 0x4e},
+  {0x35, 0, 209, 0x43},
+  {0x35, 208, 207, 0x44},
+  {0x35, 0, 2, 0x3d},
+  {0x35, 0, 206, 0x3e},
+  {0x35, 204, 203, 0x3f},
+  {0x35, 202, 204, 0x3c},
+  {0x35, 0, 4, 0x30},
+  {0x35, 0, 2, 0x33},
+  {0x35, 0, 201, 0x36},
+  {0x35, 152, 199, 0x37},
+  {0x35, 198, 199, 0x31},
+  {0x35, 0, 2, 0x2d},
+  {0x35, 0, 196, 0x2e},
+  {0x35, 195, 194, 0x2f},
+  {0x35, 195, 194, 0x2b},
+  {0x35, 0, 9, 0x17},
+  {0x35, 0, 4, 0x1f},
+  {0x35, 0, 2, 0x22},
+  {0x35, 0, 191, 0x25},
+  {0x35, 188, 182, 0x26},
+  {0x35, 187, 189, 0x21},
+  {0x35, 0, 2, 0x19},
+  {0x35, 0, 187, 0x1d},
+  {0x35, 184, 185, 0x1e},
+  {0x35, 184, 183, 0x18},
+  {0x35, 0, 4, 0xe},
+  {0x35, 0, 2, 0x12},
+  {0x35, 0, 180, 0x13},
+  {0x35, 181, 180, 0x15},
+  {0x35, 180, 178, 0x11},
+  {0x35, 0, 2, 0x3},
+  {0x35, 0, 177, 0x8},
+  {0x35, 176, 175, 0xd},
+  {0x35, 174, 175, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 168, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 171, 0, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 164, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 167, 0, 0x6},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 160, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 163, 0, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 156, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 159, 0, 0x0},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 152, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 155, 0, 0x5},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 148, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 151, 152, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 144, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 147, 0xfffffe7f},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 140, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 142, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 135, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 137, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 130, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 132, 0, 0x4},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 125, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 127, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 120, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 122, 0, 0x9},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 115, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 117, 0, 0xa},
+  {0x6, 0, 0, 0x30005},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 109, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x15, 112, 111, 0x4},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 105, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 108, 0, 0x10},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 101, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 104, 0, 0xf},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 97, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 100, 0, 0x3},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 93, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 96, 0, 0x4},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 89, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 92, 0, 0x53564d41},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 85, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 88, 0, 0x29},
+  {0x6, 0, 0, 0x30004},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 80, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 84, 83, 0xfffffff8},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 76, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 79, 0, 0x8},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 72, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 75, 0, 0xd},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 68, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 71, 0, 0xa},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 64, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 67, 0, 0x9},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 60, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 63, 0, 0xc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 56, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 59, 0, 0xb},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 52, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 55, 0, 0x11},
+  {0x20, 0, 0, 0x14},
+  {0x15, 0, 48, 0x0},
+  {0x20, 0, 0, 0x10},
+  {0x15, 51, 50, 0x10},
+  {0x20, 0, 0, 0x2c},
+  {0x15, 0, 44, 0x0},
+  {0x20, 0, 0, 0x28},
+  {0x45, 48, 47, 0xfffdb7cc},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 40, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 43, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 36, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 39, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 32, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 35, 0, 0x2},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 28, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 31, 0, 0x6},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 24, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 27, 0, 0x7},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 20, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 23, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 16, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 19, 0, 0x0},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 12, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 15, 0, 0x406},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 0, 8, 0x0},
+  {0x20, 0, 0, 0x18},
+  {0x15, 0, 12, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 4, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 8, 7, 0xfff363fc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 1, 0, 0x0},
+  {0x6, 0, 0, 0x30003},
+  {0x20, 0, 0, 0x10},
+  {0x15, 2, 0, 0x9d0},
+  {0x6, 0, 0, 0x30002},
+  {0x6, 0, 0, 0x50001},
+  {0x6, 0, 0, 0x7fff0000},
+  {0x6, 0, 0, 0x30001},
+};
+#elif defined(__x86_64__)
+struct sock_filter kTestSeccompFilter[] = {
+  {0x20, 0, 0, 0x4},
+  {0x15, 1, 0, 0xc000003e},
+  {0x6, 0, 0, 0x30007},
+  {0x20, 0, 0, 0x0},
+  {0x45, 0, 1, 0x40000000},
+  {0x6, 0, 0, 0x30006},
+  {0x35, 0, 59, 0x7f},
+  {0x35, 0, 29, 0xe4},
+  {0x35, 0, 14, 0x111},
+  {0x35, 0, 7, 0x120},
+  {0x35, 0, 3, 0x13c},
+  {0x35, 0, 1, 0x13f},
+  {0x35, 102, 95, 0x140},
+  {0x35, 101, 94, 0x13e},
+  {0x35, 0, 1, 0x123},
+  {0x35, 99, 94, 0x126},
+  {0x35, 98, 91, 0x121},
+  {0x35, 0, 3, 0x119},
+  {0x35, 0, 1, 0x11d},
+  {0x35, 95, 88, 0x11e},
+  {0x35, 94, 89, 0x11a},
+  {0x35, 0, 86, 0x112},
+  {0x35, 85, 92, 0x118},
+  {0x35, 0, 6, 0xf8},
+  {0x35, 0, 3, 0x106},
+  {0x35, 0, 1, 0x10e},
+  {0x35, 88, 83, 0x110},
+  {0x35, 80, 82, 0x107},
+  {0x35, 0, 86, 0x101},
+  {0x35, 78, 80, 0x102},
+  {0x35, 0, 4, 0xea},
+  {0x35, 0, 1, 0xec},
+  {0x35, 77, 82, 0xf7},
+  {0x35, 74, 0, 0xeb},
+  {0x5, 0, 0, 0x12a},
+  {0x35, 0, 89, 0xe5},
+  {0x35, 73, 78, 0xe7},
+  {0x35, 0, 15, 0xac},
+  {0x35, 0, 7, 0xcb},
+  {0x35, 0, 3, 0xd9},
+  {0x35, 0, 1, 0xdc},
+  {0x35, 73, 66, 0xdd},
+  {0x35, 67, 65, 0xda},
+  {0x35, 0, 1, 0xd5},
+  {0x35, 70, 65, 0xd6},
+  {0x35, 62, 69, 0xd4},
+  {0x35, 0, 4, 0xbb},
+  {0x35, 0, 1, 0xc9},
+  {0x35, 118, 61, 0xca},
+  {0x35, 0, 65, 0xc8},
+  {0x5, 0, 0, 0x121},
+  {0x35, 0, 56, 0xae},
+  {0x35, 57, 62, 0xba},
+  {0x35, 0, 6, 0x8a},
+  {0x35, 0, 3, 0x95},
+  {0x35, 0, 1, 0x9d},
+  {0x35, 58, 166, 0x9e},
+  {0x35, 57, 52, 0x97},
+  {0x35, 0, 56, 0x8c},
+  {0x35, 55, 50, 0x8e},
+  {0x35, 0, 3, 0x83},
+  {0x35, 0, 1, 0x87},
+  {0x35, 45, 52, 0x88},
+  {0x35, 44, 46, 0x84},
+  {0x35, 0, 50, 0x80},
+  {0x35, 49, 44, 0x81},
+  {0x35, 0, 28, 0x3b},
+  {0x35, 0, 14, 0x69},
+  {0x35, 0, 7, 0x74},
+  {0x35, 0, 3, 0x79},
+  {0x35, 0, 1, 0x7c},
+  {0x35, 36, 38, 0x7e},
+  {0x35, 35, 42, 0x7a},
+  {0x35, 0, 1, 0x77},
+  {0x35, 35, 33, 0x78},
+  {0x35, 34, 32, 0x76},
+  {0x35, 0, 3, 0x6e},
+  {0x35, 0, 1, 0x71},
+  {0x35, 31, 29, 0x73},
+  {0x35, 35, 30, 0x6f},
+  {0x35, 0, 27, 0x6b},
+  {0x35, 33, 28, 0x6d},
+  {0x35, 0, 6, 0x4a},
+  {0x35, 0, 3, 0x62},
+  {0x35, 0, 1, 0x67},
+  {0x35, 24, 29, 0x68},
+  {0x35, 23, 28, 0x66},
+  {0x35, 0, 27, 0x4c},
+  {0x35, 21, 19, 0x60},
+  {0x35, 0, 3, 0x3f},
+  {0x35, 0, 1, 0x48},
+  {0x35, 18, 174, 0x49},
+  {0x35, 15, 17, 0x40},
+  {0x35, 0, 14, 0x3c},
+  {0x35, 238, 15, 0x3e},
+  {0x35, 0, 15, 0x1d},
+  {0x35, 0, 6, 0x31},
+  {0x35, 0, 3, 0x36},
+  {0x35, 0, 1, 0x39},
+  {0x35, 15, 8, 0x3a},
+  {0x35, 9, 14, 0x37},
+  {0x35, 0, 6, 0x33},
+  {0x35, 238, 12, 0x35},
+  {0x35, 0, 3, 0x27},
+  {0x35, 0, 1, 0x29},
+  {0x35, 4, 2, 0x2c},
+  {0x35, 8, 3, 0x28},
+  {0x35, 1, 0, 0x20},
+  {0x5, 0, 0, 0x105},
+  {0x35, 5, 0, 0x24},
+  {0x5, 0, 0, 0x104},
+  {0x35, 0, 7, 0xb},
+  {0x35, 0, 4, 0x15},
+  {0x35, 0, 2, 0x1a},
+  {0x35, 233, 0, 0x1c},
+  {0x5, 0, 0, 0x100},
+  {0x35, 254, 253, 0x16},
+  {0x35, 0, 253, 0x12},
+  {0x35, 252, 253, 0x13},
+  {0x35, 0, 3, 0x6},
+  {0x35, 0, 1, 0x9},
+  {0x35, 233, 240, 0xa},
+  {0x35, 248, 247, 0x7},
+  {0x35, 0, 247, 0x4},
+  {0x35, 246, 245, 0x5},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 239, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 237, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 239, 0, 0x1},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 232, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 230, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 232, 0, 0x6},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 225, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 223, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 225, 0, 0x2},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 218, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 216, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 218, 0, 0x0},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 211, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 209, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 211, 0, 0x5},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 204, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 202, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 204, 205, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 197, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 195, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 197, 0xfffffe7f},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 190, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 188, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 189, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 182, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 180, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 181, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 174, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 172, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 173, 0, 0x4},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 166, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 164, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 165, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 158, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 156, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 157, 0, 0x9},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 150, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 148, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x54, 0, 0, 0xfffffe7f},
+  {0x15, 149, 0, 0xa},
+  {0x6, 0, 0, 0x30005},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 141, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 139, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 141, 0, 0x10},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 134, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 132, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 134, 0, 0xf},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 127, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 125, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 127, 0, 0x3},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 120, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 118, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 120, 0, 0x4},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 113, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 111, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 113, 0, 0x53564d41},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 106, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 104, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 106, 0, 0x29},
+  {0x6, 0, 0, 0x30004},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 98, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 96, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 98, 0, 0x3},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 91, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 89, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 91, 0, 0x1},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 84, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 82, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 84, 0, 0x2},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 77, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 75, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 77, 0, 0x6},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 70, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 68, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 70, 0, 0x7},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 63, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 61, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 63, 0, 0x5},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 56, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 54, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 56, 0, 0x0},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 49, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 47, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 49, 0, 0x406},
+  {0x20, 0, 0, 0x1c},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 42, 0xffffffff},
+  {0x20, 0, 0, 0x18},
+  {0x45, 0, 40, 0x80000000},
+  {0x20, 0, 0, 0x18},
+  {0x15, 0, 43, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 0, 41, 0x0},
+  {0x20, 0, 0, 0x20},
+  {0x45, 39, 38, 0xffe363fc},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 31, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 29, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 31, 0, 0xa57},
+  {0x6, 0, 0, 0x30003},
+  {0x20, 0, 0, 0x14},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 23, 0xffffffff},
+  {0x20, 0, 0, 0x10},
+  {0x45, 0, 21, 0x80000000},
+  {0x20, 0, 0, 0x10},
+  {0x15, 23, 24, 0x1},
+  {0x20, 0, 0, 0x24},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 16, 0xffffffff},
+  {0x20, 0, 0, 0x20},
+  {0x45, 0, 14, 0x80000000},
+  {0x20, 0, 0, 0x20},
+  {0x15, 16, 15, 0x4},
+  {0x20, 0, 0, 0x24},
+  {0x15, 3, 0, 0x0},
+  {0x15, 0, 9, 0xffffffff},
+  {0x20, 0, 0, 0x20},
+  {0x45, 0, 7, 0x80000000},
+  {0x20, 0, 0, 0x20},
+  {0x45, 10, 9, 0xfffffff8},
+  {0x20, 0, 0, 0x2c},
+  {0x15, 4, 0, 0x0},
+  {0x15, 0, 2, 0xffffffff},
+  {0x20, 0, 0, 0x28},
+  {0x45, 1, 0, 0x80000000},
+  {0x6, 0, 0, 0x30002},
+  {0x20, 0, 0, 0x28},
+  {0x45, 2, 1, 0xfffdb7cc},
+  {0x6, 0, 0, 0x50001},
+  {0x6, 0, 0, 0x7fff0000},
+  {0x6, 0, 0, 0x30001},
+};
+#endif
+
+struct sock_fprog GetTestSeccompFilterProgram() {
+  struct sock_fprog prog = {
+    .len = sizeof(kTestSeccompFilter) / sizeof(struct sock_filter),
+    .filter = kTestSeccompFilter
+  };
+  return prog;
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java b/tests/tests/os/jni/seccomp_sample_program.h
similarity index 72%
rename from apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
rename to tests/tests/os/jni/seccomp_sample_program.h
index 4231db7..1293572 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MockTvInputSettingsActivity.java
+++ b/tests/tests/os/jni/seccomp_sample_program.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 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.
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-package com.android.cts.verifier.tv;
+#include <linux/filter.h>
 
-import android.preference.PreferenceActivity;
-
-public class MockTvInputSettingsActivity extends PreferenceActivity {
-
-}
+struct sock_fprog GetTestSeccompFilterProgram();
diff --git a/tests/tests/os/src/android/os/cts/ISeccompIsolatedService.aidl b/tests/tests/os/src/android/os/cts/ISeccompIsolatedService.aidl
new file mode 100644
index 0000000..5234eff
--- /dev/null
+++ b/tests/tests/os/src/android/os/cts/ISeccompIsolatedService.aidl
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.os.cts;
+
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+
+interface ISeccompIsolatedService {
+    boolean installFilter();
+
+    boolean createThread();
+
+    boolean getSystemInfo();
+
+    boolean writeToFile(in ParcelFileDescriptor fd);
+
+    boolean openAshmem();
+
+    boolean openDevFile();
+
+    void violatePolicy();
+}
diff --git a/tests/tests/os/src/android/os/cts/SeccompTest.java b/tests/tests/os/src/android/os/cts/SeccompTest.java
index e8de783..4c2f78f 100644
--- a/tests/tests/os/src/android/os/cts/SeccompTest.java
+++ b/tests/tests/os/src/android/os/cts/SeccompTest.java
@@ -16,9 +16,36 @@
 
 package android.os.cts;
 
-import junit.framework.TestCase;
+import android.app.Service;
+import android.content.Context;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Environment;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.MemoryFile;
+import android.os.SystemClock;
+import android.os.Build;
+import android.util.Log;
+import android.test.AndroidTestCase;
 
-public class SeccompTest extends TestCase {
+import com.google.common.util.concurrent.AbstractFuture;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.Date;
+
+public class SeccompTest extends AndroidTestCase {
+    final static String TAG = "SeccompTest";
+
     static {
         System.loadLibrary("ctsos_jni");
     }
@@ -142,7 +169,218 @@
     }
 
     /**
+     * Integration test for seccomp-bpf policy applied to an isolatedProcess=true
+     * service. This will perform various operations in an isolated process under a
+     * fairly restrictive seccomp policy.
+     */
+    public void testIsolatedServicePolicy() throws InterruptedException, ExecutionException,
+           RemoteException {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
+        final IsolatedServiceConnection peer = new IsolatedServiceConnection();
+        final Intent intent = new Intent(getContext(), IsolatedService.class);
+        assertTrue(getContext().bindService(intent, peer, Context.BIND_AUTO_CREATE));
+
+        final ISeccompIsolatedService service = peer.get();
+
+        // installFilter() must be called first, to set the seccomp policy.
+        assertTrue(service.installFilter());
+        assertTrue(service.createThread());
+        assertTrue(service.getSystemInfo());
+        doFileWriteTest(service);
+        assertTrue(service.openAshmem());
+        assertTrue(service.openDevFile());
+
+        getContext().unbindService(peer);
+    }
+
+    /**
+     * Integration test for seccomp-bpf policy with isolatedProcess, where the
+     * process then violates the policy and gets killed by the kernel.
+     */
+    public void testViolateIsolatedServicePolicy() throws InterruptedException,
+           ExecutionException, RemoteException {
+        if (!OSFeatures.needsSeccompSupport())
+            return;
+
+        final IsolatedServiceConnection peer = new IsolatedServiceConnection();
+        final Intent intent = new Intent(getContext(), IsolatedService.class);
+        assertTrue(getContext().bindService(intent, peer, Context.BIND_AUTO_CREATE));
+
+        final ISeccompIsolatedService service = peer.get();
+
+        assertTrue(service.installFilter());
+        boolean gotRemoteException = false;
+        try {
+            service.violatePolicy();
+        } catch (RemoteException e) {
+            gotRemoteException = true;
+        }
+        assertTrue(gotRemoteException);
+
+        getContext().unbindService(peer);
+    }
+
+    private void doFileWriteTest(ISeccompIsolatedService service) throws RemoteException {
+        final String fileName = "seccomp_test";
+        ParcelFileDescriptor fd = null;
+        try {
+            FileOutputStream fOut = getContext().openFileOutput(fileName, 0);
+            fd = ParcelFileDescriptor.dup(fOut.getFD());
+            fOut.close();
+        } catch (FileNotFoundException e) {
+            fail(e.getMessage());
+            return;
+        } catch (IOException e) {
+            fail(e.getMessage());
+            return;
+        }
+
+        assertTrue(service.writeToFile(fd));
+
+        try {
+            FileInputStream fIn = getContext().openFileInput(fileName);
+            assertEquals('!', fIn.read());
+            fIn.close();
+        } catch (FileNotFoundException e) {
+            fail(e.getMessage());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    class IsolatedServiceConnection extends AbstractFuture<ISeccompIsolatedService>
+            implements ServiceConnection {
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            set(ISeccompIsolatedService.Stub.asInterface(service));
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+        }
+
+        @Override
+        public ISeccompIsolatedService get() throws InterruptedException, ExecutionException {
+            try {
+                return get(10, TimeUnit.SECONDS);
+            } catch (TimeoutException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    public static class IsolatedService extends Service {
+        private final ISeccompIsolatedService.Stub mService = new ISeccompIsolatedService.Stub() {
+            public boolean installFilter() {
+                return installTestFilter();
+            }
+
+            public boolean createThread() {
+                Thread thread = new Thread(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
+                            Thread.sleep(100);
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                });
+                thread.run();
+                try {
+                    thread.join();
+                } catch (InterruptedException e) {
+                    return false;
+                }
+                return true;
+            }
+
+            public boolean getSystemInfo() {
+                long uptimeMillis = SystemClock.uptimeMillis();
+                if (uptimeMillis < 1) {
+                    Log.d(TAG, "SystemClock failed");
+                    return false;
+                }
+
+                String version = Build.VERSION.CODENAME;
+                if (version.length() == 0) {
+                    Log.d(TAG, "Build.VERSION failed");
+                    return false;
+                }
+
+                long time = (new Date()).getTime();
+                if (time < 100) {
+                    Log.d(TAG, "getTime failed");
+                    return false;
+                }
+
+                return true;
+            }
+
+            public boolean writeToFile(ParcelFileDescriptor fd) {
+                FileOutputStream fOut = new FileOutputStream(fd.getFileDescriptor());
+                try {
+                    fOut.write('!');
+                    fOut.close();
+                } catch (IOException e) {
+                    return false;
+                }
+                return true;
+            }
+
+            public boolean openAshmem() {
+                byte[] buffer = {'h', 'e', 'l', 'l', 'o'};
+                try {
+                    MemoryFile file = new MemoryFile("seccomp_isolated_test", 32);
+                    file.writeBytes(buffer, 0, 0, buffer.length);
+                    file.close();
+                    return true;
+                } catch (IOException e) {
+                    return false;
+                }
+            }
+
+            public boolean openDevFile() {
+                try {
+                    FileInputStream fIn = new FileInputStream("/dev/zero");
+                    boolean succeed = fIn.read() == 0;
+                    succeed &= fIn.read() == 0;
+                    succeed &= fIn.read() == 0;
+                    fIn.close();
+                    return succeed;
+                } catch (FileNotFoundException e) {
+                    return false;
+                } catch (IOException e) {
+                    return false;
+                }
+            }
+
+            public void violatePolicy() {
+                getClockBootTime();
+            }
+        };
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return mService;
+        }
+    }
+
+    /**
      * Runs the seccomp_bpf_unittest of the given name.
      */
     private native boolean runKernelUnitTest(final String name);
+
+    /**
+     * Installs a test seccomp-bpf filter program that.
+     */
+    private native static boolean installTestFilter();
+
+    /**
+     * Attempts to get the CLOCK_BOOTTIME, which is a violation of the
+     * policy specified by installTestFilter().
+     */
+    private native static int getClockBootTime();
 }
diff --git a/tests/tests/os/src/android/os/cts/StrictModeTest.java b/tests/tests/os/src/android/os/cts/StrictModeTest.java
index 797f91f..7ebe817 100644
--- a/tests/tests/os/src/android/os/cts/StrictModeTest.java
+++ b/tests/tests/os/src/android/os/cts/StrictModeTest.java
@@ -58,7 +58,7 @@
                 + android.os.Process.myUid();
 
         // Insecure connection should be detected
-        ((HttpURLConnection) new URL("http://android.com/").openConnection()).getResponseCode();
+        ((HttpURLConnection) new URL("http://example.com/").openConnection()).getResponseCode();
 
         // Give system enough time to finish logging
         SystemClock.sleep(5000);
@@ -76,7 +76,7 @@
                 + android.os.Process.myUid();
 
         // Secure connection should be ignored
-        ((HttpURLConnection) new URL("https://android.com/").openConnection()).getResponseCode();
+        ((HttpURLConnection) new URL("https://example.com/").openConnection()).getResponseCode();
 
         // Give system enough time to finish logging
         SystemClock.sleep(5000);
diff --git a/tests/tests/permission2/src/android/permission2/cts/ReadSocialStreamPermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/ReadSocialStreamPermissionTest.java
deleted file mode 100644
index eaf6fdf..0000000
--- a/tests/tests/permission2/src/android/permission2/cts/ReadSocialStreamPermissionTest.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.permission2.cts;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.net.Uri;
-import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.StreamItems;
-import android.test.AndroidTestCase;
-
-public class ReadSocialStreamPermissionTest extends AndroidTestCase {
-
-    private ContentResolver mResolver;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mResolver = mContext.getContentResolver();
-    }
-
-    public void testReadSocialStreamPermission_byRawContactId() throws Exception {
-        try {
-            mResolver.query(Uri.withAppendedPath(
-                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, 1337),
-                    Contacts.StreamItems.CONTENT_DIRECTORY), null, null, null, null);
-            fail("Expected a READ_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a READ_SOCIAL_STREAM exception.
-        }
-    }
-
-    public void testReadSocialStreamPermission_byContactId() throws Exception {
-        try {
-            mResolver.query(Uri.withAppendedPath(
-                    ContentUris.withAppendedId(Contacts.CONTENT_URI, 1337),
-                    Contacts.StreamItems.CONTENT_DIRECTORY), null, null, null, null);
-            fail("Expected a READ_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a READ_SOCIAL_STREAM exception.
-        }
-    }
-
-    public void testReadSocialStreamPermission_byLookUpKey() throws Exception {
-        try {
-            mResolver.query(Contacts.CONTENT_LOOKUP_URI.buildUpon()
-                    .appendPath("lookDownKey")
-                    .appendPath(Contacts.StreamItems.CONTENT_DIRECTORY)
-                    .build(), null, null, null, null);
-            fail("Expected a READ_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a READ_SOCIAL_STREAM exception.
-        }
-    }
-
-    public void testReadSocialStreamPermission_byStreamItemId() throws Exception {
-        try {
-            mResolver.query(ContentUris.withAppendedId(StreamItems.CONTENT_URI, 1337),
-                    null, null, null, null);
-            fail("Expected a READ_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a READ_SOCIAL_STREAM exception.
-        }
-    }
-}
diff --git a/tests/tests/permission2/src/android/permission2/cts/WriteSocialStreamPermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/WriteSocialStreamPermissionTest.java
deleted file mode 100644
index 262fcfa..0000000
--- a/tests/tests/permission2/src/android/permission2/cts/WriteSocialStreamPermissionTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.permission2.cts;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.net.Uri;
-import android.provider.ContactsContract.RawContacts;
-import android.provider.ContactsContract.StreamItems;
-import android.test.AndroidTestCase;
-
-public class WriteSocialStreamPermissionTest extends AndroidTestCase {
-
-    private ContentResolver mResolver;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mResolver = mContext.getContentResolver();
-    }
-
-    public void testWriteSocialStreamPermission_byContentDirectory() throws Exception {
-        try {
-            ContentValues values = new ContentValues();
-            mResolver.insert(Uri.withAppendedPath(
-                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, 1337),
-                    RawContacts.StreamItems.CONTENT_DIRECTORY), values);
-            fail("Expected a WRITE_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a WRITE_SOCIAL_STREAM exception.
-        }
-    }
-
-    public void testWriteSocialStreamPermission_byContentUri() throws Exception {
-        try {
-            ContentValues values = new ContentValues();
-            mResolver.insert(StreamItems.CONTENT_URI, values);
-            fail("Expected a WRITE_SOCIAL_STREAM exception");
-        } catch (SecurityException e) {
-            // Expect a WRITE_SOCIAL_STREAM exception.
-        }
-    }
-}
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 5f18635..b1a7130 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -37,10 +37,8 @@
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
     <uses-permission android:name="android.permission.WRITE_CALL_LOG" />
     <uses-permission android:name="android.permission.WRITE_CONTACTS" />
-    <uses-permission android:name="android.permission.WRITE_SOCIAL_STREAM" />
     <uses-permission android:name="android.permission.READ_CALL_LOG" />
     <uses-permission android:name="android.permission.READ_CONTACTS" />
-    <uses-permission android:name="android.permission.READ_SOCIAL_STREAM" />
 
     <application>
         <uses-library android:name="android.test.runner"/>
diff --git a/tests/tests/provider/src/android/provider/cts/CalendarTest.java b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
index 2f5edd0..c9e2213 100644
--- a/tests/tests/provider/src/android/provider/cts/CalendarTest.java
+++ b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
@@ -61,8 +61,8 @@
     // an arbitrary int used by some tests
     private static final int SOME_ARBITRARY_INT = 143234;
 
-    // 10 sec timeout for reminder broadcast (but shouldn't usually take this long).
-    private static final int POLLING_TIMEOUT = 10000;
+    // 15 sec timeout for reminder broadcast (but shouldn't usually take this long).
+    private static final int POLLING_TIMEOUT = 15000;
 
     // @formatter:off
     private static final String[] TIME_ZONES = new String[] {
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_QuickContactsTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_QuickContactsTest.java
new file mode 100644
index 0000000..79633e7
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_QuickContactsTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 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.provider.cts;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.Contacts;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.QuickContact;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.view.View;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class ContactsContract_QuickContactsTest extends InstrumentationTestCase {
+
+    final String EXCLUDED_MIME_TYPES[] = {"exclude1", "exclude2"};
+    final String PLAIN_MIME_TYPE = "text/plain";
+    final Uri FAKE_CONTACT_URI = ContentUris.withAppendedId(Contacts.CONTENT_URI, 0);
+
+    @UiThreadTest
+    public void testPrioritizedMimeTypeAndExcludedMimeTypes() throws InterruptedException {
+        final CountDownLatch latch = new CountDownLatch(2);
+        Context context = new ContextWrapper(getInstrumentation().getContext()) {
+            @Override
+            public void startActivity(Intent intent) {
+                testCallback(intent);
+            }
+
+            @Override
+            public void startActivityAsUser(Intent intent, UserHandle user) {
+                testCallback(intent);
+            }
+
+            @Override
+            public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
+                testCallback(intent);
+            }
+
+            private void testCallback(Intent intent) {
+                assertEquals(PLAIN_MIME_TYPE, intent.getStringExtra(
+                        QuickContact.EXTRA_PRIORITIZED_MIMETYPE));
+                String excludedMimeTypes[]
+                        = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
+                assertTrue(Arrays.equals(excludedMimeTypes, EXCLUDED_MIME_TYPES));
+                latch.countDown();
+            }
+        };
+
+        // Execute
+        ContactsContract.QuickContact.showQuickContact(context, new View(context),
+                FAKE_CONTACT_URI, EXCLUDED_MIME_TYPES, PLAIN_MIME_TYPE);
+        ContactsContract.QuickContact.showQuickContact(context, (Rect) null,
+                FAKE_CONTACT_URI, EXCLUDED_MIME_TYPES, PLAIN_MIME_TYPE);
+
+        // Verify: the start activity call sets the prioritized mimetype and excludes mimetypes.
+        // We don't know which method will be used to start the activity, so we check all options.
+        assertTrue(latch.await(1, TimeUnit.SECONDS));
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java b/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
index 8ec15fd..a52d308 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/ScriptGroupTest.java
@@ -458,7 +458,7 @@
             return;
         }
 
-        ScriptGroup group = builder.create("Summation", c.getGlobal(s.getFieldID_a()));
+        ScriptGroup group = builder.create("SummationGlobal", c.getGlobal(s.getFieldID_a()));
 
         int[] a = new int[4 * ARRAY_SIZE];
         ((Allocation)group.execute(input, input1)[0]).copyTo(a);
diff --git a/tests/tests/telecom/res/drawable/ic_phone_24dp.png b/tests/tests/telecom/res/drawable/ic_phone_24dp.png
new file mode 100644
index 0000000..b0e0205
--- /dev/null
+++ b/tests/tests/telecom/res/drawable/ic_phone_24dp.png
Binary files differ
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index fb62f26..c862cc3 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -282,7 +282,7 @@
             extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, videoState);
         }
 
-        mTelecomManager.placeCall(getTestNumber(), extras);
+        mTelecomManager.placeCall(createTestNumber(), extras);
     }
 
     /**
@@ -290,8 +290,12 @@
      * calls if multiple calls to the same number are placed within a short period of time which
      * can cause certain tests to fail.
      */
-    Uri getTestNumber() {
-        return Uri.fromParts("tel", String.valueOf(sCounter++), null);
+    Uri createTestNumber() {
+        return Uri.fromParts("tel", String.valueOf(++sCounter), null);
+    }
+
+    public static Uri getTestNumber() {
+        return Uri.fromParts("tel", String.valueOf(sCounter), null);
     }
 
     void assertNumCalls(final MockInCallService inCallService, final int numCalls) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
new file mode 100644
index 0000000..a23af17
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2015 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.telecom.cts;
+
+import static android.telecom.cts.TestUtils.*;
+
+import android.os.Bundle;
+import android.net.Uri;
+import android.telecom.Call;
+import android.telecom.Connection;
+import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
+import android.telecom.GatewayInfo;
+import android.telecom.InCallService;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.StatusHints;
+import android.telecom.TelecomManager;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Suites of tests that verifies the various Call details.
+ */
+public class CallDetailsTest extends BaseTelecomTestWithMockServices {
+
+    private MockInCallService mInCallService;
+    private Call mCall;
+    public static final int CONNECTION_CAPABILITIES =
+            Connection.CAPABILITY_HOLD | Connection.CAPABILITY_MUTE |
+            /**
+             * CAPABILITY_HIGH_DEF_AUDIO & CAPABILITY_WIFI are hidden, so
+             * hardcoding the values for now.
+             */
+            0x00008000 | 0x00010000;
+    public static final int CALL_CAPABILITIES =
+            Call.Details.CAPABILITY_HOLD | Call.Details.CAPABILITY_MUTE;
+    public static final int CALL_PROPERTIES =
+            Call.Details.PROPERTY_HIGH_DEF_AUDIO | Call.Details.PROPERTY_WIFI;
+    public static final String CALLER_DISPLAY_NAME = "CTS test";
+    public static final int CALLER_DISPLAY_NAME_PRESENTATION = TelecomManager.PRESENTATION_ALLOWED;
+
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        if (TestUtils.shouldTestTelecom(mContext)) {
+            PhoneAccount account = setupConnectionService(
+                new MockConnectionService() {
+                    @Override
+                    public Connection onCreateOutgoingConnection(
+                            PhoneAccountHandle connectionManagerPhoneAccount,
+                            ConnectionRequest request) {
+                        Connection connection = super.onCreateOutgoingConnection(
+                                connectionManagerPhoneAccount,
+                                request);
+                        // Modify the connection object created with local values.
+                        connection.setConnectionCapabilities(CONNECTION_CAPABILITIES);
+                        connection.setCallerDisplayName(
+                                CALLER_DISPLAY_NAME,
+                                CALLER_DISPLAY_NAME_PRESENTATION);
+                        Bundle extras = new Bundle();
+                        extras.putString(
+                                TelecomManager.GATEWAY_PROVIDER_PACKAGE,
+                                PACKAGE);
+                        connection.setExtras(extras);
+                        lock.release();
+                        return connection;
+                    }
+                }, FLAG_REGISTER | FLAG_ENABLE);
+
+        }
+        /** Place a call as a part of the setup before we test the various
+         *  Call details.
+         */
+        placeAndVerifyCall();
+
+        mInCallService = mInCallCallbacks.getService();
+        mCall = mInCallService.getLastCall();
+    }
+
+    /**
+     * Tests whether the getAccountHandle() getter returns the correct object.
+     */
+    public void testAccountHandle() {
+        assertThat(mCall.getDetails().getAccountHandle(), is(PhoneAccountHandle.class));
+        assertEquals(TEST_PHONE_ACCOUNT_HANDLE, mCall.getDetails().getAccountHandle());
+    }
+
+    /**
+     * Tests whether the getCallCapabilities() getter returns the correct object.
+     */
+    public void testCallCapabilities() {
+        assertThat(mCall.getDetails().getCallCapabilities(), is(Integer.class));
+        assertEquals(CALL_CAPABILITIES, mCall.getDetails().getCallCapabilities());
+    }
+
+    /**
+     * Tests whether the getCallerDisplayName() getter returns the correct object.
+     */
+    public void testCallerDisplayName() {
+        assertThat(mCall.getDetails().getCallerDisplayName(), is(String.class));
+        assertEquals(CALLER_DISPLAY_NAME, mCall.getDetails().getCallerDisplayName());
+    }
+
+    /**
+     * Tests whether the getCallerDisplayNamePresentation() getter returns the correct object.
+     */
+    public void testCallerDisplayNamePresentation() {
+        assertThat(mCall.getDetails().getCallerDisplayNamePresentation(), is(Integer.class));
+        assertEquals(CALLER_DISPLAY_NAME_PRESENTATION, mCall.getDetails().getCallerDisplayNamePresentation());
+    }
+
+    /**
+     * Tests whether the getCallProperties() getter returns the correct object.
+     */
+    public void testCallProperties() {
+        assertThat(mCall.getDetails().getCallProperties(), is(Integer.class));
+        assertEquals(CALL_PROPERTIES, mCall.getDetails().getCallProperties());
+    }
+
+    /**
+     * Tests whether the getConnectTimeMillis() getter returns the correct object.
+     */
+    public void testConnectTimeMillis() {
+        assertThat(mCall.getDetails().getConnectTimeMillis(), is(Long.class));
+    }
+
+    /**
+     * Tests whether the getDisconnectCause() getter returns the correct object.
+     */
+    public void testDisconnectCause() {
+        assertThat(mCall.getDetails().getDisconnectCause(), is(DisconnectCause.class));
+    }
+
+    /**
+     * Tests whether the getExtras() getter returns the correct object.
+     */
+    public void testExtras() {
+        assertThat(mCall.getDetails().getExtras(), is(Bundle.class));
+        assertEquals(PACKAGE, mCall.getDetails().getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
+    }
+
+    /**
+     * Tests whether the getGatewayInfo() getter returns the correct object.
+     */
+    public void testGatewayInfo() {
+        assertThat(mCall.getDetails().getGatewayInfo(), is(GatewayInfo.class));
+    }
+
+    /**
+     * Tests whether the getHandle() getter returns the correct object.
+     */
+    public void testHandle() {
+        assertThat(mCall.getDetails().getHandle(), is(Uri.class));
+        assertEquals(getTestNumber(), mCall.getDetails().getHandle());
+    }
+
+    /**
+     * Tests whether the getHandlePresentation() getter returns the correct object.
+     */
+    public void testHandlePresentation() {
+        assertThat(mCall.getDetails().getHandlePresentation(), is(Integer.class));
+        assertEquals(MockConnectionService.CONNECTION_PRESENTATION, mCall.getDetails().getHandlePresentation());
+    }
+
+    /**
+     * Tests whether the getStatusHints() getter returns the correct object.
+     */
+    public void testStatusHints() {
+        assertThat(mCall.getDetails().getStatusHints(), is(StatusHints.class));
+    }
+
+    /**
+     * Tests whether the getVideoProfile() getter returns the correct object.
+     */
+    public void testVideoProfile() {
+        assertThat(mCall.getDetails().getVideoState(), is(Integer.class));
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
new file mode 100644
index 0000000..88babef
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/DataObjectUnitTests.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2015 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.telecom.cts;
+
+import static android.telecom.cts.TestUtils.*;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.Icon;
+import android.media.ToneGenerator;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.telecom.CallAudioState;
+import android.telecom.ConnectionRequest;
+import android.telecom.DisconnectCause;
+import android.telecom.GatewayInfo;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.StatusHints;
+import android.telecom.TelecomManager;
+import android.telecom.VideoProfile;
+import android.test.InstrumentationTestCase;
+
+import com.android.cts.telecom.R;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Verifies the parcelable interface of all the telecom objects.
+ */
+public class DataObjectUnitTests extends InstrumentationTestCase {
+
+
+    /**
+     * Tests the PhoneAccount object creation and recreation from a Parcel.
+     */
+    public void testPhoneAccount() throws Exception {
+        Context context = getInstrumentation().getContext();
+        PhoneAccountHandle accountHandle = new PhoneAccountHandle(
+                new ComponentName(PACKAGE, COMPONENT),
+                ACCOUNT_ID);
+        Icon phoneIcon = Icon.createWithResource(context, R.drawable.ic_phone_24dp);
+        Uri tel = Uri.parse("tel:555-TEST");
+        PhoneAccount account = PhoneAccount.builder(
+                accountHandle, LABEL)
+                .setAddress(tel)
+                .setSubscriptionAddress(tel)
+                .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+                .setHighlightColor(Color.RED)
+                .setShortDescription(LABEL)
+                .setSupportedUriSchemes(Arrays.asList("tel"))
+                .setIcon(phoneIcon)
+                .build();
+        assertNotNull(account);
+        assertEquals(accountHandle, account.getAccountHandle());
+        assertEquals(tel, account.getAddress());
+        assertEquals(tel, account.getSubscriptionAddress());
+        assertEquals(PhoneAccount.CAPABILITY_CALL_PROVIDER, account.getCapabilities());
+        assertEquals(Color.RED, account.getHighlightColor());
+        assertEquals(LABEL, account.getShortDescription());
+        assertEquals(Arrays.asList("tel"), account.getSupportedUriSchemes());
+        assertEquals(phoneIcon.toString(), account.getIcon().toString());
+        assertEquals(0, account.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        account.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        PhoneAccount parcelAccount = PhoneAccount.CREATOR.createFromParcel(p);
+        assertNotNull(parcelAccount);
+        assertEquals(accountHandle, parcelAccount.getAccountHandle());
+        assertEquals(tel, parcelAccount.getAddress());
+        assertEquals(tel, parcelAccount.getSubscriptionAddress());
+        assertEquals(PhoneAccount.CAPABILITY_CALL_PROVIDER, parcelAccount.getCapabilities());
+        assertEquals(Color.RED, parcelAccount.getHighlightColor());
+        assertEquals(LABEL, parcelAccount.getShortDescription());
+        assertEquals(Arrays.asList("tel"), parcelAccount.getSupportedUriSchemes());
+        assertEquals(phoneIcon.toString(), parcelAccount.getIcon().toString());
+        assertEquals(0, parcelAccount.describeContents());
+        p.recycle();
+    }
+
+    /**
+     * Tests the ConnectionRequest object creation and recreation from a Parcel.
+     */
+    public void testConnectionRequest() throws Exception {
+        PhoneAccountHandle accountHandle = new PhoneAccountHandle(
+                new ComponentName(PACKAGE, COMPONENT),
+                ACCOUNT_ID);
+        Bundle extras = new Bundle();
+        extras.putString(
+                TelecomManager.GATEWAY_PROVIDER_PACKAGE,
+                PACKAGE);
+        ConnectionRequest request = new ConnectionRequest(
+                accountHandle,
+                Uri.parse("tel:555-TEST"),
+                extras,
+                VideoProfile.STATE_AUDIO_ONLY);
+        assertEquals(accountHandle, request.getAccountHandle());
+        assertEquals(Uri.parse("tel:555-TEST"), request.getAddress());
+        assertEquals(extras.getString(
+                TelecomManager.GATEWAY_PROVIDER_PACKAGE),
+                request.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
+        assertEquals(VideoProfile.STATE_AUDIO_ONLY, request.getVideoState());
+        assertEquals(0, request.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        request.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        ConnectionRequest parcelRequest = ConnectionRequest.CREATOR.createFromParcel(p);
+        assertEquals(accountHandle, parcelRequest.getAccountHandle());
+        assertEquals(Uri.parse("tel:555-TEST"), parcelRequest.getAddress());
+        assertEquals(
+                extras.getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE),
+                parcelRequest.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
+        assertEquals(VideoProfile.STATE_AUDIO_ONLY, parcelRequest.getVideoState());
+        assertEquals(0, parcelRequest.describeContents());
+        p.recycle();
+    }
+
+    /**
+     * Tests the DisconnectCause object creation and recreation from a Parcel.
+     */
+    public void testDisconnectCause() throws Exception {
+        Context context = getInstrumentation().getContext();
+        final CharSequence label = "Out of service area";
+        final CharSequence description = "Mobile network not available";
+        final String reason = "CTS Testing";
+        DisconnectCause cause = new DisconnectCause(
+                DisconnectCause.ERROR,
+                label,
+                description,
+                reason,
+                ToneGenerator.TONE_CDMA_CALLDROP_LITE);
+        assertEquals(DisconnectCause.ERROR, cause.getCode());
+        assertEquals(label, cause.getLabel());
+        assertEquals(description, cause.getDescription());
+        assertEquals(reason, cause.getReason());
+        assertEquals(ToneGenerator.TONE_CDMA_CALLDROP_LITE, cause.getTone());
+        assertEquals(0, cause.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        cause.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        DisconnectCause parcelCause = DisconnectCause.CREATOR.createFromParcel(p);
+        assertEquals(DisconnectCause.ERROR, parcelCause.getCode());
+        assertEquals(label, parcelCause.getLabel());
+        assertEquals(description, parcelCause.getDescription());
+        assertEquals(reason, parcelCause.getReason());
+        assertEquals(ToneGenerator.TONE_CDMA_CALLDROP_LITE, parcelCause.getTone());
+        assertEquals(0, parcelCause.describeContents());
+        assertEquals(cause, parcelCause);
+        p.recycle();
+    }
+
+    /**
+     * Tests the StatusHints object creation and recreation from a Parcel.
+     */
+    public void testStatusHints() throws Exception {
+        Context context = getInstrumentation().getContext();
+        final CharSequence label = "Wi-Fi call";
+        Bundle extras = new Bundle();
+        extras.putString(
+                TelecomManager.GATEWAY_PROVIDER_PACKAGE,
+                PACKAGE);
+        Icon icon = Icon.createWithResource(context, R.drawable.ic_phone_24dp);
+        StatusHints hints = new StatusHints(
+                label,
+                icon,
+                extras);
+        assertEquals(label, hints.getLabel());
+        assertEquals(icon.toString(), hints.getIcon().toString());
+        assertEquals(extras.getString(
+                TelecomManager.GATEWAY_PROVIDER_PACKAGE),
+                hints.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
+        assertEquals(0, hints.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        hints.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        StatusHints parcelHints = StatusHints.CREATOR.createFromParcel(p);
+        assertEquals(label, parcelHints.getLabel());
+        assertEquals(icon.toString(), parcelHints.getIcon().toString());
+        assertEquals(
+                extras.getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE),
+                parcelHints.getExtras().getString(TelecomManager.GATEWAY_PROVIDER_PACKAGE));
+        assertEquals(0, parcelHints.describeContents());
+        // This fails because Bundle does not have a equals implementation.
+        // assertEquals(hints, parcelHints);
+        p.recycle();
+    }
+
+    /**
+     * Tests the GatewayInfo object creation and recreation from a Parcel.
+     */
+    public void testGatewayInfo() throws Exception {
+        final CharSequence label = "Wi-Fi call";
+        Uri originalAddress = Uri.parse("http://www.google.com");
+        Uri gatewayAddress = Uri.parse("http://www.google.com");
+        GatewayInfo info = new GatewayInfo(
+                PACKAGE,
+                gatewayAddress,
+                originalAddress);
+        assertEquals(PACKAGE, info.getGatewayProviderPackageName());
+        assertEquals(gatewayAddress, info.getGatewayAddress());
+        assertEquals(originalAddress, info.getOriginalAddress());
+        assertEquals(0, info.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        info.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        GatewayInfo parcelInfo = GatewayInfo.CREATOR.createFromParcel(p);
+        assertEquals(PACKAGE, parcelInfo.getGatewayProviderPackageName());
+        assertEquals(gatewayAddress, parcelInfo.getGatewayAddress());
+        assertEquals(originalAddress, parcelInfo.getOriginalAddress());
+        assertEquals(0, parcelInfo.describeContents());
+        p.recycle();
+    }
+
+    /**
+     * Tests the CallAudioState object creation and recreation from a Parcel.
+     */
+    public void testCallAudioState() throws Exception {
+        CallAudioState audioState = new CallAudioState(
+                true,
+                CallAudioState.ROUTE_EARPIECE,
+                CallAudioState.ROUTE_WIRED_OR_EARPIECE);
+        assertEquals(true, audioState.isMuted());
+        assertEquals(CallAudioState.ROUTE_EARPIECE, audioState.getRoute());
+        assertEquals(CallAudioState.ROUTE_WIRED_OR_EARPIECE, audioState.getSupportedRouteMask());
+        assertEquals(0, audioState.describeContents());
+
+        // Create a parcel of the object and recreate the object back
+        // from the parcel.
+        Parcel p = Parcel.obtain();
+        audioState.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        CallAudioState parcelAudioState = CallAudioState.CREATOR.createFromParcel(p);
+        assertEquals(true, parcelAudioState.isMuted());
+        assertEquals(CallAudioState.ROUTE_EARPIECE, parcelAudioState.getRoute());
+        assertEquals(CallAudioState.ROUTE_WIRED_OR_EARPIECE, parcelAudioState.getSupportedRouteMask());
+        assertEquals(0, parcelAudioState.describeContents());
+        assertEquals(audioState, parcelAudioState);
+        p.recycle();
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
index acd93f7..250f197 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConnectionService.java
@@ -29,6 +29,8 @@
  * received.
  */
 public class MockConnectionService extends CtsConnectionService {
+    public static final int CONNECTION_PRESENTATION =  TelecomManager.PRESENTATION_ALLOWED;
+
     /**
      * Used to control whether the {@link MockVideoProvider} will be created when connections are
      * created.  Used by {@link VideoCallTest#testVideoCallDelayProvider()} to test scenario where
@@ -44,7 +46,7 @@
     public Connection onCreateOutgoingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
         final MockConnection connection = new MockConnection();
-        connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+        connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
         if (mCreateVideoProvider) {
             connection.createMockVideoProvider();
         } else {
@@ -61,7 +63,7 @@
     public Connection onCreateIncomingConnection(PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
         final MockConnection connection = new MockConnection();
-        connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
+        connection.setAddress(request.getAddress(), CONNECTION_PRESENTATION);
         connection.createMockVideoProvider();
         connection.setVideoState(request.getVideoState());
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
index c3890a0..e725466 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockInCallService.java
@@ -21,6 +21,7 @@
 import android.util.ArrayMap;
 
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Semaphore;
 
@@ -49,9 +50,14 @@
         }
     }
 
+    /**
+     * Note that the super implementations of the callback methods are all no-ops, but we call
+     * them anyway to make sure that the CTS coverage tool detects that we are testing them.
+     */
     private Call.Callback mCallCallback = new Call.Callback() {
         @Override
         public void onStateChanged(Call call, int state) {
+            super.onStateChanged(call, state);
             if (getCallbacks() != null) {
                 getCallbacks().onCallStateChanged(call, state);
             }
@@ -59,6 +65,7 @@
 
         @Override
         public void onVideoCallChanged(Call call, InCallService.VideoCall videoCall) {
+            super.onVideoCallChanged(call, videoCall);
             saveVideoCall(call, videoCall);
         }
     };
@@ -85,6 +92,7 @@
 
     @Override
     public void onCallAdded(Call call) {
+        super.onCallAdded(call);
         if (!mCalls.contains(call)) {
             mCalls.add(call);
             call.registerCallback(mCallCallback);
@@ -101,6 +109,7 @@
 
     @Override
     public void onCallRemoved(Call call) {
+        super.onCallRemoved(call);
         mCalls.remove(call);
         if (getCallbacks() != null) {
             getCallbacks().onCallRemoved(call, mCalls.size());
diff --git a/tests/tests/telecom2/Android.mk b/tests/tests/telecom2/Android.mk
index fa234929..71edb7b 100644
--- a/tests/tests/telecom2/Android.mk
+++ b/tests/tests/telecom2/Android.mk
@@ -29,8 +29,18 @@
 src_dirs := src \
     ../telecom/src
 
+res_dirs := res \
+    ../telecom/res
+
 LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
 
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
+
+LOCAL_AAPT_FLAGS := \
+    --auto-add-overlay \
+    --extra-packages com.android.cts.telecom \
+    --rename-manifest-package com.android.cts.telecom2 \
+
 LOCAL_SDK_VERSION := current
 
 include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/telecom2/res/.gitignore b/tests/tests/telecom2/res/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/tests/telecom2/res/.gitignore
diff --git a/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java
new file mode 100644
index 0000000..67d75c9
--- /dev/null
+++ b/tests/tests/telephony/src/android/telephony/cts/CarrierConfigManagerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 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.content.Context;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.test.AndroidTestCase;
+
+public class CarrierConfigManagerTest extends AndroidTestCase {
+    private CarrierConfigManager mConfigManager;
+    private TelephonyManager mTelephonyManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mTelephonyManager = (TelephonyManager)
+                getContext().getSystemService(Context.TELEPHONY_SERVICE);
+        mConfigManager = (CarrierConfigManager)
+                getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+    }
+
+    private boolean hasValidPhone() {
+        return mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE;
+    }
+
+    private boolean isSimCardPresent() {
+        return mTelephonyManager.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE &&
+                mTelephonyManager.getSimState() != TelephonyManager.SIM_STATE_ABSENT;
+    }
+
+    private void checkConfig(PersistableBundle config) {
+        if (!hasValidPhone()) {
+            assertNull(config);
+            return;
+        }
+        if (isSimCardPresent()) {
+            assertNotNull(config);
+        } else {
+            // Static default in CarrierConfigManager will be returned when no sim card present.
+            assertEquals(config.getBoolean(CarrierConfigManager.KEY_ADDITIONAL_CALL_SETTING_BOOL),
+                         true);
+        }
+    }
+
+    public void testGetConfig() {
+        PersistableBundle config = mConfigManager.getConfig();
+        checkConfig(config);
+    }
+
+    public void testGetConfigForSubId() {
+        PersistableBundle config =
+                mConfigManager.getConfigForSubId(SubscriptionManager.getDefaultSubId());
+        checkConfig(config);
+    }
+
+    /**
+     * Tests the CarrierConfigManager.notifyConfigChangedForSubId() API. This makes a call to
+     * notifyConfigChangedForSubId() API and expects a SecurityException since the test apk is not signed
+     * by certificate on the SIM.
+     */
+    public void testNotifyConfigChangedForSubId() {
+        try {
+            if (isSimCardPresent()) {
+                mConfigManager.notifyConfigChangedForSubId(SubscriptionManager.getDefaultSubId());
+                fail("Expected SecurityException. App doesn't have carrier privileges.");
+            }
+        } catch (SecurityException expected) {
+        }
+    }
+
+}
diff --git a/tests/tests/transition/Android.mk b/tests/tests/transition/Android.mk
new file mode 100644
index 0000000..3b48e25
--- /dev/null
+++ b/tests/tests/transition/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsTransitionTestCases
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := optional
+
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/transition/AndroidManifest.xml b/tests/tests/transition/AndroidManifest.xml
new file mode 100644
index 0000000..0ce1791
--- /dev/null
+++ b/tests/tests/transition/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.transition">
+    <uses-sdk android:minSdkVersion="11" />
+    <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <application>
+        <activity android:name="android.transition.cts.TransitionActivity"
+            android:label="TransitionActivity"/>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.transition"
+                     android:label="CTS tests for android.transition package">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+</manifest>
+
diff --git a/tests/tests/transition/res/layout/scene1.xml b/tests/tests/transition/res/layout/scene1.xml
new file mode 100644
index 0000000..4ed5b03
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene1.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#F00"
+          android:id="@+id/redSquare" />
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#0F0"
+          android:id="@+id/greenSquare"
+          android:layout_below="@+id/redSquare" />
+</RelativeLayout>
diff --git a/tests/tests/transition/res/layout/scene2.xml b/tests/tests/transition/res/layout/scene2.xml
new file mode 100644
index 0000000..2033c95
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene2.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#0F0"
+          android:id="@+id/greenSquare" />
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#F00"
+          android:id="@+id/redSquare"
+          android:layout_below="@+id/greenSquare" />
+</RelativeLayout>
diff --git a/tests/tests/transition/res/layout/scene3.xml b/tests/tests/transition/res/layout/scene3.xml
new file mode 100644
index 0000000..b0625aa
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene3.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#0F0"
+          android:id="@+id/greenSquare" />
+    <View android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#F00"
+          android:id="@+id/redSquare"
+          android:layout_toRightOf="@+id/greenSquare" />
+</RelativeLayout>
diff --git a/tests/tests/transition/res/layout/transition_main.xml b/tests/tests/transition/res/layout/transition_main.xml
new file mode 100644
index 0000000..64de7dd
--- /dev/null
+++ b/tests/tests/transition/res/layout/transition_main.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="match_parent"
+             android:layout_height="match_parent"
+             android:id="@+id/container"/>
diff --git a/tests/tests/transition/res/values/strings.xml b/tests/tests/transition/res/values/strings.xml
new file mode 100644
index 0000000..579da74
--- /dev/null
+++ b/tests/tests/transition/res/values/strings.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+<resources>
+    <string name="add_button">Add Button</string>
+</resources>
diff --git a/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
new file mode 100644
index 0000000..4bbfc2c
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/BaseTransitionTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2015 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.transition.cts;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.test.ActivityInstrumentationTestCase2;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import com.android.cts.transition.R;
+
+public class BaseTransitionTest extends ActivityInstrumentationTestCase2<TransitionActivity> {
+    protected TransitionActivity mActivity;
+    protected FrameLayout mSceneRoot;
+    public float mAnimatedValue;
+    protected ArrayList<View> mTargets = new ArrayList<>();
+    protected TestTransition mTransition;
+
+    public BaseTransitionTest() {
+        super(TransitionActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        setActivityInitialTouchMode(false);
+        mActivity = getActivity();
+        mSceneRoot = (FrameLayout) mActivity.findViewById(R.id.container);
+        mTargets.clear();
+        mTransition = new TestTransition();
+    }
+
+    protected void waitForStart() throws InterruptedException {
+        waitForStart(mTransition.listener);
+    }
+
+    protected static void waitForStart(SimpleTransitionListener listener) throws InterruptedException {
+        long endTime = System.currentTimeMillis() + 50;
+        synchronized (listener) {
+            while (!listener.started) {
+                long now = System.currentTimeMillis();
+                long waitTime = endTime - now;
+                if (waitTime <= 0) {
+                    throw new InterruptedException();
+                }
+                listener.wait(waitTime);
+            }
+        }
+    }
+
+    protected void waitForEnd(long waitMillis) throws InterruptedException {
+        waitForEnd(mTransition.listener, waitMillis);
+    }
+
+    protected static void waitForEnd(SimpleTransitionListener listener, long waitMillis)
+            throws InterruptedException {
+        long endTime = System.currentTimeMillis() + waitMillis;
+        synchronized (listener) {
+            while (!listener.ended) {
+                long now = System.currentTimeMillis();
+                long waitTime = endTime - now;
+                if (waitTime <= 0) {
+                    throw new InterruptedException();
+                }
+                listener.wait(waitTime);
+            }
+        }
+    }
+
+    protected void startTransition(final int layoutId) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Scene scene = Scene.getSceneForLayout(mSceneRoot, layoutId, mActivity);
+                TransitionManager.go(scene, mTransition);
+            }
+        });
+        waitForStart();
+    }
+
+    protected void endTransition() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.endTransitions(mSceneRoot);
+            }
+        });
+    }
+
+    public class TestTransition extends Visibility {
+        public final SimpleTransitionListener listener = new SimpleTransitionListener();
+
+        public TestTransition() {
+            addListener(listener);
+            setDuration(100);
+        }
+
+        @Override
+        public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            mTargets.add(view);
+            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 0, 1);
+        }
+
+        @Override
+        public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+                TransitionValues endValues) {
+            mTargets.add(view);
+            return ObjectAnimator.ofFloat(BaseTransitionTest.this, "mAnimatedValue", 1, 0);
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java b/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
new file mode 100644
index 0000000..4d18bbfb
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/SimpleTransitionListener.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.transition.cts;
+
+import android.transition.Transition;
+import android.transition.Transition.TransitionListener;
+
+/**
+ * Listener captures whether each of the methods is called.
+ */
+class SimpleTransitionListener implements TransitionListener {
+
+    public boolean started;
+
+    public boolean ended;
+
+    public boolean canceled;
+
+    public boolean paused;
+
+    public boolean resumed;
+
+    @Override
+    public synchronized void onTransitionStart(Transition transition) {
+        started = true;
+        notifyAll();
+    }
+
+    @Override
+    public synchronized void onTransitionEnd(Transition transition) {
+        ended = true;
+        notifyAll();
+    }
+
+    @Override
+    public synchronized void onTransitionCancel(Transition transition) {
+        canceled = true;
+        notifyAll();
+    }
+
+    @Override
+    public synchronized void onTransitionPause(Transition transition) {
+        paused = true;
+        notifyAll();
+    }
+
+    @Override
+    public synchronized void onTransitionResume(Transition transition) {
+        resumed = true;
+        notifyAll();
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionActivity.java b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
new file mode 100644
index 0000000..8236bd5
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TransitionActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 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.transition.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.Shader;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.OvalShape;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import java.util.ArrayList;
+
+import com.android.cts.transition.R;
+
+public class TransitionActivity extends Activity {
+    @Override
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+        setContentView(R.layout.transition_main);
+    }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
new file mode 100644
index 0000000..5d16b19
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2015 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.transition.cts;
+
+import com.android.cts.transition.R;
+
+import android.transition.Scene;
+import android.transition.TransitionManager;
+import android.view.View;
+import android.widget.FrameLayout;
+
+public class TransitionManagerTest extends BaseTransitionTest {
+
+    public TransitionManagerTest() {
+    }
+
+    public void testBeginDelayedTransition() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                TransitionManager.beginDelayedTransition(mSceneRoot, mTransition);
+                View view = mActivity.getLayoutInflater().inflate(R.layout.scene1, mSceneRoot,
+                        false);
+                mSceneRoot.addView(view);
+            }
+        });
+
+        waitForStart();
+        waitForEnd(150);
+        assertFalse(mTransition.listener.resumed);
+        assertFalse(mTransition.listener.paused);
+        assertFalse(mTransition.listener.canceled);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertNotNull(mActivity.findViewById(R.id.redSquare));
+                assertNotNull(mActivity.findViewById(R.id.greenSquare));
+            }
+        });
+    }
+
+    public void testGo() throws Throwable {
+        startTransition(R.layout.scene1);
+        waitForStart();
+        waitForEnd(150);
+
+        assertFalse(mTransition.listener.resumed);
+        assertFalse(mTransition.listener.paused);
+        assertFalse(mTransition.listener.canceled);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertNotNull(mActivity.findViewById(R.id.redSquare));
+                assertNotNull(mActivity.findViewById(R.id.greenSquare));
+            }
+        });
+    }
+
+    public void testSetTransition1() throws Throwable {
+        final TransitionManager transitionManager = new TransitionManager();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+                transitionManager.setTransition(scene, mTransition);
+                transitionManager.transitionTo(scene);
+            }
+        });
+
+        waitForStart();
+        waitForEnd(150);
+        assertFalse(mTransition.listener.resumed);
+        assertFalse(mTransition.listener.paused);
+        assertFalse(mTransition.listener.canceled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertNotNull(mActivity.findViewById(R.id.redSquare));
+                assertNotNull(mActivity.findViewById(R.id.greenSquare));
+                mTransition.listener.started = false;
+                mTransition.listener.ended = false;
+                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+                transitionManager.transitionTo(scene);
+            }
+        });
+        Thread.sleep(50);
+        assertFalse(mTransition.listener.started);
+        endTransition();
+    }
+
+    public void testSetTransition2() throws Throwable {
+        final TransitionManager transitionManager = new TransitionManager();
+        final Scene[] scenes = new Scene[3];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                scenes[0] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+                scenes[1] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+                scenes[2] = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, mActivity);
+                transitionManager.setTransition(scenes[0], scenes[1], mTransition);
+                transitionManager.transitionTo(scenes[0]);
+            }
+        });
+        Thread.sleep(50);
+        assertFalse(mTransition.listener.started);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                transitionManager.transitionTo(scenes[1]);
+            }
+        });
+
+        waitForStart();
+        waitForEnd(150);
+        assertFalse(mTransition.listener.resumed);
+        assertFalse(mTransition.listener.paused);
+        assertFalse(mTransition.listener.canceled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTransition.listener.started = false;
+                mTransition.listener.ended = false;
+                transitionManager.transitionTo(scenes[2]);
+            }
+        });
+        Thread.sleep(50);
+        assertFalse(mTransition.listener.started);
+        endTransition();
+    }
+
+    public void testEndTransitions() throws Throwable {
+        mTransition.setDuration(400);
+
+        startTransition(R.layout.scene1);
+        waitForStart();
+        endTransition();
+        waitForEnd(50);
+    }
+
+    public void testEndTransitionsBeforeStarted() throws Throwable {
+        mTransition.setDuration(400);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene1, mActivity);
+                TransitionManager.go(scene, mTransition);
+                TransitionManager.endTransitions(mSceneRoot);
+            }
+        });
+        Thread.sleep(50);
+        assertFalse(mTransition.listener.started);
+        assertFalse(mTransition.listener.ended);
+    }
+}
+
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
new file mode 100644
index 0000000..6ecf8a4
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 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.transition.cts;
+
+import com.android.cts.transition.R;
+
+import android.transition.AutoTransition;
+import android.transition.Scene;
+import android.transition.TransitionManager;
+
+public class TransitionTest extends BaseTransitionTest {
+
+    public TransitionTest() {
+    }
+
+    public void testAddListener() throws Throwable {
+        startTransition(R.layout.scene1);
+
+        waitForStart();
+
+        final SimpleTransitionListener listener2 = new SimpleTransitionListener();
+        mTransition.addListener(listener2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                AutoTransition autoTransition = new AutoTransition();
+                autoTransition.setDuration(100);
+                autoTransition.addListener(listener2);
+                Scene scene = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, mActivity);
+                TransitionManager.go(scene, autoTransition);
+            }
+        });
+
+        waitForStart(listener2);
+
+        assertTrue(mTransition.listener.paused);
+        assertTrue(mTransition.listener.resumed);
+        assertFalse(mTransition.listener.canceled);
+        assertTrue(mTransition.listener.ended);
+        assertTrue(mTransition.listener.started);
+
+        assertTrue(listener2.paused);
+        assertTrue(listener2.resumed);
+        assertFalse(listener2.canceled);
+        assertTrue(listener2.ended);
+        assertTrue(listener2.started);
+        endTransition();
+    }
+
+    public void testRemoveListener() throws Throwable {
+        startTransition(R.layout.scene1);
+        waitForStart();
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mTransition.removeListener(mTransition.listener);
+            }
+        });
+
+        Thread.sleep(150);
+        assertFalse(mTransition.listener.ended);
+    }
+}
+
diff --git a/tests/tests/uirendering/res/drawable-nodpi/black1.png b/tests/tests/uirendering/res/drawable-nodpi/black1.png
index 3487ced..bbfc2c1 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/black1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/black1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
index 8fd3b50..6a8a830 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/blackitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bold1.png b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
index 199cccc..cd0465b 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/bold1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/bold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
index 985635e..0819c8a 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/bolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensed1.png b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
index 6889a3a..16f03e2 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensed1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
index 9554dee..98174f0 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbold1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
index 0483355..8b017ba 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedbolditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
index 6584147..5fc1f9c 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condenseditalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
index 49d01ac..1aca9cf 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlight1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
index 6fe4a76..47ecd67 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/condensedlightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/hello1.png b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
index 7a4be5a..6c9cb58 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/hello1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/hello1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/italic1.png b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
index a5f9ef2..0afb3ae 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/italic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/italic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/light1.png b/tests/tests/uirendering/res/drawable-nodpi/light1.png
index dfa59da..6822edb 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/light1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/light1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
index 283ddc4..b49d2d6 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/lightitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/medium1.png b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
index e615186..5b187bc 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/medium1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/medium1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
index 3e15fc8..057edc0 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/mediumitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thin1.png b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
index 9637262..a780f16 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/thin1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/thin1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
index 0afbb9a..6ddb52b 100644
--- a/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
+++ b/tests/tests/uirendering/res/drawable-nodpi/thinitalic1.png
Binary files differ
diff --git a/tests/tests/uirendering/res/layout/circle_clipped_webview.xml b/tests/tests/uirendering/res/layout/circle_clipped_webview.xml
new file mode 100644
index 0000000..44b65be
--- /dev/null
+++ b/tests/tests/uirendering/res/layout/circle_clipped_webview.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+  -->
+<android.uirendering.cts.testclasses.view.CircleClipFrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/test_width"
+    android:layout_height="@dimen/test_height">
+    <WebView
+        android:id="@+id/webview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</android.uirendering.cts.testclasses.view.CircleClipFrameLayout>
diff --git a/tests/tests/uirendering/res/layout/simple_red_layout.xml b/tests/tests/uirendering/res/layout/simple_red_layout.xml
index 2af8db6..1c551d3 100644
--- a/tests/tests/uirendering/res/layout/simple_red_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_red_layout.xml
@@ -16,5 +16,4 @@
 <View xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/test_width"
     android:layout_height="@dimen/test_height"
-    android:id="@+id/test_root"
-    android:background="#f00" />
+    android:background="#f00"/>
diff --git a/tests/tests/uirendering/res/layout/test_container.xml b/tests/tests/uirendering/res/layout/test_container.xml
index 94a8eab..deff9de 100644
--- a/tests/tests/uirendering/res/layout/test_container.xml
+++ b/tests/tests/uirendering/res/layout/test_container.xml
@@ -13,12 +13,16 @@
        limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/test_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <ViewStub
-        android:id="@+id/test_content_stub"
+    <FrameLayout
         android:layout_gravity="center"
+        android:id="@+id/test_content_wrapper"
         android:layout_width="@dimen/test_width"
-        android:layout_height="@dimen/test_height"/>
+        android:layout_height="@dimen/test_height">
+        <ViewStub
+            android:id="@+id/test_content_stub"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </FrameLayout>
 </FrameLayout>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorVerifier.java
index 7f62b3e..aa91c2e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/ColorVerifier.java
@@ -15,27 +15,31 @@
  */
 package android.uirendering.cts.bitmapverifiers;
 
+import android.annotation.ColorInt;
+
 /**
  * Checks to see if a bitmap is entirely a single color
  */
 public class ColorVerifier extends PerPixelBitmapVerifier {
+    @ColorInt
     private int mColor;
 
-    public ColorVerifier(int color) {
+    public ColorVerifier(@ColorInt int color) {
         this(color, DEFAULT_THRESHOLD);
     }
 
-    public ColorVerifier(int color, int colorTolerance) {
+    public ColorVerifier(@ColorInt int color, int colorTolerance) {
         super(colorTolerance);
         mColor = color;
     }
 
-    public ColorVerifier(int color, int colorThreshold, float spatialTolerance) {
+    public ColorVerifier(@ColorInt int color, int colorThreshold, float spatialTolerance) {
         super(colorThreshold, spatialTolerance);
         mColor = color;
     }
 
     @Override
+    @ColorInt
     protected int getExpectedColor(int x, int y) {
         return mColor;
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
index d4a63de..42e8960 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/GoldenImageVerifier.java
@@ -25,8 +25,8 @@
     private int[] mGoldenBitmapArray;
 
     public GoldenImageVerifier(Bitmap goldenBitmap, BitmapComparer bitmapComparer) {
-        mGoldenBitmapArray = new int[goldenBitmap.getWidth() * goldenBitmap.getHeight()];
-        goldenBitmap.getPixels(mGoldenBitmapArray, 0, goldenBitmap.getWidth(), 0, 0,
+        mGoldenBitmapArray = new int[ActivityTestBase.TEST_WIDTH * ActivityTestBase.TEST_HEIGHT];
+        goldenBitmap.getPixels(mGoldenBitmapArray, 0, ActivityTestBase.TEST_WIDTH, 0, 0,
                 ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
         mBitmapComparer = bitmapComparer;
     }
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 2d00db5..8fe75ee 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
@@ -15,6 +15,7 @@
  */
 package android.uirendering.cts.bitmapverifiers;
 
+import android.annotation.ColorInt;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -47,6 +48,7 @@
         mSpatialTolerance = spatialTolerance;
     }
 
+    @ColorInt
     protected int getExpectedColor(int x, int y) {
         return Color.WHITE;
     }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
new file mode 100644
index 0000000..becc2f7
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2015 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.uirendering.cts.testclasses;
+
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.CanvasClient;
+
+/**
+ * Tests of state query-able from canvas at draw time.
+ *
+ * Although these tests don't verify drawing content, they still make use of ActivityTestBase's
+ * capability to test the hardware accelerated Canvas in the way that it is used by Views.
+ */
+public class CanvasStateTests extends ActivityTestBase {
+
+    @SmallTest
+    public void testClipRectReturnValues() {
+        createTest()
+                .addCanvasClient(new CanvasClient() {
+                    @Override
+                    public void draw(Canvas canvas, int width, int height) {
+                        canvas.save();
+                        boolean isNonEmpty = canvas.clipRect(0, 0, 20, 20);
+                        assertTrue("clip state should be non empty", isNonEmpty);
+
+                        isNonEmpty = canvas.clipRect(0, 40, 20, 60);
+                        assertFalse("clip state should be empty", isNonEmpty);
+                        canvas.restore();
+                    }
+                })
+                .runWithoutVerification();
+    }
+
+    @SmallTest
+    public void testClipRegionReturnValues() {
+        createTest()
+                .addCanvasClient(new CanvasClient() {
+                    @Override
+                    public void draw(Canvas canvas, int width, int height) {
+                        canvas.save();
+                        RectF clipRectF = new RectF(0, 0, 20, 20);
+
+                        assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+                        if (!canvas.isHardwareAccelerated()) {
+                            // SW canvas may not be in View space, so we offset the clipping region
+                            // so it will operate within the canvas client's window.
+                            // (Currently, this isn't necessary, since SW layer size == draw area)
+                            canvas.getMatrix().mapRect(clipRectF);
+                        }
+
+                        Region rectRegion = new Region();
+                        rectRegion.set((int) clipRectF.left, (int) clipRectF.top,
+                                (int) clipRectF.right, (int) clipRectF.bottom);
+
+                        boolean isNonEmpty = canvas.clipRegion(rectRegion);
+                        assertTrue("clip state should be non empty", isNonEmpty);
+
+                        // Note: we don't test that non-intersecting clip regions empty the clip,
+                        // For region clipping, the impl is allowed to return true conservatively
+                        // in many cases.
+                        canvas.restore();
+                    }
+                })
+                .runWithoutVerification();
+    }
+
+    @SmallTest
+    public void testClipPathReturnValues() {
+        createTest()
+                .addCanvasClient(new CanvasClient() {
+                    @Override
+                    public void draw(Canvas canvas, int width, int height) {
+                        canvas.save();
+                        Path rectPath = new Path();
+                        rectPath.addRect(0, 0, 20, 20, Path.Direction.CW);
+
+                        boolean isNonEmpty = canvas.clipPath(rectPath);
+                        assertTrue("clip state should be non empty", isNonEmpty);
+
+                        rectPath.offset(0, 40);
+                        isNonEmpty = canvas.clipPath(rectPath);
+                        assertFalse("clip state should be empty", isNonEmpty);
+                        canvas.restore();
+                    }
+                })
+                .runWithoutVerification();
+    }
+    @SmallTest
+    public void testQuickReject() {
+        createTest()
+                .addCanvasClient(new CanvasClient() {
+                    @Override
+                    public void draw(Canvas canvas, int width, int height) {
+                        canvas.save();
+                        canvas.clipRect(0, 0, 20, 20);
+
+                        // not rejected!
+                        assertFalse(canvas.quickReject(0, 0, 20, 20, Canvas.EdgeType.BW));
+
+                        // rejected!
+                        assertTrue(canvas.quickReject(0, 40, 20, 60, Canvas.EdgeType.BW));
+                        canvas.restore();
+                    }
+                })
+                .runWithoutVerification();
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index e7ed7ac..5833f20 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -32,17 +32,24 @@
 import com.android.cts.uirendering.R;
 
 public class FontRenderingTests extends ActivityTestBase {
-    // Threshold is barely loose enough for differences between sw and hw renderers
-    static double MSSIM_THRESHOLD = 0.91;
-
-    private final BitmapComparer mFuzzyComparer = new MSSIMComparer(MSSIM_THRESHOLD);
+    // Thresholds are barely loose enough for differences between sw and hw renderers.
+    private static final double REGULAR_THRESHOLD = 0.92;
+    private static final double THIN_THRESHOLD = 0.87;
 
     // Representative characters including some from Unicode 7
-    private final String mTestString1 = "Hamburg \u20bd";
-    private final String mTestString2 = "\u20b9\u0186\u0254\u1e24\u1e43";
+    private static final String sTestString1 = "Hambu";
+    private static final String sTestString2 = "rg \u20bd";
+    private static final String sTestString3 = "\u20b9\u0186\u0254\u1e24\u1e43";
 
-    private void fontTestBody(final Typeface typeface, int id) {
+    private void fontTestBody(String family, int style, int id) {
         Bitmap goldenBitmap = BitmapFactory.decodeResource(getActivity().getResources(), id);
+
+        // adjust threshold based on thinness - more variance is expected in thin cases
+        boolean thinTestCase = family.endsWith("-thin") && ((style & Typeface.BOLD) == 0);
+        BitmapComparer comparer = new MSSIMComparer(
+                thinTestCase ? THIN_THRESHOLD : REGULAR_THRESHOLD);
+
+        final Typeface typeface = Typeface.create(family, style);
         createTest()
                 .addCanvasClient(new CanvasClient() {
                     @Override
@@ -50,174 +57,201 @@
                         Paint p = new Paint();
                         p.setAntiAlias(true);
                         p.setColor(Color.BLACK);
-                        p.setTextSize(30);
+                        p.setTextSize(26);
                         p.setTypeface(typeface);
-                        canvas.drawText(mTestString1, 10, 60, p);
-                        canvas.drawText(mTestString2, 10, 100, p);
+                        canvas.drawText(sTestString1, 1, 20, p);
+                        canvas.drawText(sTestString2, 1, 50, p);
+                        canvas.drawText(sTestString3, 1, 80, p);
                     }
                 })
-                .runWithVerifier(new GoldenImageVerifier(goldenBitmap, mFuzzyComparer));
+                .runWithVerifier(new GoldenImageVerifier(goldenBitmap, comparer));
     }
 
     @SmallTest
     public void testDefaultFont() {
-        Typeface tf = Typeface.create("sans-serif", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.hello1);
+        fontTestBody("sans-serif",
+                Typeface.NORMAL,
+                R.drawable.hello1);
     }
 
     @SmallTest
     public void testBoldFont() {
-        Typeface tf = Typeface.create("sans-serif", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.bold1);
+        fontTestBody("sans-serif",
+                Typeface.BOLD,
+                R.drawable.bold1);
     }
 
     @SmallTest
     public void testItalicFont() {
-        Typeface tf = Typeface.create("sans-serif", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.italic1);
+        fontTestBody("sans-serif",
+                Typeface.ITALIC,
+                R.drawable.italic1);
     }
 
     @SmallTest
     public void testBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.bolditalic1);
+        fontTestBody("sans-serif",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.bolditalic1);
     }
 
     @SmallTest
     public void testMediumFont() {
-        Typeface tf = Typeface.create("sans-serif-medium", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.medium1);
+        fontTestBody("sans-serif-medium",
+                Typeface.NORMAL,
+                R.drawable.medium1);
     }
 
     @SmallTest
     public void testMediumBoldFont() {
         // bold attribute on medium base font = black
-        Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.black1);
+        fontTestBody("sans-serif-medium",
+                Typeface.BOLD,
+                R.drawable.black1);
     }
 
     @SmallTest
     public void testMediumItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-medium", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.mediumitalic1);
+        fontTestBody("sans-serif-medium",
+                Typeface.ITALIC,
+                R.drawable.mediumitalic1);
     }
 
     @SmallTest
     public void testMediumBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-medium", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.blackitalic1);
+        fontTestBody("sans-serif-medium",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.blackitalic1);
     }
 
     @SmallTest
     public void testLightFont() {
-        Typeface tf = Typeface.create("sans-serif-light", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.light1);
+        fontTestBody("sans-serif-light",
+                Typeface.NORMAL,
+                R.drawable.light1);
     }
 
     @SmallTest
     public void testLightBoldFont() {
         // bold attribute on light base font = medium
-        Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.medium1);
+        fontTestBody("sans-serif-light",
+                Typeface.BOLD,
+                R.drawable.medium1);
     }
 
     @SmallTest
     public void testLightItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-light", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.lightitalic1);
+        fontTestBody("sans-serif-light",
+                Typeface.ITALIC,
+                R.drawable.lightitalic1);
     }
 
     @SmallTest
     public void testLightBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-light", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.mediumitalic1);
+        fontTestBody("sans-serif-light",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.mediumitalic1);
     }
 
     @SmallTest
     public void testThinFont() {
-        Typeface tf = Typeface.create("sans-serif-thin", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.thin1);
+        fontTestBody("sans-serif-thin",
+                Typeface.NORMAL,
+                R.drawable.thin1);
     }
 
     @SmallTest
     public void testThinBoldFont() {
         // bold attribute on thin base font = normal
-        Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.hello1);
+        fontTestBody("sans-serif-thin",
+                Typeface.BOLD,
+                R.drawable.hello1);
     }
 
     @SmallTest
     public void testThinItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-thin", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.thinitalic1);
+        fontTestBody("sans-serif-thin",
+                Typeface.ITALIC,
+                R.drawable.thinitalic1);
     }
 
     @SmallTest
     public void testThinBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-thin", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.italic1);
+        fontTestBody("sans-serif-thin",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.italic1);
     }
 
     @SmallTest
     public void testBlackFont() {
-        Typeface tf = Typeface.create("sans-serif-black", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.black1);
+        fontTestBody("sans-serif-black",
+                Typeface.NORMAL,
+                R.drawable.black1);
     }
 
     @SmallTest
     public void testBlackBoldFont() {
         // bold attribute on black base font = black
-        Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.black1);
+        fontTestBody("sans-serif-black",
+                Typeface.BOLD,
+                R.drawable.black1);
     }
 
     @SmallTest
     public void testBlackItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-black", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.blackitalic1);
+        fontTestBody("sans-serif-black",
+                Typeface.ITALIC,
+                R.drawable.blackitalic1);
     }
 
     @SmallTest
     public void testBlackBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-black", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.blackitalic1);
+        fontTestBody("sans-serif-black",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.blackitalic1);
     }
 
     /* condensed fonts */
 
     @SmallTest
     public void testCondensedFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.condensed1);
+        fontTestBody("sans-serif-condensed",
+                Typeface.NORMAL,
+                R.drawable.condensed1);
     }
 
     @SmallTest
     public void testCondensedBoldFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD);
-        fontTestBody(tf, R.drawable.condensedbold1);
+        fontTestBody("sans-serif-condensed",
+                Typeface.BOLD,
+                R.drawable.condensedbold1);
     }
 
     @SmallTest
     public void testCondensedItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.condenseditalic1);
+        fontTestBody("sans-serif-condensed",
+                Typeface.ITALIC,
+                R.drawable.condenseditalic1);
     }
 
     @SmallTest
     public void testCondensedBoldItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed", Typeface.BOLD | Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.condensedbolditalic1);
+        fontTestBody("sans-serif-condensed",
+                Typeface.BOLD | Typeface.ITALIC,
+                R.drawable.condensedbolditalic1);
     }
 
     @SmallTest
     public void testCondensedLightFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.NORMAL);
-        fontTestBody(tf, R.drawable.condensedlight1);
+        fontTestBody("sans-serif-condensed-light",
+                Typeface.NORMAL,
+                R.drawable.condensedlight1);
     }
 
     @SmallTest
     public void testCondensedLightItalicFont() {
-        Typeface tf = Typeface.create("sans-serif-condensed-light", Typeface.ITALIC);
-        fontTestBody(tf, R.drawable.condensedlightitalic1);
+        fontTestBody("sans-serif-condensed-light",
+                Typeface.ITALIC,
+                R.drawable.condensedlightitalic1);
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index c86ff76..dfaaaea 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -75,7 +75,7 @@
         final Rect clipRect = new Rect(0, 0, 50, 50);
         ViewInitializer viewInitializer = new ViewInitializer() {
             @Override
-            public void intializeView(View view) {
+            public void initializeView(View view) {
                 view.setClipBounds(clipRect);
             }
         };
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
new file mode 100644
index 0000000..a5f76dd
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 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.uirendering.cts.testclasses;
+
+import android.annotation.ColorInt;
+import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
+import android.uirendering.cts.testinfrastructure.ActivityTestBase;
+import android.uirendering.cts.testinfrastructure.ViewInitializer;
+import android.view.View;
+import com.android.cts.uirendering.R;
+
+public class LayerTests extends ActivityTestBase {
+    @SmallTest
+    public void testLayerPaintAlpha() {
+        // red channel full strength, other channels 75% strength
+        // (since 25% alpha red subtracts from them)
+        @ColorInt
+        final int expectedColor = Color.rgb(255, 191, 191);
+        createTest()
+                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
+                    @Override
+                    public void initializeView(View view) {
+                        // reduce alpha by 50%
+                        Paint paint = new Paint();
+                        paint.setAlpha(128);
+                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+
+                        // reduce alpha by another 50% (ensuring two alphas combine correctly)
+                        view.setAlpha(0.5f);
+                    }
+                })
+                .runWithVerifier(new ColorVerifier(expectedColor));
+    }
+
+    @SmallTest
+    public void testLayerPaintColorFilter() {
+        // Red, fully desaturated. Note that it's not 255/3 in each channel.
+        // See ColorMatrix#setSaturation()
+        @ColorInt
+        final int expectedColor = Color.rgb(54, 54, 54);
+        createTest()
+                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
+                    @Override
+                    public void initializeView(View view) {
+                        Paint paint = new Paint();
+                        ColorMatrix desatMatrix = new ColorMatrix();
+                        desatMatrix.setSaturation(0.0f);
+                        paint.setColorFilter(new ColorMatrixColorFilter(desatMatrix));
+                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+                    }
+                })
+                .runWithVerifier(new ColorVerifier(expectedColor));
+    }
+
+    @SmallTest
+    public void testLayerPaintBlend() {
+        // Red, drawn underneath opaque white, so output should be white.
+        // TODO: consider doing more interesting blending test here
+        @ColorInt
+        final int expectedColor = Color.WHITE;
+        createTest()
+                .addLayout(R.layout.simple_red_layout, new ViewInitializer() {
+                    @Override
+                    public void initializeView(View view) {
+                        Paint paint = new Paint();
+                        /* Note that when drawing in SW, we're blending within an otherwise empty
+                         * SW layer, as opposed to in the frame buffer (which has a white
+                         * background).
+                         *
+                         * For this reason we use just use DST, which just throws out the SRC
+                         * content, regardless of the DST alpha channel.
+                         */
+                        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST));
+                        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+                    }
+                })
+                .runWithVerifier(new ColorVerifier(expectedColor));
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 6911cf0..2726dac 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 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.uirendering.cts.testclasses;
 
 import android.graphics.Canvas;
@@ -14,14 +30,15 @@
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 import android.view.View;
 import android.view.ViewGroup;
+import android.webkit.WebView;
 import com.android.cts.uirendering.R;
 
 public class PathClippingTests extends ActivityTestBase {
     // draw circle with hole in it, with stroked circle
-    static final CanvasClient sCircleDrawCanvasClient = new CanvasClient() {
+    static final CanvasClient sTorusDrawCanvasClient = new CanvasClient() {
         @Override
         public String getDebugString() {
-            return "StrokedCircleDraw";
+            return "TorusDraw";
         }
 
         @Override
@@ -36,10 +53,10 @@
     };
 
     // draw circle with hole in it, by path operations + path clipping
-    static final CanvasClient sCircleClipCanvasClient = new CanvasClient() {
+    static final CanvasClient sTorusClipCanvasClient = new CanvasClient() {
         @Override
         public String getDebugString() {
-            return "CircleClipDraw";
+            return "TorusClipDraw";
         }
 
         @Override
@@ -60,15 +77,15 @@
     @SmallTest
     public void testCircleWithCircle() {
         createTest()
-                .addCanvasClient(sCircleDrawCanvasClient, false)
-                .addCanvasClient(sCircleClipCanvasClient)
+                .addCanvasClient(sTorusDrawCanvasClient, false)
+                .addCanvasClient(sTorusClipCanvasClient)
                 .runWithComparer(new MSSIMComparer(0.90));
     }
 
     @SmallTest
     public void testCircleWithPoints() {
         createTest()
-                .addCanvasClient(sCircleClipCanvasClient)
+                .addCanvasClient(sTorusClipCanvasClient)
                 .runWithVerifier(new SamplePointVerifier(
                         new Point[] {
                                 // inside of circle
@@ -92,7 +109,7 @@
         createTest()
                 .addLayout(R.layout.blue_padded_layout, new ViewInitializer() {
                     @Override
-                    public void intializeView(View view) {
+                    public void initializeView(View view) {
                         ViewGroup rootView = (ViewGroup) view;
                         rootView.setClipChildren(true);
                         View childView = rootView.getChildAt(0);
@@ -143,4 +160,29 @@
                 })
                 .runWithComparer(new MSSIMComparer(0.90));
     }
+
+    @SmallTest
+    public void testWebViewClipWithCircle() {
+        createTest()
+                // golden client - draw a simple non-AA circle
+                .addCanvasClient(new CanvasClient() {
+                    @Override
+                    public void draw(Canvas canvas, int width, int height) {
+                        Paint paint = new Paint();
+                        paint.setAntiAlias(false);
+                        paint.setColor(Color.BLUE);
+                        canvas.drawOval(0, 0, width, height, paint);
+                    }
+                }, false)
+                // verify against solid color webview, clipped to its parent oval
+                .addLayout(R.layout.circle_clipped_webview, new ViewInitializer() {
+                    @Override
+                    public void initializeView(View view) {
+                        WebView webview = (WebView)view.findViewById(R.id.webview);
+                        assertNotNull(webview);
+                        webview.loadData("<body style=\"background-color:blue\">", null, null);
+                    }
+                })
+                .runWithComparer(new MSSIMComparer(0.95));
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index 32ab0e4..71b4f3f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -345,17 +345,6 @@
                 null, bitmapVerifiers);
     }
 
-    /*
-    @SmallTest
-    public void testShaderSweeps() {
-        int mask = DisplayModifier.Accessor.AA_MASK
-                | DisplayModifier.Accessor.SHADER_MASK
-                | DisplayModifier.Accessor.XFERMODE_MASK
-                | DisplayModifier.Accessor.SHAPES_MASK;
-        sweepModifiersForMask(mask, null, DEFAULT_MSSIM_COMPARER, null);
-    }
-    */
-
     protected void sweepModifiersForMask(int mask, final DisplayModifier drawOp,
             BitmapComparer[] bitmapComparers, BitmapVerifier[] bitmapVerifiers) {
         if ((mask & DisplayModifier.Accessor.ALL_OPTIONS_MASK) == 0) {
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 343228f..f1f7c99 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -28,13 +28,13 @@
 
     final ViewInitializer BOUNDS_CLIP_INIT = new ViewInitializer() {
         @Override
-        public void intializeView(View rootView) {
+        public void initializeView(View rootView) {
             ((ViewGroup)rootView).setClipChildren(true);
         }
     };
     final ViewInitializer PADDING_CLIP_INIT = new ViewInitializer() {
         @Override
-        public void intializeView(View rootView) {
+        public void initializeView(View rootView) {
             ViewGroup child = (ViewGroup) rootView.findViewById(R.id.child);
             child.setClipToPadding(true);
             child.setWillNotDraw(true);
@@ -43,7 +43,7 @@
     };
     final ViewInitializer OUTLINE_CLIP_INIT = new ViewInitializer() {
         @Override
-        public void intializeView(View rootView) {
+        public void initializeView(View rootView) {
             View child = rootView.findViewById(R.id.child);
             child.setOutlineProvider(new ViewOutlineProvider() {
                 @Override
@@ -56,7 +56,7 @@
     };
     final ViewInitializer CLIP_BOUNDS_CLIP_INIT = new ViewInitializer() {
         @Override
-        public void intializeView(View view) {
+        public void initializeView(View view) {
             view.setClipBounds(CLIP_BOUNDS_RECT);
         }
     };
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/CircleClipFrameLayout.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/CircleClipFrameLayout.java
new file mode 100644
index 0000000..4329c60
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/CircleClipFrameLayout.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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.uirendering.cts.testclasses.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+public class CircleClipFrameLayout extends FrameLayout {
+    final Path mClipPath = new Path();
+    public CircleClipFrameLayout(Context context) {
+        this(context, null);
+    }
+
+    public CircleClipFrameLayout(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CircleClipFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public CircleClipFrameLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        canvas.save();
+
+        mClipPath.reset();
+        mClipPath.addOval(0, 0, getWidth(), getHeight(), Path.Direction.CW);
+        canvas.clipPath(mClipPath);
+        super.dispatchDraw(canvas);
+
+        canvas.restore();
+    }
+}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
index b8935fb..900e14d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/view/UnclippedBlueView.java
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2015 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.uirendering.cts.testclasses.view;
 
 import android.content.Context;
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 8c5f245..526f4f9 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -263,6 +263,20 @@
             }
         }
 
+        /**
+         * Runs a test where each testcase is run without verification. Should only be used
+         * where custom CanvasClients, Views, or ViewInitializers do their own internal
+         * test assertions.
+         */
+        public void runWithoutVerification() {
+            runWithVerifier(new BitmapVerifier() {
+                @Override
+                public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
+                    return true;
+                }
+            });
+        }
+
         public TestCaseBuilder addWebView(String webViewUrl,
                 @Nullable ViewInitializer viewInitializer) {
             return addWebView(webViewUrl, viewInitializer, false)
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DisplayModifier.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DisplayModifier.java
index b42ac88..99a9ef6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DisplayModifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DisplayModifier.java
@@ -519,14 +519,17 @@
             for (Map.Entry<String, LinkedHashMap<String, DisplayModifier>> entry :
                     mDisplayMap.entrySet()) {
                 int displayModifierIndex = mIndices[mapIndex];
-                mDebugString += "Modification : " + entry.getKey();
+                if (!mDebugString.isEmpty()) {
+                    mDebugString += ", ";
+                }
+                mDebugString += entry.getKey();
                 // Loop until we find the modification we are going to use
                 for (Map.Entry<String, DisplayModifier> modifierEntry :
                         entry.getValue().entrySet()) {
                     // Once we find the modification we want, then we will add it to the list,
                     // and the last applied modifications
                     if (displayModifierIndex == 0) {
-                        mDebugString += " value : " + modifierEntry.getKey() + " ";
+                        mDebugString += ": " + modifierEntry.getKey();
                         modifierArrayList.add(modifierEntry.getValue());
                         break;
                     }
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 041fcdd..d585f5f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -39,6 +39,7 @@
 
     private Handler mHandler;
     private View mView;
+    private View mViewWrapper;
     private boolean mOnTv;
 
     public void onCreate(Bundle bundle){
@@ -93,6 +94,7 @@
             int drawCountDelay = 0;
             setContentView(R.layout.test_container);
             ViewStub stub = (ViewStub) findViewById(R.id.test_content_stub);
+            mViewWrapper = findViewById(R.id.test_content_wrapper);
             switch (message.what) {
                 case LAYOUT_MSG: {
                     stub.setLayoutResource(message.arg1);
@@ -119,9 +121,12 @@
             }
 
             if (mViewInitializer != null) {
-                mViewInitializer.intializeView(mView);
+                mViewInitializer.initializeView(mView);
             }
-            mView.setLayerType(message.arg2, null);
+
+            // set layer on wrapper parent of view, so view initializer
+            // can control layer type of View under test.
+            mViewWrapper.setLayerType(message.arg2, null);
 
             DrawCounterListener onDrawListener = new DrawCounterListener(drawCountDelay);
 
@@ -147,7 +152,7 @@
                 mView.postInvalidate();
             } else {
                 synchronized (mLock) {
-                    mLock.set(mView.getLeft(), mView.getTop());
+                    mLock.set(mViewWrapper.getLeft(), mViewWrapper.getTop());
                     mLock.notify();
                 }
                 mView.getViewTreeObserver().removeOnPreDrawListener(this);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
index 8980df3..9a3cbb1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ViewInitializer.java
@@ -21,5 +21,5 @@
  * Called after a view is created to set various properties on the view
  */
 public abstract class ViewInitializer {
-    public abstract void intializeView(View view);
+    public abstract void initializeView(View view);
 }
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index e6e1550..b501a4d 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -21,7 +21,8 @@
     android:id="@+id/viewlayout_root"
     android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:scrollIndicators="left|right">
 
     <android.view.cts.MockView
         android:id="@+id/mock_view"
diff --git a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
index c40f095..012a13d 100644
--- a/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
+++ b/tests/tests/view/src/android/view/cts/ContextThemeWrapperTest.java
@@ -43,11 +43,11 @@
     }
 
     public void testConstructor() {
-        // new the ContextThemeWrapper instance
         new ContextThemeWrapper();
 
-        // new the ContextThemeWrapper instance
         new ContextThemeWrapper(getContext(), R.style.TextAppearance);
+
+        new ContextThemeWrapper(getContext(), getContext().getTheme());
     }
 
     public void testAccessTheme() {
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 34e4d09..fe3bd60 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -250,6 +250,31 @@
         assertSame(parent, view.getParent());
     }
 
+    public void testAccessScrollIndicators() {
+        View view = mActivity.findViewById(R.id.viewlayout_root);
+
+        assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT,
+                view.getScrollIndicators());
+    }
+
+    public void testSetScrollIndicators() {
+        View view = new View(mActivity);
+
+        view.setScrollIndicators(0);
+        assertEquals(0, view.getScrollIndicators());
+
+        view.setScrollIndicators(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT);
+        assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT,
+                view.getScrollIndicators());
+
+        view.setScrollIndicators(View.SCROLL_INDICATOR_TOP, View.SCROLL_INDICATOR_TOP);
+        assertEquals(View.SCROLL_INDICATOR_LEFT | View.SCROLL_INDICATOR_RIGHT
+                        | View.SCROLL_INDICATOR_TOP, view.getScrollIndicators());
+
+        view.setScrollIndicators(0, view.getScrollIndicators());
+        assertEquals(0, view.getScrollIndicators());
+    }
+
     public void testFindViewById() {
         View parent = mActivity.findViewById(R.id.viewlayout_root);
         assertSame(parent, parent.findViewById(R.id.viewlayout_root));
diff --git a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
index bf5382a..2269e00 100644
--- a/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CompoundButtonTest.java
@@ -188,6 +188,7 @@
         // set null drawable
         compoundButton = new MockCompoundButton(mContext);
         compoundButton.setButtonDrawable(null);
+        assertNull(compoundButton.getButtonDrawable());
 
         // set drawable when checkedTextView is GONE
         compoundButton = new MockCompoundButton(mContext);
@@ -197,6 +198,7 @@
         assertEquals(StateSet.WILD_CARD, firstDrawable.getState());
 
         compoundButton.setButtonDrawable(firstDrawable);
+        assertSame(firstDrawable, compoundButton.getButtonDrawable());
         assertFalse(firstDrawable.isVisible());
 
         // update drawable when checkedTextView is VISIBLE
@@ -206,6 +208,7 @@
         assertEquals(StateSet.WILD_CARD, secondDrawable.getState());
 
         compoundButton.setButtonDrawable(secondDrawable);
+        assertSame(secondDrawable, compoundButton.getButtonDrawable());
         assertTrue(secondDrawable.isVisible());
         // the firstDrawable is not active.
         assertFalse(firstDrawable.isVisible());
diff --git a/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java b/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
new file mode 100644
index 0000000..0c021eb
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/DatePickerDialogTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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.widget.cts;
+
+import android.app.AlertDialog;
+import android.app.DatePickerDialog;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.UiThreadTest;
+
+/**
+ * Test {@link DatePickerDialog}.
+ */
+public class DatePickerDialogTest extends AndroidTestCase {
+    private Context mContext;
+
+    @Override
+    public void setUp() {
+        mContext = getContext();
+    }
+
+    @UiThreadTest
+    @SuppressWarnings("deprecation")
+    public void testConstructor() {
+        new DatePickerDialog(mContext, null, 1970, 1, 1);
+
+        new DatePickerDialog(mContext, AlertDialog.THEME_TRADITIONAL, null, 1970, 1, 1);
+
+        new DatePickerDialog(mContext, AlertDialog.THEME_HOLO_DARK, null, 1970, 1, 1);
+
+        new DatePickerDialog(mContext,
+                android.R.style.Theme_Material_Dialog_Alert, null, 1970, 1, 1);
+
+        try {
+            new DatePickerDialog(null, null, 1970, 1, 1);
+            fail("should throw NullPointerException");
+        } catch (Exception e) {
+        }
+    }
+
+    @UiThreadTest
+    public void testShow() {
+        DatePickerDialog d = createDatePickerDialog();
+
+        d.show();
+        assertTrue("Showing date picker", d.isShowing());
+
+        d.show();
+        assertTrue("Date picker still showing", d.isShowing());
+
+        d.dismiss();
+        assertFalse("Dismissed date picker", d.isShowing());
+
+        d.dismiss();
+        assertTrue("Date picker still dismissed", d.isShowing());
+    }
+
+    private MockDatePickerDialog createDatePickerDialog() {
+        return new MockDatePickerDialog(mContext, null, 1970, 1, 1);
+    }
+
+    private class MockDatePickerDialog extends DatePickerDialog {
+        public MockDatePickerDialog(Context context, OnDateSetListener callBack,
+                int year, int monthOfYear, int dayOfMonth) {
+            super(context, callBack, year, monthOfYear, dayOfMonth);
+        }
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
new file mode 100644
index 0000000..fa4e8063
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/ListPopupWindowTest.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2015 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.widget.cts;
+
+import com.android.cts.widget.R;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.ListPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.PopupWindow.OnDismissListener;
+
+public class ListPopupWindowTest extends
+        ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
+    private Instrumentation mInstrumentation;
+    private Activity mActivity;
+
+    /** The list popup window. */
+    private ListPopupWindow mPopupWindow;
+
+    /**
+     * Instantiates a new popup window test.
+     */
+    public ListPopupWindowTest() {
+        super(MockPopupWindowCtsActivity.class);
+    }
+
+    /*
+     * (non-Javadoc)
+     *
+     * @see android.test.ActivityInstrumentationTestCase#setUp()
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testConstructor() {
+        new ListPopupWindow(mActivity);
+
+        new ListPopupWindow(mActivity, null);
+
+        new ListPopupWindow(mActivity, null, android.R.attr.popupWindowStyle);
+
+        new ListPopupWindow(mActivity, null, 0, android.R.style.Widget_Material_ListPopupWindow);
+    }
+
+    public void testAccessBackground() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+
+        Drawable drawable = new ColorDrawable();
+        mPopupWindow.setBackgroundDrawable(drawable);
+        assertSame(drawable, mPopupWindow.getBackground());
+
+        mPopupWindow.setBackgroundDrawable(null);
+        assertNull(mPopupWindow.getBackground());
+    }
+
+    public void testAccessAnimationStyle() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertEquals(0, mPopupWindow.getAnimationStyle());
+
+        mPopupWindow.setAnimationStyle(android.R.style.Animation_Toast);
+        assertEquals(android.R.style.Animation_Toast, mPopupWindow.getAnimationStyle());
+
+        // abnormal values
+        mPopupWindow.setAnimationStyle(-100);
+        assertEquals(-100, mPopupWindow.getAnimationStyle());
+    }
+
+    public void testAccessHeight() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getHeight());
+
+        int height = getDisplay().getHeight() / 2;
+        mPopupWindow.setHeight(height);
+        assertEquals(height, mPopupWindow.getHeight());
+
+        height = getDisplay().getHeight();
+        mPopupWindow.setHeight(height);
+        assertEquals(height, mPopupWindow.getHeight());
+
+        mPopupWindow.setHeight(0);
+        assertEquals(0, mPopupWindow.getHeight());
+
+        height = getDisplay().getHeight() * 2;
+        mPopupWindow.setHeight(height);
+        assertEquals(height, mPopupWindow.getHeight());
+
+        height = -getDisplay().getHeight() / 2;
+        mPopupWindow.setHeight(height);
+        assertEquals(height, mPopupWindow.getHeight());
+    }
+
+    /**
+     * Gets the display.
+     *
+     * @return the display
+     */
+    private Display getDisplay() {
+        WindowManager wm = (WindowManager) mActivity.getSystemService(Context.WINDOW_SERVICE);
+        return wm.getDefaultDisplay();
+    }
+
+    public void testAccessWidth() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertEquals(WindowManager.LayoutParams.WRAP_CONTENT, mPopupWindow.getWidth());
+
+        int width = getDisplay().getWidth() / 2;
+        mPopupWindow.setWidth(width);
+        assertEquals(width, mPopupWindow.getWidth());
+
+        width = getDisplay().getWidth();
+        mPopupWindow.setWidth(width);
+        assertEquals(width, mPopupWindow.getWidth());
+
+        mPopupWindow.setWidth(0);
+        assertEquals(0, mPopupWindow.getWidth());
+
+        width = getDisplay().getWidth() * 2;
+        mPopupWindow.setWidth(width);
+        assertEquals(width, mPopupWindow.getWidth());
+
+        width = - getDisplay().getWidth() / 2;
+        mPopupWindow.setWidth(width);
+        assertEquals(width, mPopupWindow.getWidth());
+    }
+
+    public void testShow() {
+        int[] anchorXY = new int[2];
+        int[] viewOnScreenXY = new int[2];
+        int[] viewInWindowXY = new int[2];
+
+        mPopupWindow = new ListPopupWindow(mActivity);
+
+        final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
+        mPopupWindow.setAnchorView(upperAnchor);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            public void run() {
+                mPopupWindow.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mPopupWindow.isShowing());
+
+        mPopupWindow.getListView().getLocationOnScreen(viewOnScreenXY);
+        upperAnchor.getLocationOnScreen(anchorXY);
+        mPopupWindow.getListView().getLocationInWindow(viewInWindowXY);
+        assertEquals(anchorXY[0] + viewInWindowXY[0], viewOnScreenXY[0]);
+        assertEquals(anchorXY[1] + viewInWindowXY[1] + upperAnchor.getHeight(), viewOnScreenXY[1]);
+
+        dismissPopup();
+    }
+
+    public void testSetWindowLayoutType() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+
+        final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
+        mPopupWindow.setAnchorView(upperAnchor);
+        mPopupWindow.setWindowLayoutType(
+                WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            public void run() {
+                mPopupWindow.show();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertTrue(mPopupWindow.isShowing());
+
+        WindowManager.LayoutParams p = (WindowManager.LayoutParams)
+                mPopupWindow.getListView().getRootView().getLayoutParams();
+        assertEquals(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL, p.type);
+
+        dismissPopup();
+    }
+
+    @UiThreadTest
+    public void testDismiss() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertFalse(mPopupWindow.isShowing());
+        View anchorView = mActivity.findViewById(R.id.anchor_upper);
+        mPopupWindow.setAnchorView(anchorView);
+        mPopupWindow.show();
+
+        mPopupWindow.dismiss();
+        assertFalse(mPopupWindow.isShowing());
+
+        mPopupWindow.dismiss();
+        assertFalse(mPopupWindow.isShowing());
+    }
+
+    public void testSetOnDismissListener() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        mPopupWindow.setOnDismissListener(null);
+
+        MockOnDismissListener onDismissListener = new MockOnDismissListener();
+        mPopupWindow.setOnDismissListener(onDismissListener);
+        showPopup();
+        dismissPopup();
+        assertEquals(1, onDismissListener.getOnDismissCalledCount());
+
+        showPopup();
+        dismissPopup();
+        assertEquals(2, onDismissListener.getOnDismissCalledCount());
+
+        mPopupWindow.setOnDismissListener(null);
+        showPopup();
+        dismissPopup();
+        assertEquals(2, onDismissListener.getOnDismissCalledCount());
+    }
+
+    public void testAccessInputMethodMode() {
+        mPopupWindow = new ListPopupWindow(mActivity);
+        assertEquals(PopupWindow.INPUT_METHOD_NEEDED, mPopupWindow.getInputMethodMode());
+
+        mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_FROM_FOCUSABLE);
+        assertEquals(PopupWindow.INPUT_METHOD_FROM_FOCUSABLE, mPopupWindow.getInputMethodMode());
+
+        mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+        assertEquals(PopupWindow.INPUT_METHOD_NEEDED, mPopupWindow.getInputMethodMode());
+
+        mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        assertEquals(PopupWindow.INPUT_METHOD_NOT_NEEDED, mPopupWindow.getInputMethodMode());
+
+        mPopupWindow.setInputMethodMode(-1);
+        assertEquals(-1, mPopupWindow.getInputMethodMode());
+    }
+
+    /**
+     * The listener interface for receiving OnDismiss events. The class that is
+     * interested in processing a OnDismiss event implements this interface, and
+     * the object created with that class is registered with a component using
+     * the component's <code>setOnDismissListener<code> method. When
+     * the OnDismiss event occurs, that object's appropriate
+     * method is invoked.
+     */
+    private static class MockOnDismissListener implements OnDismissListener {
+
+        /** The Ondismiss called count. */
+        private int mOnDismissCalledCount;
+
+        /**
+         * Gets the onDismiss() called count.
+         *
+         * @return the on dismiss called count
+         */
+        public int getOnDismissCalledCount() {
+            return mOnDismissCalledCount;
+        }
+
+        /*
+         * (non-Javadoc)
+         *
+         * @see android.widget.PopupWindow.OnDismissListener#onDismiss()
+         */
+        public void onDismiss() {
+            mOnDismissCalledCount++;
+        }
+
+    }
+
+    /**
+     * Show PopupWindow.
+     */
+    // FIXME: logcat info complains that there is window leakage due to that mPopupWindow is not
+    // clean up. Need to fix it.
+    private void showPopup() {
+        mInstrumentation.runOnMainSync(new Runnable() {
+            public void run() {
+                if (mPopupWindow == null || mPopupWindow.isShowing()) {
+                    return;
+                }
+                View anchor = mActivity.findViewById(R.id.anchor_upper);
+                mPopupWindow.setAnchorView(anchor);
+                mPopupWindow.show();
+                assertTrue(mPopupWindow.isShowing());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Dismiss PopupWindow.
+     */
+    private void dismissPopup() {
+        mInstrumentation.runOnMainSync(new Runnable() {
+            public void run() {
+                if (mPopupWindow == null || !mPopupWindow.isShowing())
+                    return;
+                mPopupWindow.dismiss();
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
index b5ce5c9..a8d7f54 100644
--- a/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RelativeLayoutTest.java
@@ -318,6 +318,18 @@
         assertFalse(myRelativeLayout.checkLayoutParams(p3));
     }
 
+    public void testGetRule() {
+        RelativeLayout.LayoutParams p = new RelativeLayout.LayoutParams(0, 0);
+        p.addRule(RelativeLayout.LEFT_OF, R.id.abslistview_root);
+        p.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
+
+        assertEquals("Get resource ID rule", R.id.abslistview_root,
+                p.getRule(RelativeLayout.LEFT_OF));
+        assertEquals("Get boolean rule", RelativeLayout.TRUE,
+                p.getRule(RelativeLayout.CENTER_IN_PARENT));
+        assertEquals("Get missing rule", 0, p.getRule(RelativeLayout.ABOVE));
+    }
+
     private class MyRelativeLayout extends RelativeLayout {
         public MyRelativeLayout(Context context) {
             super(context);
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 291e5c2..ec098f8 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -33,6 +33,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Path;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.RectF;
 import android.graphics.Typeface;
@@ -77,12 +78,16 @@
 import android.util.TypedValue;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.ExtractedText;
@@ -2614,6 +2619,88 @@
         assertTrue(mTextView.getHeight() <= maxLines * mTextView.getLineHeight());
     }
 
+    public int calculateTextWidth(String text) {
+        mTextView = findTextView(R.id.textview_text);
+
+        // Set the TextView width as the half of the whole text.
+        float[] widths = new float[text.length()];
+        mTextView.getPaint().getTextWidths(text, widths);
+        float textfieldWidth = 0.0f;
+        for (int i = 0; i < text.length(); ++i) {
+            textfieldWidth += widths[i];
+        }
+        return (int)textfieldWidth;
+
+    }
+
+    @UiThreadTest
+    public void testHyphenationNotHappen_frequencyNone() {
+        final int[] BREAK_STRATEGIES = {
+            Layout.BREAK_STRATEGY_SIMPLE, Layout.BREAK_STRATEGY_HIGH_QUALITY,
+            Layout.BREAK_STRATEGY_BALANCED };
+
+        mTextView = findTextView(R.id.textview_text);
+
+        for (int breakStrategy : BREAK_STRATEGIES) {
+            for (int charWidth = 10; charWidth < 120; charWidth += 5) {
+                // Change the text view's width to charWidth width.
+                mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
+
+                mTextView.setText(LONG_TEXT);
+                mTextView.setBreakStrategy(breakStrategy);
+
+                mTextView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
+
+                mTextView.requestLayout();
+                mTextView.onPreDraw();  // For freezing the layout.
+                Layout layout = mTextView.getLayout();
+
+                final int lineCount = layout.getLineCount();
+                for (int line = 0; line < lineCount; ++line) {
+                    final int lineEnd = layout.getLineEnd(line);
+                    // In any width, any break strategy, hyphenation should not happen if
+                    // HYPHENATION_FREQUENCY_NONE is specified.
+                    assertTrue(lineEnd == LONG_TEXT.length() ||
+                            Character.isWhitespace(LONG_TEXT.charAt(lineEnd - 1)));
+                }
+            }
+        }
+    }
+
+    @UiThreadTest
+    public void testHyphenationNotHappen_breakStrategySimple() {
+        final int[] HYPHENATION_FREQUENCIES = {
+            Layout.HYPHENATION_FREQUENCY_NORMAL, Layout.HYPHENATION_FREQUENCY_FULL,
+            Layout.HYPHENATION_FREQUENCY_NONE };
+
+        mTextView = findTextView(R.id.textview_text);
+
+        for (int hyphenationFrequency: HYPHENATION_FREQUENCIES) {
+            for (int charWidth = 10; charWidth < 120; charWidth += 5) {
+                // Change the text view's width to charWidth width.
+                mTextView.setWidth(calculateTextWidth(LONG_TEXT.substring(0, charWidth)));
+
+                mTextView.setText(LONG_TEXT);
+                mTextView.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
+
+                mTextView.setHyphenationFrequency(hyphenationFrequency);
+
+                mTextView.requestLayout();
+                mTextView.onPreDraw();  // For freezing the layout.
+                Layout layout = mTextView.getLayout();
+
+                final int lineCount = layout.getLineCount();
+                for (int line = 0; line < lineCount; ++line) {
+                    final int lineEnd = layout.getLineEnd(line);
+                    // In any width, any hyphenation frequency, hyphenation should not happen if
+                    // BREAK_STRATEGY_SIMPLE is specified.
+                    assertTrue(lineEnd == LONG_TEXT.length() ||
+                            Character.isWhitespace(LONG_TEXT.charAt(lineEnd - 1)));
+                }
+            }
+        }
+    }
+
     @UiThreadTest
     public void testSetMaxLinesException() {
         mTextView = new TextView(mActivity);
@@ -2831,7 +2918,7 @@
         assertEquals(40, mTextView.getPaddingBottom());
     }
 
-    public void testSetTextAppearance() {
+    public void testDeprecatedSetTextAppearance() {
         mTextView = new TextView(mActivity);
 
         mTextView.setTextAppearance(mActivity, R.style.TextAppearance_All);
@@ -2860,10 +2947,49 @@
         assertEquals(null, mTextView.getTypeface());
     }
 
+    public void testSetTextAppearance() {
+        mTextView = new TextView(mActivity);
+
+        mTextView.setTextAppearance(R.style.TextAppearance_All);
+        assertEquals(mActivity.getResources().getColor(R.drawable.black),
+                mTextView.getCurrentTextColor());
+        assertEquals(20f, mTextView.getTextSize(), 0.01f);
+        assertEquals(Typeface.BOLD, mTextView.getTypeface().getStyle());
+        assertEquals(mActivity.getResources().getColor(R.drawable.red),
+                mTextView.getCurrentHintTextColor());
+        assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+                mTextView.getLinkTextColors().getDefaultColor());
+
+        mTextView.setTextAppearance(R.style.TextAppearance_Colors);
+        assertEquals(mActivity.getResources().getColor(R.drawable.black),
+                mTextView.getCurrentTextColor());
+        assertEquals(mActivity.getResources().getColor(R.drawable.blue),
+                mTextView.getCurrentHintTextColor());
+        assertEquals(mActivity.getResources().getColor(R.drawable.yellow),
+                mTextView.getLinkTextColors().getDefaultColor());
+
+        mTextView.setTextAppearance(R.style.TextAppearance_NotColors);
+        assertEquals(17f, mTextView.getTextSize(), 0.01f);
+        assertEquals(Typeface.NORMAL, mTextView.getTypeface().getStyle());
+
+        mTextView.setTextAppearance(R.style.TextAppearance_Style);
+        assertEquals(null, mTextView.getTypeface());
+    }
+
     public void testOnPreDraw() {
         // Do not test. Implementation details.
     }
 
+    public void testAccessCompoundDrawableTint() {
+        mTextView = new TextView(mActivity);
+
+        ColorStateList colors = ColorStateList.valueOf(Color.RED);
+        mTextView.setCompoundDrawableTintList(colors);
+        mTextView.setCompoundDrawableTintMode(PorterDuff.Mode.XOR);
+        assertSame(colors, mTextView.getCompoundDrawableTintList());
+        assertEquals(PorterDuff.Mode.XOR, mTextView.getCompoundDrawableTintMode());
+    }
+
     public void testSetHorizontallyScrolling() {
         // make the text view has more than one line
         mTextView = findTextView(R.id.textview_text);
@@ -4301,6 +4427,135 @@
         assertEquals(Layout.HYPHENATION_FREQUENCY_FULL, tv.getHyphenationFrequency());
     }
 
+    public void testSetAndGetCustomSelectionActionModeCallback() {
+        final String text = "abcde";
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView = new EditText(mActivity);
+                mActivity.setContentView(mTextView);
+                mTextView.setText(text, BufferType.SPANNABLE);
+                mTextView.setTextIsSelectable(true);
+                mTextView.requestFocus();
+                mTextView.setSelected(true);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Check default value.
+        assertNull(mTextView.getCustomSelectionActionModeCallback());
+
+        MockActionModeCallback callbackBlockActionMode = new MockActionModeCallback(false);
+        mTextView.setCustomSelectionActionModeCallback(callbackBlockActionMode);
+        assertEquals(callbackBlockActionMode,
+                mTextView.getCustomSelectionActionModeCallback());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Set selection and try to start action mode.
+                final Bundle args = new Bundle();
+                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
+                mTextView.performAccessibilityActionInternal(
+                        AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(1, callbackBlockActionMode.getCreateCount());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Remove selection and stop action mode.
+                mTextView.onTextContextMenuItem(android.R.id.copy);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Action mode was blocked.
+        assertEquals(0, callbackBlockActionMode.getDestroyCount());
+
+        // Overwrite callback.
+        MockActionModeCallback callbackStartActionMode = new MockActionModeCallback(true);
+        mTextView.setCustomSelectionActionModeCallback(callbackStartActionMode);
+        assertEquals(callbackStartActionMode, mTextView.getCustomSelectionActionModeCallback());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Set selection and try to start action mode.
+                final Bundle args = new Bundle();
+                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, 0);
+                args.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, text.length());
+                mTextView.performAccessibilityActionInternal(
+                        AccessibilityNodeInfo.ACTION_SET_SELECTION, args);
+
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        assertEquals(1, callbackStartActionMode.getCreateCount());
+
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                // Remove selection and stop action mode.
+                mTextView.onTextContextMenuItem(android.R.id.copy);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        // Action mode was started
+        assertEquals(1, callbackStartActionMode.getDestroyCount());
+    }
+
+    public void testSetAndGetCustomInseltionActionMode() {
+        initTextViewForTyping();
+        // Check default value.
+        assertNull(mTextView.getCustomInsertionActionModeCallback());
+
+        MockActionModeCallback callback = new MockActionModeCallback(false);
+        mTextView.setCustomInsertionActionModeCallback(callback);
+        assertEquals(callback, mTextView.getCustomInsertionActionModeCallback());
+        // TODO(Bug: 22033189): Tests the set callback is actually used.
+    }
+
+    private static class MockActionModeCallback implements ActionMode.Callback {
+        private int mCreateCount = 0;
+        private int mDestroyCount = 0;
+        private final boolean mAllowToStartActionMode;
+
+        public MockActionModeCallback(boolean allowToStartActionMode) {
+            mAllowToStartActionMode = allowToStartActionMode;
+        }
+
+        public int getCreateCount() {
+            return mCreateCount;
+        }
+
+        public int getDestroyCount() {
+            return mDestroyCount;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {
+            mDestroyCount++;
+        }
+
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            mCreateCount++;
+            return mAllowToStartActionMode;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return false;
+        }
+    };
+
     private static class MockOnEditorActionListener implements OnEditorActionListener {
         private boolean isOnEditorActionCalled;
 
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
index 833bf69..328b855 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -20,6 +20,7 @@
 
 import vogar.Expectation;
 import vogar.ExpectationStore;
+import vogar.Result;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -228,7 +229,8 @@
     }
 
     public static boolean isKnownFailure(ExpectationStore expectationStore, String testName) {
-        return expectationStore != null && expectationStore.get(testName) != Expectation.SUCCESS;
+        return expectationStore != null
+            && expectationStore.get(testName).getResult() != Result.SUCCESS;
     }
 
     // Returns the list of ABIs supported by this TestCase on this architecture.
diff --git a/tools/utils/CollectAllTests.java b/tools/utils/CollectAllTests.java
index 95b77f2..83c451e 100644
--- a/tools/utils/CollectAllTests.java
+++ b/tools/utils/CollectAllTests.java
@@ -447,6 +447,9 @@
                                                                     expectations,
                                                                     testClassName,
                                                                     testName);
+        int timeoutInMinutes = VogarUtils.timeoutInMinutes(expectations,
+                                                           testClassName,
+                                                           testName);
         TestClass testClass;
         if (testCases.containsKey(testClassName)) {
             testClass = testCases.get(testClassName);
@@ -456,7 +459,7 @@
         }
 
         testClass.mCases.add(new TestMethod(testName, "", "", supportedAbis,
-              knownFailure, false, false));
+              knownFailure, false, false, timeoutInMinutes));
     }
 
     private static boolean isJunit3Test(Class<?> klass) {
diff --git a/tools/utils/DescriptionGenerator.java b/tools/utils/DescriptionGenerator.java
index 09e1118..1e2542f 100644
--- a/tools/utils/DescriptionGenerator.java
+++ b/tools/utils/DescriptionGenerator.java
@@ -86,6 +86,7 @@
     static final String ATTRIBUTE_NAME = "name";
     static final String ATTRIBUTE_ABIS = "abis";
     static final String ATTRIBUTE_HOST_CONTROLLER = "HostController";
+    static final String ATTRIBUTE_TIMEOUT = "timeout";
 
     static final String XML_OUTPUT_PATH = "./description.xml";
 
@@ -438,6 +439,10 @@
                     if ((caze.mController != null) && (caze.mController.length() != 0)) {
                         setAttribute(caseNode, ATTRIBUTE_HOST_CONTROLLER, caze.mController);
                     }
+                    if (caze.mTimeoutInMinutes != 0) {
+                        setAttribute(caseNode, ATTRIBUTE_TIMEOUT,
+                                     Integer.toString(caze.mTimeoutInMinutes));
+                    }
 
                     if (caze.mDescription != null && !caze.mDescription.equals("")) {
                         caseNode.appendChild(mDoc.createElement(TAG_DESCRIPTION))
@@ -573,9 +578,10 @@
                             VogarUtils.buildFullTestName(clazz.toString(), name));
                     Set<String> supportedAbis =
                             VogarUtils.extractSupportedAbis(architecture, expectation);
+                    int timeoutInMinutes = VogarUtils.timeoutInMinutes(expectation);
                     cases.add(new TestMethod(
                             name, method.commentText(), controller, supportedAbis,
-                                    knownFailure, isBroken, isSuppressed));
+                                    knownFailure, isBroken, isSuppressed, timeoutInMinutes));
                 }
             }
 
@@ -635,6 +641,7 @@
         String mKnownFailure;
         boolean mIsBroken;
         boolean mIsSuppressed;
+        int mTimeoutInMinutes;  // zero to use default timeout.
 
         /**
          * Construct an test case object.
@@ -644,7 +651,10 @@
          * @param knownFailure The reason of known failure.
          */
         TestMethod(String name, String description, String controller, Set<String> abis,
-                String knownFailure, boolean isBroken, boolean isSuppressed) {
+                String knownFailure, boolean isBroken, boolean isSuppressed, int timeoutInMinutes) {
+            if (timeoutInMinutes < 0) {
+                throw new IllegalArgumentException("timeoutInMinutes < 0: " + timeoutInMinutes);
+            }
             mName = name;
             mDescription = description;
             mController = controller;
@@ -652,6 +662,7 @@
             mKnownFailure = knownFailure;
             mIsBroken = isBroken;
             mIsSuppressed = isSuppressed;
+            mTimeoutInMinutes = timeoutInMinutes;
         }
     }
 }
diff --git a/tools/utils/VogarUtils.java b/tools/utils/VogarUtils.java
index 5e8b944..8e77e7c 100644
--- a/tools/utils/VogarUtils.java
+++ b/tools/utils/VogarUtils.java
@@ -19,6 +19,7 @@
 import vogar.Expectation;
 import vogar.ExpectationStore;
 import vogar.ModeId;
+import vogar.Result;
 
 import java.io.File;
 import java.io.FilenameFilter;
@@ -52,14 +53,14 @@
         }
         String fullTestName = buildFullTestName(testClassName, testMethodName);
         Expectation expectation = expectationStore.get(fullTestName);
-        if (expectation == Expectation.SUCCESS) {
+        if (expectation.getResult() == Result.SUCCESS) {
             return false;
         }
 
         String description = expectation.getDescription();
         boolean foundAbi = AbiUtils.parseAbiList(description).size() > 0;
 
-        return expectation != Expectation.SUCCESS && !foundAbi;
+        return expectation.getResult() != Result.SUCCESS && !foundAbi;
     }
 
     public static ExpectationStore provideExpectationStore(String dir) throws IOException {
@@ -119,7 +120,7 @@
                                                    String className,
                                                    String testName) {
 
-        String fullTestName = VogarUtils.buildFullTestName(className, testName);
+        String fullTestName = buildFullTestName(className, testName);
         Set<String> supportedAbiSet = AbiUtils.getAbisForArch(architecture);
         for (ExpectationStore expectationStore : expectationStores) {
             Expectation expectation = expectationStore.get(fullTestName);
@@ -128,4 +129,44 @@
 
         return supportedAbiSet;
     }
+
+    /**
+     * Returns the greatest timeout in minutes for the test in all
+     * expectation stores, or 0 if no timeout was found.
+     */
+    public static int timeoutInMinutes(ExpectationStore[] expectationStores,
+            final String testClassName,
+            final String testMethodName) {
+        int timeoutInMinutes = 0;
+        for (ExpectationStore expectationStore : expectationStores) {
+            timeoutInMinutes = Math.max(timeoutInMinutes,
+                                        timeoutInMinutes(expectationStore,
+                                                         testClassName,
+                                                         testMethodName));
+        }
+        return timeoutInMinutes;
+    }
+
+    /**
+     * Returns the timeout in minutes for the test in the expectation
+     * stores, or 0 if no timeout was found.
+     */
+    public static int timeoutInMinutes(ExpectationStore expectationStore,
+            final String testClassName,
+            final String testMethodName) {
+        if (expectationStore == null) {
+            return 0;
+        }
+        String fullTestName = buildFullTestName(testClassName, testMethodName);
+        return timeoutInMinutes(expectationStore.get(fullTestName));
+    }
+
+    /**
+     * Returns the timeout in minutes for the expectation. Currently a
+     * tag of large results in a 60 minute timeout, otherwise 0 is
+     * returned to indicate a default timeout should be used.
+     */
+    public static int timeoutInMinutes(Expectation expectation) {
+        return expectation.getTags().contains("large") ? 60 : 0;
+    }
 }