Merge "[CtsVerifier] Added Battery and Data usage settings test in BYOD flow" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 0950994..f743fb2 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -83,7 +83,9 @@
     CtsDeviceOpenGl \
     CtsWifiConfigCreator \
     CtsDeviceAndProfileOwnerApp \
+    CtsDeviceAppUsageTestApp \
     CtsDeviceInfo \
+    CtsDeviceOsTestApp \
     CtsDeviceOwnerApp \
     CtsDeviceTaskswitchingAppA \
     CtsDeviceTaskswitchingAppB \
@@ -222,7 +224,9 @@
     CtsHostJank \
     CtsHostsideNetworkTests \
     CtsHostUi \
+    CtsJdwpSecurityHostTestCases \
     CtsMonkeyTestCases \
+    CtsOsHostTestCases \
     CtsThemeHostTestCases \
     CtsUsageHostTestCases \
     CtsSecurityHostTestCases \
@@ -244,7 +248,8 @@
     CtsUiAutomatorTests
 
 cts_device_jars := \
-    CtsDeviceJank
+    CtsDeviceJank \
+    CtsJdwpApp
 
 cts_target_junit_tests := \
     CtsJdwp
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 5ddfcb2..8cec7ea 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -41,7 +41,7 @@
 
 LOCAL_PACKAGE_NAME := CtsVerifier
 
-LOCAL_AAPT_FLAGS += --version-name "5.0_r1.91 $(BUILD_NUMBER)"
+LOCAL_AAPT_FLAGS += --version-name "6.0_r0 $(BUILD_NUMBER)"
 
 LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni libaudioloopback_jni
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 272e192..217913c 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -19,7 +19,7 @@
       package="com.android.cts.verifier"
       android:versionCode="5">
 
-    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
+    <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="23"/>
 
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
@@ -1423,10 +1423,15 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_AUDIO" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
         </activity>
 
+        <activity android:name=".managedprovisioning.NfcTestActivity">
+            <meta-data android:name="test_required_features" android:value="android.hardware.nfc" />
+        </activity>
+
         <provider
             android:name="android.support.v4.content.FileProvider"
             android:authorities="com.android.cts.verifier.managedprovisioning.fileprovider"
@@ -1648,8 +1653,30 @@
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_audio" />
             <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
-            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.watch" />
-            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
+        </activity>
+
+        <activity android:name=".audio.AudioFrequencySpeakerActivity"
+                  android:label="@string/audio_frequency_speaker_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_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
+        </activity>
+
+        <activity android:name=".audio.AudioFrequencyMicActivity"
+                  android:label="@string/audio_frequency_mic_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_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.audio.output" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
         </activity>
 
         <service android:name=".tv.MockTvInputService"
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
new file mode 100644
index 0000000..10b0003
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_frequency_mic_activity.xml
@@ -0,0 +1,133 @@
+<?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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="10dip"
+    android:orientation="vertical">
+
+    <ScrollView
+       android:layout_width="match_parent"
+       android:layout_height="match_parent"
+       android:id="@+id/scrollView">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+        <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+          <TextView
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_weight="1"
+              android:id="@+id/info_text"
+              android:text="@string/audio_frequency_mic_instructions"/>
+
+           <ProgressBar
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_weight="1"
+                        android:id="@+id/audio_frequency_mic_progress_bar"/>
+         </LinearLayout>
+
+          <Button
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:id="@+id/audio_frequency_mic_speakers_ready_btn"
+              android:text="@string/audio_frequency_mic_speakers_ready_btn"/>
+
+          <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:scrollbars="vertical"
+                android:gravity="bottom"
+                android:id="@+id/audio_frequency_mic_speakers_ready_status"
+                android:text="@string/audio_frequency_mic_speakers_ready_status"/>
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/audio_frequency_mic_layout_test1">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/audio_frequency_mic_instructions2"
+                android:id="@+id/audio_frequency_mic_instructions2"/>
+
+              <Button
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_test1_btn"
+                    android:id="@+id/audio_frequency_mic_test1_btn"/>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_mic_results_text"
+                    android:id="@+id/audio_frequency_mic_results1_text"/>
+          </LinearLayout>
+
+          <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/audio_frequency_mic_layout_test2a">
+
+            <Button
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_frequency_mic_mic_ready_btn"
+                android:text="@string/audio_frequency_mic_mic_ready_btn"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/audio_frequency_mic_usb_status"
+                android:id="@+id/audio_frequency_mic_usb_status"/>
+           </LinearLayout>
+
+          <LinearLayout
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:id="@+id/audio_frequency_mic_layout_test2b">
+
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/audio_frequency_mic_test2_btn"
+                android:id="@+id/audio_frequency_mic_test2_btn"/>
+
+              <TextView
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:text="@string/audio_frequency_mic_results_text"
+                  android:id="@+id/audio_frequency_mic_results_text"/>
+
+        </LinearLayout>
+
+        <include layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+      </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml
new file mode 100644
index 0000000..5dd55b1
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_frequency_speaker_activity.xml
@@ -0,0 +1,92 @@
+<?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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:padding="10dip"
+    android:orientation="vertical">
+
+    <ScrollView
+       android:layout_width="match_parent"
+       android:layout_height="match_parent"
+       android:id="@+id/scrollView">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+        <TextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:scrollbars="vertical"
+            android:gravity="bottom"
+            android:id="@+id/info_text"
+            android:text="@string/audio_frequency_speaker_instructions"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+            <Button
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_frequency_speaker_mic_ready_btn"
+                android:text="@string/audio_frequency_speaker_mic_ready_btn"/>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/audio_frequency_speaker_usb_status"
+                android:id="@+id/audio_frequency_speaker_usb_status"/>
+
+            <LinearLayout
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:id="@+id/audio_frequency_speaker_layout">
+                    <Button
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/audio_frequency_speaker_test_btn"
+                        android:id="@+id/audio_frequency_speaker_test_btn"/>
+
+                    <ProgressBar
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:id="@+id/audio_frequency_speaker_progress_bar"/>
+                </LinearLayout>
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/audio_frequency_speaker_results_text"
+                    android:id="@+id/audio_frequency_speaker_results_text"/>
+
+            </LinearLayout>
+        </LinearLayout>
+
+        <include layout="@layout/pass_fail_buttons"/>
+        </LinearLayout>
+      </ScrollView>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/byod_nfc_test_activity.xml b/apps/CtsVerifier/res/layout/byod_nfc_test_activity.xml
new file mode 100644
index 0000000..52251b4
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/byod_nfc_test_activity.xml
@@ -0,0 +1,31 @@
+<?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"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <Button android:text="@string/provisioning_byod_send_manual_beam"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/manual_beam_button" />
+
+    <Button android:text="@string/provisioning_byod_send_share_intent"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/intent_share_button"
+        android:layout_below="@+id/manual_beam_button" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 98cb7eb..e2d67a1 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1609,6 +1609,28 @@
     </string>
 
     <string name="provisioning_byod_cross_profile_intent_filters">Cross profile intent filters are set</string>
+
+    <string name="provisioning_byod_nfc_beam">Disable Nfc beam</string>
+    <string name="provisioning_byod_nfc_beam_allowed_instruction">
+        Please press the Go button to test if Nfc beam can be triggered in the work profile.\n
+        \n
+        For the first test, press \"Send manual beam\" to trigger a beam, then bump into another device to send the file. Verify that the file is successfully received.\n
+        \n
+        For the second test, press \"Send share intent\" to trigger a beam, then bump into another device to send the file. Verify that the file is successfully received.\n
+        \n
+        Then use the Back button to return to this test and mark accordingly.
+    </string>
+    <string name="provisioning_byod_nfc_beam_disallowed_instruction">
+        Please press the Go button to test if Nfc beam is disallowed by policy
+        \n
+        Verify that Nfc beam is not triggered when pressing the button.\n
+        \n
+        Then use the Back button to return to this test and mark accordingly.
+    </string>
+    <string name="provisioning_byod_send_manual_beam">Send manual beam</string>
+    <string name="provisioning_byod_send_share_intent">Send share intent</string>
+    <string name="provisioning_byod_cannot_resolve_beam_activity">Cannot find beam activity</string>
+
     <string name="provisioning_byod_no_activity">Cannot communicate with activity in the work profile.</string>
     <string name="provisioning_byod_delete_profile">Initiate deletion of work profile.</string>
     <string name="provisioning_byod_profile_deleted">Work profile deleted.</string>
@@ -2007,13 +2029,11 @@
    <!-- Audio Frequency Line Test -->
     <string name="audio_frequency_line_test">Audio Frequency Line Test</string>
     <string name="audio_frequency_line_info">
+        The system will measure the frequency response of the left and right line outputs, 
+        by feeding them back thru the microphone conection with the loopback jack.
         This test requires the Loopback Plug. Please connect a Loopback Plug on the headset
         connector, and proceed with the instructions on the screen.
-        The system will measure the input-output audio latency by injecting a pulse on the output,
-        and computing the distance between replicas of the pulse.
-        You can vary the Audio Level slider to ensure the pulse will feed back at adecuate levels.
-        Repeat until a confidence level >= 0.6 is achieved.
-    </string>
+        </string>
     <string name="audio_frequency_line_instructions">
           Please connect a "Loopback Plug" and press "Loopback Plug Ready".
     </string>
@@ -2022,4 +2042,48 @@
     <string name="audio_frequency_line_test_btn">Test</string>
     <string name="audio_frequency_line_results_text">Results...</string>
 
+    <!-- Audio Frequency Speaker Test -->
+    <string name="audio_frequency_speaker_test">Audio Frequency Speaker Test</string>
+    <string name="audio_frequency_speaker_info">
+        This test requires an external USB reference microphone. Please connect the USB microphone and proceed with the instructions on the screen.
+        The system will measure frequency response of the left and right speakers (if there are two speakers), or twice the response of the mono speaker.
+       </string>
+    <string name="audio_frequency_speaker_instructions">
+          Please connect an USB reference microphone and press "USB Reference microphone ready"
+    </string>
+    <string name="audio_frequency_speaker_usb_status">Waiting for USB microphone...</string>
+    <string name="audio_frequency_speaker_mic_ready_btn">USB Reference microphone ready</string>
+    <string name="audio_frequency_speaker_mic_ready_text">USB Audio device detected\n\nPlease set up Device Under test
+    in quiet room, and Microphone 20 cms perpendicular to center of screen, then press TEST</string>
+    <string name="audio_frequency_speaker_mic_not_ready_text">"No USB Audio device detected. Please reconnect."</string>
+    <string name="audio_frequency_speaker_test_btn">Test</string>
+    <string name="audio_frequency_speaker_results_text">Results...</string>
+
+    <!-- Audio Frequency Microphone Test -->
+    <string name="audio_frequency_mic_test">Audio Frequency Microphone Test</string>
+    <string name="audio_frequency_mic_info">
+        This test requires an external USB reference microphone and external speakers.
+        Please use the headphone connector to connect external speakers. Position the device 40 cms
+        from the speakers and proceed with the instructions on the screen.
+        The system will measure frequency response of the built in microphone.
+       </string>
+    <string name="audio_frequency_mic_instructions">
+          Please connect external speakers using the headphone connector. Please unplug any USB audio device (if any)
+    </string>
+    <string name="audio_frequency_mic_speakers_ready_btn">External speakers ready</string>
+    <string name="audio_frequency_mic_speakers_ready_status">...</string>
+    <string name="audio_frequency_mic_instructions2">
+          Please position the speakers 40 cms from the device under test and press TEST 1
+    </string>
+    <string name="audio_frequency_mic_test1_btn">Test 1</string>
+    <string name="audio_frequency_mic_usb_status">Waiting for USB microphone...</string>
+    <string name="audio_frequency_mic_connect_mic">Please Connect USB microphone, position it next to
+    the built in microphone in the device and press USB reference microphone</string>
+    <string name="audio_frequency_mic_mic_ready_btn">USB Reference microphone ready</string>
+    <string name="audio_frequency_mic_mic_ready_text">USB Audio device detected\n\nPlease set up Device Under test
+    in quiet room, and Microphone 20 cms perpendicular to center of screen, then press TEST</string>
+    <string name="audio_frequency_mic_mic_not_ready_text">"No USB Audio device detected. Please reconnect."</string>
+    <string name="audio_frequency_mic_test2_btn">Test 2</string>
+    <string name="audio_frequency_mic_results_text">Results...</string>
+
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index cbd4887..789effa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -101,7 +101,32 @@
         getPassButton().setEnabled(mAdapter.allTestsPassed());
     }
 
-    private void showManualTestDialog(final DialogTestListItem test) {
+    public class DefaultTestCallback implements DialogTestListItem.TestCallback {
+        final private DialogTestListItem mTest;
+
+        public DefaultTestCallback(DialogTestListItem test) {
+            mTest = test;
+        }
+
+        @Override
+        public void onPass() {
+            clearRemainingState(mTest);
+            setTestResult(mTest, TestResult.TEST_RESULT_PASSED);
+        }
+
+        @Override
+        public void onFail() {
+            clearRemainingState(mTest);
+            setTestResult(mTest, TestResult.TEST_RESULT_FAILED);
+        }
+    }
+
+    public void showManualTestDialog(final DialogTestListItem test) {
+        showManualTestDialog(test, new DefaultTestCallback(test));
+    }
+
+    public void showManualTestDialog(final DialogTestListItem test,
+            final DialogTestListItem.TestCallback callback) {
         AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this)
                 .setIcon(android.R.drawable.ic_dialog_info)
                 .setTitle(mTitleStringId)
@@ -109,15 +134,13 @@
                 .setPositiveButton(R.string.pass_button_text, new AlertDialog.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        clearRemainingState(test);
-                        setTestResult(test, TestResult.TEST_RESULT_PASSED);
+                        callback.onPass();
                     }
                 })
                 .setNegativeButton(R.string.fail_button_text, new AlertDialog.OnClickListener() {
                     @Override
                     public void onClick(DialogInterface dialog, int which) {
-                        clearRemainingState(test);
-                        setTestResult(test, TestResult.TEST_RESULT_FAILED);
+                        callback.onFail();
                     }
                 });
         View customView = test.getCustomView();
@@ -189,6 +212,11 @@
 
     protected static class DialogTestListItem extends TestListAdapter.TestListItem {
 
+        public interface TestCallback {
+            void onPass();
+            void onFail();
+        }
+
         private String mManualInstruction;
 
         public DialogTestListItem(Context context, int nameResId, String testId) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
new file mode 100644
index 0000000..b37a721
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyMicActivity.java
@@ -0,0 +1,851 @@
+/*
+ * 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.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.wavelib.*;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.SeekBar;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+
+/**
+ * Tests Audio built in Microphone response using external speakers and USB reference microphone.
+ */
+public class AudioFrequencyMicActivity extends PassFailButtons.Activity implements Runnable,
+    AudioRecord.OnRecordPositionUpdateListener {
+    private static final String TAG = "AudioFrequencyMicActivity";
+
+    private static final int TEST_STARTED = 900;
+    private static final int TEST_ENDED = 901;
+    private static final int TEST_MESSAGE = 902;
+    private static final int TEST1_MESSAGE = 903;
+    private static final int TEST1_ENDED = 904;
+    private static final double MIN_ENERGY_BAND_1 = -50.0;          //dB Full Scale
+    private static final double MAX_ENERGY_BAND_1_BASE = -60.0;     //dB Full Scale
+    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+    private static final double MAX_VAL = Math.pow(2, 15);
+    private static final double CLIP_LEVEL = (MAX_VAL-10) / MAX_VAL;
+
+    final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+    Context mContext;
+
+    Button mSpeakersReady;              //user signal to have connected external speakers
+    Button mTest1Button;                //execute test 1
+    Button mUsbMicReady;          //user signal to have connected USB Microphone
+    Button mTest2Button;                 //user to start test
+    String mUsbDevicesInfo;             //usb device info for report
+    LinearLayout mLayoutTest1;
+    LinearLayout mLayoutTest2a;
+    LinearLayout mLayoutTest2b;
+
+    TextView mSpeakerReadyText;
+    TextView mTest2Result;
+    TextView mUsbStatusText;
+    TextView mTest1Result;
+    ProgressBar mProgressBar;
+
+    private boolean mIsRecording = false;
+    private final Object mRecordingLock = new Object();
+    private AudioRecord mRecorder;
+    private int mMinRecordBufferSizeInSamples = 0;
+    private short[] mAudioShortArray;
+    private short[] mAudioShortArray2;
+
+    private final int mBlockSizeSamples = 1024;
+    private final int mSamplingRate = 48000;
+    private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+    private final int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;
+    private final int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    private Thread mRecordThread;
+
+    PipeShort mPipe = new PipeShort(65536);
+    SoundPlayerObject mSPlayer;
+
+    private DspBufferComplex mC;
+    private DspBufferDouble mData;
+
+    private DspWindow mWindow;
+    private DspFftServer mFftServer;
+    private VectorAverage mFreqAverageMain = new VectorAverage();
+
+    private VectorAverage mFreqAverageBase = new VectorAverage();
+    private VectorAverage mFreqAverageBuiltIn = new VectorAverage();
+    private VectorAverage mFreqAverageReference = new VectorAverage();
+
+    private int mCurrentTest = -1;
+    int mBands = 4;
+    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
+    AudioBandSpecs[] baseBandSpecsArray = new AudioBandSpecs[mBands];
+
+    int mMaxLevel;
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+            case R.id.audio_frequency_mic_speakers_ready_btn:
+                testSpeakersReady();
+                break;
+            case R.id.audio_frequency_mic_test1_btn:
+                startTest1();
+                break;
+            case R.id.audio_frequency_mic_mic_ready_btn:
+                testUSB();
+                break;
+            case R.id.audio_frequency_mic_test2_btn:
+                startTest2();
+                break;
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_frequency_mic_activity);
+        mContext = this;
+        mSpeakerReadyText = (TextView) findViewById(R.id.audio_frequency_mic_speakers_ready_status);
+
+        mSpeakersReady  = (Button)findViewById(R.id.audio_frequency_mic_speakers_ready_btn);
+        mSpeakersReady.setOnClickListener(mBtnClickListener);
+        mTest1Button = (Button)findViewById(R.id.audio_frequency_mic_test1_btn);
+        mTest1Button.setOnClickListener(mBtnClickListener);
+        mTest1Result = (TextView)findViewById(R.id.audio_frequency_mic_results1_text);
+        mLayoutTest1 = (LinearLayout) findViewById(R.id.audio_frequency_mic_layout_test1);
+        mLayoutTest2a = (LinearLayout) findViewById(R.id.audio_frequency_mic_layout_test2a);
+        mLayoutTest2b = (LinearLayout) findViewById(R.id.audio_frequency_mic_layout_test2b);
+        mUsbMicReady = (Button)findViewById(R.id.audio_frequency_mic_mic_ready_btn);
+        mUsbMicReady.setOnClickListener(mBtnClickListener);
+
+        mUsbStatusText = (TextView)findViewById(R.id.audio_frequency_mic_usb_status);
+        mTest2Button = (Button)findViewById(R.id.audio_frequency_mic_test2_btn);
+        mTest2Button.setOnClickListener(mBtnClickListener);
+        mTest2Result = (TextView)findViewById(R.id.audio_frequency_mic_results_text);
+        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_mic_progress_bar);
+        showWait(false);
+        enableLayout(mLayoutTest1, false);
+        enableLayout(mLayoutTest2a, false);
+        enableLayout(mLayoutTest2b, false);
+
+        mSPlayer = new SoundPlayerObject();
+        mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.stereo_mono_white_noise_48);
+        mSPlayer.setBalance(0.5f);
+
+        //Init FFT stuff
+        mAudioShortArray2 = new short[mBlockSizeSamples*2];
+        mData = new DspBufferDouble(mBlockSizeSamples);
+        mC = new DspBufferComplex(mBlockSizeSamples);
+        mFftServer = new DspFftServer(mBlockSizeSamples);
+
+        int overlap = mBlockSizeSamples / 2;
+
+        mWindow = new DspWindow(DspWindow.WINDOW_HANNING, mBlockSizeSamples, overlap);
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_frequency_mic_test,
+                R.string.audio_frequency_mic_info, -1);
+
+        //Init bands for BuiltIn/Reference test
+        bandSpecsArray[0] = new AudioBandSpecs(
+                50, 500,        /* frequency start,stop */
+                -20.0, -50,     /* start top,bottom value */
+                4.0, -4.0       /* stop top,bottom value */);
+
+        bandSpecsArray[1] = new AudioBandSpecs(
+                500,4000,       /* frequency start,stop */
+                4.0, -4.0,      /* start top,bottom value */
+                4.0, -4.0        /* stop top,bottom value */);
+
+        bandSpecsArray[2] = new AudioBandSpecs(
+                4000, 12000,    /* frequency start,stop */
+                4.0, -4.0,      /* start top,bottom value */
+                5.0, -5.0       /* stop top,bottom value */);
+
+        bandSpecsArray[3] = new AudioBandSpecs(
+                12000, 20000,   /* frequency start,stop */
+                5.0, -5.0,      /* start top,bottom value */
+                5.0, -30.0      /* stop top,bottom value */);
+
+        //Init base bands for silence
+        baseBandSpecsArray[0] = new AudioBandSpecs(
+                50, 500,        /* frequency start,stop */
+                40.0, -50.0,     /* start top,bottom value */
+                5.0, -50.0       /* stop top,bottom value */);
+
+        baseBandSpecsArray[1] = new AudioBandSpecs(
+                500,4000,       /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0        /* stop top,bottom value */);
+
+        baseBandSpecsArray[2] = new AudioBandSpecs(
+                4000, 12000,    /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0       /* stop top,bottom value */);
+
+        baseBandSpecsArray[3] = new AudioBandSpecs(
+                12000, 20000,   /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0      /* stop top,bottom value */);
+
+    }
+
+    /**
+     * enable test ui elements
+     */
+    private void enableLayout(LinearLayout layout, boolean enable) {
+        for (int i = 0; i < layout.getChildCount(); i++) {
+            View view = layout.getChildAt(i);
+            view.setEnabled(enable);
+        }
+    }
+
+    /**
+     * show active progress bar
+     */
+    private void showWait(boolean show) {
+        if (show) {
+            mProgressBar.setVisibility(View.VISIBLE);
+        } else {
+            mProgressBar.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    private void setMaxLevel() {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mMaxLevel = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(mMaxLevel), 0);
+    }
+
+    private void setMinLevel() {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
+    }
+
+    /**
+     *  Start the loopback audio test
+     */
+    private void startTest1() {
+        if (mTestThread != null && !mTestThread.isAlive()) {
+            mTestThread = null; //kill it.
+        }
+
+        if (mTestThread == null) {
+            Log.v(TAG,"Executing test Thread");
+            mTestThread = new Thread(mTest1Runnable);
+            //getPassButton().setEnabled(false);
+            if (!mSPlayer.isAlive())
+                mSPlayer.start();
+            mTestThread.start();
+        } else {
+            Log.v(TAG,"test Thread already running.");
+        }
+    }
+
+    Thread mTestThread;
+    Runnable mTest1Runnable = new Runnable() {
+        public void run() {
+            Message msg = Message.obtain();
+            msg.what = TEST_STARTED;
+            mMessageHandler.sendMessage(msg);
+
+            setMinLevel();
+            sendMessage("Testing Background Environment");
+            mCurrentTest = 0;
+            mSPlayer.setBalance(0.5f);
+            mFreqAverageBase.reset();
+            play();
+
+            setMaxLevel();
+            sendMessage("Testing Built in Microphone");
+            mCurrentTest = 1;
+            mFreqAverageBuiltIn.reset();
+            mSPlayer.setBalance(0.5f);
+            play();
+
+            mCurrentTest = -1;
+            sendMessage("Testing Completed");
+
+            Message msg2 = Message.obtain();
+            msg2.what = TEST1_ENDED;
+            mMessageHandler.sendMessage(msg2);
+        }
+
+        private void play() {
+            startRecording();
+            mSPlayer.play(true);
+
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+                //restore interrupted status
+                Thread.currentThread().interrupt();
+            }
+
+            mSPlayer.play(false);
+            stopRecording();
+        }
+
+        private void sendMessage(String str) {
+            Message msg = Message.obtain();
+            msg.what = TEST1_MESSAGE;
+            msg.obj = str;
+            mMessageHandler.sendMessage(msg);
+        }
+    };
+
+    /**
+     *  Start the loopback audio test
+     */
+    private void startTest2() {
+        if (mTestThread != null && !mTestThread.isAlive()) {
+            mTestThread = null; //kill it.
+        }
+
+        if (mTestThread == null) {
+            Log.v(TAG,"Executing test2 Thread");
+            mTestThread = new Thread(mTest2Runnable);
+            //getPassButton().setEnabled(false);
+            if (!mSPlayer.isAlive())
+                mSPlayer.start();
+            mTestThread.start();
+        } else {
+            Log.v(TAG,"test Thread already running.");
+        }
+    }
+
+    Runnable mTest2Runnable = new Runnable() {
+        public void run() {
+            Message msg = Message.obtain();
+            msg.what = TEST_STARTED;
+            mMessageHandler.sendMessage(msg);
+
+            sendMessage("Testing Reference USB Microphone");
+            mCurrentTest = 2;
+            mFreqAverageReference.reset();
+            mSPlayer.setBalance(0.5f);
+            play();
+
+            mCurrentTest = -1;
+            sendMessage("Testing Completed");
+
+            Message msg2 = Message.obtain();
+            msg2.what = TEST_ENDED;
+            mMessageHandler.sendMessage(msg2);
+        }
+
+        private void play() {
+            startRecording();
+            mSPlayer.play(true);
+
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+                //restore interrupted status
+                Thread.currentThread().interrupt();
+            }
+
+            mSPlayer.play(false);
+            stopRecording();
+        }
+
+        private void sendMessage(String str) {
+            Message msg = Message.obtain();
+            msg.what = TEST_MESSAGE;
+            msg.obj = str;
+            mMessageHandler.sendMessage(msg);
+        }
+    };
+
+    private Handler mMessageHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+            case TEST_STARTED:
+                showWait(true);
+                getPassButton().setEnabled(false);
+                break;
+            case TEST_ENDED:
+                showWait(false);
+                computeTest2Results();
+                break;
+            case TEST1_MESSAGE: {
+                    String str = (String)msg.obj;
+                    if (str != null) {
+                        mTest1Result.setText(str);
+                    }
+                }
+                break;
+            case TEST1_ENDED:
+                showWait(false);
+                computeTest1Results();
+                break;
+            case TEST_MESSAGE: {
+                    String str = (String)msg.obj;
+                    if (str != null) {
+                        mTest2Result.setText(str);
+                    }
+                }
+                break;
+            default:
+                Log.e(TAG, String.format("Unknown message: %d", msg.what));
+            }
+        }
+    };
+
+    private class Results {
+        private String mLabel;
+        public double[] mValuesLog;
+        int[] mPointsPerBand = new int[mBands];
+        double[] mAverageEnergyPerBand = new double[mBands];
+        int[] mInBoundPointsPerBand = new int[mBands];
+        public boolean mIsBaseMeasurement = false;
+        public Results(String label) {
+            mLabel = label;
+        }
+
+        //append results
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(String.format("Channel %s\n", mLabel));
+            sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"FAILED") +
+                    (mIsBaseMeasurement ? " (Base Meas.)" : "") + "\n");
+            for (int b = 0; b < mBands; b++) {
+                double percent = 0;
+                if (mPointsPerBand[b] > 0) {
+                    percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
+                }
+                sb.append(String.format(
+                        " Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
+                        b, mAverageEnergyPerBand[b],
+                        mInBoundPointsPerBand[b],
+                        mPointsPerBand[b],
+                        percent,
+                        (testInBand(b) ? "OK" : "FAILED")));
+            }
+            return sb.toString();
+        }
+
+        public boolean testLevel() {
+            if (mIsBaseMeasurement && mAverageEnergyPerBand[1] <= MAX_ENERGY_BAND_1_BASE) {
+                return true;
+            } else if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
+                return true;
+            }
+            return false;
+        }
+
+        public boolean testInBand(int b) {
+            if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
+                if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
+                    MIN_FRACTION_POINTS_IN_BAND) {
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean testAll() {
+            if (!testLevel()) {
+                return false;
+            }
+            for (int b = 0; b < mBands; b++) {
+                if (!testInBand(b)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+
+    /**
+     * compute test1 results
+     */
+    private void computeTest1Results() {
+
+        Results resultsBase = new Results("Base");
+        if (computeResultsForVector(mFreqAverageBase, resultsBase, true, baseBandSpecsArray)) {
+            appendResultsToScreen(resultsBase.toString(), mTest1Result);
+            recordTestResults(resultsBase);
+        }
+
+        Results resultsBuiltIn = new Results("BuiltIn");
+        if (computeResultsForVector(mFreqAverageBuiltIn, resultsBuiltIn, false, bandSpecsArray)) {
+            appendResultsToScreen(resultsBuiltIn.toString(), mTest1Result);
+            recordTestResults(resultsBuiltIn);
+        }
+
+        //tell user to connect USB Microphone
+        appendResultsToScreen("\n\n" +
+                getResources().getText(R.string.audio_frequency_mic_connect_mic), mTest1Result);
+        enableLayout(mLayoutTest2a, true);
+    }
+
+    /**
+     * compute test results
+     */
+    private void computeTest2Results() {
+        Results resultsReference = new Results("Reference");
+        if (computeResultsForVector(mFreqAverageReference, resultsReference,
+                false, bandSpecsArray)) {
+            appendResultsToScreen(resultsReference.toString(),mTest2Result);
+            recordTestResults(resultsReference);
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    private boolean computeResultsForVector(VectorAverage freqAverage, Results results,
+            boolean isBase, AudioBandSpecs[] bandSpecs) {
+
+        results.mIsBaseMeasurement = isBase;
+        int points = freqAverage.getSize();
+        if (points > 0) {
+            //compute vector in db
+            double[] values = new double[points];
+            freqAverage.getData(values, false);
+            results.mValuesLog = new double[points];
+            for (int i = 0; i < points; i++) {
+                results.mValuesLog[i] = 20 * Math.log10(values[i]);
+            }
+
+            int currentBand = 0;
+            for (int i = 0; i < points; i++) {
+                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+                if (freq > bandSpecs[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecs[currentBand].mFreqStart) {
+                    results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+                    results.mPointsPerBand[currentBand]++;
+                }
+            }
+
+            for (int b = 0; b < mBands; b++) {
+                if (results.mPointsPerBand[b] > 0) {
+                    results.mAverageEnergyPerBand[b] =
+                            results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+                }
+            }
+
+            //set offset relative to band 1 level
+            for (int b = 0; b < mBands; b++) {
+                bandSpecs[b].setOffset(results.mAverageEnergyPerBand[1]);
+            }
+
+            //test points in band.
+            currentBand = 0;
+            for (int i = 0; i < points; i++) {
+                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+                if (freq >  bandSpecs[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecs[currentBand].mFreqStart) {
+                    double value = results.mValuesLog[i];
+                    if (bandSpecs[currentBand].isInBounds(freq, value)) {
+                        results.mInBoundPointsPerBand[currentBand]++;
+                    }
+                }
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    //append results
+    private void appendResultsToScreen(String str, TextView text) {
+        String currentText = text.getText().toString();
+        text.setText(currentText + "\n" + str);
+    }
+
+    /**
+     * Store test results in log
+     */
+    private void recordTestResults(Results results) {
+        String channelLabel = "channel_" + results.mLabel;
+
+        for (int b = 0; b < mBands; b++) {
+            String bandLabel = String.format(channelLabel + "_%d", b);
+            getReportLog().addValue(
+                    bandLabel + "_Level",
+                    results.mAverageEnergyPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.NONE);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointsinbound",
+                    results.mInBoundPointsPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.COUNT);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointstotal",
+                    results.mPointsPerBand[b],
+                    ResultType.NEUTRAL,
+                    ResultUnit.COUNT);
+        }
+
+        getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
+                results.mValuesLog,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        Log.v(TAG, "Results Recorded");
+    }
+
+    private void startRecording() {
+        synchronized (mRecordingLock) {
+            mIsRecording = true;
+        }
+
+        boolean successful = initRecord();
+        if (successful) {
+            startRecordingForReal();
+        } else {
+            Log.v(TAG, "Recorder initialization error.");
+            synchronized (mRecordingLock) {
+                mIsRecording = false;
+            }
+        }
+    }
+
+    private void startRecordingForReal() {
+        // start streaming
+        if (mRecordThread == null) {
+            mRecordThread = new Thread(AudioFrequencyMicActivity.this);
+            mRecordThread.setName("FrequencyAnalyzerThread");
+        }
+        if (!mRecordThread.isAlive()) {
+            mRecordThread.start();
+        }
+
+        mPipe.flush();
+
+        long startTime = SystemClock.uptimeMillis();
+        mRecorder.startRecording();
+        if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+            stopRecording();
+            return;
+        }
+        Log.v(TAG, "Start time: " + (long) (SystemClock.uptimeMillis() - startTime) + " ms");
+    }
+
+    private void stopRecording() {
+        synchronized (mRecordingLock) {
+            stopRecordingForReal();
+            mIsRecording = false;
+        }
+    }
+
+    private void stopRecordingForReal() {
+
+        // stop streaming
+        Thread zeThread = mRecordThread;
+        mRecordThread = null;
+        if (zeThread != null) {
+            zeThread.interrupt();
+            try {
+                zeThread.join();
+            } catch(InterruptedException e) {
+                //restore interrupted status of recording thread
+                zeThread.interrupt();
+            }
+        }
+         // release recording resources
+        if (mRecorder != null) {
+            mRecorder.stop();
+            mRecorder.release();
+            mRecorder = null;
+        }
+    }
+
+    private boolean initRecord() {
+        int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
+                mChannelConfig, mAudioFormat);
+        Log.v(TAG,"FrequencyAnalyzer: min buff size = " + minRecordBuffSizeInBytes + " bytes");
+        if (minRecordBuffSizeInBytes <= 0) {
+            return false;
+        }
+
+        mMinRecordBufferSizeInSamples = minRecordBuffSizeInBytes / 2;
+        // allocate the byte array to read the audio data
+
+        mAudioShortArray = new short[mMinRecordBufferSizeInSamples];
+
+        Log.v(TAG, "Initiating record:");
+        Log.v(TAG, "      using source " + mSelectedRecordSource);
+        Log.v(TAG, "      at " + mSamplingRate + "Hz");
+
+        try {
+            mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate,
+                    mChannelConfig, mAudioFormat, 2 * minRecordBuffSizeInBytes);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
+            mRecorder.release();
+            mRecorder = null;
+            return false;
+        }
+        mRecorder.setRecordPositionUpdateListener(this);
+        mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
+        return true;
+    }
+
+    // ---------------------------------------------------------
+    // Implementation of AudioRecord.OnPeriodicNotificationListener
+    // --------------------
+    public void onPeriodicNotification(AudioRecord recorder) {
+        int samplesAvailable = mPipe.availableToRead();
+        int samplesNeeded = mBlockSizeSamples;
+        if (samplesAvailable >= samplesNeeded) {
+            mPipe.read(mAudioShortArray2, 0, samplesNeeded);
+
+            //compute stuff.
+            int clipcount = 0;
+            double sum = 0;
+            double maxabs = 0;
+            int i;
+
+            for (i = 0; i < samplesNeeded; i++) {
+                double value = mAudioShortArray2[i] / MAX_VAL;
+                double valueabs = Math.abs(value);
+
+                if (valueabs > maxabs) {
+                    maxabs = valueabs;
+                }
+
+                if (valueabs > CLIP_LEVEL) {
+                    clipcount++;
+                }
+
+                sum += value * value;
+                //fft stuff
+                mData.mData[i] = value;
+            }
+
+            //for the current frame, compute FFT and send to the viewer.
+
+            //apply window and pack as complex for now.
+            DspBufferMath.mult(mData, mData, mWindow.mBuffer);
+            DspBufferMath.set(mC, mData);
+            mFftServer.fft(mC, 1);
+
+            double[] halfMagnitude = new double[mBlockSizeSamples / 2];
+            for (i = 0; i < mBlockSizeSamples / 2; i++) {
+                halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
+            }
+
+            mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
+
+            switch(mCurrentTest) {
+                case 0:
+                    mFreqAverageBase.setData(halfMagnitude, false);
+                    break;
+                case 1:
+                    mFreqAverageBuiltIn.setData(halfMagnitude, false);
+                    break;
+                case 2:
+                    mFreqAverageReference.setData(halfMagnitude, false);
+                    break;
+            }
+        }
+    }
+
+    public void onMarkerReached(AudioRecord track) {
+    }
+
+    // ---------------------------------------------------------
+    // Implementation of Runnable for the audio recording + playback
+    // --------------------
+    public void run() {
+        Thread thisThread = Thread.currentThread();
+        while (!thisThread.isInterrupted()) {
+            // read from native recorder
+            int nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBufferSizeInSamples);
+            if (nSamplesRead > 0) {
+                mPipe.write(mAudioShortArray, 0, nSamplesRead);
+            }
+        }
+    }
+
+    private void testSpeakersReady() {
+        boolean isUsbConnected =
+                UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        if (isUsbConnected) {
+            mSpeakerReadyText.setText(" USB device detected, please remove it");
+            enableLayout(mLayoutTest1, false);
+            //fail
+        } else {
+            mSpeakerReadyText.setText(" No USB device detected. OK");
+            enableLayout(mLayoutTest1, true);
+        }
+    }
+
+    private void testUSB() {
+        boolean isConnected = UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        mUsbDevicesInfo = UsbMicrophoneTester.getUSBDeviceListString(getApplicationContext());
+
+        if (isConnected) {
+            mUsbStatusText.setText(
+                    getResources().getText(R.string.audio_frequency_mic_mic_ready_text));
+            enableLayout(mLayoutTest2b, true);
+        } else {
+            mUsbStatusText.setText(
+                    getResources().getText(R.string.audio_frequency_mic_mic_not_ready_text));
+            enableLayout(mLayoutTest2b, false);
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
new file mode 100644
index 0000000..f9334b3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
@@ -0,0 +1,732 @@
+/*
+ * 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.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.wavelib.*;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.SeekBar;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+
+/**
+ * Tests Audio Device roundtrip latency by using a loopback plug.
+ */
+public class AudioFrequencySpeakerActivity extends PassFailButtons.Activity implements Runnable,
+    AudioRecord.OnRecordPositionUpdateListener {
+    private static final String TAG = "AudioFrequencySpeakerActivity";
+
+    static final int TEST_STARTED = 900;
+    static final int TEST_ENDED = 901;
+    static final int TEST_MESSAGE = 902;
+    static final double MIN_ENERGY_BAND_1 = -50.0;          //dB Full Scale
+    static final double MAX_ENERGY_BAND_1_BASE = -60.0;     //dB Full Scale
+    static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+
+    final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+    Context mContext;
+
+    Button mLoopbackPlugReady;          //user signal to have connected USB Microphone
+    Button mTestButton;                 //user to start test
+    String mUsbDevicesInfo;             //usb device info for report
+    LinearLayout mLinearLayout;
+    TextView mResultText;
+    TextView mUsbStatusText;
+    ProgressBar mProgressBar;
+
+    private boolean mIsRecording = false;
+    private final Object mRecordingLock = new Object();
+    private AudioRecord mRecorder;
+    private int mMinRecordBufferSizeInSamples = 0;
+    private short[] mAudioShortArray;
+    private short[] mAudioShortArray2;
+
+    private final int mBlockSizeSamples = 1024;
+    private final int mSamplingRate = 48000;
+    private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+    private final int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;
+    private final int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    private Thread mRecordThread;
+    private boolean mRecordThreadShutdown = false;
+
+    PipeShort mPipe = new PipeShort(65536);
+    SoundPlayerObject mSPlayer;
+
+    private DspBufferComplex mC;
+    private DspBufferDouble mData;
+
+    private DspWindow mWindow;
+    private DspFftServer mFftServer;
+    private VectorAverage mFreqAverageMain = new VectorAverage();
+
+    private VectorAverage mFreqAverageBase = new VectorAverage();
+    private VectorAverage mFreqAverageLeft = new VectorAverage();
+    private VectorAverage mFreqAverageRight = new VectorAverage();
+
+    private int mCurrentTest = -1;
+    int mBands = 4;
+    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
+    AudioBandSpecs[] baseBandSpecsArray = new AudioBandSpecs[mBands];
+
+    int mMaxLevel;
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+            case R.id.audio_frequency_speaker_mic_ready_btn:
+                testUSB();
+                break;
+            case R.id.audio_frequency_speaker_test_btn:
+                startAudioTest();
+                break;
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_frequency_speaker_activity);
+
+        mContext = this;
+
+        mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_speaker_mic_ready_btn);
+        mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+        mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_speaker_layout);
+        mUsbStatusText = (TextView)findViewById(R.id.audio_frequency_speaker_usb_status);
+        mTestButton = (Button)findViewById(R.id.audio_frequency_speaker_test_btn);
+        mTestButton.setOnClickListener(mBtnClickListener);
+        mResultText = (TextView)findViewById(R.id.audio_frequency_speaker_results_text);
+        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_speaker_progress_bar);
+        showWait(false);
+        enableLayout(false);         //disabled all content
+
+        mSPlayer = new SoundPlayerObject();
+        mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.stereo_mono_white_noise_48);
+        mSPlayer.setBalance(0.5f);
+
+        //Init FFT stuff
+        mAudioShortArray2 = new short[mBlockSizeSamples*2];
+        mData = new DspBufferDouble(mBlockSizeSamples);
+        mC = new DspBufferComplex(mBlockSizeSamples);
+        mFftServer = new DspFftServer(mBlockSizeSamples);
+
+        int overlap = mBlockSizeSamples / 2;
+
+        mWindow = new DspWindow(DspWindow.WINDOW_HANNING, mBlockSizeSamples, overlap);
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_frequency_speaker_test,
+                R.string.audio_frequency_speaker_info, -1);
+
+        //Init bands for Left/Right test
+        bandSpecsArray[0] = new AudioBandSpecs(
+                50, 500,        /* frequency start,stop */
+                -20.0, -50,     /* start top,bottom value */
+                4.0, -4.0       /* stop top,bottom value */);
+
+        bandSpecsArray[1] = new AudioBandSpecs(
+                500,4000,       /* frequency start,stop */
+                4.0, -4.0,      /* start top,bottom value */
+                4.0, -4.0        /* stop top,bottom value */);
+
+        bandSpecsArray[2] = new AudioBandSpecs(
+                4000, 12000,    /* frequency start,stop */
+                4.0, -4.0,      /* start top,bottom value */
+                5.0, -5.0       /* stop top,bottom value */);
+
+        bandSpecsArray[3] = new AudioBandSpecs(
+                12000, 20000,   /* frequency start,stop */
+                5.0, -5.0,      /* start top,bottom value */
+                5.0, -30.0      /* stop top,bottom value */);
+
+        //Init base bands for silence
+        baseBandSpecsArray[0] = new AudioBandSpecs(
+                50, 500,        /* frequency start,stop */
+                40.0, -50.0,     /* start top,bottom value */
+                5.0, -50.0       /* stop top,bottom value */);
+
+        baseBandSpecsArray[1] = new AudioBandSpecs(
+                500,4000,       /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0        /* stop top,bottom value */);
+
+        baseBandSpecsArray[2] = new AudioBandSpecs(
+                4000, 12000,    /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0       /* stop top,bottom value */);
+
+        baseBandSpecsArray[3] = new AudioBandSpecs(
+                12000, 20000,   /* frequency start,stop */
+                5.0, -50.0,      /* start top,bottom value */
+                5.0, -50.0      /* stop top,bottom value */);
+
+    }
+
+    /**
+     * enable test ui elements
+     */
+    private void enableLayout(boolean enable) {
+        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+            View view = mLinearLayout.getChildAt(i);
+            view.setEnabled(enable);
+        }
+    }
+
+    /**
+     * show active progress bar
+     */
+    private void showWait(boolean show) {
+        if (show) {
+            mProgressBar.setVisibility(View.VISIBLE);
+        } else {
+            mProgressBar.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    private void setMaxLevel() {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        mMaxLevel = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(mMaxLevel), 0);
+    }
+
+    private void setMinLevel() {
+        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+        am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
+    }
+
+    /**
+     *  Start the loopback audio test
+     */
+    private void startAudioTest() {
+        if (mTestThread != null && !mTestThread.isAlive()) {
+            mTestThread = null; //kill it.
+        }
+
+        if (mTestThread == null) {
+            Log.v(TAG,"Executing test Thread");
+            mTestThread = new Thread(mPlayRunnable);
+            getPassButton().setEnabled(false);
+            if (!mSPlayer.isAlive())
+                mSPlayer.start();
+            mTestThread.start();
+        } else {
+            Log.v(TAG,"test Thread already running.");
+        }
+    }
+
+    Thread mTestThread;
+    Runnable mPlayRunnable = new Runnable() {
+        public void run() {
+            Message msg = Message.obtain();
+            msg.what = TEST_STARTED;
+            mMessageHandler.sendMessage(msg);
+
+            setMinLevel();
+            sendMessage("Testing Background Environment");
+            mCurrentTest = 0;
+            mSPlayer.setBalance(0.5f);
+            mFreqAverageBase.reset();
+            play();
+
+            setMaxLevel();
+            sendMessage("Testing Left Capture");
+            mCurrentTest = 1;
+            mFreqAverageLeft.reset();
+            mSPlayer.setBalance(0.0f);
+            play();
+
+            sendMessage("Testing Right Capture");
+            mCurrentTest = 2;
+            mFreqAverageRight.reset();
+            mSPlayer.setBalance(1.0f);
+            play();
+
+            mCurrentTest = -1;
+            sendMessage("Testing Completed");
+
+            Message msg2 = Message.obtain();
+            msg2.what = TEST_ENDED;
+            mMessageHandler.sendMessage(msg2);
+        }
+
+        private void play() {
+            startRecording();
+            mSPlayer.play(true);
+
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+
+            mSPlayer.play(false);
+            stopRecording();
+        }
+
+        private void sendMessage(String str) {
+            Message msg = Message.obtain();
+            msg.what = TEST_MESSAGE;
+            msg.obj = str;
+            mMessageHandler.sendMessage(msg);
+        }
+    };
+
+    private Handler mMessageHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            super.handleMessage(msg);
+            switch (msg.what) {
+            case TEST_STARTED:
+                showWait(true);
+                getPassButton().setEnabled(false);
+                break;
+            case TEST_ENDED:
+                showWait(false);
+                computeResults();
+                break;
+            case TEST_MESSAGE:
+                String str = (String)msg.obj;
+                if (str != null) {
+                    mResultText.setText(str);
+                }
+                break;
+            default:
+                Log.e(TAG, String.format("Unknown message: %d", msg.what));
+            }
+        }
+    };
+
+    private class Results {
+        private String mLabel;
+        public double[] mValuesLog;
+        int[] mPointsPerBand = new int[mBands];
+        double[] mAverageEnergyPerBand = new double[mBands];
+        int[] mInBoundPointsPerBand = new int[mBands];
+        public boolean mIsBaseMeasurement = false;
+        public Results(String label) {
+            mLabel = label;
+        }
+
+        //append results
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(String.format("Channel %s\n", mLabel));
+            sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"FAILED") +
+                    (mIsBaseMeasurement ? " (Base Meas.)" : "") + "\n");
+            for (int b = 0; b < mBands; b++) {
+                double percent = 0;
+                if (mPointsPerBand[b] > 0) {
+                    percent = 100.0 * (double)mInBoundPointsPerBand[b] / mPointsPerBand[b];
+                }
+                sb.append(String.format(
+                        " Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
+                        b, mAverageEnergyPerBand[b],
+                        mInBoundPointsPerBand[b],
+                        mPointsPerBand[b],
+                        percent,
+                        (testInBand(b) ? "OK" : "FAILED")));
+            }
+            return sb.toString();
+        }
+
+        public boolean testLevel() {
+            if (mIsBaseMeasurement && mAverageEnergyPerBand[1] <= MAX_ENERGY_BAND_1_BASE) {
+                return true;
+            } else if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
+                return true;
+            }
+            return false;
+        }
+
+        public boolean testInBand(int b) {
+            if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
+                if ((double)mInBoundPointsPerBand[b] / mPointsPerBand[b] >
+                MIN_FRACTION_POINTS_IN_BAND)
+                    return true;
+            }
+            return false;
+        }
+
+        public boolean testAll() {
+            if (!testLevel()) {
+                return false;
+            }
+            for (int b = 0; b < mBands; b++) {
+                if (!testInBand(b)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
+    /**
+     * compute test results
+     */
+    private void computeResults() {
+
+        Results resultsBase = new Results("Base");
+        computeResultsForVector(mFreqAverageBase, resultsBase, true, baseBandSpecsArray);
+        Results resultsLeft = new Results("Left");
+        computeResultsForVector(mFreqAverageLeft, resultsLeft, false, bandSpecsArray);
+        Results resultsRight = new Results("Right");
+        computeResultsForVector(mFreqAverageRight, resultsRight, false, bandSpecsArray);
+        if (resultsLeft.testAll() && resultsRight.testAll() && resultsBase.testAll()) {
+            //enable button
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    private void computeResultsForVector(VectorAverage freqAverage,Results results, boolean isBase,
+            AudioBandSpecs[] bandSpecs) {
+
+        results.mIsBaseMeasurement = isBase;
+        int points = freqAverage.getSize();
+        if (points > 0) {
+            //compute vector in db
+            double[] values = new double[points];
+            freqAverage.getData(values, false);
+            results.mValuesLog = new double[points];
+            for (int i = 0; i < points; i++) {
+                results.mValuesLog[i] = 20 * Math.log10(values[i]);
+            }
+
+            int currentBand = 0;
+            for (int i = 0; i < points; i++) {
+                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+                if (freq > bandSpecs[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecs[currentBand].mFreqStart) {
+                    results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+                    results.mPointsPerBand[currentBand]++;
+                }
+            }
+
+            for (int b = 0; b < mBands; b++) {
+                if (results.mPointsPerBand[b] > 0) {
+                    results.mAverageEnergyPerBand[b] =
+                            results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+                }
+            }
+
+            //set offset relative to band 1 level
+            for (int b = 0; b < mBands; b++) {
+                bandSpecs[b].setOffset(results.mAverageEnergyPerBand[1]);
+            }
+
+            //test points in band.
+            currentBand = 0;
+            for (int i = 0; i < points; i++) {
+                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+                if (freq >  bandSpecs[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecs[currentBand].mFreqStart) {
+                    double value = results.mValuesLog[i];
+                    if (bandSpecs[currentBand].isInBounds(freq, value)) {
+                        results.mInBoundPointsPerBand[currentBand]++;
+                    }
+                }
+            }
+
+            appendResultsToScreen(results.toString());
+            //store results
+            recordTestResults(results);
+        } else {
+            appendResultsToScreen("Failed testing channel " + results.mLabel);
+        }
+    }
+
+    //append results
+    private void appendResultsToScreen(String str) {
+        String currentText = mResultText.getText().toString();
+        mResultText.setText(currentText + "\n" + str);
+    }
+
+    /**
+     * Store test results in log
+     */
+    private void recordTestResults(Results results) {
+        String channelLabel = "channel_" + results.mLabel;
+
+        for (int b = 0; b < mBands; b++) {
+            String bandLabel = String.format(channelLabel + "_%d", b);
+            getReportLog().addValue(
+                    bandLabel + "_Level",
+                    results.mAverageEnergyPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.NONE);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointsinbound",
+                    results.mInBoundPointsPerBand[b],
+                    ResultType.HIGHER_BETTER,
+                    ResultUnit.COUNT);
+
+            getReportLog().addValue(
+                    bandLabel + "_pointstotal",
+                    results.mPointsPerBand[b],
+                    ResultType.NEUTRAL,
+                    ResultUnit.COUNT);
+        }
+
+        getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
+                results.mValuesLog,
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+
+        Log.v(TAG, "Results Recorded");
+    }
+
+    private void startRecording() {
+        synchronized (mRecordingLock) {
+            mIsRecording = true;
+        }
+
+        boolean successful = initRecord();
+        if (successful) {
+            startRecordingForReal();
+        } else {
+            Log.v(TAG, "Recorder initialization error.");
+            synchronized (mRecordingLock) {
+                mIsRecording = false;
+            }
+        }
+    }
+
+    private void startRecordingForReal() {
+        // start streaming
+        if (mRecordThread == null) {
+            mRecordThread = new Thread(AudioFrequencySpeakerActivity.this);
+            mRecordThread.setName("FrequencyAnalyzerThread");
+            mRecordThreadShutdown = false;
+        }
+        if (!mRecordThread.isAlive()) {
+            mRecordThread.start();
+        }
+
+        mPipe.flush();
+
+        long startTime = SystemClock.uptimeMillis();
+        mRecorder.startRecording();
+        if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+            stopRecording();
+            return;
+        }
+        Log.v(TAG, "Start time: " + (long) (SystemClock.uptimeMillis() - startTime) + " ms");
+    }
+
+    private void stopRecording() {
+        synchronized (mRecordingLock) {
+            stopRecordingForReal();
+            mIsRecording = false;
+        }
+    }
+
+    private void stopRecordingForReal() {
+
+        // stop streaming
+        Thread zeThread = mRecordThread;
+        mRecordThread = null;
+        mRecordThreadShutdown = true;
+        if (zeThread != null) {
+            zeThread.interrupt();
+            try {
+                zeThread.join();
+            } catch(InterruptedException e) {
+                Log.v(TAG,"Error shutting down recording thread " + e);
+                //we don't really care about this error, just logging it.
+            }
+        }
+         // release recording resources
+        if (mRecorder != null) {
+            mRecorder.stop();
+            mRecorder.release();
+            mRecorder = null;
+        }
+    }
+
+    private boolean initRecord() {
+        int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
+                mChannelConfig, mAudioFormat);
+        Log.v(TAG,"FrequencyAnalyzer: min buff size = " + minRecordBuffSizeInBytes + " bytes");
+        if (minRecordBuffSizeInBytes <= 0) {
+            return false;
+        }
+
+        mMinRecordBufferSizeInSamples = minRecordBuffSizeInBytes / 2;
+        // allocate the byte array to read the audio data
+
+        mAudioShortArray = new short[mMinRecordBufferSizeInSamples];
+
+        Log.v(TAG, "Initiating record:");
+        Log.v(TAG, "      using source " + mSelectedRecordSource);
+        Log.v(TAG, "      at " + mSamplingRate + "Hz");
+
+        try {
+            mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate,
+                    mChannelConfig, mAudioFormat, 2 * minRecordBuffSizeInBytes);
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+        if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
+            mRecorder.release();
+            mRecorder = null;
+            return false;
+        }
+        mRecorder.setRecordPositionUpdateListener(this);
+        mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
+        return true;
+    }
+
+    // ---------------------------------------------------------
+    // Implementation of AudioRecord.OnPeriodicNotificationListener
+    // --------------------
+    public void onPeriodicNotification(AudioRecord recorder) {
+        int samplesAvailable = mPipe.availableToRead();
+        int samplesNeeded = mBlockSizeSamples;
+        if (samplesAvailable >= samplesNeeded) {
+            mPipe.read(mAudioShortArray2, 0, samplesNeeded);
+
+            //compute stuff.
+            double maxval = Math.pow(2, 15);
+            int clipcount = 0;
+            double cliplevel = (maxval-10) / maxval;
+            double sum = 0;
+            double maxabs = 0;
+            int i;
+            int index = 0;
+
+            for (i = 0; i < samplesNeeded; i++) {
+                double value = mAudioShortArray2[i] / maxval;
+                double valueabs = Math.abs(value);
+
+                if (valueabs > maxabs) {
+                    maxabs = valueabs;
+                }
+
+                if (valueabs > cliplevel) {
+                    clipcount++;
+                }
+
+                sum += value * value;
+                //fft stuff
+                if (index < mBlockSizeSamples) {
+                    mData.mData[index] = value;
+                }
+                index++;
+            }
+
+            //for the current frame, compute FFT and send to the viewer.
+
+            //apply window and pack as complex for now.
+            DspBufferMath.mult(mData, mData, mWindow.mBuffer);
+            DspBufferMath.set(mC, mData);
+            mFftServer.fft(mC, 1);
+
+            double[] halfMagnitude = new double[mBlockSizeSamples / 2];
+            for (i = 0; i < mBlockSizeSamples / 2; i++) {
+                halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
+            }
+
+            mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
+
+            switch(mCurrentTest) {
+                case 0:
+                    mFreqAverageBase.setData(halfMagnitude, false);
+                    break;
+                case 1:
+                    mFreqAverageLeft.setData(halfMagnitude, false);
+                    break;
+                case 2:
+                    mFreqAverageRight.setData(halfMagnitude, false);
+                    break;
+            }
+        }
+    }
+
+    public void onMarkerReached(AudioRecord track) {
+    }
+
+    // ---------------------------------------------------------
+    // Implementation of Runnable for the audio recording + playback
+    // --------------------
+    public void run() {
+        int nSamplesRead = 0;
+
+        Thread thisThread = Thread.currentThread();
+        while (mRecordThread == thisThread && !mRecordThreadShutdown) {
+            // read from native recorder
+            nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBufferSizeInSamples);
+            if (nSamplesRead > 0) {
+                mPipe.write(mAudioShortArray, 0, nSamplesRead);
+            }
+        }
+    }
+
+    private void testUSB() {
+        boolean isConnected = UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        mUsbDevicesInfo = UsbMicrophoneTester.getUSBDeviceListString(getApplicationContext());
+
+        if (isConnected) {
+            mUsbStatusText.setText(
+                    getResources().getText(R.string.audio_frequency_speaker_mic_ready_text));
+            enableLayout(true);
+        } else {
+            mUsbStatusText.setText(
+                    getResources().getText(R.string.audio_frequency_speaker_mic_not_ready_text));
+            enableLayout(false);
+        }
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMicrophoneTester.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMicrophoneTester.java
new file mode 100644
index 0000000..c0b6b6a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/UsbMicrophoneTester.java
@@ -0,0 +1,67 @@
+/*
+ * 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.audio;
+
+import android.content.Context;
+
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+
+import java.util.HashMap;
+import java.util.Iterator;
+
+public class UsbMicrophoneTester {
+
+    public static String getUSBDeviceListString(Context context) {
+        UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+        StringBuilder sb = new StringBuilder();
+        HashMap<String, UsbDevice> devicelist = manager.getDeviceList();
+        for(UsbDevice usbDevice : devicelist.values()) {
+            sb.append("Model    : " + usbDevice.getDeviceName() + "\n");
+            sb.append(" Id      : " + usbDevice.getDeviceId() + "\n");
+            sb.append(" Class   : " + usbDevice.getDeviceClass() + "\n");
+            sb.append(" Prod.Id : " + usbDevice.getProductId() + "\n");
+            sb.append(" Vendor.Id : " + usbDevice.getVendorId() + "\n");
+            int iCount = usbDevice.getInterfaceCount();
+            for (int i = 0; i < iCount; i++) {
+                UsbInterface usbInterface = usbDevice.getInterface(i);
+                sb.append("    Interface " + i + " :\n");
+                sb.append("     Class: " + usbInterface.getInterfaceClass() + "\n");
+            }
+        }
+        return sb.toString();
+    }
+
+    public static boolean getIsMicrophoneConnected(Context context) {
+        UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
+        StringBuilder sb = new StringBuilder();
+        HashMap<String, UsbDevice> devicelist = manager.getDeviceList();
+        for(UsbDevice usbDevice : devicelist.values()) {
+            int iCount = usbDevice.getInterfaceCount();
+            for (int i = 0; i < iCount; i++) {
+                UsbInterface usbInterface = usbDevice.getInterface(i);
+                if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_AUDIO) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index 856b18d..0200a4f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -77,6 +77,7 @@
     private DialogTestListItem mCrossProfileVideoCaptureSupportTest;
     private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
     private TestListItem mKeyguardDisabledFeaturesTest;
+    private DialogTestListItem mDisableNfcBeamTest;
 
     public ByodFlowTestActivity() {
         super(R.layout.provisioning_byod,
@@ -350,6 +351,38 @@
                     .show();
         }
 
+        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
+            mDisableNfcBeamTest = new DialogTestListItem(this, R.string.provisioning_byod_nfc_beam,
+                    "BYOD_DisableNfcBeamTest",
+                    R.string.provisioning_byod_nfc_beam_allowed_instruction,
+                    new Intent(ByodHelperActivity.ACTION_TEST_NFC_BEAM)) {
+                @Override
+                public void performTest(final DialogTestListActivity activity) {
+                    activity.showManualTestDialog(mDisableNfcBeamTest,
+                            new DefaultTestCallback(mDisableNfcBeamTest) {
+                        @Override
+                        public void onPass() {
+                            // Start a second test with beam disallowed by policy.
+                            Intent testNfcBeamIntent = new Intent(
+                                    ByodHelperActivity.ACTION_TEST_NFC_BEAM);
+                            testNfcBeamIntent.putExtra(NfcTestActivity.EXTRA_DISALLOW_BY_POLICY,
+                                    true);
+                            DialogTestListItem disableNfcBeamTest2 =
+                                    new DialogTestListItem(activity,
+                                    R.string.provisioning_byod_nfc_beam,
+                                    "BYOD_DisableNfcBeamTest",
+                                    R.string.provisioning_byod_nfc_beam_disallowed_instruction,
+                                    testNfcBeamIntent);
+                            // The result should be reflected on the original test.
+                            activity.showManualTestDialog(disableNfcBeamTest2,
+                                    new DefaultTestCallback(mDisableNfcBeamTest));
+                        }
+                    });
+                }
+            };
+            adapter.add(mDisableNfcBeamTest);
+        }
+
         /* TODO: reinstate when bug b/20131958 is fixed
         if (canResolveIntent(ByodHelperActivity.getCaptureAudioIntent())) {
             // Capture audio intent can be resolved in primary profile, so test.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 09e6393..3fec414 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -71,6 +71,7 @@
             "com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES";
     public static final String ACTION_LOCKNOW =
             "com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW";
+    public static final String ACTION_TEST_NFC_BEAM = "com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM";
 
     public static final String EXTRA_PROVISIONED = "extra_provisioned";
     public static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
@@ -200,6 +201,12 @@
         } else if (ACTION_LOCKNOW.equals(action)) {
             mDevicePolicyManager.lockNow();
             setResult(RESULT_OK);
+        } else if (action.equals(ACTION_TEST_NFC_BEAM)) {
+            Intent testNfcBeamIntent = new Intent(this, NfcTestActivity.class);
+            testNfcBeamIntent.putExtras(intent);
+            startActivity(testNfcBeamIntent);
+            finish();
+            return;
         }
         // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
         finish();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index b18e816..008091b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -63,6 +63,7 @@
             filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_AUDIO);
             filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
             filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
+            filter.addAction(ByodHelperActivity.ACTION_TEST_NFC_BEAM);
             filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/NfcTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/NfcTestActivity.java
new file mode 100644
index 0000000..2f7619c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/NfcTestActivity.java
@@ -0,0 +1,158 @@
+/*
+ * 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.managedprovisioning;
+
+import android.app.Activity;
+import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.nfc.NfcAdapter;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.support.v4.content.FileProvider;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+public class NfcTestActivity extends Activity {
+    private static final String TAG = "NfcTestActivity";
+
+    /* package */ static final String EXTRA_DISALLOW_BY_POLICY = "disallowByPolicy";
+
+    private static final String NFC_BEAM_PACKAGE = "com.android.nfc";
+    private static final String NFC_BEAM_ACTIVITY = "com.android.nfc.BeamShareActivity";
+    private static final String SAMPLE_IMAGE_FILENAME = "image_to_share.jpg";
+    private static final String SAMPLE_IMAGE_CONTENT = "sample image";
+    private static final int MARGIN = 80;
+    private static final int TEXT_SIZE = 200;
+
+    private ComponentName mAdminReceiverComponent;
+    private DevicePolicyManager mDevicePolicyManager;
+    private UserManager mUserMangaer;
+    private NfcAdapter mNfcAdapter;
+    private boolean mDisallowByPolicy;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.byod_nfc_test_activity);
+
+        mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        mDevicePolicyManager = (DevicePolicyManager) getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        mUserMangaer = (UserManager) getSystemService(Context.USER_SERVICE);
+        mDisallowByPolicy = getIntent().getBooleanExtra(EXTRA_DISALLOW_BY_POLICY, false);
+        if (mDisallowByPolicy) {
+            mDevicePolicyManager.addUserRestriction(mAdminReceiverComponent,
+                    UserManager.DISALLOW_OUTGOING_BEAM);
+        }
+
+        final Uri uri = createUriForImage(SAMPLE_IMAGE_FILENAME, SAMPLE_IMAGE_CONTENT);
+        Uri[] uris = new Uri[] { uri };
+
+        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
+        mNfcAdapter.setBeamPushUris(uris, this);
+
+        findViewById(R.id.manual_beam_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                mNfcAdapter.invokeBeam(NfcTestActivity.this);
+            }
+        });
+        findViewById(R.id.intent_share_button).setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                Intent shareIntent = new Intent(Intent.ACTION_SEND);
+                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
+                shareIntent.setType("image/jpg");
+                shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                // Specify the package name of NfcBeamActivity so that the tester don't need to
+                // select the activity manually.
+                shareIntent.setClassName(NFC_BEAM_PACKAGE, NFC_BEAM_ACTIVITY);
+                try {
+                    startActivity(shareIntent);
+                } catch (ActivityNotFoundException e) {
+                    Toast.makeText(NfcTestActivity.this,
+                            R.string.provisioning_byod_cannot_resolve_beam_activity,
+                            Toast.LENGTH_SHORT).show();
+                    Log.e(TAG, "Nfc beam activity not found", e);
+                }
+            }
+        });
+    }
+
+    @Override
+    public void finish() {
+        if (mUserMangaer.hasUserRestriction(UserManager.DISALLOW_OUTGOING_BEAM)) {
+            mDevicePolicyManager.clearUserRestriction(mAdminReceiverComponent,
+                    UserManager.DISALLOW_OUTGOING_BEAM);
+        }
+        super.finish();
+    }
+
+    /**
+     * Creates a Bitmap image that contains red on white text with a specified margin.
+     * @param text Text to be displayed in the image.
+     * @return A Bitmap image with the above specification.
+     */
+    private Bitmap createSampleImage(String text) {
+        Paint paint = new Paint();
+        paint.setStyle(Paint.Style.FILL);
+        paint.setTextSize(TEXT_SIZE);
+        Rect rect = new Rect();
+        paint.getTextBounds(text, 0, text.length(), rect);
+        int w = 2 * MARGIN + rect.right - rect.left;
+        int h = 2 * MARGIN + rect.bottom - rect.top;
+        Bitmap dest = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas();
+        canvas.setBitmap(dest);
+        paint.setColor(Color.WHITE);
+        canvas.drawPaint(paint);
+        paint.setColor(Color.RED);
+        canvas.drawText(text, MARGIN - rect.left, MARGIN - rect.top, paint);
+        return dest;
+    }
+
+    private Uri createUriForImage(String name, String text) {
+        final File file = new File(getFilesDir() + File.separator + "images"
+                + File.separator + name);
+        file.getParentFile().mkdirs(); //if the folder doesn't exists it is created
+        try {
+            createSampleImage(text).compress(Bitmap.CompressFormat.JPEG, 100,
+                    new FileOutputStream(file));
+        } catch (FileNotFoundException e) {
+            return null;
+        }
+        return FileProvider.getUriForFile(this,
+                "com.android.cts.verifier.managedprovisioning.fileprovider", file);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/ScreenLockBoundKeysTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/ScreenLockBoundKeysTest.java
index 618b99a..863488b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/ScreenLockBoundKeysTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/ScreenLockBoundKeysTest.java
@@ -53,7 +53,7 @@
 public class ScreenLockBoundKeysTest extends PassFailButtons.Activity {
 
     /** Alias for our key in the Android Key Store. */
-    private static final String KEY_NAME = "my_key";
+    private static final String KEY_NAME = "my_lock_key";
     private static final byte[] SECRET_BYTE_ARRAY = new byte[] {1, 2, 3, 4, 5, 6};
     private static final int AUTHENTICATION_DURATION_SECONDS = 5;
     private static final int CONFIRM_CREDENTIALS_REQUEST_CODE = 1;
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
index 76d90cc..70414ca 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
@@ -292,13 +292,17 @@
     }
 
     private LocalVolumeInfo getAdoptionVolume() throws Exception {
-        final String[] lines = getDevice().executeShellCommand("sm list-volumes private")
-                .split("\n");
-        for (String line : lines) {
-            final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
-            if (!"private".equals(info.volId)) {
-                return info;
+        String[] lines = null;
+        int attempt = 0;
+        while (attempt++ < 5) {
+            lines = getDevice().executeShellCommand("sm list-volumes private").split("\n");
+            for (String line : lines) {
+                final LocalVolumeInfo info = new LocalVolumeInfo(line.trim());
+                if (!"private".equals(info.volId) && "mounted".equals(info.state)) {
+                    return info;
+                }
             }
+            Thread.sleep(1000);
         }
         throw new AssertionError("Expected private volume; found " + Arrays.toString(lines));
     }
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index ee0511d..78da8ac 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -25,6 +25,7 @@
 
 import java.io.BufferedReader;
 import java.io.File;
+import java.io.Reader;
 import java.io.StringReader;
 import java.util.Arrays;
 import java.util.HashSet;
@@ -37,11 +38,86 @@
  * Test to check that atrace is usable, to enable usage of systrace.
  */
 public class AtraceHostTest extends DeviceTestCase implements IBuildReceiver {
-    private static final String TAG = "AtraceHostTest";
-
     private static final String TEST_APK = "CtsAtraceTestApp.apk";
     private static final String TEST_PKG = "com.android.cts.atracetestapp";
 
+    private interface FtraceEntryCallback {
+        void onTraceEntry(String threadName, int pid, int tid, String eventType, String args);
+        void onFinished();
+    }
+
+    /**
+     * Helper for parsing ftrace data.
+     * Regexs copied from (and should be kept in sync with) ftrace importer in catapult.
+     */
+    private static class FtraceParser {
+        // Matches the trace record in 3.2 and later with the print-tgid option:
+        //          <idle>-0    0 [001] d...  1.23: sched_switch
+        private static final Pattern sLineWithTgid = Pattern.compile(
+                "^\\s*(.+)-(\\d+)\\s+\\(\\s*(\\d+|-+)\\)\\s\\[(\\d+)\\]"
+                + "\\s+[dX.][N.][Hhs.][0-9a-f.]"
+                + "\\s+(\\d+\\.\\d+):\\s+(\\S+):\\s(.*)");
+
+        // Matches the default trace record in 3.2 and later (includes irq-info):
+        //          <idle>-0     [001] d...  1.23: sched_switch
+        private static final Pattern sLineWithIrqInfo = Pattern.compile(
+                "^\\s*(.+)-(\\d+)\\s+\\[(\\d+)\\]"
+                + "\\s+[dX.][N.][Hhs.][0-9a-f.]"
+                + "\\s+(\\d+\\.\\d+):\\s+(\\S+):\\s(.*)$");
+
+        // Matches the default trace record pre-3.2:
+        //          <idle>-0     [001]  1.23: sched_switch
+        private static final Pattern sLineLegacy = Pattern.compile(
+                "^\\s*(.+)-(\\d+)\\s+\\[(\\d+)\\]\\s*(\\d+\\.\\d+):\\s+(\\S+):\\s(.*)");
+        private static void parseLine(String line, FtraceEntryCallback callback) {
+            Matcher m = sLineWithTgid.matcher(line);
+            if (m.matches()) {
+                callback.onTraceEntry(
+                        /*threadname*/ m.group(1),
+                        /*pid*/ m.group(3).startsWith("-") ? -1 : Integer.parseInt(m.group(3)),
+                        /*tid*/ Integer.parseInt(m.group(2)),
+                        /*eventName*/ m.group(6),
+                        /*details*/ m.group(7));
+                return;
+            }
+
+            m = sLineWithIrqInfo.matcher(line);
+            if (m.matches()) {
+                callback.onTraceEntry(
+                        /*threadname*/ m.group(1),
+                        /*pid*/ -1,
+                        /*tid*/ Integer.parseInt(m.group(2)),
+                        /*eventName*/ m.group(5),
+                        /*details*/ m.group(6));
+                return;
+            }
+
+            m = sLineLegacy.matcher(line);
+            if (m.matches()) {
+                callback.onTraceEntry(
+                        /*threadname*/ m.group(1),
+                        /*pid*/ -1,
+                        /*tid*/ Integer.parseInt(m.group(2)),
+                        /*eventName*/ m.group(5),
+                        /*details*/ m.group(6));
+                return;
+            }
+            System.err.println("line doesn't match: " + line);
+        }
+
+        private static void parse(Reader reader, FtraceEntryCallback callback) throws Exception {
+            try {
+                BufferedReader bufferedReader = new BufferedReader(reader);
+                String line;
+                while ((line = bufferedReader.readLine()) != null) {
+                    FtraceParser.parseLine(line, callback);
+                }
+            } finally {
+                callback.onFinished();
+            }
+        }
+    }
+
     private CtsBuildHelper mCtsBuild;
 
     /**
@@ -109,15 +185,12 @@
 
         if (!requiredCategories.isEmpty()) {
             for (String missingCategory : requiredCategories) {
-                Log.d(TAG, "missing category: " + missingCategory);
+                System.err.println("missing category: " + missingCategory);
             }
             fail("Expected categories missing from atrace");
         }
     }
 
-
-    private static final String TRACE_MARKER_REGEX =
-            "\\s*(\\S+)-(\\d+)\\s+\\(\\s*(\\d+)\\).*tracing_mark_write:\\s*(B|E)(.*)";
     /**
      * Tests that atrace captures app launch, including app level tracing
      */
@@ -131,20 +204,20 @@
             File testAppFile = mCtsBuild.getTestApp(TEST_APK);
             String installResult = getDevice().installPackage(testAppFile, false);
             assertNull(
-                    String.format("failed to install simple app. Reason: %s", installResult),
+                    String.format("failed to install atrace test app. Reason: %s", installResult),
                     installResult);
 
             // capture a launch of the app with async tracing
             String atraceArgs = "-a " + TEST_PKG + " -c -b 16000 view"; // TODO: zipping
             getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
             getDevice().executeShellCommand("atrace --async_start " + atraceArgs);
-            String start = getDevice().executeShellCommand("am start " + TEST_PKG);
+            getDevice().executeShellCommand("am start " + TEST_PKG);
             getDevice().executeShellCommand("sleep 1");
-            atraceOutput = getDevice().executeShellCommand("atrace --async_dump " + atraceArgs);
+            atraceOutput = getDevice().executeShellCommand("atrace --async_stop " + atraceArgs);
         } finally {
+            assertNotNull("unable to capture atrace output", atraceOutput);
             getDevice().uninstallPackage(TEST_PKG);
         }
-        assertNotNull(atraceOutput);
 
 
         // now parse the trace data (see external/chromium-trace/systrace.py)
@@ -153,81 +226,64 @@
         assertTrue(dataStart >= 0);
         String traceData = atraceOutput.substring(dataStart + MARKER.length());
 
-        /**
-         * Pattern that matches standard begin/end userspace tracing.
-         *
-         * Groups are:
-         * 1 - truncated thread name
-         * 2 - tid
-         * 3 - pid
-         * 4 - B/E
-         * 5 - ignored, for grouping
-         * 6 - if B, section title, else null
-         */
-        final Pattern beginEndPattern = Pattern.compile(
-                "\\s*(\\S+)-(\\d+)\\s+\\(\\s*(\\d+)\\).*tracing_mark_write:\\s*(B|E)(\\|\\d+\\|(.+))?");
+        FtraceEntryCallback callback = new FtraceEntryCallback() {
+            private int matches = 0;
+            private int nextSectionIndex = 0;
+            private int appPid = -1;
 
-        int appPid = -1;
-        String line;
+            // list of tags expected to be seen on app launch, in order.
+            private final String[] requiredSectionList = {
+                    "traceable-app-test-section",
+                    "inflate",
+                    "Choreographer#doFrame",
+                    "traversal",
+                    "measure",
+                    "layout",
+                    "draw",
+                    "Record View#draw()"
+            };
 
-        // list of tags expected to be seen on app launch, in order.
-        String[] requiredSectionList = {
-                "traceable-app-test-section",
-                "inflate",
-                "performTraversals",
-                "measure",
-                "layout",
-                "draw",
-                "Record View#draw()"
-        };
-        int nextSectionIndex = 0;
-        int matches = 0;
-        try (BufferedReader reader = new BufferedReader(new StringReader(traceData))) {
-            while ((line = reader.readLine()) != null) {
-                Matcher matcher = beginEndPattern.matcher(line);
-                if (matcher.find()) {
+            @Override
+            public void onTraceEntry(String truncatedThreadName, int pid, int tid,
+                    String eventName, String details) {
+                if (!"tracing_mark_write".equals(eventName)) {
+                    // not userspace trace, ignore
+                    return;
+                }
+
+                matches++;
+                assertNotNull(truncatedThreadName);
+                assertTrue(tid > 0);
+                if (TEST_PKG.endsWith(truncatedThreadName)) {
                     matches++;
 
-                    String truncatedThreadName = matcher.group(1);
-                    assertNotNull(truncatedThreadName);
-
-                    int tid = assertInt(matcher.group(2));
-                    assertTrue(tid > 0);
-                    int pid = assertInt(matcher.group(3));
-                    assertTrue(pid > 0);
-
-                    if (TEST_PKG.endsWith(truncatedThreadName)) {
-                        // should be something like "s.aptracetestapp" since beginning may be truncated
+                    if (pid >= 0) {
+                        // verify pid, if present
                         if (appPid == -1) {
                             appPid = pid;
                         } else {
                             assertEquals(appPid, pid);
                         }
+                    }
 
-                        if ("B".equals(matcher.group(4))) {
-                            String sectionTitle = matcher.group(6);
-                            if (nextSectionIndex < requiredSectionList.length
-                                    && requiredSectionList[nextSectionIndex].equals(sectionTitle)) {
-                                nextSectionIndex++;
-                            }
-                        }
+                    if (nextSectionIndex < requiredSectionList.length
+                            && details != null
+                            && details.startsWith("B|")
+                            && details.endsWith("|" + requiredSectionList[nextSectionIndex])) {
+                        nextSectionIndex++;
                     }
                 }
             }
-        }
-        assertTrue("Unable to parse any userspace sections from atrace output",
-                matches != 0);
-        assertEquals("Didn't see required list of traced sections, in order",
-                requiredSectionList.length, nextSectionIndex);
-    }
 
-    private static int assertInt(String input) {
-        try {
-            return Integer.parseInt(input);
-        } catch (NumberFormatException e) {
-            fail("Expected an integer but found \"" + input + "\"");
-            // Won't be hit, above throws AssertException
-            return -1;
-        }
+            @Override
+            public void onFinished() {
+                assertTrue("Unable to parse any userspace sections from atrace output",
+                        matches != 0);
+                assertEquals("Didn't see required list of traced sections, in order",
+                        requiredSectionList.length, nextSectionIndex);
+            }
+        };
+
+        FtraceParser.parse(new StringReader(traceData), callback);
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementTest.java
index c40539b..2d30ee3 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementTest.java
@@ -33,14 +33,13 @@
  * Fire up a remote unprivileged service and attempt to add/remove/list
  * accounts from it to verify the enforcement is in place.
  *
- * This test depend on MockAccountService, which provides authenticator of type
- * {@code com.android.cts.deviceandprofileowner.account.type}
+ * This test depend on {@link MockAccountService}, which provides authenticator of type
+ * {@link MockAccountService#ACCOUNT_TYPE}.
  */
 public class AccountManagementTest extends BaseDeviceAdminTest {
 
     // Account type for MockAccountAuthenticator
-    private final static String ACCOUNT_TYPE_1 =
-            "com.android.cts.deviceandprofileowner.account.type";
+    private final static String ACCOUNT_TYPE_1 = MockAccountAuthenticator.ACCOUNT_TYPE;
     private final static String ACCOUNT_TYPE_2 = "com.dummy.account";
     private final static Account ACCOUNT_0 = new Account("user0", ACCOUNT_TYPE_1);
     private final static Account ACCOUNT_1 = new Account("user1", ACCOUNT_TYPE_1);
@@ -52,13 +51,13 @@
         super.setUp();
         mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
         clearAllAccountManagementDisabled();
-        removeAllAccounts();
+        AccountUtilsTest.removeAllAccountsForType(mAccountManager, ACCOUNT_TYPE_1);
     }
 
     @Override
     protected void tearDown() throws Exception {
         clearAllAccountManagementDisabled();
-        removeAllAccounts();
+        AccountUtilsTest.removeAllAccountsForType(mAccountManager, ACCOUNT_TYPE_1);
         super.tearDown();
     }
 
@@ -165,15 +164,4 @@
         }
         assertEquals(0, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
     }
-
-    private void removeAllAccounts() throws OperationCanceledException, AuthenticatorException,
-            IOException {
-        for (Account account : mAccountManager.getAccountsByType(ACCOUNT_TYPE_1)) {
-            AccountManagerFuture<Boolean> result = mAccountManager.removeAccount(account, null,
-                    null);
-            assertTrue(result.getResult());
-        }
-        assertEquals(0, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
-    }
-
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountUtilsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountUtilsTest.java
new file mode 100644
index 0000000..7a9e5ad
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountUtilsTest.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 com.android.cts.deviceandprofileowner;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.content.Context;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+
+/**
+ * Utility class that allows adding and removing accounts.
+ *
+ * This test depend on {@link MockAccountService}, which provides authenticator of type
+ * {@link MockAccountService#ACCOUNT_TYPE}.
+ */
+public class AccountUtilsTest extends AndroidTestCase {
+
+    private final static Account ACCOUNT_0 = new Account("user0",
+            MockAccountAuthenticator.ACCOUNT_TYPE);
+    private AccountManager mAccountManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAccountManager = (AccountManager) getContext().getSystemService(Context.ACCOUNT_SERVICE);
+    }
+
+    public void testAddAccount() throws Exception {
+        assertEquals(0, mAccountManager.getAccountsByType(MockAccountAuthenticator.ACCOUNT_TYPE)
+                .length);
+        assertTrue(mAccountManager.addAccountExplicitly(ACCOUNT_0, "password", null));
+        assertEquals(1, mAccountManager.getAccountsByType(MockAccountAuthenticator.ACCOUNT_TYPE)
+                .length);
+    }
+
+    public void testRemoveAccounts() throws Exception {
+        removeAllAccountsForType(mAccountManager, MockAccountAuthenticator.ACCOUNT_TYPE);
+    }
+
+    static void removeAllAccountsForType(AccountManager am, String accountType)
+            throws Exception {
+        Account[] accounts = am.getAccountsByType(accountType);
+        for (Account account : accounts) {
+            AccountManagerFuture<Boolean> result = am.removeAccount(account, null, null);
+            assertTrue(result.getResult());
+        }
+        assertEquals(0, am.getAccountsByType(accountType).length);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearDeviceOwnerTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearDeviceOwnerTest.java
index eefe781..2fe0569 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ClearDeviceOwnerTest.java
@@ -21,7 +21,7 @@
 import android.content.Context;
 import android.test.AndroidTestCase;
 
-public class ClearDeviceOwnerTest extends BaseDeviceAdminTest {
+public class ClearDeviceOwnerTest extends AndroidTestCase {
 
     private DevicePolicyManager mDevicePolicyManager;
 
@@ -30,12 +30,13 @@
         mDevicePolicyManager = (DevicePolicyManager)
                 mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         if (mDevicePolicyManager != null) {
-            removeActiveAdmin(ADMIN_RECEIVER_COMPONENT);
-            if (mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME)) {
-                mDevicePolicyManager.clearDeviceOwnerApp(PACKAGE_NAME);
+            removeActiveAdmin(BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT);
+            if (mDevicePolicyManager.isDeviceOwnerApp(BaseDeviceAdminTest.PACKAGE_NAME)) {
+                mDevicePolicyManager.clearDeviceOwnerApp(BaseDeviceAdminTest.PACKAGE_NAME);
             }
-            assertFalse(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT));
-            assertFalse(mDevicePolicyManager.isDeviceOwnerApp(PACKAGE_NAME));
+            assertFalse(mDevicePolicyManager.isAdminActive(
+                    BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT));
+            assertFalse(mDevicePolicyManager.isDeviceOwnerApp(BaseDeviceAdminTest.PACKAGE_NAME));
         }
 
         super.tearDown();
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java
index 161410f..e8e5b45 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java
@@ -27,7 +27,7 @@
 /* package */ class MockAccountAuthenticator extends AbstractAccountAuthenticator {
     private static MockAccountAuthenticator sMockAuthenticator = null;
     private static final String ACCOUNT_NAME = "com.android.cts.deviceandprofileowner.account.name";
-    private static final String ACCOUNT_TYPE = "com.android.cts.deviceandprofileowner.account.type";
+    static final String ACCOUNT_TYPE = "com.android.cts.deviceandprofileowner.account.type";
     private static final String AUTH_TOKEN = "mockAuthToken";
     private static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
 
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 3bd21d9..35c16ea 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
@@ -61,7 +61,7 @@
     public static final int MSG_CHECK_PACKAGE_ADDED = 1;
     public static final int MSG_CHECK_PACKAGE_REMOVED = 2;
     public static final int MSG_CHECK_PACKAGE_CHANGED = 3;
-    public static final int MSG_CHECK_NO_CALLBACK = 4;
+    public static final int MSG_CHECK_NO_PACKAGE_ADDED = 4;
 
     public static final int RESULT_PASS = 1;
     public static final int RESULT_FAIL = 2;
@@ -139,8 +139,8 @@
         assertEquals(RESULT_PASS, result);
     }
 
-    public void testNoCallbackForUser() throws Throwable {
-        int result = sendMessageToCallbacksService(MSG_CHECK_NO_CALLBACK,
+    public void testNoPackageAddedCallbackForUser() throws Throwable {
+        int result = sendMessageToCallbacksService(MSG_CHECK_NO_PACKAGE_ADDED,
                 mUser, SIMPLE_APP_PACKAGE);
         assertEquals(RESULT_PASS, result);
     }
@@ -238,8 +238,8 @@
 
         public int waitForResult() {
             try {
-                if (mSemaphore.tryAcquire(5, TimeUnit.SECONDS)) {
-                    return result;
+                if (mSemaphore.tryAcquire(120, TimeUnit.SECONDS)) {
+                     return result;
                 }
             } catch (InterruptedException e) {
             }
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
index 8d61496..195a18b 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -22,6 +22,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.Message;
 import android.os.Messenger;
@@ -31,6 +32,9 @@
 import android.util.Pair;
 
 import java.util.ArrayList;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
 import java.util.List;
 
 /**
@@ -49,23 +53,28 @@
     public static final int MSG_CHECK_PACKAGE_ADDED = 1;
     public static final int MSG_CHECK_PACKAGE_REMOVED = 2;
     public static final int MSG_CHECK_PACKAGE_CHANGED = 3;
-    public static final int MSG_CHECK_NO_CALLBACK = 4;
+    public static final int MSG_CHECK_NO_PACKAGE_ADDED = 4;
 
     public static final int RESULT_PASS = 1;
     public static final int RESULT_FAIL = 2;
 
     private static final String TAG = "LauncherCallbackTests";
 
-    private static List<Pair<String, UserHandle>> mPackagesAdded
-            = new ArrayList<Pair<String, UserHandle>>();
-    private static List<Pair<String, UserHandle>> mPackagesRemoved
-            = new ArrayList<Pair<String, UserHandle>>();
-    private static List<Pair<String, UserHandle>> mPackagesChanged
-            = new ArrayList<Pair<String, UserHandle>>();
-    private static Object mPackagesLock = new Object();
+    private static BlockingQueue<Pair<String, UserHandle>> mPackagesAdded
+            = new LinkedBlockingQueue();
+    private static BlockingQueue<Pair<String, UserHandle>> mPackagesRemoved
+            = new LinkedBlockingQueue();
+    private static BlockingQueue<Pair<String, UserHandle>> mPackagesChanged
+            = new LinkedBlockingQueue();
 
     private TestCallback mCallback;
+    private Object mCallbackLock = new Object();
     private final Messenger mMessenger = new Messenger(new CheckHandler());
+    private final HandlerThread mCallbackThread = new HandlerThread("callback");
+
+    public LauncherCallbackTestsService() {
+        mCallbackThread.start();
+    }
 
     class CheckHandler extends Handler {
         @Override
@@ -77,6 +86,7 @@
             try {
                 switch (msg.what) {
                     case MSG_CHECK_PACKAGE_ADDED: {
+                        Log.i(TAG, "MSG_CHECK_PACKAGE_ADDED");
                         boolean exists = eventExists(params, mPackagesAdded);
                         teardown();
                         msg.replyTo.send(Message.obtain(null, MSG_RESULT,
@@ -84,6 +94,7 @@
                         break;
                     }
                     case MSG_CHECK_PACKAGE_REMOVED: {
+                        Log.i(TAG, "MSG_CHECK_PACKAGE_REMOVED");
                         boolean exists = eventExists(params, mPackagesRemoved);
                         teardown();
                         msg.replyTo.send(Message.obtain(null, MSG_RESULT,
@@ -91,16 +102,16 @@
                         break;
                     }
                     case MSG_CHECK_PACKAGE_CHANGED: {
+                        Log.i(TAG, "MSG_CHECK_PACKAGE_CHANGED");
                         boolean exists = eventExists(params, mPackagesChanged);
                         teardown();
                         msg.replyTo.send(Message.obtain(null, MSG_RESULT,
                                         exists ? RESULT_PASS : RESULT_FAIL, 0));
                         break;
                     }
-                    case MSG_CHECK_NO_CALLBACK: {
-                        boolean exists = eventExists(params, mPackagesAdded)
-                                || eventExists(params, mPackagesRemoved)
-                                || eventExists(params, mPackagesChanged);
+                    case MSG_CHECK_NO_PACKAGE_ADDED: {
+                        Log.i(TAG, "MSG_CHECK_NO_PACKAGE_ADDED");
+                        boolean exists = eventExists(params, mPackagesAdded);
                         teardown();
                         msg.replyTo.send(Message.obtain(null, MSG_RESULT,
                                         exists ? RESULT_FAIL : RESULT_PASS, 0));
@@ -129,24 +140,26 @@
     private void setup() {
         LauncherApps launcherApps = (LauncherApps) getSystemService(
                 Context.LAUNCHER_APPS_SERVICE);
-        synchronized (mPackagesLock) {
-            mPackagesAdded.clear();
-            mPackagesRemoved.clear();
-            mPackagesChanged.clear();
+        synchronized (mCallbackLock) {
             if (mCallback != null) {
                 launcherApps.unregisterCallback(mCallback);
             }
+            mPackagesAdded.clear();
+            mPackagesRemoved.clear();
+            mPackagesChanged.clear();
             mCallback = new TestCallback();
-            launcherApps.registerCallback(mCallback);
+            launcherApps.registerCallback(mCallback, new Handler(mCallbackThread.getLooper()));
+            Log.i(TAG, "started listening for events");
         }
     }
 
     private void teardown() {
         LauncherApps launcherApps = (LauncherApps) getSystemService(
                 Context.LAUNCHER_APPS_SERVICE);
-        synchronized (mPackagesLock) {
+        synchronized (mCallbackLock) {
             if (mCallback != null) {
                 launcherApps.unregisterCallback(mCallback);
+                Log.i(TAG, "stopped listening for events");
                 mCallback = null;
             }
             mPackagesAdded.clear();
@@ -155,20 +168,23 @@
         }
     }
 
-    private boolean eventExists(Bundle params, List<Pair<String, UserHandle>> events) {
+    private boolean eventExists(Bundle params, BlockingQueue<Pair<String, UserHandle>> events) {
         UserHandle user = params.getParcelable(USER_EXTRA);
         String packageName = params.getString(PACKAGE_EXTRA);
-        synchronized (mPackagesLock) {
-            if (events != null) {
-                for (Pair<String, UserHandle> added : events) {
-                    if (added.first.equals(packageName) && added.second.equals(user)) {
-                        Log.i(TAG, "Event exists " + packageName + " for user " + user);
-                        return true;
-                    }
+        Log.i(TAG, "checking for " + packageName + " " + user);
+        try {
+            Pair<String, UserHandle> event = events.poll(60, TimeUnit.SECONDS);
+            while (event != null) {
+                if (event.first.equals(packageName) && event.second.equals(user)) {
+                    Log.i(TAG, "Event exists " + packageName + " for user " + user);
+                    return true;
                 }
+                event = events.poll(20, TimeUnit.SECONDS);
             }
-            return false;
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Failed checking for event", e);
         }
+        return false;
     }
 
     @Override
@@ -178,20 +194,29 @@
 
     private class TestCallback extends LauncherApps.Callback {
         public void onPackageRemoved(String packageName, UserHandle user) {
-            synchronized (mPackagesLock) {
-                mPackagesRemoved.add(new Pair<String, UserHandle>(packageName, user));
+            Log.i(TAG, "package removed event " + packageName + " " + user);
+            try {
+                mPackagesRemoved.put(new Pair(packageName, user));
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Failed saving event", e);
             }
         }
 
         public void onPackageAdded(String packageName, UserHandle user) {
-            synchronized (mPackagesLock) {
-                mPackagesAdded.add(new Pair<String, UserHandle>(packageName, user));
+            Log.i(TAG, "package added event " + packageName + " " + user);
+            try {
+                mPackagesAdded.put(new Pair(packageName, user));
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Failed saving event", e);
             }
         }
 
         public void onPackageChanged(String packageName, UserHandle user) {
-            synchronized (mPackagesLock) {
-                mPackagesChanged.add(new Pair<String, UserHandle>(packageName, user));
+            Log.i(TAG, "package changed event " + packageName + " " + user);
+            try {
+                mPackagesChanged.put(new Pair(packageName, user));
+            } catch (InterruptedException e) {
+                Log.e(TAG, "Failed saving event", e);
             }
         }
 
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index e6351c5..7cb8f3b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -29,28 +29,30 @@
 
     private static final String DEVICE_OWNER_PKG = "com.android.cts.deviceowner";
     private static final String DEVICE_OWNER_APK = "CtsDeviceOwnerApp.apk";
+    private static final String DEVICE_OWNER_ADMIN
+            = DEVICE_OWNER_PKG + ".BaseDeviceOwnerTest$BasicAdminReceiver";
+    private static final String DEVICE_OWNER_ADMIN_COMPONENT
+            = DEVICE_OWNER_PKG + "/" + DEVICE_OWNER_ADMIN;
+    private static final String DEVICE_OWNER_CLEAR
+            = DEVICE_OWNER_PKG + ".ClearDeviceOwnerTest";
+
+    private static final String DEVICE_AND_PROFILE_OWNER_PKG
+            = "com.android.cts.deviceandprofileowner";
+    protected static final String DEVICE_AND_PROFILE_OWNER_APK = "CtsDeviceAndProfileOwnerApp.apk";
+    protected static final String DEVICE_AND_PROFILE_OWNER_ADMIN
+            = ".BaseDeviceAdminTest$BasicAdminReceiver";
+    protected static final String DEVICE_AND_PROFILE_OWNER_ADMIN_COMPONENT
+            = DEVICE_AND_PROFILE_OWNER_PKG + "/" + DEVICE_AND_PROFILE_OWNER_ADMIN;
+    protected static final String DEVICE_AND_PROFILE_OWNER_CLEAR
+            = DEVICE_AND_PROFILE_OWNER_PKG + ".ClearDeviceOwnerTest";
+
     private static final String INTENT_RECEIVER_PKG = "com.android.cts.intent.receiver";
     private static final String INTENT_RECEIVER_APK = "CtsIntentReceiverApp.apk";
 
-    private static final String CLEAR_DEVICE_OWNER_TEST_CLASS =
-            DEVICE_OWNER_PKG + ".ClearDeviceOwnerTest";
-
-    private static final String ADMIN_RECEIVER_TEST_CLASS =
-            DEVICE_OWNER_PKG + ".BaseDeviceOwnerTest$BasicAdminReceiver";
-    private static final String ADMIN_RECEIVER_COMPONENT =
-            DEVICE_OWNER_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS;
-
-    public void setUp() throws Exception {
-        super.setUp();
-
-        if (mHasFeature) {
-            installApp(DEVICE_OWNER_APK);
-        }
-    }
-
     public void tearDown() throws Exception {
         if (mHasFeature) {
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
+            getDevice().uninstallPackage(DEVICE_AND_PROFILE_OWNER_PKG);
         }
 
         super.tearDown();
@@ -60,6 +62,7 @@
         if (!mHasFeature) {
             return;
         }
+        installApp(DEVICE_OWNER_APK);
         try {
             installApp(INTENT_RECEIVER_APK);
 
@@ -71,27 +74,47 @@
                     "testOwnerChangedBroadcastNotReceived", 0));
 
             // Setting the device owner should send the owner changed broadcast.
-            assertTrue(setDeviceOwner(ADMIN_RECEIVER_COMPONENT));
+            assertTrue(setDeviceOwner(DEVICE_OWNER_ADMIN_COMPONENT));
 
             assertTrue(runDeviceTests(INTENT_RECEIVER_PKG, testClass,
                     "testOwnerChangedBroadcastReceived", 0));
         } finally {
             getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
             assertTrue("Failed to remove device owner.",
-                    runDeviceTests(DEVICE_OWNER_PKG, CLEAR_DEVICE_OWNER_TEST_CLASS));
+                    runDeviceTests(DEVICE_OWNER_PKG, DEVICE_OWNER_CLEAR));
         }
     }
 
     public void testCannotSetDeviceOwnerWhenSecondaryUserPresent() throws Exception {
-        if (!mHasFeature) {
+        if (!mHasFeature || getMaxNumberOfUsersSupported() < 2) {
             return;
         }
         int userId = -1;
+        installApp(DEVICE_OWNER_APK);
         try {
             userId = createUser();
-            assertFalse(setDeviceOwner(ADMIN_RECEIVER_COMPONENT));
+            assertFalse(setDeviceOwner(DEVICE_OWNER_ADMIN_COMPONENT));
         } finally {
             removeUser(userId);
+            // make sure we clean up in case we succeeded in setting the device owner
+            runDeviceTests(DEVICE_OWNER_PKG, DEVICE_OWNER_CLEAR);
+        }
+    }
+
+    public void testCannotSetDeviceOwnerWhenAccountPresent() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installApp(DEVICE_AND_PROFILE_OWNER_APK);
+        try {
+            assertTrue(runDeviceTestsAsUser(DEVICE_AND_PROFILE_OWNER_PKG, ".AccountUtilsTest",
+                    "testAddAccount", 0));
+            assertFalse(setDeviceOwner(DEVICE_AND_PROFILE_OWNER_ADMIN_COMPONENT));
+        } finally {
+            // make sure we clean up in case we succeeded in setting the device owner
+            runDeviceTests(DEVICE_AND_PROFILE_OWNER_PKG, DEVICE_AND_PROFILE_OWNER_CLEAR);
+            assertTrue(runDeviceTestsAsUser(DEVICE_AND_PROFILE_OWNER_PKG, ".AccountUtilsTest",
+                    "testRemoveAccounts", 0));
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
index 0af38a4..8da189f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/LauncherAppsMultiUserTest.java
@@ -81,7 +81,7 @@
         try {
             assertTrue(runDeviceTests(LAUNCHER_TESTS_PKG,
                     LAUNCHER_TESTS_CLASS,
-                            "testNoCallbackForUser",
+                            "testNoPackageAddedCallbackForUser",
                             0, "-e testUser " + mSecondaryUserSerialNumber));
         } finally {
             getDevice().uninstallPackage(SIMPLE_APP_PKG);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 54b535a..93e1aff 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -34,6 +34,7 @@
     private static final String DEVICE_OWNER_APK = "CtsDeviceOwnerApp.apk";
     private static final String DEVICE_OWNER_ADMIN =
             DEVICE_OWNER_PKG + ".BaseDeviceOwnerTest$BasicAdminReceiver";
+    private static final String DEVICE_OWNER_CLEAR = DEVICE_OWNER_PKG + ".ClearDeviceOwnerTest";
 
     private static final String INTENT_SENDER_PKG = "com.android.cts.intent.sender";
     private static final String INTENT_SENDER_APK = "CtsIntentSenderApp.apk";
@@ -552,20 +553,25 @@
                 MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS, mUserId));
 
         // verify that we can't set a different admin receiver as profile owner
+        installAppAsUser(DEVICE_OWNER_APK, mUserId);
+        assertFalse(setProfileOwner(DEVICE_OWNER_PKG + "/" + DEVICE_OWNER_ADMIN, mUserId));
+    }
+
+    public void testCannotSetDeviceOwnerWhenProfilePresent() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
         try {
             installApp(DEVICE_OWNER_APK);
             assertFalse(setDeviceOwner(DEVICE_OWNER_PKG + "/" + DEVICE_OWNER_ADMIN));
         } finally {
+            // make sure we clean up in case we succeeded in setting the device owner
+            runDeviceTests(DEVICE_OWNER_PKG, DEVICE_OWNER_CLEAR);
             getDevice().uninstallPackage(DEVICE_OWNER_PKG);
         }
     }
 
-    public void testCannotSetDeviceOwnerWhenProfilePresent() throws Exception {
-        if (mHasFeature) {
-            assertFalse(setDeviceOwner(MANAGED_PROFILE_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS));
-        }
-    }
-
     public void testNfcRestriction() throws Exception {
         if (!mHasFeature || !mHasNfcFeature) {
             return;
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
new file mode 100644
index 0000000..561d346
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -0,0 +1,32 @@
+# 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsJdwpSecurityHostTestCases
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.host.jdwpsecurity
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/jdwpsecurity/app/Android.mk b/hostsidetests/jdwpsecurity/app/Android.mk
new file mode 100644
index 0000000..13b5be4
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/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 := CtsJdwpApp
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+include $(BUILD_JAVA_LIBRARY)
+
+# Copy the built module to the cts dir
+cts_library_jar := $(CTS_TESTCASES_OUT)/$(LOCAL_MODULE).jar
+$(cts_library_jar): $(LOCAL_BUILT_MODULE)
+	$(copy-file-to-target)
+
+# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
+$(my_register_name) : $(cts_library_jar)
+
diff --git a/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
new file mode 100644
index 0000000..f2e5980
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/app/src/com/android/cts/jdwpsecurity/JdwpTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.jdwpsecurity;
+
+public class JdwpTest {
+    private static final long LOOP_TIMEOUT_MS = 60 * 1000;
+
+    public static void main(String[] args) throws Exception {
+        // Print pid so the test knows who we are.
+        int pid = android.os.Process.myPid();
+        System.out.println(pid);
+
+        // Loop to keep alive so the host test has the time to check whether we have a JDWP
+        // connection.
+        // Note: we use a timeout to avoid indefinite loop in case something wrong happens
+        // with the test harness.
+        long start = System.currentTimeMillis();
+        while(getElapsedTime(start) < LOOP_TIMEOUT_MS) {
+            Thread.sleep(100);
+        }
+    }
+
+    private static long getElapsedTime(long start) {
+        return System.currentTimeMillis() - start;
+    }
+}
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
new file mode 100644
index 0000000..8e276ed
--- /dev/null
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -0,0 +1,284 @@
+/*
+ * 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.jdwpsecurity.cts;
+
+import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.util.ArrayUtil;
+import com.android.tradefed.util.RunUtil;
+
+import java.io.BufferedReader;
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Test to check non-zygote apps do not have an active JDWP connection.
+ */
+public class JdwpSecurityHostTest extends DeviceTestCase implements IBuildReceiver {
+
+    private static final String DEVICE_LOCATION = "/data/local/tmp/jdwpsecurity";
+    private static final String DEVICE_SCRIPT_FILENAME = "jdwptest";
+    private static final String DEVICE_JAR_FILENAME = "CtsJdwpApp.jar";
+    private static final String JAR_MAIN_CLASS_NAME = "com.android.cts.jdwpsecurity.JdwpTest";
+
+    private CtsBuildHelper mCtsBuild;
+
+    private static String getDeviceScriptFilepath() {
+        return DEVICE_LOCATION + File.separator + DEVICE_SCRIPT_FILENAME;
+    }
+
+    private static String getDeviceJarFilepath() {
+        return DEVICE_LOCATION + File.separator + DEVICE_JAR_FILENAME;
+    }
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+        mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Create test directory on the device.
+        createRemoteDir(DEVICE_LOCATION);
+
+        // Also create the dalvik-cache directory. It needs to exist before the runtime starts.
+        createRemoteDir(DEVICE_LOCATION + File.separator + "dalvik-cache");
+
+        // Create and push script on the device.
+        File tempFile = createScriptTempFile();
+        try {
+            boolean success = getDevice().pushFile(tempFile, getDeviceScriptFilepath());
+            assertTrue("Failed to push script to " + getDeviceScriptFilepath(), success);
+        } finally {
+            if (tempFile != null) {
+                tempFile.delete();
+            }
+        }
+
+        // Make the script executable.
+        getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
+
+        // Push jar file.
+        File jarFile = mCtsBuild.getTestApp(DEVICE_JAR_FILENAME);
+        boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
+        assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // Delete the whole test directory on the device.
+        getDevice().executeShellCommand(String.format("rm -r %s", DEVICE_LOCATION));
+
+        super.tearDown();
+    }
+
+    /**
+     * Tests a non-zygote app does not have a JDWP connection, thus not being
+     * debuggable.
+     *
+     * Runs a script executing a Java app (jar file) with app_process,
+     * without forking from zygote. Then checks its pid is not returned
+     * by 'adb jdwp', meaning it has no JDWP connection and cannot be
+     * debugged.
+     *
+     * @throws Exception
+     */
+    public void testNonZygoteProgramIsNotDebuggable() throws Exception {
+        String scriptFilepath = getDeviceScriptFilepath();
+        Process scriptProcess = null;
+        String scriptPid = null;
+        List<String> activeJdwpPids = null;
+        try {
+            // Run the script on the background so it's running when we collect the list of
+            // pids with a JDWP connection using 'adb jdwp'.
+            // command.
+            scriptProcess = runScriptInBackground(scriptFilepath);
+
+            // On startup, the script will print its pid on its output.
+            scriptPid = readScriptPid(scriptProcess);
+
+            // Collect the list of pids with a JDWP connection.
+            activeJdwpPids = getJdwpPids();
+        } finally {
+            // Stop the script.
+            if (scriptProcess != null) {
+                scriptProcess.destroy();
+            }
+        }
+
+        assertNotNull("Failed to get script pid", scriptPid);
+        assertNotNull("Failed to get active JDWP pids", activeJdwpPids);
+        assertFalse("Test app should not have an active JDWP connection" +
+                " (pid " + scriptPid + " is returned by 'adb jdwp')",
+                activeJdwpPids.contains(scriptPid));
+    }
+
+    private Process runScriptInBackground(String scriptFilepath) throws IOException {
+        String[] shellScriptCommand = buildAdbCommand("shell", scriptFilepath);
+        return RunUtil.getDefault().runCmdInBackground(shellScriptCommand);
+    }
+
+    private String readScriptPid(Process scriptProcess) throws IOException {
+        BufferedReader br = null;
+        try {
+            br = new BufferedReader(new InputStreamReader(scriptProcess.getInputStream()));
+            // We only expect to read one line containing the pid.
+            return br.readLine();
+        } finally {
+            if (br != null) {
+                br.close();
+            }
+        }
+    }
+
+    private List<String> getJdwpPids() throws Exception {
+        return new AdbJdwpOutputReader().listPidsWithAdbJdwp();
+    }
+
+    /**
+     * Creates the script file on the host so it can be pushed onto the device.
+     *
+     * @return the script file
+     * @throws IOException
+     */
+    private static File createScriptTempFile() throws IOException {
+        File tempFile = File.createTempFile("jdwptest", ".tmp");
+
+        PrintWriter pw = null;
+        try {
+            pw = new PrintWriter(tempFile);
+
+            // We need a dalvik-cache in /data/local/tmp so we have read-write access.
+            // Note: this will cause the runtime to optimize the DEX file (contained in
+            // the jar file) before executing it.
+            pw.println(String.format("export ANDROID_DATA=%s", DEVICE_LOCATION));
+            pw.println(String.format("export CLASSPATH=%s", getDeviceJarFilepath()));
+            pw.println(String.format("exec app_process /system/bin %s \"$@\"",
+                    JAR_MAIN_CLASS_NAME));
+        } finally {
+            if (pw != null) {
+                pw.close();
+            }
+        }
+
+        return tempFile;
+    }
+
+    /**
+     * Helper class collecting all pids returned by 'adb jdwp' command.
+     */
+    private class AdbJdwpOutputReader implements Runnable {
+        /**
+         * A list of all pids with a JDWP connection returned by 'adb jdwp'.
+         */
+        private final List<String> lines = new ArrayList<String>();
+
+        /**
+         * The input stream of the process running 'adb jdwp'.
+         */
+        private InputStream in;
+
+        public List<String> listPidsWithAdbJdwp() throws Exception {
+            // The 'adb jdwp' command does not return normally, it only terminates with Ctrl^C.
+            // Therefore we cannot use ITestDevice.executeAdbCommand but need to run that command
+            // in the background. Since we know the tested app is already running, we only need to
+            // capture the output for a short amount of time before stopping the 'adb jdwp'
+            // command.
+            String[] adbJdwpCommand = buildAdbCommand("jdwp");
+            Process adbProcess = RunUtil.getDefault().runCmdInBackground(adbJdwpCommand);
+            in = adbProcess.getInputStream();
+
+            // Read the output for 5s in a separate thread before stopping the command.
+            Thread t = new Thread(this);
+            t.start();
+            Thread.sleep(5000);
+
+            // Kill the 'adb jdwp' process and wait for the thread to stop.
+            adbProcess.destroy();
+            t.join();
+
+            return lines;
+        }
+
+        @Override
+        public void run() {
+            BufferedReader br = null;
+            try {
+                br = new BufferedReader(new InputStreamReader(in));
+                String line;
+                while ((line = readLineIgnoreException(br)) != null) {
+                    lines.add(line);
+                }
+            } catch (IOException e) {
+                CLog.e(e);
+            } finally {
+                if (br != null) {
+                    try {
+                        br.close();
+                    } catch (IOException e) {
+                        // Ignore it.
+                    }
+                }
+            }
+        }
+
+        private String readLineIgnoreException(BufferedReader reader) throws IOException {
+            try {
+                return reader.readLine();
+            } catch (IOException e) {
+                if (e instanceof EOFException) {
+                    // This is expected when the process's input stream is closed.
+                    return null;
+                } else {
+                    throw e;
+                }
+            }
+        }
+    }
+
+    private String[] buildAdbCommand(String... args) {
+        return ArrayUtil.buildArray(new String[] {"adb", "-s", getDevice().getSerialNumber()},
+                args);
+    }
+
+    private boolean createRemoteDir(String remoteFilePath) throws DeviceNotAvailableException {
+        if (getDevice().doesFileExist(remoteFilePath)) {
+            return true;
+        }
+        File remoteFile = new File(remoteFilePath);
+        String parentPath = remoteFile.getParent();
+        if (parentPath != null) {
+            if (!createRemoteDir(parentPath)) {
+                return false;
+            }
+        }
+        getDevice().executeShellCommand(String.format("mkdir %s", remoteFilePath));
+        return getDevice().doesFileExist(remoteFilePath);
+    }
+}
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
new file mode 100644
index 0000000..6962e0c
--- /dev/null
+++ b/hostsidetests/os/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
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsOsHostTestCases
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.host.os
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/$(CTS_MODULE_TEST_CONFIG)
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/os/AndroidTest.xml b/hostsidetests/os/AndroidTest.xml
new file mode 100644
index 0000000..6694c30
--- /dev/null
+++ b/hostsidetests/os/AndroidTest.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.
+-->
+<configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
+    <include name="common-config" />
+    <option name="cts-apk-installer:test-file-name" value="CtsDeviceOsTestApp.apk" />
+</configuration>
diff --git a/hostsidetests/os/app/Android.mk b/hostsidetests/os/app/Android.mk
new file mode 100644
index 0000000..46861d69
--- /dev/null
+++ b/hostsidetests/os/app/Android.mk
@@ -0,0 +1,28 @@
+# 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)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := CtsDeviceOsTestApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/os/app/AndroidManifest.xml b/hostsidetests/os/app/AndroidManifest.xml
new file mode 100755
index 0000000..103cf63
--- /dev/null
+++ b/hostsidetests/os/app/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="com.android.cts.app.os.test">
+
+    <application>
+        <activity android:name=".TestNonExported"
+                android:exported="false" />
+    </application>
+</manifest>
+
diff --git a/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java b/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java
new file mode 100644
index 0000000..c865c89
--- /dev/null
+++ b/hostsidetests/os/app/src/com/android/cts/app/os/test/TestNonExported.java
@@ -0,0 +1,25 @@
+/*
+ * 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.app.os.test;
+
+import android.app.Activity;
+
+/**
+ * Should never be launched: intentionally not exported
+ */
+public class TestNonExported extends Activity {
+}
diff --git a/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java b/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java
new file mode 100644
index 0000000..d01a521
--- /dev/null
+++ b/hostsidetests/os/src/com/android/cts/app/os/OsHostTests.java
@@ -0,0 +1,63 @@
+/*
+ * 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.app.os;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
+public class OsHostTests extends DeviceTestCase implements IBuildReceiver {
+    private static final String TEST_APP_PACKAGE = "com.android.cts.app.os.test";
+    private static final String TEST_NON_EXPORTED_ACTIVITY_CLASS = "TestNonExported";
+
+    private static final String START_NON_EXPORTED_ACTIVITY_COMMAND = String.format(
+            "am start -n %s/%s.%s",
+            TEST_APP_PACKAGE, TEST_APP_PACKAGE, TEST_NON_EXPORTED_ACTIVITY_CLASS);
+
+    /**
+     * A reference to the device under test.
+     */
+    private ITestDevice mDevice;
+
+    @Override
+    public void setBuild(IBuildInfo buildInfo) {
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // Get the device, this gives a handle to run commands and install APKs.
+        mDevice = getDevice();
+    }
+
+    /**
+     * Test whether non-exported activities are properly not launchable.
+     *
+     * @throws Exception
+     */
+    public void testNonExportedActivities() throws Exception {
+        // Attempt to launch the non-exported activity in the test app
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(START_NON_EXPORTED_ACTIVITY_COMMAND, outputReceiver);
+        final String output = outputReceiver.getOutput();
+
+        assertTrue(output.contains("Permission Denial") && output.contains(" not exported"));
+    }
+}
diff --git a/hostsidetests/theme/app/src/android/theme/app/DisplayInfoActivity.java b/hostsidetests/theme/app/src/android/theme/app/DisplayInfoActivity.java
index 91b2127..5255698 100644
--- a/hostsidetests/theme/app/src/android/theme/app/DisplayInfoActivity.java
+++ b/hostsidetests/theme/app/src/android/theme/app/DisplayInfoActivity.java
@@ -68,6 +68,9 @@
             case DisplayMetrics.DENSITY_400:
                 return "400dpi";
 
+            case DisplayMetrics.DENSITY_420:
+                return "420dpi";
+
             case DisplayMetrics.DENSITY_XXHIGH:
                 return "xxhdpi";
 
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index 917528b..1d4e36d 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -18,8 +18,6 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_MODULE_TAGS := optional
-
 # Must match the package name in CtsTestCaseList.mk
 LOCAL_MODULE := CtsUsageHostTestCases
 
@@ -29,4 +27,4 @@
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
 
-include $(call all-subdir-makefiles)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java b/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java
index f24be0e..b94d086 100644
--- a/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java
+++ b/hostsidetests/usage/src/com/android/cts/app/usage/AppIdleHostTest.java
@@ -118,20 +118,12 @@
     }
 
     /**
-     * Tests that the app is idle when the idle threshold is passed, and that the app is not-idle
-     * before the threshold is passed.
-     *
-     * @throws Exception
+     * Tests that the app is not idle right after it is launched.
      */
-    public void testAppIsIdle() throws Exception {
+    public void testAppIsNotIdleAfterBeingLaunched() throws Exception {
         final String previousState = getAppIdleSettings();
         try {
-            // Set the app idle time to be super low.
-            setAppIdleSettings("idle_duration=5,wallclock_threshold=5");
-            startAndStopTestApp();
-            assertTrue(isAppIdle(TEST_APP_PACKAGE));
-
-            // Set the app idle time to something larger.
+            // Set the app idle time to something large.
             setAppIdleSettings("idle_duration=10000,wallclock_threshold=10000");
             startAndStopTestApp();
             assertFalse(isAppIdle(TEST_APP_PACKAGE));
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index cf4772f..754e38a 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -193,6 +193,21 @@
   bug: 22092756
 },
 {
+  description: "The new long processing test is not yet passing on all devices",
+  names: [
+    "android.hardware.camera2.cts.ImageReaderTest#testLongProcessingRepeatingRaw",
+    "android.hardware.camera2.cts.ImageReaderTest#testLongProcessingRepeatingFlexibleYuv"
+  ],
+  bug: 22861512
+},
+{
+  description: "The timing measurements for preview callbacks are not reliable",
+  names: [
+    "android.hardware.cts.CameraTest#testPreviewFpsRange"
+  ],
+  bug: 23008511
+},
+{
   description: "known failures",
   names: [
     "android.hardware.cts.SensorBatchingTests#testAccelerometer_50hz_batching",
@@ -210,6 +225,7 @@
     "android.hardware.cts.SensorIntegrationTests#testSensorsMovingRates",
     "android.hardware.cts.SensorIntegrationTests#testSensorsWithSeveralClients",
     "android.hardware.cts.SensorTest#testSensorTimeStamps",
+    "android.hardware.cts.SensorTest#testBatchAndFlush",
     "android.hardware.cts.SingleSensorTests#testGyroscope_15hz",
     "android.hardware.cts.SingleSensorTests#testGyroscope_1hz",
     "android.hardware.cts.SingleSensorTests#testMagneticField_1hz",
diff --git a/tests/tests/admin/AndroidTest.xml b/tests/tests/admin/AndroidTest.xml
new file mode 100644
index 0000000..c29d404
--- /dev/null
+++ b/tests/tests/admin/AndroidTest.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.
+-->
+<configuration description="CTS device admin test config">
+    <include name="common-config" />
+    <option name="run-command:run-command" value="dpm set-active-admin android.deviceadmin.cts/.CtsDeviceAdminReceiver" />
+    <option name="run-command:run-command" value="dpm set-active-admin android.deviceadmin.cts/.CtsDeviceAdminReceiver2" />
+</configuration>
diff --git a/tests/tests/app.usage/AndroidManifest.xml b/tests/tests/app.usage/AndroidManifest.xml
index 54fde71..7869223 100644
--- a/tests/tests/app.usage/AndroidManifest.xml
+++ b/tests/tests/app.usage/AndroidManifest.xml
@@ -24,6 +24,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
index b2bede1..b6fef4a 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java
@@ -28,6 +28,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.telephony.TelephonyManager;
 import android.test.InstrumentationTestCase;
 import android.util.Log;
 
@@ -37,6 +38,7 @@
 import java.io.InputStreamReader;
 import java.net.URL;
 import java.text.MessageFormat;
+import java.util.Scanner;
 import javax.net.ssl.HttpsURLConnection;
 
 import libcore.io.IoUtils;
@@ -44,8 +46,8 @@
 
 public class NetworkUsageStatsTest extends InstrumentationTestCase {
     private static final String LOG_TAG = "NetworkUsageStatsTest";
-    private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} " +
-            AppOpsManager.OPSTR_GET_USAGE_STATS + " {1}";
+    private static final String APPOPS_SET_SHELL_COMMAND = "appops set {0} {1} {2}";
+    private static final String APPOPS_GET_SHELL_COMMAND = "appops get {0} {1}";
 
     private static final long MINUTE = 1000 * 60;
 
@@ -66,11 +68,14 @@
     private long mEndTime;
 
     private long mBytesRead;
+    private String mWriteSettingsMode;
+    private String mUsageStatsMode;
 
     private void exerciseRemoteHost(int transportType) throws Exception {
         final int timeout = 15000;
         mCm.requestNetwork(new NetworkRequest.Builder()
             .addTransportType(transportType)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
             .build(), new ConnectivityManager.NetworkCallback() {
                 @Override
                 public void onAvailable(Network network) {
@@ -133,11 +138,26 @@
 
         mCm = (ConnectivityManager) getInstrumentation().getContext()
                 .getSystemService(Context.CONNECTIVITY_SERVICE);
+
+        mWriteSettingsMode = getAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS);
+        setAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS, "allow");
+        mUsageStatsMode = getAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS);
     }
 
-    private void setAppOpsMode(String mode) throws Exception {
+    @Override
+    protected void tearDown() throws Exception {
+        if (mWriteSettingsMode != null) {
+            setAppOpsMode(AppOpsManager.OPSTR_WRITE_SETTINGS, mWriteSettingsMode);
+        }
+        if (mUsageStatsMode != null) {
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, mUsageStatsMode);
+        }
+        super.tearDown();
+    }
+
+    private void setAppOpsMode(String appop, String mode) throws Exception {
         final String command = MessageFormat.format(APPOPS_SET_SHELL_COMMAND,
-                getInstrumentation().getContext().getPackageName(), mode);
+                getInstrumentation().getContext().getPackageName(), appop, mode);
         ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
                 .executeShellCommand(command);
         try {
@@ -147,6 +167,29 @@
         }
     }
 
+    private String getAppOpsMode(String appop) throws Exception {
+        String result;
+        final String command = MessageFormat.format(APPOPS_GET_SHELL_COMMAND,
+                getInstrumentation().getContext().getPackageName(), appop);
+        ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
+                .executeShellCommand(command);
+        try {
+            result = convertStreamToString(new FileInputStream(pfd.getFileDescriptor()));
+        } finally {
+            IoUtils.closeQuietly(pfd.getFileDescriptor());
+        }
+        if (result == null) {
+            Log.w(LOG_TAG, "App op " + appop + " could not be read.");
+        }
+        return result;
+    }
+
+    private static String convertStreamToString(InputStream is) {
+        try (Scanner scanner = new Scanner(is).useDelimiter("\\A")) {
+            return scanner.hasNext() ? scanner.next() : null;
+        }
+    }
+
     private boolean shouldTestThisNetworkType(int networkTypeIndex, long tolerance)
             throws Exception {
         NetworkInfo networkInfo = mCm.getNetworkInfo(sNetworkTypesToTest[networkTypeIndex]);
@@ -159,16 +202,26 @@
         return true;
     }
 
+    private String getSubscriberId(int networkType) {
+        if (ConnectivityManager.TYPE_MOBILE == networkType) {
+            TelephonyManager tm = (TelephonyManager) getInstrumentation().getContext()
+                    .getSystemService(Context.TELEPHONY_SERVICE);
+            return tm.getSubscriberId();
+        }
+        return "";
+    }
+
     public void testDeviceSummary() throws Exception {
         for (int i = 0; i < sNetworkTypesToTest.length; ++i) {
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
-            setAppOpsMode("allow");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
             NetworkStats.Bucket bucket = null;
             try {
                 bucket = mNsm.querySummaryForDevice(
-                        sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
             } catch (RemoteException | SecurityException e) {
                 fail("testDeviceSummary fails with exception: " + e.toString());
             }
@@ -176,10 +229,11 @@
             assertTimestamps(bucket);
             assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
             assertEquals(bucket.getUid(), NetworkStats.Bucket.UID_ALL);
-            setAppOpsMode("deny");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForDevice(
-                        ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 fail("negative testDeviceSummary fails: no exception thrown.");
             } catch (RemoteException e) {
                 fail("testDeviceSummary fails with exception: " + e.toString());
@@ -194,11 +248,12 @@
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
-            setAppOpsMode("allow");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
             NetworkStats.Bucket bucket = null;
             try {
                 bucket = mNsm.querySummaryForUser(
-                        sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
             } catch (RemoteException | SecurityException e) {
                 fail("testUserSummary fails with exception: " + e.toString());
             }
@@ -206,10 +261,11 @@
             assertTimestamps(bucket);
             assertEquals(bucket.getState(), NetworkStats.Bucket.STATE_ALL);
             assertEquals(bucket.getUid(), NetworkStats.Bucket.UID_ALL);
-            setAppOpsMode("deny");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 bucket = mNsm.querySummaryForUser(
-                        ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 fail("negative testUserSummary fails: no exception thrown.");
             } catch (RemoteException e) {
                 fail("testUserSummary fails with exception: " + e.toString());
@@ -224,11 +280,12 @@
             if (!shouldTestThisNetworkType(i, MINUTE/2)) {
                 continue;
             }
-            setAppOpsMode("allow");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
             NetworkStats result = null;
             try {
                 result = mNsm.querySummary(
-                        sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
@@ -257,10 +314,11 @@
                     result.close();
                 }
             }
-            setAppOpsMode("deny");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.querySummary(
-                        ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 fail("negative testAppSummary fails: no exception thrown.");
             } catch (RemoteException e) {
                 fail("testAppSummary fails with exception: " + e.toString());
@@ -276,11 +334,12 @@
             if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
                 continue;
             }
-            setAppOpsMode("allow");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
             NetworkStats result = null;
             try {
                 result = mNsm.queryDetails(
-                        sNetworkTypesToTest[i], "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
@@ -310,10 +369,11 @@
                     result.close();
                 }
             }
-            setAppOpsMode("deny");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.queryDetails(
-                        ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime);
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime);
                 fail("negative testAppDetails fails: no exception thrown.");
             } catch (RemoteException e) {
                 fail("testAppDetails fails with exception: " + e.toString());
@@ -329,11 +389,12 @@
             if (!shouldTestThisNetworkType(i, MINUTE * 120)) {
                 continue;
             }
-            setAppOpsMode("allow");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "allow");
             NetworkStats result = null;
             try {
                 result = mNsm.queryDetailsForUid(
-                        sNetworkTypesToTest[i], "", mStartTime, mEndTime, Process.myUid());
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime, Process.myUid());
                 assertTrue(result != null);
                 NetworkStats.Bucket bucket = new NetworkStats.Bucket();
                 long totalTxPackets = 0;
@@ -362,10 +423,11 @@
                     result.close();
                 }
             }
-            setAppOpsMode("deny");
+            setAppOpsMode(AppOpsManager.OPSTR_GET_USAGE_STATS, "deny");
             try {
                 result = mNsm.queryDetailsForUid(
-                        ConnectivityManager.TYPE_WIFI, "", mStartTime, mEndTime, Process.myUid());
+                        sNetworkTypesToTest[i], getSubscriberId(sNetworkTypesToTest[i]),
+                        mStartTime, mEndTime, Process.myUid());
                 fail("negative testUidDetails fails: no exception thrown.");
             } catch (RemoteException e) {
                 fail("testUidDetails fails with exception: " + e.toString());
diff --git a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index 55191b5..dfa278a 100644
--- a/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -56,6 +56,7 @@
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 48);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 64);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96);
+            expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_560, 192);
             expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 256);
@@ -70,6 +71,7 @@
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 128);
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_360, 160);
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_400, 192);
+            expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_420, 228);
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 256);
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_560, 384);
             expectedMemorySizeForLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 512);
@@ -84,6 +86,7 @@
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XHIGH, 192);
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_360, 240);
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_400, 288);
+            expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_420, 336);
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXHIGH, 384);
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_560, 576);
             expectedMemorySizeForXLargeScreen.put(DisplayMetrics.DENSITY_XXXHIGH, 768);
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
index a8fb7c1..e722646 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationTest.java
@@ -61,6 +61,7 @@
         allowedDensities.add(DisplayMetrics.DENSITY_XHIGH);
         allowedDensities.add(DisplayMetrics.DENSITY_360);
         allowedDensities.add(DisplayMetrics.DENSITY_400);
+        allowedDensities.add(DisplayMetrics.DENSITY_420);
         allowedDensities.add(DisplayMetrics.DENSITY_XXHIGH);
         allowedDensities.add(DisplayMetrics.DENSITY_560);
         allowedDensities.add(DisplayMetrics.DENSITY_XXXHIGH);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
index d4fb235..229185d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
@@ -728,7 +728,12 @@
                             mCameraIds[i]));
                     continue;
                 }
-
+                if (!staticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, String.format(
+                        "Skipping this test for camera %s, does not support regular outputs",
+                        mCameraIds[i]));
+                    continue;
+                }
                 // Open camera and execute test
                 Log.i(TAG, "Testing Camera " + mCameraIds[i]);
                 try {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
index 3c9c061..75de9c0 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
@@ -81,14 +81,8 @@
                 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());
-                mCollector.expectTrue("Missing ActiveArraySize",
-                        activeArray.width() > 0 && activeArray.height() > 0);
-                mCollector.expectContains(
-                        "Available sizes for RAW format must include ActiveArraySize",
-                        rawSizes, size);
-
+                // Check happens in getRawDimensChecked.
+                Size rawSize = mStaticInfo.getRawDimensChecked();
             } finally {
                 closeDevice();
             }
@@ -500,8 +494,7 @@
     {
         // capture size
         Size previewSize = mOrderedPreviewSizes.get(0);
-        Rect activeArray = mStaticInfo.getActiveArraySizeChecked();
-        Size rawSize = new Size(activeArray.width(), activeArray.height());
+        Size rawSize = mStaticInfo.getRawDimensChecked();
 
         // builder
         CaptureRequest.Builder previewCaptureBuilder = mCamera.createCaptureRequest(
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
index 5ac9d09..d8fae6d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -50,6 +50,9 @@
                 Log.i(TAG, "Testing YUV Burst for camera " + id);
                 openDevice(id);
 
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                }
                 if (!mStaticInfo.isAeLockSupported() || !mStaticInfo.isAwbLockSupported()) {
                     Log.i(TAG, "AE/AWB lock is not supported in camera " + id +
                             ". Skip the test");
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
index d71acd6..44fda14 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -34,6 +34,7 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 import android.hardware.camera2.params.MeteringRectangle;
 import android.media.ImageReader;
@@ -282,6 +283,11 @@
                             sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
                         continue;
                     }
+                    // Skip non-PREVIEW templates for non-color output
+                    if (!mStaticInfo.isColorOutputSupported() &&
+                            sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
+                        continue;
+                    }
                     CaptureRequest.Builder capReq = mCamera.createCaptureRequest(sTemplates[j]);
                     assertNotNull("Failed to create capture request", capReq);
                     if (mStaticInfo.areKeysAvailable(CaptureRequest.SENSOR_EXPOSURE_TIME)) {
@@ -405,9 +411,6 @@
      */
     public void testChainedOperation() throws Throwable {
 
-        // Set up single dummy target
-        createDefaultImageReader(DEFAULT_CAPTURE_SIZE, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
-                /*listener*/ null);
         final ArrayList<Surface> outputs = new ArrayList<>();
         outputs.add(mReaderSurface);
 
@@ -546,6 +549,12 @@
         for (int i = 0; i < mCameraIds.length; i++) {
             Throwable result;
 
+            if (!(new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraIds[i]))).
+                    isColorOutputSupported()) {
+                Log.i(TAG, "Camera " + mCameraIds[i] + " does not support color outputs, skipping");
+                continue;
+            }
+
             // Start chained cascade
             ChainedCameraListener cameraListener = new ChainedCameraListener();
             mCameraManager.openCamera(mCameraIds[i], cameraListener, mHandler);
@@ -594,6 +603,11 @@
             try {
                 openDevice(mCameraIds[i], mCameraMockListener);
                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
 
                 prepareTestByCamera();
             }
@@ -611,6 +625,11 @@
             try {
                 openDevice(mCameraIds[i], mCameraMockListener);
                 waitForDeviceState(STATE_OPENED, CAMERA_OPEN_TIMEOUT_MS);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
 
                 testCreateSessionsByCamera(mCameraIds[i]);
             }
@@ -982,6 +1001,11 @@
                                 sTemplates[j] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
                             continue;
                         }
+                        // Skip non-PREVIEW templates for non-color output
+                        if (!mStaticInfo.isColorOutputSupported() &&
+                                sTemplates[j] != CameraDevice.TEMPLATE_PREVIEW) {
+                            continue;
+                        }
                         captureSingleShot(mCameraIds[i], sTemplates[j], repeating, abort);
                     }
                 }
@@ -989,13 +1013,16 @@
                     // Test: burst of one shot
                     captureBurstShot(mCameraIds[i], sTemplates, 1, repeating, abort);
 
+                    int template = mStaticInfo.isColorOutputSupported() ?
+                        CameraDevice.TEMPLATE_STILL_CAPTURE :
+                        CameraDevice.TEMPLATE_PREVIEW;
                     int[] templates = new int[] {
-                            CameraDevice.TEMPLATE_STILL_CAPTURE,
-                            CameraDevice.TEMPLATE_STILL_CAPTURE,
-                            CameraDevice.TEMPLATE_STILL_CAPTURE,
-                            CameraDevice.TEMPLATE_STILL_CAPTURE,
-                            CameraDevice.TEMPLATE_STILL_CAPTURE
-                            };
+                        template,
+                        template,
+                        template,
+                        template,
+                        template
+                    };
 
                     // Test: burst of 5 shots of the same template type
                     captureBurstShot(mCameraIds[i], templates, templates.length, repeating, abort);
@@ -1075,6 +1102,11 @@
                     templates[i] == CameraDevice.TEMPLATE_VIDEO_SNAPSHOT) {
                 continue;
             }
+            // Skip non-PREVIEW templates for non-color outpu
+            if (!mStaticInfo.isColorOutputSupported() &&
+                    templates[i] != CameraDevice.TEMPLATE_PREVIEW) {
+                continue;
+            }
             CaptureRequest.Builder requestBuilder = mCamera.createCaptureRequest(templates[i]);
             assertNotNull("Failed to create capture request", requestBuilder);
             requestBuilder.addTarget(mReaderSurface);
@@ -1135,6 +1167,11 @@
         mSessionMockListener = spy(new BlockingSessionCallback());
         mSessionWaiter = mSessionMockListener.getStateWaiter();
 
+        if (!mStaticInfo.isColorOutputSupported()) {
+            createDefaultImageReader(getMaxDepthSize(mCamera.getId(), mCameraManager),
+                    ImageFormat.DEPTH16, MAX_NUM_IMAGES, new ImageDropperListener());
+        }
+
         List<Surface> outputSurfaces = new ArrayList<>(Arrays.asList(mReaderSurface));
         mCamera.createCaptureSession(outputSurfaces, mSessionMockListener, mHandler);
 
@@ -1229,9 +1266,9 @@
 
     private void checkAfMode(CaptureRequest.Builder request, int template,
             CameraCharacteristics props) {
-        boolean hasFocuser = !props.getKeys().contains(CameraCharacteristics.
-                LENS_INFO_MINIMUM_FOCUS_DISTANCE) ||
-                props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f;
+        boolean hasFocuser = props.getKeys().contains(CameraCharacteristics.
+                LENS_INFO_MINIMUM_FOCUS_DISTANCE) &&
+                (props.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE) > 0f);
 
         if (!hasFocuser) {
             return;
@@ -1273,6 +1310,8 @@
             return;
         }
 
+        if (!mStaticInfo.isColorOutputSupported()) return;
+
         List<Integer> availableAntiBandingModes =
                 Arrays.asList(toObject(mStaticInfo.getAeAvailableAntiBandingModesChecked()));
 
@@ -1324,12 +1363,16 @@
         }
 
         // 3A settings--AE/AWB/AF.
-        int maxRegionsAe = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
-        int maxRegionsAwb = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
-        int maxRegionsAf = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+        Integer maxRegionsAeVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+        int maxRegionsAe = maxRegionsAeVal != null ? maxRegionsAeVal : 0;
+        Integer maxRegionsAwbVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
+        int maxRegionsAwb = maxRegionsAwbVal != null ? maxRegionsAwbVal : 0;
+        Integer maxRegionsAfVal = props.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+        int maxRegionsAf = maxRegionsAfVal != null ? maxRegionsAfVal : 0;
+
+        checkFpsRange(request, template, props);
 
         checkAfMode(request, template, props);
-        checkFpsRange(request, template, props);
         checkAntiBandingMode(request, template);
 
         if (template == CameraDevice.TEMPLATE_MANUAL) {
@@ -1339,45 +1382,47 @@
             mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
                     CaptureRequest.CONTROL_AWB_MODE_OFF);
         } else {
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
-                    CaptureRequest.CONTROL_AE_MODE_ON);
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
-            mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
-                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
-            // if AE lock is not supported, expect the control key to be non-exist or false
-            if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
-                mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
-            }
+            if (mStaticInfo.isColorOutputSupported()) {
+                mCollector.expectKeyValueEquals(request, CONTROL_AE_MODE,
+                        CaptureRequest.CONTROL_AE_MODE_ON);
+                mCollector.expectKeyValueEquals(request, CONTROL_AE_EXPOSURE_COMPENSATION, 0);
+                mCollector.expectKeyValueEquals(request, CONTROL_AE_PRECAPTURE_TRIGGER,
+                        CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_IDLE);
+                // if AE lock is not supported, expect the control key to be non-exist or false
+                if (mStaticInfo.isAeLockSupported() || request.get(CONTROL_AE_LOCK) != null) {
+                    mCollector.expectKeyValueEquals(request, CONTROL_AE_LOCK, false);
+                }
 
-            mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
-                    CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+                mCollector.expectKeyValueEquals(request, CONTROL_AF_TRIGGER,
+                        CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
 
-            mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
-                    CaptureRequest.CONTROL_AWB_MODE_AUTO);
-            // if AWB lock is not supported, expect the control key to be non-exist or false
-            if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
-                mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
-            }
+                mCollector.expectKeyValueEquals(request, CONTROL_AWB_MODE,
+                        CaptureRequest.CONTROL_AWB_MODE_AUTO);
+                // if AWB lock is not supported, expect the control key to be non-exist or false
+                if (mStaticInfo.isAwbLockSupported() || request.get(CONTROL_AWB_LOCK) != null) {
+                    mCollector.expectKeyValueEquals(request, CONTROL_AWB_LOCK, false);
+                }
 
-            // Check 3A regions.
-            if (VERBOSE) {
-                Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}",
-                        maxRegionsAe, maxRegionsAwb, maxRegionsAf));
-            }
-            if (maxRegionsAe > 0) {
-                mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS);
-                MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
-                checkMeteringRect(aeRegions);
-            }
-            if (maxRegionsAwb > 0) {
-                mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS);
-                MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS);
-                checkMeteringRect(awbRegions);
-            }
-            if (maxRegionsAf > 0) {
-                mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS);
-                MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
-                checkMeteringRect(afRegions);
+                // Check 3A regions.
+                if (VERBOSE) {
+                    Log.v(TAG, String.format("maxRegions is: {AE: %s, AWB: %s, AF: %s}",
+                                    maxRegionsAe, maxRegionsAwb, maxRegionsAf));
+                }
+                if (maxRegionsAe > 0) {
+                    mCollector.expectKeyValueNotNull(request, CONTROL_AE_REGIONS);
+                    MeteringRectangle[] aeRegions = request.get(CONTROL_AE_REGIONS);
+                    checkMeteringRect(aeRegions);
+                }
+                if (maxRegionsAwb > 0) {
+                    mCollector.expectKeyValueNotNull(request, CONTROL_AWB_REGIONS);
+                    MeteringRectangle[] awbRegions = request.get(CONTROL_AWB_REGIONS);
+                    checkMeteringRect(awbRegions);
+                }
+                if (maxRegionsAf > 0) {
+                    mCollector.expectKeyValueNotNull(request, CONTROL_AF_REGIONS);
+                    MeteringRectangle[] afRegions = request.get(CONTROL_AF_REGIONS);
+                    checkMeteringRect(afRegions);
+                }
             }
         }
 
@@ -1446,10 +1491,12 @@
         }
 
         // ISP-processing settings.
-        mCollector.expectKeyValueEquals(
-                request, STATISTICS_FACE_DETECT_MODE,
-                CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF);
-        mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
+        if (mStaticInfo.isColorOutputSupported()) {
+            mCollector.expectKeyValueEquals(
+                    request, STATISTICS_FACE_DETECT_MODE,
+                    CaptureRequest.STATISTICS_FACE_DETECT_MODE_OFF);
+            mCollector.expectKeyValueEquals(request, FLASH_MODE, CaptureRequest.FLASH_MODE_OFF);
+        }
 
         List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
         if (mStaticInfo.areKeysAvailable(STATISTICS_LENS_SHADING_MAP_MODE)) {
@@ -1608,6 +1655,10 @@
                 } else if (sLegacySkipTemplates.contains(template) &&
                         mStaticInfo.isHardwareLevelLegacy()) {
                     // OK
+                } else if (template != CameraDevice.TEMPLATE_PREVIEW &&
+                        mStaticInfo.isDepthOutputSupported() &&
+                        !mStaticInfo.isColorOutputSupported()) {
+                    // OK, depth-only devices need only support PREVIEW template
                 } else {
                     throw e; // rethrow
                 }
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 a823512..c5eb27b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -817,9 +817,10 @@
 
         ByteBuffer buffer = null;
         // JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
-        if (format == ImageFormat.JPEG) {
+        // Same goes for DEPTH_POINT_CLOUD
+        if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD) {
             buffer = planes[0].getBuffer();
-            assertNotNull("Fail to get jpeg ByteBuffer", buffer);
+            assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
             data = new byte[buffer.remaining()];
             buffer.get(data);
             buffer.rewind();
@@ -897,7 +898,9 @@
                 break;
             case ImageFormat.JPEG:
             case ImageFormat.RAW_SENSOR:
-                assertEquals("Jpeg Image should have one plane", 1, planes.length);
+            case ImageFormat.DEPTH16:
+            case ImageFormat.DEPTH_POINT_CLOUD:
+                assertEquals("JPEG/RAW/depth Images should have one plane", 1, planes.length);
                 break;
             default:
                 fail("Unsupported Image Format: " + format);
@@ -1164,6 +1167,16 @@
     }
 
     /**
+     * Get max depth size for a camera device.
+     */
+    static public Size getMaxDepthSize(String cameraId, CameraManager cameraManager)
+            throws CameraAccessException {
+        List<Size> sizes = getSortedSizesForFormat(cameraId, cameraManager, ImageFormat.DEPTH16,
+                /*bound*/ null);
+        return sizes.get(0);
+    }
+
+    /**
      * Get the largest size by area.
      *
      * @param sizes an array of sizes, must have at least 1 element
@@ -1172,7 +1185,7 @@
      *
      * @throws IllegalArgumentException if sizes was null or had 0 elements
      */
-    public static Size getMaxSize(Size[] sizes) {
+    public static Size getMaxSize(Size... sizes) {
         if (sizes == null || sizes.length == 0) {
             throw new IllegalArgumentException("sizes was empty");
         }
@@ -1267,10 +1280,6 @@
 
     /**
      * Validate image based on format and size.
-     * <p>
-     * Only RAW_SENSOR, YUV420_888 and JPEG formats are supported. Calling this
-     * method with other formats will cause a UnsupportedOperationException.
-     * </p>
      *
      * @param image The image to be validated.
      * @param width The image width.
@@ -1278,8 +1287,7 @@
      * @param format The image format.
      * @param filePath The debug dump file path, null if don't want to dump to
      *            file.
-     * @throws UnsupportedOperationException if calling with format other than
-     *             RAW_SENSOR, YUV420_888 or JPEG.
+     * @throws UnsupportedOperationException if calling with an unknown format
      */
     public static void validateImage(Image image, int width, int height, int format,
             String filePath) {
@@ -1306,6 +1314,12 @@
             case ImageFormat.RAW_SENSOR:
                 validateRaw16Data(data, width, height, format, image.getTimestamp(), filePath);
                 break;
+            case ImageFormat.DEPTH16:
+                validateDepth16Data(data, width, height, format, image.getTimestamp(), filePath);
+                break;
+            case ImageFormat.DEPTH_POINT_CLOUD:
+                validateDepthPointCloudData(data, width, height, format, image.getTimestamp(), filePath);
+                break;
             default:
                 throw new UnsupportedOperationException("Unsupported format for validation: "
                         + format);
@@ -1389,7 +1403,7 @@
             long ts, String filePath) {
         if (VERBOSE) Log.v(TAG, "Validating raw data");
         int expectedSize = width * height * ImageFormat.getBitsPerPixel(format) / 8;
-        assertEquals("Yuv data doesn't match", expectedSize, rawData.length);
+        assertEquals("Raw data doesn't match", expectedSize, rawData.length);
 
         // TODO: Can add data validation for test pattern.
 
@@ -1402,6 +1416,41 @@
         return;
     }
 
+    private static void validateDepth16Data(byte[] depthData, int width, int height, int format,
+            long ts, String filePath) {
+
+        if (VERBOSE) Log.v(TAG, "Validating depth16 data");
+        int expectedSize = width * height * ImageFormat.getBitsPerPixel(format) / 8;
+        assertEquals("Depth data doesn't match", expectedSize, depthData.length);
+
+
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".depth16";
+            dumpFile(fileName, depthData);
+        }
+
+        return;
+
+    }
+
+    private static void validateDepthPointCloudData(byte[] depthData, int width, int height, int format,
+            long ts, String filePath) {
+
+        if (VERBOSE) Log.v(TAG, "Validating depth point cloud data");
+
+        // Can't validate size since it is variable
+
+        if (DEBUG && filePath != null) {
+            String fileName =
+                    filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".depth_point_cloud";
+            dumpFile(fileName, depthData);
+        }
+
+        return;
+
+    }
+
     public static <T> T getValueNotNull(CaptureResult result, CaptureResult.Key<T> key) {
         if (result == null) {
             throw new IllegalArgumentException("Result must not be null");
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 235c1f8..3e76fbc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -268,7 +268,7 @@
                 // Without manual sensor control, exposure time cannot be verified
                 if (!mStaticInfo.isCapabilitySupported(
                         CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
-                    return;
+                    continue;
                 }
 
                 int[] modes = mStaticInfo.getAeAvailableAntiBandingModesChecked();
@@ -300,6 +300,11 @@
         for (int i = 0; i < mCameraIds.length; i++) {
             try {
                 openDevice(mCameraIds[i]);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
 
                 Size maxPreviewSz = mOrderedPreviewSizes.get(0); // Max preview size.
 
@@ -327,6 +332,11 @@
         for (int i = 0; i < mCameraIds.length; i++) {
             try {
                 openDevice(mCameraIds[i]);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
 
                 SimpleCaptureCallback listener = new SimpleCaptureCallback();
                 CaptureRequest.Builder requestBuilder =
@@ -364,7 +374,11 @@
         for (int i = 0; i < mCameraIds.length; i++) {
             try {
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 faceDetectionTestByCamera();
             } finally {
                 closeDevice();
@@ -479,7 +493,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 awbModeAndLockTestByCamera();
             } finally {
                 closeDevice();
@@ -494,7 +511,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 afModeTestByCamera();
             } finally {
                 closeDevice();
@@ -517,7 +537,10 @@
                     Log.i(TAG, "Camera " + id + " doesn't support any stabilization modes");
                     continue;
                 }
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 stabilizationTestByCamera();
             } finally {
                 closeDevice();
@@ -533,7 +556,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 Size maxPreviewSize = mOrderedPreviewSizes.get(0);
                 digitalZoomTestByCamera(maxPreviewSize);
             } finally {
@@ -550,7 +576,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 digitalZoomPreviewCombinationTestByCamera();
             } finally {
                 closeDevice();
@@ -581,7 +610,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 effectModeTestByCamera();
             } finally {
                 closeDevice();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
index df3f151..b752c07 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -97,10 +97,16 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-                // Create image reader and surface.
-                Size size = mOrderedPreviewSizes.get(0);
-                createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
-                        new ImageDropperListener());
+                if (mStaticInfo.isColorOutputSupported()) {
+                    // Create image reader and surface.
+                    Size size = mOrderedPreviewSizes.get(0);
+                    createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
+                            new ImageDropperListener());
+                } else {
+                    Size size = getMaxDepthSize(id, mCameraManager);
+                    createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES,
+                            new ImageDropperListener());
+                }
 
                 // Configure output streams.
                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
@@ -158,9 +164,15 @@
                 }
 
                 // Create image reader and surface.
-                Size size = mOrderedPreviewSizes.get(0);
-                createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
-                        new ImageDropperListener());
+                if (mStaticInfo.isColorOutputSupported()) {
+                    Size size = mOrderedPreviewSizes.get(0);
+                    createDefaultImageReader(size, ImageFormat.YUV_420_888, MAX_NUM_IMAGES,
+                            new ImageDropperListener());
+                } else {
+                    Size size = getMaxDepthSize(id, mCameraManager);
+                    createDefaultImageReader(size, ImageFormat.DEPTH16, MAX_NUM_IMAGES,
+                            new ImageDropperListener());
+                }
 
                 // Configure output streams.
                 List<Surface> outputSurfaces = new ArrayList<Surface>(1);
@@ -263,6 +275,10 @@
             SimpleImageReaderListener prevListener = new SimpleImageReaderListener();
             try {
                 openDevice(id);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
 
                 CaptureRequest.Builder previewBuilder =
                         mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
@@ -469,6 +485,8 @@
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT)) {
             waiverKeys.add(CaptureResult.LENS_POSE_ROTATION);
             waiverKeys.add(CaptureResult.LENS_POSE_TRANSLATION);
+            waiverKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION);
+            waiverKeys.add(CaptureResult.LENS_RADIAL_DISTORTION);
         }
 
         if (mStaticInfo.getAeMaxRegionsChecked() == 0) {
@@ -539,12 +557,12 @@
             waiverKeys.add(CaptureResult.LENS_FILTER_DENSITY);
         }
 
-        if (mStaticInfo.isHardwareLevelLimited()) {
+        if (mStaticInfo.isHardwareLevelLimited() && mStaticInfo.isColorOutputSupported()) {
             return waiverKeys;
         }
 
         /*
-         * Hardware Level = LEGACY
+         * Hardware Level = LEGACY or no regular output is supported
          */
         waiverKeys.add(CaptureResult.CONTROL_AE_PRECAPTURE_TRIGGER);
         waiverKeys.add(CaptureResult.CONTROL_AE_STATE);
@@ -558,6 +576,30 @@
         waiverKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
         waiverKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
 
+        if (mStaticInfo.isHardwareLevelLegacy()) {
+            return waiverKeys;
+        }
+
+        /*
+         * Regular output not supported, only depth, waive color-output-related keys
+         */
+        waiverKeys.add(CaptureResult.CONTROL_SCENE_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_EFFECT_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_VIDEO_STABILIZATION_MODE);
+        waiverKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
+        waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
+        waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_AE_ANTIBANDING_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_AE_EXPOSURE_COMPENSATION);
+        waiverKeys.add(CaptureResult.CONTROL_AE_LOCK);
+        waiverKeys.add(CaptureResult.CONTROL_AE_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_AF_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_AWB_MODE);
+        waiverKeys.add(CaptureResult.CONTROL_AWB_LOCK);
+        waiverKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
+        waiverKeys.add(CaptureResult.FLASH_MODE);
+        waiverKeys.add(CaptureResult.SCALER_CROP_REGION);
+
         return waiverKeys;
     }
 
@@ -706,6 +748,8 @@
         resultKeys.add(CaptureResult.LENS_OPTICAL_STABILIZATION_MODE);
         resultKeys.add(CaptureResult.LENS_POSE_ROTATION);
         resultKeys.add(CaptureResult.LENS_POSE_TRANSLATION);
+        resultKeys.add(CaptureResult.LENS_INTRINSIC_CALIBRATION);
+        resultKeys.add(CaptureResult.LENS_RADIAL_DISTORTION);
         resultKeys.add(CaptureResult.LENS_FOCUS_RANGE);
         resultKeys.add(CaptureResult.LENS_STATE);
         resultKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
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 f8ee615..80cd288 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -146,7 +146,17 @@
                     mIds[counter]), config);
             int[] outputFormats = config.getOutputFormats();
 
+            int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+            assertNotNull("android.request.availableCapabilities must never be null",
+                    actualCapabilities);
+
             // Check required formats exist (JPEG, and YUV_420_888).
+            if (!arrayContains(actualCapabilities, BC)) {
+                Log.i(TAG, "Camera " + mIds[counter] +
+                    ": BACKWARD_COMPATIBLE capability not supported, skipping test");
+                continue;
+            }
+
             assertArrayContains(
                     String.format("No valid YUV_420_888 preview formats found for: ID %s",
                             mIds[counter]), outputFormats, ImageFormat.YUV_420_888);
@@ -291,75 +301,76 @@
              * for a fact most keys are going to be illegal there so they should never be
              * available.
              *
-             * (TODO: Codegen this)
+             * For LIMITED-level keys, if the level is >= LIMITED, then the capabilities are used to
+             * do the actual checking.
              */
             {
                 //                                           (Key Name)                                     (HW Level)  (Capabilities <Var-Arg>)
-                expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES     , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES                         , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE                       , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE                      , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE                          , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF                          , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB                         , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES     , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_MODES                         , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_ANTIBANDING_MODES          , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES                      , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES          , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE                   , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP                    , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AE_LOCK_AVAILABLE                       , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES                      , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS                       , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES                   , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES     , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES                     , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_AWB_LOCK_AVAILABLE                      , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AE                          , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AF                          , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB                         , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.EDGE_AVAILABLE_EDGE_MODES                       , FULL     ,   NONE                 );
-                expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE                            , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.FLASH_INFO_AVAILABLE                            , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES             , OPT      ,   RAW                  );
-                expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.LENS_FACING                                     , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL                   , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.JPEG_AVAILABLE_THUMBNAIL_SIZES                  , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.LENS_FACING                                     , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES                   , FULL     ,   MANUAL_SENSOR        );
                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FILTER_DENSITIES            , FULL     ,   MANUAL_SENSOR        );
-                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION       , LIMITED  ,   MANUAL_SENSOR        );
+                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS               , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION       , LIMITED  ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_FOCUS_DISTANCE_CALIBRATION            , LIMITED  ,   MANUAL_SENSOR        );
-                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE                   , LIMITED  ,   MANUAL_SENSOR        );
-                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE                , LIMITED  ,   NONE                 );
-                expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE                   , LIMITED  ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE                , LIMITED  ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES                  , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_INPUT_STREAMS                   , OPT      ,   YUV_REPROCESS, OPAQUE_REPROCESS);
                 expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , OPT      ,   CONSTRAINED_HIGH_SPEED);
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC                     , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING            , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW                      , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE                            , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             , LEGACY   ,   NONE                 );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC                     , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_PROC_STALLING            , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_MAX_NUM_OUTPUT_RAW                      , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT                    , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH                      , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SCALER_AVAILABLE_MAX_DIGITAL_ZOOM               , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP                 , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SCALER_CROPPING_TYPE                            , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_AVAILABLE_TEST_PATTERN_MODES             , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN                      , FULL     ,   MANUAL_SENSOR, RAW   );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_CALIBRATION_TRANSFORM1                   , OPT      ,   RAW                  );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_COLOR_TRANSFORM1                         , OPT      ,   RAW                  );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_FORWARD_MATRIX1                          , OPT      ,   RAW                  );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   , LEGACY   ,   BC, RAW              );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE                   , OPT      ,   BC, RAW              );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT            , FULL     ,   RAW                  );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE                 , FULL     ,   MANUAL_SENSOR        );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_MAX_FRAME_DURATION                  , FULL     ,   MANUAL_SENSOR        );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE                       , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE                    , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE                   , FULL     ,   MANUAL_SENSOR        );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL                         , OPT      ,   RAW                  );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE                    , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE                    , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_MAX_ANALOG_SENSITIVITY                   , FULL     ,   MANUAL_SENSOR        );
-                expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION                              , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SENSOR_ORIENTATION                              , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.SENSOR_REFERENCE_ILLUMINANT1                    , OPT      ,   RAW                  );
                 expectKeyAvailable(c, CameraCharacteristics.SHADING_AVAILABLE_MODES                         , LIMITED  ,   MANUAL_POSTPROC, RAW );
-                expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES     , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES   , OPT      ,   RAW                  );
                 expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, LIMITED  ,   RAW                  );
-                expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  , LEGACY   ,   BC                   );
-                expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY                                , LEGACY   ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT                  , OPT      ,   BC                   );
+                expectKeyAvailable(c, CameraCharacteristics.SYNC_MAX_LATENCY                                , OPT      ,   BC                   );
                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_AVAILABLE_TONE_MAP_MODES                , FULL     ,   MANUAL_POSTPROC      );
                 expectKeyAvailable(c, CameraCharacteristics.TONEMAP_MAX_CURVE_POINTS                        , FULL     ,   MANUAL_POSTPROC      );
 
@@ -476,6 +487,14 @@
             // Check if the burst capability is defined
             boolean haveBurstCapability = arrayContains(actualCapabilities,
                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE);
+            boolean haveBC = arrayContains(actualCapabilities,
+                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+
+            if(haveBurstCapability && !haveBC) {
+                fail("Must have BACKWARD_COMPATIBLE capability if BURST_CAPTURE capability is defined");
+            }
+
+            if (!haveBC) continue;
 
             StreamConfigurationMap config =
                     c.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
@@ -730,31 +749,41 @@
             assertNotNull(String.format("No stream configuration map found for: ID %s",
                             mIds[counter]), config);
 
-            assertTrue("ImageReader must be supported",
+            int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+            assertNotNull("android.request.availableCapabilities must never be null",
+                    actualCapabilities);
+
+            if (arrayContains(actualCapabilities, BC)) {
+                assertTrue("ImageReader must be supported",
                     config.isOutputSupportedFor(android.media.ImageReader.class));
-            assertTrue("MediaRecorder must be supported",
+                assertTrue("MediaRecorder must be supported",
                     config.isOutputSupportedFor(android.media.MediaRecorder.class));
-            assertTrue("MediaCodec must be supported",
+                assertTrue("MediaCodec must be supported",
                     config.isOutputSupportedFor(android.media.MediaCodec.class));
-            assertTrue("Allocation must be supported",
+                assertTrue("Allocation must be supported",
                     config.isOutputSupportedFor(android.renderscript.Allocation.class));
-            assertTrue("SurfaceHolder must be supported",
+                assertTrue("SurfaceHolder must be supported",
                     config.isOutputSupportedFor(android.view.SurfaceHolder.class));
-            assertTrue("SurfaceTexture must be supported",
+                assertTrue("SurfaceTexture must be supported",
                     config.isOutputSupportedFor(android.graphics.SurfaceTexture.class));
 
-            assertTrue("YUV_420_888 must be supported",
+                assertTrue("YUV_420_888 must be supported",
                     config.isOutputSupportedFor(ImageFormat.YUV_420_888));
-            assertTrue("JPEG must be supported",
+                assertTrue("JPEG must be supported",
                     config.isOutputSupportedFor(ImageFormat.JPEG));
+            } else {
+                assertTrue("YUV_420_88 may not be supported if BACKWARD_COMPATIBLE capability is not listed",
+                    !config.isOutputSupportedFor(ImageFormat.YUV_420_888));
+                assertTrue("JPEG may not be supported if BACKWARD_COMPATIBLE capability is not listed",
+                    !config.isOutputSupportedFor(ImageFormat.JPEG));
+            }
 
             // Legacy YUV formats should not be listed
             assertTrue("NV21 must not be supported",
                     !config.isOutputSupportedFor(ImageFormat.NV21));
 
-            int[] actualCapabilities = c.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
-            assertNotNull("android.request.availableCapabilities must never be null",
-                    actualCapabilities);
+            // Check RAW
+
             if (arrayContains(actualCapabilities,
                     CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
                 assertTrue("RAW_SENSOR must be supported if RAW capability is advertised",
@@ -872,49 +901,50 @@
             } // formats
 
             // Cross-check opaque format and sizes
+            if (arrayContains(actualCapabilities, BC)) {
+                SurfaceTexture st = new SurfaceTexture(1);
+                Surface surf = new Surface(st);
 
-            SurfaceTexture st = new SurfaceTexture(1);
-            Surface surf = new Surface(st);
+                Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class,
+                        mIds[counter], mCameraManager);
+                assertTrue("Opaque format has no sizes listed",
+                        opaqueSizes.length > 0);
+                for (Size size : opaqueSizes) {
+                    long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size);
+                    assertTrue("Opaque output may not have a non-zero stall duration",
+                            stallDuration == 0);
 
-            Size[] opaqueSizes = CameraTestUtils.getSupportedSizeForClass(SurfaceTexture.class,
-                    mIds[counter], mCameraManager);
-            assertTrue("Opaque format has no sizes listed",
-                    opaqueSizes.length > 0);
-            for (Size size : opaqueSizes) {
-                long stallDuration = config.getOutputStallDuration(SurfaceTexture.class, size);
-                assertTrue("Opaque output may not have a non-zero stall duration",
-                        stallDuration == 0);
+                    long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size);
+                    if (arrayContains(actualCapabilities,
+                                    CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+                        assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
+                                + "opaque format",
+                                minDuration > 0);
+                    } else {
+                        assertTrue("Need non-negative min frame duration for opaque format ",
+                                minDuration >= 0);
+                    }
+                    st.setDefaultBufferSize(size.getWidth(), size.getHeight());
 
-                long minDuration = config.getOutputMinFrameDuration(SurfaceTexture.class, size);
-                if (arrayContains(actualCapabilities,
-                                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
-                    assertTrue("MANUAL_SENSOR capability, need positive min frame duration for"
-                            + "opaque format",
-                            minDuration > 0);
-                } else {
-                    assertTrue("Need non-negative min frame duration for opaque format ",
-                            minDuration >= 0);
-                }
-                st.setDefaultBufferSize(size.getWidth(), size.getHeight());
+                    assertTrue(
+                            String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
+                                    size.toString()),
+                            config.isOutputSupportedFor(surf));
 
+                } // opaque sizes
+
+                // Try invalid opaque size, should get rounded
+                Size invalidSize = findInvalidSize(opaqueSizes);
+                st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight());
                 assertTrue(
-                    String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
-                            size.toString()),
-                    config.isOutputSupportedFor(surf));
+                        String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
+                                invalidSize.toString()),
+                        config.isOutputSupportedFor(surf));
 
-            } // opaque sizes
+                counter++;
+            }
 
-            // Try invalid opaque size, should get rounded
-            Size invalidSize = findInvalidSize(opaqueSizes);
-            st.setDefaultBufferSize(invalidSize.getWidth(), invalidSize.getHeight());
-            assertTrue(
-                String.format("isOutputSupportedFor fails for SurfaceTexture config %s",
-                        invalidSize.toString()),
-                config.isOutputSupportedFor(surf));
-
-            counter++;
         } // mCharacteristics
-
     }
 
     /**
@@ -1036,7 +1066,8 @@
 
         T value = c.get(key);
 
-        if (compareHardwareLevel(actualHwLevel, hwLevel) >= 0) {
+        // For LIMITED-level targeted keys, rely on capability check, not level
+        if ((compareHardwareLevel(actualHwLevel, hwLevel) >= 0) && (hwLevel != LIMITED)) {
             mCollector.expectTrue(
                     String.format("Key (%s) must be in characteristics for this hardware level " +
                             "(required minimal HW level %s, actual HW level %s)",
@@ -1050,18 +1081,21 @@
                             toStringHardwareLevel(actualHwLevel)),
                     allKeys.contains(key));
         } else if (arrayContainsAnyOf(actualCapabilities, capabilities)) {
-            mCollector.expectTrue(
+            if (!(hwLevel == LIMITED && compareHardwareLevel(actualHwLevel, hwLevel) < 0)) {
+                // Don't enforce LIMITED-starting keys on LEGACY level, even if cap is defined
+                mCollector.expectTrue(
                     String.format("Key (%s) must be in characteristics for these capabilities " +
                             "(required capabilities %s, actual capabilities %s)",
                             key.getName(), Arrays.toString(capabilities),
                             Arrays.toString(actualCapabilities)),
                     value != null);
-            mCollector.expectTrue(
+                mCollector.expectTrue(
                     String.format("Key (%s) must be in characteristics list of keys for " +
                             "these capabilities (required capabilities %s, actual capabilities %s)",
                             key.getName(), Arrays.toString(capabilities),
                             Arrays.toString(actualCapabilities)),
                     allKeys.contains(key));
+            }
         } else {
             if (actualHwLevel == LEGACY && hwLevel != OPT) {
                 if (value != null || allKeys.contains(key)) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 8cba6fd..7c80c7d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -66,8 +66,12 @@
     private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    // number of frame (for streaming requests) to be verified.
+    // Number of frame (for streaming requests) to be verified.
     private static final int NUM_FRAME_VERIFIED = 2;
+    // Number of frame (for streaming requests) to be verified with log processing time.
+    private static final int NUM_LONG_PROCESS_TIME_FRAME_VERIFIED = 10;
+    // The time to hold each image for to simulate long processing time.
+    private static final int LONG_PROCESS_TIME_MS = 300;
     // Max number of images can be accessed simultaneously from ImageReader.
     private static final int MAX_NUM_IMAGES = 5;
     // Max difference allowed between YUV and JPEG patches. This tolerance is intentionally very
@@ -104,6 +108,30 @@
         }
     }
 
+    public void testDepth16() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.DEPTH16, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testDepthPointCloud() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.i(TAG, "Testing Camera " + id);
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.DEPTH_POINT_CLOUD, /*repeating*/true);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
     public void testJpeg() throws Exception {
         for (String id : mCameraIds) {
             try {
@@ -154,6 +182,30 @@
         }
     }
 
+    public void testLongProcessingRepeatingRaw() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing long processing on repeating raw for camera " + id);
+                openDevice(id);
+                bufferFormatLongProcessingTimeTestByCamera(ImageFormat.RAW_SENSOR);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    public void testLongProcessingRepeatingFlexibleYuv() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Testing long processing on repeating YUV for camera " + id);
+                openDevice(id);
+                bufferFormatLongProcessingTimeTestByCamera(ImageFormat.YUV_420_888);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
     /**
      * Test invalid access of image after an image is closed, further access
      * of the image will get an IllegalStateException. The basic assumption of
@@ -185,7 +237,11 @@
             try {
                 Log.v(TAG, "YUV and JPEG testing for camera " + id);
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 bufferFormatWithYuvTestByCamera(ImageFormat.JPEG);
             } finally {
                 closeDevice(id);
@@ -202,7 +258,11 @@
             try {
                 Log.v(TAG, "YUV and RAW testing for camera " + id);
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 bufferFormatWithYuvTestByCamera(ImageFormat.RAW_SENSOR);
             } finally {
                 closeDevice(id);
@@ -220,6 +280,11 @@
                 Log.v(TAG, "Testing all YUV image resolutions for camera " + id);
                 openDevice(id);
 
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
+
                 // Skip warmup on FULL mode devices.
                 int warmupCaptureNumber = (mStaticInfo.isHardwareLevelLegacy()) ?
                         MAX_NUM_IMAGES - 1 : 0;
@@ -594,7 +659,9 @@
     }
 
     private void invalidAccessTestAfterClose() throws Exception {
-        final int FORMAT = ImageFormat.YUV_420_888;
+        final int FORMAT = mStaticInfo.isColorOutputSupported() ?
+            ImageFormat.YUV_420_888 : ImageFormat.DEPTH16;
+
         Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(FORMAT,
                 StaticMetadata.StreamDirection.Output);
         Image img = null;
@@ -655,6 +722,94 @@
         }
     }
 
+    private void bufferFormatLongProcessingTimeTestByCamera(int format)
+            throws Exception {
+
+        final int TEST_SENSITIVITY_VALUE = mStaticInfo.getSensitivityClampToRange(204);
+        final long TEST_EXPOSURE_TIME_NS = mStaticInfo.getExposureClampToRange(28000000);
+        final long EXPOSURE_TIME_ERROR_MARGIN_NS = 100000;
+
+        Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
+                StaticMetadata.StreamDirection.Output);
+
+        // for each resolution, test imageReader:
+        for (Size sz : availableSizes) {
+            Log.v(TAG, "testing size " + sz.toString());
+            try {
+                if (VERBOSE) {
+                    Log.v(TAG, "Testing long processing time: size " + sz.toString() + " format " +
+                            format + " for camera " + mCamera.getId());
+                }
+
+                // Create ImageReader.
+                mListener  = new SimpleImageListener();
+                createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+
+                // Setting manual controls
+                List<Surface> outputSurfaces = new ArrayList<Surface>();
+                outputSurfaces.add(mReader.getSurface());
+                CaptureRequest.Builder requestBuilder = prepareCaptureRequestForSurfaces(
+                        outputSurfaces, CameraDevice.TEMPLATE_STILL_CAPTURE);
+
+                requestBuilder.set(
+                        CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_OFF);
+                requestBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
+                requestBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+                requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
+                        CaptureRequest.CONTROL_AE_MODE_OFF);
+                requestBuilder.set(CaptureRequest.CONTROL_AWB_MODE,
+                        CaptureRequest.CONTROL_AWB_MODE_OFF);
+                requestBuilder.set(CaptureRequest.SENSOR_SENSITIVITY, TEST_SENSITIVITY_VALUE);
+                requestBuilder.set(CaptureRequest.SENSOR_EXPOSURE_TIME, TEST_EXPOSURE_TIME_NS);
+
+                SimpleCaptureCallback listener = new SimpleCaptureCallback();
+                startCapture(requestBuilder.build(), /*repeating*/true, listener, mHandler);
+
+                for (int i = 0; i < NUM_LONG_PROCESS_TIME_FRAME_VERIFIED; i++) {
+                    mListener.waitForAnyImageAvailable(CAPTURE_WAIT_TIMEOUT_MS);
+
+                    // Verify image.
+                    Image img = mReader.acquireNextImage();
+                    assertNotNull("Unable to acquire next image", img);
+                    CameraTestUtils.validateImage(img, sz.getWidth(), sz.getHeight(), format,
+                            DEBUG_FILE_NAME_BASE);
+
+                    // Verify the exposure time and iso match the requested values.
+                    CaptureResult result = listener.getCaptureResult(CAPTURE_RESULT_TIMEOUT_MS);
+
+                    long exposureTimeDiff = TEST_EXPOSURE_TIME_NS -
+                            getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME);
+                    int sensitivityDiff = TEST_SENSITIVITY_VALUE -
+                            getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
+
+                    mCollector.expectTrue(
+                            String.format("Long processing frame %d format %d size %s " +
+                                    "exposure time was %d expecting %d.", i, format, sz.toString(),
+                                    getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME),
+                                    TEST_EXPOSURE_TIME_NS),
+                            exposureTimeDiff < EXPOSURE_TIME_ERROR_MARGIN_NS &&
+                            exposureTimeDiff > 0);
+
+                    mCollector.expectTrue(
+                            String.format("Long processing frame %d format %d size %s " +
+                                    "sensitivity was %d expecting %d.", i, format, sz.toString(),
+                                    getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY),
+                                    TEST_SENSITIVITY_VALUE),
+                            sensitivityDiff == 0);
+
+
+                    // Sleep to Simulate long porcessing before closing the image.
+                    Thread.sleep(LONG_PROCESS_TIME_MS);
+                    img.close();
+                }
+                // stop capture.
+                stopCapture(/*fast*/false);
+            } finally {
+                closeDefaultImageReader();
+            }
+        }
+    }
+
     /**
      * Validate capture results.
      *
@@ -753,7 +908,7 @@
             if (VERBOSE) Log.v(TAG, "Got the latest image");
             CameraTestUtils.validateImage(img, sz.getWidth(), sz.getHeight(), format,
                     DEBUG_FILE_NAME_BASE);
-            if (VERBOSE) Log.v(TAG, "finish vaildation of image " + numImageVerified);
+            if (VERBOSE) Log.v(TAG, "finish validation of image " + numImageVerified);
             img.close();
             numImageVerified++;
             reTryCount = 0;
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
index be96aeb..167e637 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
@@ -93,6 +93,10 @@
             try {
                 Log.i(TAG, "Testing Camera " + id);
                 openDevice(id);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 readerWriterFormatTestByCamera(ImageFormat.YUV_420_888);
             } finally {
                 closeDevice(id);
@@ -124,6 +128,10 @@
             try {
                 Log.i(TAG, "Testing Camera " + id);
                 openDevice(id);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 readerWriterFormatTestByCamera(CAMERA_PRIVATE_FORMAT);
             } finally {
                 closeDevice(id);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
index 0d0ecb4..dfba587 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
@@ -47,10 +47,29 @@
 
     public void testTextureViewPreview() throws Exception {
         for (String cameraId : mCameraIds) {
-            openCamera(cameraId);
-            List<TextureView> views = Arrays.asList(mTextureView[0]);
-            textureViewPreview(cameraId, views, /*ImageReader*/null);
-            closeCamera(cameraId);
+            Exception prior = null;
+
+            try {
+                openCamera(cameraId);
+                if (!getStaticInfo(cameraId).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
+                    continue;
+                }
+                List<TextureView> views = Arrays.asList(mTextureView[0]);
+                textureViewPreview(cameraId, views, /*ImageReader*/null);
+            } catch (Exception e) {
+                prior = e;
+            } finally {
+                try {
+                    closeCamera(cameraId);
+                } catch (Exception e) {
+                    if (prior != null) {
+                        Log.e(TAG, "Prior exception received: " + prior);
+                    }
+                    prior = e;
+                }
+                if (prior != null) throw prior; // Rethrow last exception.
+            }
         }
     }
 
@@ -63,6 +82,10 @@
 
             try {
                 openCamera(cameraId);
+                if (!getStaticInfo(cameraId).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
+                    continue;
+                }
                 Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
                 yuvListener =
                         new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888);
@@ -96,6 +119,10 @@
             Exception prior = null;
             try {
                 openCamera(cameraId);
+                if (!getStaticInfo(cameraId).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
+                    continue;
+                }
                 int maxNumStreamsProc =
                         getStaticInfo(cameraId).getMaxNumOutputStreamsProcessedChecked();
                 if (maxNumStreamsProc < 2) {
@@ -128,6 +155,10 @@
 
             try {
                 openCamera(cameraId);
+                if (!getStaticInfo(cameraId).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + cameraId + " does not support color outputs, skipping");
+                    continue;
+                }
                 Size previewSize = getOrderedPreviewSizes(cameraId).get(0);
                 yuvListener =
                         new ImageVerifierListener(previewSize, ImageFormat.YUV_420_888);
@@ -165,6 +196,11 @@
         try {
             for (int i = 0; i < NUM_CAMERAS_TESTED; i++) {
                 openCamera(mCameraIds[i]);
+                if (!getStaticInfo(mCameraIds[i]).isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 List<TextureView> views = Arrays.asList(mTextureView[i]);
 
                 startTextureViewPreview(mCameraIds[i], views, /*ImageReader*/null);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
index 908e6a5..4af88ca 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -109,7 +109,9 @@
      * case, there is no way for client to know the exact preview frame
      * arrival time. To approximate this time, a companion YUV420_888 stream is
      * created. The first YUV420_888 Image coming out of the ImageReader is treated
-     * as the first preview arrival time.
+     * as the first preview arrival time.</p>
+     * <p>
+     * For depth-only devices, timing is done with the DEPTH16 format instead.
      * </p>
      */
     public void testCameraLaunch() throws Exception {
@@ -124,7 +126,15 @@
         int counter = 0;
         for (String id : mCameraIds) {
             try {
-                initializeImageReader(id, ImageFormat.YUV_420_888);
+                mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(id));
+                if (mStaticInfo.isColorOutputSupported()) {
+                    initializeImageReader(id, ImageFormat.YUV_420_888);
+                } else {
+                    assertTrue("Depth output must be supported if regular output isn't!",
+                            mStaticInfo.isDepthOutputSupported());
+                    initializeImageReader(id, ImageFormat.DEPTH16);
+                }
+
                 SimpleImageListener imageListener = null;
                 long startTimeMs, openTimeMs, configureTimeMs, previewStartedTimeMs;
                 for (int i = 0; i < NUM_TEST_LOOPS; i++) {
@@ -195,8 +205,10 @@
             }
             counter++;
         }
-        mReportLog.printSummary("Camera launch average time for all cameras ",
-                Stat.getAverage(avgCameraLaunchTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+        if (mCameraIds.length != 0) {
+            mReportLog.printSummary("Camera launch average time for all cameras ",
+                    Stat.getAverage(avgCameraLaunchTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+        }
     }
 
     /**
@@ -223,6 +235,12 @@
             try {
                 openDevice(id);
 
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
+
+
                 boolean partialsExpected = mStaticInfo.getPartialResultCount() > 1;
                 long startTimeMs;
                 boolean isPartialTimingValid = partialsExpected;
@@ -306,8 +324,10 @@
         }
 
         // Result will not be reported in CTS report if no summary is printed.
-        mReportLog.printSummary("Camera capture result average latency for all cameras ",
-                Stat.getAverage(avgResultTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+        if (mCameraIds.length != 0) {
+            mReportLog.printSummary("Camera capture result average latency for all cameras ",
+                    Stat.getAverage(avgResultTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+        }
     }
 
     /**
@@ -476,7 +496,7 @@
         for (int i = 0; i < maxCaptureGapsMs.length; i++) {
             double stallDurationBound = averageFrameDurationMs[i] *
                     (maxCaptureStallFrames + 1) * (1 + REPROCESS_STALL_MARGIN);
-            assertTrue("max capture stall duration should be no larger than ",
+            assertTrue("max capture stall duration should be no larger than " + stallDurationBound,
                     maxCaptureGapsMs[i] <= stallDurationBound);
         }
     }
@@ -656,7 +676,9 @@
 
         CaptureRequest.Builder previewBuilder =
                 mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
-        previewBuilder.addTarget(mPreviewSurface);
+        if (mStaticInfo.isColorOutputSupported()) {
+            previewBuilder.addTarget(mPreviewSurface);
+        }
         previewBuilder.addTarget(mReaderSurface);
         mSession.setRepeatingRequest(previewBuilder.build(), listener, mHandler);
         imageListener.waitForImageAvailable(CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
@@ -671,7 +693,9 @@
         }
         mSessionListener = new BlockingSessionCallback();
         List<Surface> outputSurfaces = new ArrayList<>();
-        outputSurfaces.add(mPreviewSurface);
+        if (mStaticInfo.isColorOutputSupported()) {
+            outputSurfaces.add(mPreviewSurface);
+        }
         outputSurfaces.add(mReaderSurface);
         mSession = CameraTestUtils.configureCameraSession(mCamera, outputSurfaces,
                 mSessionListener, mHandler);
@@ -683,8 +707,8 @@
      * @param format The format used to create ImageReader instance.
      */
     private void initializeImageReader(String cameraId, int format) throws Exception {
-        mOrderedPreviewSizes = CameraTestUtils.getSupportedPreviewSizes(
-                cameraId, mCameraManager,
+        mOrderedPreviewSizes = CameraTestUtils.getSortedSizesForFormat(
+                cameraId, mCameraManager, format,
                 CameraTestUtils.getPreviewSizeBound(mWindowManager,
                     CameraTestUtils.PREVIEW_SIZE_BOUND));
         Size maxPreviewSize = mOrderedPreviewSizes.get(0);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 3885376..a6cf613 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -50,6 +50,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.HashMap;
 
 /**
  * CameraDevice video recording use case tests by using MediaRecorder and
@@ -109,7 +110,11 @@
                 // Re-use the MediaRecorder object for the same camera device.
                 mMediaRecorder = new MediaRecorder();
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 initSupportedVideoSize(mCameraIds[i]);
 
                 basicRecordingTestByCamera(mCamcorderProfileList);
@@ -174,7 +179,11 @@
                 // Re-use the MediaRecorder object for the same camera device.
                 mMediaRecorder = new MediaRecorder();
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 initSupportedVideoSize(mCameraIds[i]);
 
                 recordingSizeTestByCamera();
@@ -271,7 +280,11 @@
                 // Re-use the MediaRecorder object for the same camera device.
                 mMediaRecorder = new MediaRecorder();
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 initSupportedVideoSize(mCameraIds[i]);
 
                 int minFpsProfileId = -1, minFps = 1000;
@@ -323,7 +336,11 @@
                 // Re-use the MediaRecorder object for the same camera device.
                 mMediaRecorder = new MediaRecorder();
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 if (!mStaticInfo.isHighSpeedVideoSupported()) {
                     continue;
                 }
@@ -708,6 +725,12 @@
 
                     openDevice(id);
 
+                    if (!mStaticInfo.isColorOutputSupported()) {
+                        Log.i(TAG, "Camera " + id +
+                                " does not support color outputs, skipping");
+                        continue;
+                    }
+
                     initSupportedVideoSize(id);
 
                     videoSnapshotTestByCamera(burstTest);
@@ -787,28 +810,59 @@
             // For LEGACY, find closest supported smaller or equal JPEG size to the current video
             // size; if no size is smaller than the video, pick the smallest JPEG size.  The assert
             // for video size above guarantees that for LIMITED or FULL, we select videoSz here.
+            // Also check for minFrameDuration here to make sure jpeg stream won't slow down
+            // video capture
             Size videoSnapshotSz = mOrderedStillSizes.get(mOrderedStillSizes.size() - 1);
+            // Allow a bit tolerance so we don't fail for a few nano seconds of difference
+            final float FRAME_DURATION_TOLERANCE = 0.01f;
+            long videoFrameDuration = (long) (1e9 / profile.videoFrameRate *
+                    (1.0 + FRAME_DURATION_TOLERANCE));
+            HashMap<Size, Long> minFrameDurationMap = mStaticInfo.
+                    getAvailableMinFrameDurationsForFormatChecked(ImageFormat.JPEG);
             for (int i = mOrderedStillSizes.size() - 2; i >= 0; i--) {
                 Size candidateSize = mOrderedStillSizes.get(i);
+                Long jpegFrameDuration = minFrameDurationMap.get(candidateSize);
+                assertTrue("Cannot find minimum frame duration for jpeg size " + candidateSize,
+                        jpegFrameDuration != null);
                 if (candidateSize.getWidth() <= videoSz.getWidth() &&
-                        candidateSize.getHeight() <= videoSz.getHeight()) {
+                        candidateSize.getHeight() <= videoSz.getHeight() &&
+                        jpegFrameDuration <= videoFrameDuration) {
                     videoSnapshotSz = candidateSize;
                 }
             }
-            if (videoSnapshotSz.getWidth() * videoSnapshotSz.getHeight() > FRAME_SIZE_15M)
-                kFrameDrop_Tolerence = (int)(FRAMEDROP_TOLERANCE * FRAME_DROP_TOLERENCE_FACTOR);
 
             /**
              * Only test full res snapshot when below conditions are all true.
              * 1. Camera is a FULL device
              * 2. video size is up to max preview size, which will be bounded by 1080p.
+             * 3. Full resolution jpeg stream can keep up to video stream speed.
+             *    When full res jpeg stream cannot keep up to video stream speed, search
+             *    the largest jpeg size that can susptain video speed instead.
              */
             if (mStaticInfo.isHardwareLevelFull() &&
                     videoSz.getWidth() <= maxPreviewSize.getWidth() &&
                     videoSz.getHeight() <= maxPreviewSize.getHeight()) {
-                videoSnapshotSz = mOrderedStillSizes.get(0);
+                for (Size jpegSize : mOrderedStillSizes) {
+                    Long jpegFrameDuration = minFrameDurationMap.get(jpegSize);
+                    assertTrue("Cannot find minimum frame duration for jpeg size " + jpegSize,
+                            jpegFrameDuration != null);
+                    if (jpegFrameDuration <= videoFrameDuration) {
+                        videoSnapshotSz = jpegSize;
+                        break;
+                    }
+                    if (jpegSize.equals(videoSz)) {
+                        throw new AssertionFailedError(
+                                "Cannot find adequate video snapshot size for video size" +
+                                        videoSz);
+                    }
+                }
             }
 
+            Log.i(TAG, "Testing video snapshot size " + videoSnapshotSz +
+                    " for video size " + videoSz);
+            if (videoSnapshotSz.getWidth() * videoSnapshotSz.getHeight() > FRAME_SIZE_15M)
+                kFrameDrop_Tolerence = (int)(FRAMEDROP_TOLERANCE * FRAME_DROP_TOLERENCE_FACTOR);
+
             createImageReader(
                     videoSnapshotSz, ImageFormat.JPEG,
                     MAX_VIDEO_SNAPSHOT_IMAGES, /*listener*/null);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
index e774738..8a60dc2 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
@@ -54,7 +54,7 @@
     private static final int CAPTURE_TIMEOUT_MS = 3000;
     private static final int WAIT_FOR_SURFACE_CHANGE_TIMEOUT_MS = 1000;
     private static final int CAPTURE_TEMPLATE = CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG;
-    private static final int PREVIEW_TEMPLATE = CameraDevice.TEMPLATE_PREVIEW;
+    private static final int ZSL_TEMPLATE = CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG;
     private static final int NUM_REPROCESS_TEST_LOOP = 3;
     private static final int NUM_REPROCESS_CAPTURES = 3;
     private static final int NUM_REPROCESS_BURST = 3;
@@ -1242,7 +1242,7 @@
      * Start preview without a listener.
      */
     private void startPreview(Surface previewSurface) throws Exception {
-        CaptureRequest.Builder builder = mCamera.createCaptureRequest(PREVIEW_TEMPLATE);
+        CaptureRequest.Builder builder = mCamera.createCaptureRequest(ZSL_TEMPLATE);
         builder.addTarget(previewSurface);
         mSession.setRepeatingRequest(builder.build(), null, mHandler);
     }
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 5e1f399..34f2d85 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -81,10 +81,17 @@
                 Log.i(TAG, "Testing Camera " + id);
                 openDevice(id);
 
+                List<Size> testSizes = null;
+                int format = mStaticInfo.isColorOutputSupported() ?
+                    ImageFormat.YUV_420_888 : ImageFormat.DEPTH16;
+
+                testSizes = CameraTestUtils.getSortedSizesForFormat(id, mCameraManager,
+                        format, null);
+
                 // Find some size not supported by the camera
                 Size weirdSize = new Size(643, 577);
                 int count = 0;
-                while(mOrderedPreviewSizes.contains(weirdSize)) {
+                while(testSizes.contains(weirdSize)) {
                     // Really, they can't all be supported...
                     weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
                     count++;
@@ -93,7 +100,7 @@
 
                 // Setup imageReader with invalid dimension
                 ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
-                        weirdSize.getHeight(), ImageFormat.YUV_420_888, 3);
+                        weirdSize.getHeight(), format, 3);
 
                 // Setup ImageReaderListener
                 SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
@@ -138,7 +145,7 @@
                 Size actualSize = new Size(imageWidth, imageHeight);
 
                 assertTrue("Camera does not contain outputted image resolution " + actualSize,
-                        mOrderedPreviewSizes.contains(actualSize));
+                        testSizes.contains(actualSize));
             } finally {
                 closeDevice(id);
             }
@@ -221,10 +228,12 @@
                 Log.v(TAG, "StreamConfigurationMap: " + streamConfigurationMapString);
             }
 
-            // Always run legacy-level tests
+            // Always run legacy-level tests for color-supporting devices
 
-            for (int[] config : LEGACY_COMBINATIONS) {
-                testOutputCombination(id, config, maxSizes);
+            if (mStaticInfo.isColorOutputSupported()) {
+                for (int[] config : LEGACY_COMBINATIONS) {
+                    testOutputCombination(id, config, maxSizes);
+                }
             }
 
             // Then run higher-level tests if applicable
@@ -233,8 +242,10 @@
 
                 // If not legacy, at least limited, so run limited-level tests
 
-                for (int[] config : LIMITED_COMBINATIONS) {
-                    testOutputCombination(id, config, maxSizes);
+                if (mStaticInfo.isColorOutputSupported()) {
+                    for (int[] config : LIMITED_COMBINATIONS) {
+                        testOutputCombination(id, config, maxSizes);
+                    }
                 }
 
                 // Check for BURST_CAPTURE, FULL and RAW and run those if appropriate
@@ -370,6 +381,11 @@
                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
                     continue;
                 }
+                // Depth-only devices won't support AE
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
 
                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
@@ -506,6 +522,11 @@
                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
                     continue;
                 }
+                // Depth-only devices won't support AE
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
 
                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
@@ -605,6 +626,11 @@
                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
                     continue;
                 }
+                // Depth-only devices won't support AE
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
 
                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
@@ -718,6 +744,11 @@
                 if (mStaticInfo.isHardwareLevelLegacy() || !mStaticInfo.hasFocuser()) {
                     continue;
                 }
+                // Depth-only devices won't support AE
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
 
                 int[] availableAfModes = mStaticInfo.getCharacteristics().get(
                     CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES);
@@ -1043,17 +1074,25 @@
 
             maxRawSize = (rawSizes.length != 0) ? CameraTestUtils.getMaxSize(rawSizes) : null;
 
-            maxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize);
-            maxYuvSizes[PREVIEW]  = getMaxSize(yuvSizes, maxPreviewSize);
-            maxJpegSizes[PREVIEW] = getMaxSize(jpegSizes, maxPreviewSize);
+            if (sm.isColorOutputSupported()) {
+                maxPrivSizes[PREVIEW] = getMaxSize(privSizes, maxPreviewSize);
+                maxYuvSizes[PREVIEW]  = getMaxSize(yuvSizes, maxPreviewSize);
+                maxJpegSizes[PREVIEW] = getMaxSize(jpegSizes, maxPreviewSize);
 
-            maxPrivSizes[RECORD] = getMaxRecordingSize(cameraId);
-            maxYuvSizes[RECORD]  = getMaxRecordingSize(cameraId);
-            maxJpegSizes[RECORD] = getMaxRecordingSize(cameraId);
+                maxPrivSizes[RECORD] = getMaxRecordingSize(cameraId);
+                maxYuvSizes[RECORD]  = getMaxRecordingSize(cameraId);
+                maxJpegSizes[RECORD] = getMaxRecordingSize(cameraId);
 
-            maxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes);
-            maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
-            maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
+                maxPrivSizes[MAXIMUM] = CameraTestUtils.getMaxSize(privSizes);
+                maxYuvSizes[MAXIMUM] = CameraTestUtils.getMaxSize(yuvSizes);
+                maxJpegSizes[MAXIMUM] = CameraTestUtils.getMaxSize(jpegSizes);
+
+                // Must always be supported, add unconditionally
+                final Size vgaSize = new Size(640, 480);
+                maxPrivSizes[VGA] = vgaSize;
+                maxYuvSizes[VGA] = vgaSize;
+                maxJpegSizes[VGA] = vgaSize;
+            }
 
             StreamConfigurationMap configs = sm.getCharacteristics().get(
                     CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
@@ -1064,11 +1103,6 @@
             maxInputYuvSize = yuvInputSizes != null ?
                     CameraTestUtils.getMaxSize(yuvInputSizes) : null;
 
-            // Must always be supported, add unconditionally
-            final Size vgaSize = new Size(640, 480);
-            maxPrivSizes[VGA] = vgaSize;
-            maxJpegSizes[VGA] = vgaSize;
-            maxYuvSizes[VGA] = vgaSize;
         }
 
         public final Size[] maxPrivSizes = new Size[RESOLUTION_COUNT];
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 0bc74b3..4415ecc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
@@ -73,8 +73,10 @@
             Size sensorSize = new Size(activeRect.width(), activeRect.height());
             List<Integer> availableCaps = mStaticInfo.getAvailableCapabilitiesChecked();
 
-            mCollector.expectTrue("All device must contains BACKWARD_COMPATIBLE capability",
-                    availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE));
+            mCollector.expectTrue("All devices must contains BACKWARD_COMPATIBLE capability or " +
+                    "DEPTH_OUTPUT capabillity" ,
+                    availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) ||
+                    availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) );
 
             if (mStaticInfo.isHardwareLevelFull()) {
                 // Capability advertisement must be right.
@@ -91,18 +93,25 @@
                         mStaticInfo.isPerFrameControlSupported());
             }
 
+            if (mStaticInfo.isHardwareLevelLegacy()) {
+                mCollector.expectTrue("Legacy devices must contain BACKWARD_COMPATIBLE capability",
+                        availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE));
+            }
+
             if (availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
                 mCollector.expectTrue("MANUAL_SENSOR capability always requires " +
                         "READ_SENSOR_SETTINGS capability as well",
                         availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS));
             }
 
-            // Max jpeg resolution must be very close to  sensor resolution
-            Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
-            Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
-            mCollector.expectSizesAreSimilar(
+            if (mStaticInfo.isColorOutputSupported()) {
+                // Max jpeg resolution must be very close to  sensor resolution
+                Size[] jpegSizes = mStaticInfo.getJpegOutputSizesChecked();
+                Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+                mCollector.expectSizesAreSimilar(
                     "Active array size and max JPEG size should be similar",
                     sensorSize, maxJpegSize, SIZE_ERROR_MARGIN);
+            }
 
             // TODO: test all the keys mandatory for all capability devices.
         }
@@ -127,9 +136,9 @@
                 mCollector.expectTrue("max number of processed (non-stalling) output streams" +
                         "must be >= 3 for FULL device",
                         maxNumStreamsProc >= 3);
-            } else {
+            } else if (mStaticInfo.isColorOutputSupported()) {
                 mCollector.expectTrue("max number of processed (non-stalling) output streams" +
-                        "must be >= 2 for LIMITED device",
+                        "must be >= 2 for devices that support color output",
                         maxNumStreamsProc >= 2);
             }
         }
@@ -319,7 +328,7 @@
                 Boolean contrastCurveModeSupported = false;
                 Boolean gammaAndPresetModeSupported = false;
                 Boolean offColorAberrationModeSupported = false;
-                if (mStaticInfo.isHardwareLevelLimitedOrBetter()) {
+                if (mStaticInfo.isHardwareLevelLimitedOrBetter() && mStaticInfo.isColorOutputSupported()) {
                     int[] tonemapModes = mStaticInfo.getAvailableToneMapModesChecked();
                     List<Integer> modeList = (tonemapModes.length == 0) ?
                             new ArrayList<Integer>() :
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 d8dda8f..5e931fe 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -83,7 +83,11 @@
             try {
                 Log.i(TAG, "Testing JPEG exif for Camera " + mCameraIds[i]);
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 jpegExifTestByCamera();
             } finally {
                 closeDevice();
@@ -107,7 +111,10 @@
             try {
                 Log.i(TAG, "Testing basic take picture for Camera " + id);
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null);
             } finally {
                 closeDevice();
@@ -185,7 +192,11 @@
                 if (!(mStaticInfo.hasFocuser() && maxAfRegions > 0)) {
                     continue;
                 }
-
+                // TODO: Relax test to use non-SurfaceView output for depth cases
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 touchForFocusTestByCamera();
             } finally {
                 closeDevice();
@@ -206,7 +217,10 @@
             try {
                 Log.i(TAG, "Testing Still preview capture combination for Camera " + id);
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 previewStillCombinationTestByCamera();
             } finally {
                 closeDevice();
@@ -235,7 +249,10 @@
                     Log.i(TAG, "Skipping test on legacy devices");
                     continue;
                 }
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 aeCompensationTestByCamera();
             } finally {
                 closeDevice();
@@ -327,6 +344,10 @@
             try {
                 Log.i(TAG, "Testing preview persistence for Camera " + id);
                 openDevice(id);
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 previewPersistenceTestByCamera();
             } finally {
                 closeDevice();
@@ -346,7 +367,10 @@
                     Log.i(TAG, "Skipping AE precapture trigger cancel test on legacy devices");
                     continue;
                 }
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 takePictureTestByCamera(/*aeRegions*/null, /*awbRegions*/null, /*afRegions*/null,
                         /*addAeTriggerCancel*/true);
             } finally {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
index da9b0ce..06daa51 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
@@ -77,7 +77,11 @@
             try {
                 Log.i(TAG, "Testing preview for Camera " + mCameraIds[i]);
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 previewTestByCamera();
             } finally {
                 closeDevice();
@@ -97,7 +101,11 @@
             try {
                 Log.i(TAG, "Testing preview for Camera " + mCameraIds[i]);
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 previewTestPatternTestByCamera();
             } finally {
                 closeDevice();
@@ -113,7 +121,10 @@
         for (String id : mCameraIds) {
             try {
                 openDevice(id);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
                 previewFpsRangeTestByCamera();
             } finally {
                 closeDevice();
@@ -134,7 +145,11 @@
         for (int i = 0; i < mCameraIds.length; i++) {
             try {
                 openDevice(mCameraIds[i]);
-
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + mCameraIds[i] +
+                            " does not support color outputs, skipping");
+                    continue;
+                }
                 preparePerformanceTestByCamera(mCameraIds[i]);
             }
             finally {
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 e097c18..4310b3a 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
@@ -437,7 +437,7 @@
      * @return AE max regions supported by the camera device
      */
     public int getAeMaxRegionsChecked() {
-        Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
+        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AE);
         if (regionCount == null) {
             return 0;
         }
@@ -450,7 +450,7 @@
      * @return AWB max regions supported by the camera device
      */
     public int getAwbMaxRegionsChecked() {
-        Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
+        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AWB);
         if (regionCount == null) {
             return 0;
         }
@@ -463,7 +463,7 @@
      * @return AF max regions supported by the camera device
      */
     public int getAfMaxRegionsChecked() {
-        Integer regionCount = getValueFromKeyNonNull(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
+        Integer regionCount = mCharacteristics.get(CameraCharacteristics.CONTROL_MAX_REGIONS_AF);
         if (regionCount == null) {
             return 0;
         }
@@ -2190,6 +2190,23 @@
     }
 
     /**
+     * Check if depth output is supported, based on the depth capability
+     */
+    public boolean isDepthOutputSupported() {
+        return isCapabilitySupported(
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT);
+    }
+
+    /**
+     * Check if standard outputs (PRIVATE, YUV, JPEG) outputs are supported, based on the
+     * backwards-compatible capability
+     */
+    public boolean isColorOutputSupported() {
+        return isCapabilitySupported(
+                CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE);
+    }
+
+    /**
      * Get the value in index for a fixed-size array from a given key.
      *
      * <p>If the camera device is incorrectly reporting values, log a warning and return
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
index 86dbb5b..0108ee6 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
@@ -192,11 +192,13 @@
         mCollector.setCameraId(cameraId);
         mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
                 CheckLevel.ASSERT, /*collector*/null);
-        mOrderedPreviewSizes = getSupportedPreviewSizes(
-                cameraId, mCameraManager,
-                getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
-        mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
-        mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
+        if (mStaticInfo.isColorOutputSupported()) {
+            mOrderedPreviewSizes = getSupportedPreviewSizes(
+                    cameraId, mCameraManager,
+                    getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+            mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
+            mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
+        }
 
         if (VERBOSE) {
             Log.v(TAG, "Camera " + cameraId + " is opened");
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
index 5d832d6..39bf0a5 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
@@ -362,9 +362,11 @@
                     mCameraId, mCameraListener, mHandler);
             mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(mCameraId),
                     CheckLevel.ASSERT, /*collector*/null);
-            mOrderedPreviewSizes = getSupportedPreviewSizes(
-                    mCameraId, mCameraManager,
-                    getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+            if (mStaticInfo.isColorOutputSupported()) {
+                mOrderedPreviewSizes = getSupportedPreviewSizes(
+                        mCameraId, mCameraManager,
+                        getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+            }
             assertNotNull(String.format("Failed to open camera device ID: %s", mCameraId), mCamera);
         }
 
@@ -414,4 +416,3 @@
         }
     }
 }
-
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index d25f1f5..7330a4c 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -563,14 +563,16 @@
         mCollector.setCameraId(cameraId);
         mStaticInfo = new StaticMetadata(mCameraManager.getCameraCharacteristics(cameraId),
                 CheckLevel.ASSERT, /*collector*/null);
-        mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager,
-                getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
-        mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
-        mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
-        // Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview
-        // in public API side.
-        mMinPreviewFrameDurationMap =
+        if (mStaticInfo.isColorOutputSupported()) {
+            mOrderedPreviewSizes = getSupportedPreviewSizes(cameraId, mCameraManager,
+                    getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+            mOrderedVideoSizes = getSupportedVideoSizes(cameraId, mCameraManager, PREVIEW_SIZE_BOUND);
+            mOrderedStillSizes = getSupportedStillSizes(cameraId, mCameraManager, null);
+            // Use ImageFormat.YUV_420_888 for now. TODO: need figure out what's format for preview
+            // in public API side.
+            mMinPreviewFrameDurationMap =
                 mStaticInfo.getAvailableMinFrameDurationsForFormatChecked(ImageFormat.YUV_420_888);
+        }
     }
 
     /**
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
new file mode 100644
index 0000000..4c6362a
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
@@ -0,0 +1,125 @@
+/*
+ * 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.hardware.cts;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.FifoLengthVerification;
+
+/**
+ * Checks the minimum Hardware FIFO length for each of the Hardware sensor.
+ * Further verifies if the advertised FIFO (Sensor.getFifoMaxEventCount()) is actually allocated
+ * for the sensor.
+ *
+ */
+public class SensorBatchingFifoTest extends SensorTestCase {
+    private static final int ACCELEROMETER_MIN_FIFO_LENGTH = 3000;
+    private static final int UNCAL_MAGNETOMETER_MIN_FIFO_LENGTH = 600;
+    private static final int PRESSURE_MIN_FIFO_LENGTH = 300;
+    private static final int GAME_ROTATION_VECTOR_MIN_FIFO_LENGTH = 300;
+    private static final int PROXIMITY_SENSOR_MIN_FIFO_LENGTH = 300;
+    private static final int STEP_DETECTOR_MIN_FIFO_LENGTH = 100;
+
+    private static final int SAMPLING_INTERVAL = 1000; /* every 1ms */
+    private static final String TAG = "batching_fifo_test";
+
+    private SensorManager mSensorManager;
+    private boolean mHasHifiSensors;
+    @Override
+    protected void setUp() throws Exception {
+        mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+        mHasHifiSensors = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_HIFI_SENSORS);
+    }
+
+    public void testAccelerometerFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        runBatchingSensorFifoTest(
+                Sensor.TYPE_ACCELEROMETER,
+                checkMinFifoLength(Sensor.TYPE_ACCELEROMETER, ACCELEROMETER_MIN_FIFO_LENGTH));
+    }
+
+    public void testUncalMagnetometerFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        runBatchingSensorFifoTest(
+                Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+                checkMinFifoLength(
+                        Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED,
+                        UNCAL_MAGNETOMETER_MIN_FIFO_LENGTH));
+    }
+
+    public void testPressureFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        runBatchingSensorFifoTest(
+                Sensor.TYPE_PRESSURE,
+                checkMinFifoLength(Sensor.TYPE_PRESSURE, PRESSURE_MIN_FIFO_LENGTH));
+    }
+
+    public void testGameRotationVectorFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        runBatchingSensorFifoTest(
+                Sensor.TYPE_GAME_ROTATION_VECTOR,
+                checkMinFifoLength(
+                        Sensor.TYPE_GAME_ROTATION_VECTOR, GAME_ROTATION_VECTOR_MIN_FIFO_LENGTH));
+    }
+
+    public void testProximityFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+        if (sensor != null) {
+            assertTrue(sensor.getFifoReservedEventCount() <= PROXIMITY_SENSOR_MIN_FIFO_LENGTH);
+        }
+    }
+
+    public void testStepDetectorFifoLength() throws Throwable {
+        if (!mHasHifiSensors) return;
+        checkMinFifoLength(Sensor.TYPE_STEP_DETECTOR, STEP_DETECTOR_MIN_FIFO_LENGTH);
+    }
+
+    private int checkMinFifoLength(int sensorType, int minRequiredLength) {
+        Sensor sensor = mSensorManager.getDefaultSensor(sensorType);
+        assertTrue(String.format("sensor of type=%d (null)", sensorType), sensor != null);
+        int maxFifoLength = sensor.getFifoReservedEventCount();
+        assertTrue(String.format("Sensor=%s, min required fifo length=%d actual=%d",
+                    sensor.getName(), minRequiredLength, maxFifoLength),
+                    maxFifoLength >= minRequiredLength);
+        return maxFifoLength;
+    }
+
+    private void runBatchingSensorFifoTest(int sensorType, int fifoLength) throws Throwable {
+        if (fifoLength == 0) {
+            return;
+        }
+        Sensor sensor = mSensorManager.getDefaultSensor(sensorType);
+        TestSensorEnvironment environment =  new TestSensorEnvironment(getContext(),
+                sensor,
+                false,
+                sensor.getMinDelay(),
+                Integer.MAX_VALUE);
+
+        TestSensorOperation op = TestSensorOperation.createOperation(environment,
+                sensor.getFifoReservedEventCount() * 2);
+        op.addVerification(FifoLengthVerification.getDefault(environment));
+        op.execute(getCurrentTestNode());
+        op.getStats().log(TAG);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
index f0f0186..413639a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -41,6 +41,7 @@
     public static final String DELIMITER = "__";
 
     public static final String ERROR = "error";
+    public static final String EVENT_FIFO_LENGTH = "event_fifo_length_observed";
     public static final String EVENT_GAP_COUNT_KEY = "event_gap_count";
     public static final String EVENT_GAP_POSITIONS_KEY = "event_gap_positions";
     public static final String EVENT_OUT_OF_ORDER_COUNT_KEY = "event_out_of_order_count";
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
new file mode 100644
index 0000000..09bbdc8
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
@@ -0,0 +1,163 @@
+/*
+ * 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.hardware.cts.helpers.sensorverification;
+
+import junit.framework.Assert;
+
+import android.hardware.Sensor;
+import android.hardware.cts.helpers.SensorCtsHelper;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.util.Log;
+
+import java.util.LinkedList;
+
+/**
+ * A {@link ISensorVerification} which verifies that each batch of events has the FIFO
+ *  length within the 5% of the expected value.
+ */
+public class FifoLengthVerification extends AbstractSensorVerification {
+    public static final String PASSED_KEY = "fifo_length_passed";
+
+    private static double FIFO_LENGTH_TOLERANCE = 0.8;
+
+    private final int mExpectedFifoLength;
+
+    private int mIndex = 0;
+    private LinkedList<Long> mRecvdTimeStampDiffs = new LinkedList<>();
+    private long mPrevRecvdTimeStampMs = -1,  mExpectedReportLatencyUs;
+
+    /**
+     * Construct a {@link FifoLengthVerification}
+     *
+     * @param expectedLength the expected FIFO length for the batch.
+     */
+    public FifoLengthVerification(int expectedLength, long expectedReportLatencyUs) {
+        mExpectedFifoLength = expectedLength;
+        mExpectedReportLatencyUs = expectedReportLatencyUs;
+    }
+
+    /**
+     * Get the default {@link FifoLengthVerification}.
+     *
+     * @param environment the test environment
+     * @return the verification or null if the verification is not a continuous mode sensor.
+     */
+    public static FifoLengthVerification getDefault(
+            TestSensorEnvironment environment) {
+        if (environment.getSensor().getReportingMode() != Sensor.REPORTING_MODE_CONTINUOUS) {
+            return null;
+        }
+        long expectedReportLatencyUs = environment.getMaxReportLatencyUs();
+        long fifoMaxEventCount = environment.getSensor().getFifoMaxEventCount();
+        int maximumExpectedSamplingPeriodUs = environment.getMaximumExpectedSamplingPeriodUs();
+        if (fifoMaxEventCount > 0 && maximumExpectedSamplingPeriodUs != Integer.MAX_VALUE) {
+            long fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+            // If the device goes into suspend mode and the sensor is a non wake-up sensor, the
+            // FIFO will keep overwriting itself and the reportLatency will be equal to the time
+            // it takes to fill up the FIFO.
+            if (environment.isDeviceSuspendTest() && !environment.getSensor().isWakeUpSensor()) {
+                expectedReportLatencyUs = fifoBasedReportLatencyUs;
+            } else {
+                // In this case the sensor under test is either a wake-up sensor OR it
+                // is a non wake-up sensor but the device does not go into suspend.
+                // So the expected delay of a sensor_event is the minimum of the
+                // fifoBasedReportLatencyUs and the requested latency by the application.
+                expectedReportLatencyUs = Math.min(expectedReportLatencyUs,
+                        fifoBasedReportLatencyUs);
+            }
+        }
+
+        return new FifoLengthVerification(environment.getSensor().getFifoMaxEventCount(),
+                expectedReportLatencyUs);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void verify(TestSensorEnvironment environment, SensorStats stats) {
+        if (mExpectedFifoLength <= 0) {
+            // the expected length isn't defined.
+            stats.addValue(PASSED_KEY, "skipped (no fifo length requirements)");
+            return;
+        }
+        int batchCount = 0;
+        boolean success, endofbatch = false;
+        long maxTsDiff = -1;
+        for (long timestampDiff : mRecvdTimeStampDiffs) {
+            if (maxTsDiff < timestampDiff) maxTsDiff = timestampDiff;
+            // Any event that arrives within before 0.5*expectedReportLatency is considered
+            // to be in the same batch of events, else it is considered as the beginning of a new
+            // batch.
+            if (timestampDiff < 0.5 * mExpectedReportLatencyUs/1000) {
+                batchCount++;
+            } else {
+                endofbatch = true;
+                break;
+            }
+        }
+        Log.v("SensorFifoLengthVerification", "batchCount =" +batchCount + " mExpected=" +
+                mExpectedFifoLength + " maxTsDiff=" + maxTsDiff + " expectedReportLatency=" +
+                mExpectedReportLatencyUs/1000 + " recvdEventCount=" + mRecvdTimeStampDiffs.size());
+        // Fifo length must be at least 80% of the advertized FIFO length.
+        success = endofbatch && (batchCount >= mExpectedFifoLength * FIFO_LENGTH_TOLERANCE);
+
+        stats.addValue(PASSED_KEY, success);
+        stats.addValue(SensorStats.EVENT_FIFO_LENGTH, batchCount);
+
+        if (!success) {
+            StringBuilder sb = new StringBuilder();
+            if (endofbatch) {
+                sb.append(String.format("Fifo length verification error: Fifo length found=%d," +
+                            "expected fifo length ~%d, maxReportLatencyObserved=%dms, " +
+                            "expectedMaxReportLantency=%dms",
+                            batchCount, mExpectedFifoLength, maxTsDiff,
+                            mExpectedReportLatencyUs/1000));
+            } else {
+               sb.append(String.format("End of batch NOT observed maxReportLatencyObserved=%dms,"
+                            + " expectedMaxReportLantency=%dms", maxTsDiff,
+                            mExpectedReportLatencyUs/1000));
+            }
+            Assert.fail(sb.toString());
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public FifoLengthVerification clone() {
+        return new FifoLengthVerification(mExpectedFifoLength, mExpectedReportLatencyUs);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void addSensorEventInternal(TestSensorEvent event) {
+        if (mPrevRecvdTimeStampMs == -1) {
+            mPrevRecvdTimeStampMs = (long)event.receivedTimestamp/(1000 * 1000);
+        } else {
+            long currRecvdTimeStampMs = (long) event.receivedTimestamp/(1000 * 1000);
+            mRecvdTimeStampDiffs.add(currRecvdTimeStampMs - mPrevRecvdTimeStampMs);
+            mPrevRecvdTimeStampMs = currRecvdTimeStampMs;
+        }
+        mIndex++;
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index 668629b..aa34de3 100644
--- a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -241,7 +241,12 @@
         CameraManager manager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
         assertNotNull(manager);
         String[] cameraIds = manager.getCameraIdList();
-        assertNotEmpty(cameraIds);
+
+        if (cameraIds.length == 0) {
+            Log.i(TAG, "Skipping testBasicCamera2ActivityEviction, device has no cameras.");
+            return;
+        }
+
         assertTrue(mContext.getMainLooper() != null);
 
         // Setup camera manager
diff --git a/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java b/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java
index 520b54d..1f6ebd7 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AESCipherNistCavpKatTest.java
@@ -19,7 +19,6 @@
 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;
@@ -28,7 +27,6 @@
 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;
@@ -40,58 +38,142 @@
 
 public class AESCipherNistCavpKatTest extends AndroidTestCase {
 
-    private static final String TAG = AESCipherNistCavpKatTest.class.getSimpleName();
+    public void testECBVarKey128() throws Exception {
+        runTestsForKatFile("ECBVarKey128.rsp");
+    }
 
-    public void testSomething() throws Exception {
+    public void testECBVarKey192() throws Exception {
+        runTestsForKatFile("ECBVarKey192.rsp");
+    }
+    public void testECBVarKey256() throws Exception {
+        runTestsForKatFile("ECBVarKey256.rsp");
+    }
+
+    public void testECBVarTxt128() throws Exception {
+        runTestsForKatFile("ECBVarTxt128.rsp");
+    }
+
+    public void testECBVarTxt192() throws Exception {
+        runTestsForKatFile("ECBVarTxt192.rsp");
+    }
+
+    public void testECBVarTxt256() throws Exception {
+        runTestsForKatFile("ECBVarTxt256.rsp");
+    }
+
+    public void testECBGFSbox128() throws Exception {
+        runTestsForKatFile("ECBGFSbox128.rsp");
+    }
+
+    public void testECBGFSbox192() throws Exception {
+        runTestsForKatFile("ECBGFSbox192.rsp");
+    }
+
+    public void testECBGFSbox256() throws Exception {
+        runTestsForKatFile("ECBGFSbox256.rsp");
+    }
+
+    public void testECBKeySbox128() throws Exception {
+        runTestsForKatFile("ECBKeySbox128.rsp");
+    }
+
+    public void testECBKeySbox192() throws Exception {
+        runTestsForKatFile("ECBKeySbox192.rsp");
+    }
+
+    public void testECBKeySbox256() throws Exception {
+        runTestsForKatFile("ECBKeySbox256.rsp");
+    }
+
+    public void testCBCVarKey128() throws Exception {
+        runTestsForKatFile("CBCVarKey128.rsp");
+    }
+
+    public void testCBCVarKey192() throws Exception {
+        runTestsForKatFile("CBCVarKey192.rsp");
+    }
+    public void testCBCVarKey256() throws Exception {
+        runTestsForKatFile("CBCVarKey256.rsp");
+    }
+
+    public void testCBCVarTxt128() throws Exception {
+        runTestsForKatFile("CBCVarTxt128.rsp");
+    }
+
+    public void testCBCVarTxt192() throws Exception {
+        runTestsForKatFile("CBCVarTxt192.rsp");
+    }
+
+    public void testCBCVarTxt256() throws Exception {
+        runTestsForKatFile("CBCVarTxt256.rsp");
+    }
+
+    public void testCBCGFSbox128() throws Exception {
+        runTestsForKatFile("CBCGFSbox128.rsp");
+    }
+
+    public void testCBCGFSbox192() throws Exception {
+        runTestsForKatFile("CBCGFSbox192.rsp");
+    }
+
+    public void testCBCGFSbox256() throws Exception {
+        runTestsForKatFile("CBCGFSbox256.rsp");
+    }
+
+    public void testCBCKeySbox128() throws Exception {
+        runTestsForKatFile("CBCKeySbox128.rsp");
+    }
+
+    public void testCBCKeySbox192() throws Exception {
+        runTestsForKatFile("CBCKeySbox192.rsp");
+    }
+
+    public void testCBCKeySbox256() throws Exception {
+        runTestsForKatFile("CBCKeySbox256.rsp");
+    }
+
+    private void runTestsForKatFile(String fileName) throws Exception {
         try (ZipInputStream zipIn = new ZipInputStream(
                 getContext().getResources().getAssets().open("nist_cavp_aes_kat.zip"))) {
             ZipEntry zipEntry;
+            byte[] entryContents = null;
             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()];
+                // We have to read the contents of all entries because there's no way to skip an
+                // entry without reading its contents.
+                entryContents = new byte[(int) zipEntry.getSize()];
                 readFully(zipIn, entryContents);
-                runTestsForKatFile(entryName, entryContents);
+
+                if (fileName.equals(entryName)) {
+                    break;
+                }
             }
+
+            if (entryContents == null) {
+                fail(fileName + " not found");
+                return;
+            }
+
+            String blockMode = fileName.substring(0, 3);
+            if ("CFB".equals(blockMode)) {
+                blockMode = fileName.substring(0, 4);
+            }
+            runTestsForKatFile(blockMode, 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;
-        }
-
+    private void runTestsForKatFile(String blockMode, byte[] fileContents) throws Exception {
         BufferedReader in = null;
+        int testNumber = 0;
         try {
             in = new BufferedReader(new InputStreamReader(
-                    new ByteArrayInputStream(contents), "ISO-8859-1"));
+                    new ByteArrayInputStream(fileContents), "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) {
@@ -145,8 +227,7 @@
                         } else {
                             throw new IOException("Unexpected test operation: " + section);
                         }
-                        Log.d(TAG, "Running test #" + testNumber + ": AES/" + mode + " from " + fileName);
-                        runKatTest(mode, encrypt, testVector);
+                        runKatTest(blockMode, encrypt, testVector);
                         insideTestDefinition = false;
                         testVector = null;
                     } else {
@@ -174,6 +255,8 @@
                     }
                 }
             }
+        } catch (Throwable e) {
+            throw new RuntimeException("Test #" + testNumber + " failed", e);
         } finally {
             if (in != null) {
                 try {
@@ -225,7 +308,7 @@
         while (remaining > 0) {
             int chunkSize = in.read(buf, offset, remaining);
             if (chunkSize == -1) {
-                throw new EOFException("Premature EOF. Remainig: " + remaining);
+                throw new EOFException("Premature EOF. Remaining: " + remaining);
             }
             offset += chunkSize;
             remaining -= chunkSize;
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
index ebf3688..d552631 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyFactoryTest.java
@@ -46,9 +46,11 @@
 import java.security.spec.X509EncodedKeySpec;
 import java.security.Provider.Service;
 import java.security.PublicKey;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Set;
 
@@ -120,10 +122,21 @@
                 assertEquals("test1", keyInfo.getKeystoreAlias());
                 assertEquals(purposes, keyInfo.getPurposes());
                 TestUtils.assertContentsInAnyOrder(
-                        Arrays.asList(blockModes), keyInfo.getBlockModes());
+                        Arrays.asList(keyInfo.getBlockModes()), blockModes);
+
+                List<String> actualEncryptionPaddings =
+                        new ArrayList<String>(Arrays.asList(keyInfo.getEncryptionPaddings()));
+                // Keystore may have added ENCRYPTION_PADDING_NONE to allow software padding.
+                actualEncryptionPaddings.remove(KeyProperties.ENCRYPTION_PADDING_NONE);
                 TestUtils.assertContentsInAnyOrder(
-                        Arrays.asList(encryptionPaddings), keyInfo.getEncryptionPaddings());
-                TestUtils.assertContentsInAnyOrder(Arrays.asList(digests), keyInfo.getDigests());
+                        actualEncryptionPaddings, encryptionPaddings);
+
+                List<String> actualDigests =
+                        new ArrayList<String>(Arrays.asList(keyInfo.getDigests()));
+                // Keystore may have added DIGEST_NONE to allow software digesting.
+                actualDigests.remove(KeyProperties.DIGEST_NONE);
+                TestUtils.assertContentsInAnyOrder(actualDigests, digests);
+
                 MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings()));
                 assertEquals(keyValidityStart, keyInfo.getKeyValidityStart());
                 assertEquals(keyValidityForOriginationEnd,
@@ -461,4 +474,4 @@
             NoSuchProviderException {
         return KeyFactory.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
index 401857c..4c59652 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyPairGeneratorTest.java
@@ -328,10 +328,21 @@
                 KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
                 assertEquals(purposes, keyInfo.getPurposes());
                 TestUtils.assertContentsInAnyOrder(
-                        Arrays.asList(blockModes), keyInfo.getBlockModes());
+                        Arrays.asList(keyInfo.getBlockModes()), blockModes);
+
+                List<String> actualEncryptionPaddings =
+                        new ArrayList<String>(Arrays.asList(keyInfo.getEncryptionPaddings()));
+                // Keystore may have added ENCRYPTION_PADDING_NONE to allow software OAEP
+                actualEncryptionPaddings.remove(KeyProperties.ENCRYPTION_PADDING_NONE);
                 TestUtils.assertContentsInAnyOrder(
-                        Arrays.asList(encryptionPaddings), keyInfo.getEncryptionPaddings());
-                TestUtils.assertContentsInAnyOrder(Arrays.asList(digests), keyInfo.getDigests());
+                        actualEncryptionPaddings, encryptionPaddings);
+
+                List<String> actualDigests =
+                        new ArrayList<String>(Arrays.asList(keyInfo.getDigests()));
+                // Keystore may have added DIGEST_NONE, to allow software digesting.
+                actualDigests.remove(KeyProperties.DIGEST_NONE);
+                TestUtils.assertContentsInAnyOrder(actualDigests, digests);
+
                 MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings()));
                 assertEquals(keyValidityStart, keyInfo.getKeyValidityStart());
                 assertEquals(keyValidityForOriginationEnd,
@@ -792,8 +803,13 @@
         assertEquals(keyValidityEndDateForOrigination, keyInfo.getKeyValidityForOriginationEnd());
         assertEquals(keyValidityEndDateForConsumption, keyInfo.getKeyValidityForConsumptionEnd());
         MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getBlockModes()));
-        MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getDigests()),
-                KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512);
+
+        List<String> actualDigests = new ArrayList<String>(Arrays.asList(keyInfo.getDigests()));
+        // Keystore may have added DIGEST_NONE, to allow software digesting.
+        actualDigests.remove(KeyProperties.DIGEST_NONE);
+        TestUtils.assertContentsInAnyOrder(
+                actualDigests, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512);
+
         MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings()));
         MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getEncryptionPaddings()));
         assertFalse(keyInfo.isUserAuthenticationRequired());
@@ -855,16 +871,28 @@
         assertEquals(keyValidityStart, keyInfo.getKeyValidityStart());
         assertEquals(keyValidityEndDateForOrigination, keyInfo.getKeyValidityForOriginationEnd());
         assertEquals(keyValidityEndDateForConsumption, keyInfo.getKeyValidityForConsumptionEnd());
-        MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getDigests()),
-                KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512);
-        MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getSignaturePaddings()),
+
+        List<String> actualDigests =
+	    new ArrayList<String>(Arrays.asList(keyInfo.getDigests()));
+        // Keystore may have added DIGEST_NONE, to allow software digesting.
+        actualDigests.remove(KeyProperties.DIGEST_NONE);
+        TestUtils.assertContentsInAnyOrder(
+                actualDigests, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512);
+
+        TestUtils.assertContentsInAnyOrder(Arrays.asList(keyInfo.getSignaturePaddings()),
                 KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
                 KeyProperties.SIGNATURE_PADDING_RSA_PSS);
         MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getBlockModes()),
                 KeyProperties.BLOCK_MODE_ECB);
-        MoreAsserts.assertContentsInAnyOrder(Arrays.asList(keyInfo.getEncryptionPaddings()),
-                KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
-                KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
+
+        List<String> actualEncryptionPaddings =
+                new ArrayList<String>(Arrays.asList(keyInfo.getEncryptionPaddings()));
+        // Keystore may have added ENCRYPTION_PADDING_NONE, to allow software padding.
+        actualEncryptionPaddings.remove(KeyProperties.ENCRYPTION_PADDING_NONE);
+        TestUtils.assertContentsInAnyOrder(actualEncryptionPaddings,
+                KeyProperties.ENCRYPTION_PADDING_RSA_OAEP,
+                KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1);
+
         assertFalse(keyInfo.isUserAuthenticationRequired());
         assertEquals(-1, keyInfo.getUserAuthenticationValidityDurationSeconds());
     }
diff --git a/tests/tests/keystore/src/android/keystore/cts/PutOverflowTest.java b/tests/tests/keystore/src/android/keystore/cts/PutOverflowTest.java
new file mode 100644
index 0000000..088af35
--- /dev/null
+++ b/tests/tests/keystore/src/android/keystore/cts/PutOverflowTest.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.AndroidTestCase;
+import java.lang.reflect.Method;
+
+public class PutOverflowTest extends AndroidTestCase {
+    public void testCrash() throws Exception {
+        try {
+            Class<?> keystoreClass = Class.forName("android.security.KeyStore");
+            Method getInstance = keystoreClass.getMethod("getInstance");
+            Method put = keystoreClass.getMethod("put",
+                    String.class, byte[].class, int.class, int.class);
+            Object keystore = getInstance.invoke(null);
+            byte[] buffer = new byte[65536];
+            Boolean result = (Boolean)put.invoke(keystore, "crashFile", buffer, -1, 0);
+            assertTrue("Fix for ANDROID-22802399 not present", result);
+        } catch (ReflectiveOperationException ignored) {
+            // Since this test requires reflection avoid causing undue failures if classes or
+            // methods were changed.
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/CodecState.java b/tests/tests/media/src/android/media/cts/CodecState.java
index 8f62227..8494a74 100644
--- a/tests/tests/media/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/src/android/media/cts/CodecState.java
@@ -328,12 +328,10 @@
         if (mAudioTrack != null) {
             ByteBuffer buffer = mCodecOutputBuffers[index];
             buffer.clear();
-            buffer.position(0 /* offset */);
+            ByteBuffer audioBuffer = ByteBuffer.allocate(buffer.remaining());
+            audioBuffer.put(buffer);
 
-            byte[] audioCopy = new byte[info.size];
-            buffer.get(audioCopy, 0, info.size);
-
-            mAudioTrack.write(audioCopy, info.size);
+            mAudioTrack.write(audioBuffer, info.size, info.presentationTimeUs*1000);
 
             mCodec.releaseOutputBuffer(index, false /* render */);
 
diff --git a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
index 20c1dff..3847252 100644
--- a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
+++ b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
@@ -21,6 +21,7 @@
 import android.media.AudioAttributes;
 import android.util.Log;
 
+import java.nio.ByteBuffer;
 import java.util.LinkedList;
 
 /**
@@ -32,20 +33,16 @@
 public class NonBlockingAudioTrack {
     private static final String TAG = NonBlockingAudioTrack.class.getSimpleName();
 
-    class QueueElem {
-        byte[] data;
-        int offset;
+    class QueueElement {
+        ByteBuffer data;
         int size;
+        long pts;
     }
 
     private AudioTrack mAudioTrack;
-    private boolean mWriteMorePending = false;
     private int mSampleRate;
-    private int mFrameSize;
-    private int mBufferSizeInFrames;
-    private int mNumFramesSubmitted = 0;
     private int mNumBytesQueued = 0;
-    private LinkedList<QueueElem> mQueue = new LinkedList<QueueElem>();
+    private LinkedList<QueueElement> mQueue = new LinkedList<QueueElement>();
 
     public NonBlockingAudioTrack(int sampleRate, int channelCount, boolean hwAvSync,
                     int audioSessionId) {
@@ -97,8 +94,6 @@
         }
 
         mSampleRate = sampleRate;
-        mFrameSize = 2 * channelCount;
-        mBufferSizeInFrames = bufferSize / mFrameSize;
     }
 
     public long getAudioTimeUs() {
@@ -116,18 +111,13 @@
     }
 
     public void stop() {
-        cancelWriteMore();
-
         mAudioTrack.stop();
 
-        mNumFramesSubmitted = 0;
         mQueue.clear();
         mNumBytesQueued = 0;
     }
 
     public void pause() {
-        cancelWriteMore();
-
         mAudioTrack.pause();
     }
 
@@ -136,95 +126,48 @@
             return;
         }
         mAudioTrack.flush();
-        mNumFramesSubmitted = 0;
         mQueue.clear();
         mNumBytesQueued = 0;
     }
 
     public void release() {
-        cancelWriteMore();
-
+        mQueue.clear();
+        mNumBytesQueued = 0;
         mAudioTrack.release();
         mAudioTrack = null;
     }
 
     public void process() {
-        mWriteMorePending = false;
-        writeMore();
+        while (!mQueue.isEmpty()) {
+            QueueElement element = mQueue.peekFirst();
+            int written = mAudioTrack.write(element.data, element.size,
+                                            AudioTrack.WRITE_NON_BLOCKING, element.pts);
+            if (written < 0) {
+                throw new RuntimeException("Audiotrack.write() failed.");
+            }
+
+            mNumBytesQueued -= written;
+            element.size -= written;
+            if (element.size != 0) {
+                break;
+            }
+            mQueue.removeFirst();
+        }
     }
 
     public int getPlayState() {
         return mAudioTrack.getPlayState();
     }
 
-    private void writeMore() {
-        if (mQueue.isEmpty()) {
-            return;
-        }
-
-        int numFramesPlayed = mAudioTrack.getPlaybackHeadPosition();
-        int numFramesPending = mNumFramesSubmitted - numFramesPlayed;
-        int numFramesAvailableToWrite = mBufferSizeInFrames - numFramesPending;
-        int numBytesAvailableToWrite = numFramesAvailableToWrite * mFrameSize;
-
-        while (numBytesAvailableToWrite > 0) {
-            QueueElem elem = mQueue.peekFirst();
-
-            int numBytes = elem.size;
-            if (numBytes > numBytesAvailableToWrite) {
-                numBytes = numBytesAvailableToWrite;
-            }
-
-            int written = mAudioTrack.write(elem.data, elem.offset, numBytes);
-            assert(written == numBytes);
-
-            mNumFramesSubmitted += written / mFrameSize;
-
-            elem.size -= numBytes;
-            numBytesAvailableToWrite -= numBytes;
-            mNumBytesQueued -= numBytes;
-
-            if (elem.size == 0) {
-                mQueue.removeFirst();
-
-                if (mQueue.isEmpty()) {
-                    break;
-                }
-            } else {
-                elem.offset += numBytes;
-            }
-        }
-
-        if (!mQueue.isEmpty()) {
-            scheduleWriteMore();
-        }
-    }
-
-    private void scheduleWriteMore() {
-        if (mWriteMorePending) {
-            return;
-        }
-
-        int numFramesPlayed = mAudioTrack.getPlaybackHeadPosition();
-        int numFramesPending = mNumFramesSubmitted - numFramesPlayed;
-        int pendingDurationMs = 1000 * numFramesPending / mSampleRate;
-
-        mWriteMorePending = true;
-    }
-
-    private void cancelWriteMore() {
-        mWriteMorePending = false;
-    }
-
-    public void write(byte[] data, int size) {
-        QueueElem elem = new QueueElem();
-        elem.data = data;
-        elem.offset = 0;
-        elem.size = size;
+    public void write(ByteBuffer data, int size, long pts) {
+        QueueElement element = new QueueElement();
+        element.data = data;
+        element.size = size;
+        element.pts  = pts;
 
         // accumulate size written to queue
         mNumBytesQueued += size;
-        mQueue.add(elem);
+        mQueue.add(element);
     }
 }
 
diff --git a/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java b/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
index 8ebe6ac..0ef08f0 100644
--- a/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
+++ b/tests/tests/security/src/android/security/cts/ClonedSecureRandomTest.java
@@ -21,10 +21,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.os.DeadObjectException;
 import android.os.IBinder;
 import android.security.cts.activity.ISecureRandomService;
 import android.security.cts.activity.SecureRandomService;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
 
 import java.io.BufferedReader;
 import java.io.EOFException;
@@ -35,10 +37,11 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@LargeTest
 public class ClonedSecureRandomTest extends AndroidTestCase {
-    private static final int MAX_SHUTDOWN_TRIES = 10;
+    private static final int MAX_SHUTDOWN_TRIES = 50;
 
-    private static final int ANSWER_TIMEOUT_SECONDS = 60;
+    private static final int ANSWER_TIMEOUT_SECONDS = 180;
 
     private static final String SEPARATE_PROCESS_NAME = ":secureRandom";
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 216ba97..19d27af 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -27,6 +27,8 @@
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
 
+import java.util.List;
+
 /**
  * Extended suite of tests that use {@link CtsConnectionService} and {@link MockInCallService} to
  * verify the functionality of the Telecom service.
@@ -407,6 +409,35 @@
         assertGetCannedTextResponsesNotEmpty(call);
     }
 
+    public void testGetCalls() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        placeAndVerifyCall();
+        final MockConnection connection1 = verifyConnectionForOutgoingCall(0);
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call1 = inCallService.getLastCall();
+        assertCallState(call1, Call.STATE_DIALING);
+
+        connection1.setActive();
+
+        assertCallState(call1, Call.STATE_ACTIVE);
+
+        List<Call> calls = inCallService.getCalls();
+        assertEquals("InCallService.getCalls() should return list with 1 call.", 1, calls.size());
+        assertEquals(call1, calls.get(0));
+
+        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        verifyConnectionForIncomingCall();
+
+        final Call call2 = inCallService.getLastCall();
+        calls = inCallService.getCalls();
+        assertEquals("InCallService.getCalls() should return list with 2 calls.", 2, calls.size());
+        assertEquals(call1, calls.get(0));
+        assertEquals(call2, calls.get(1));
+    }
+
     private void assertGetCannedTextResponsesNotEmpty(final Call call) {
         waitUntilConditionIsTrueOrTimeout(
                 new Condition() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index cfa8e9f..cc03288 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -46,17 +46,31 @@
             .setCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
             .setHighlightColor(Color.RED)
             .setShortDescription(ACCOUNT_LABEL)
-            .setSupportedUriSchemes(Arrays.asList("tel"))
+            .setSupportedUriSchemes(Arrays.asList(PhoneAccount.SCHEME_TEL))
             .build();
 
     public static final PhoneAccount TEST_NO_SIM_PHONE_ACCOUNT = PhoneAccount.builder(
             TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL)
             .setAddress(Uri.parse("tel:555-TEST"))
             .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
-            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)
+            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                    PhoneAccount.CAPABILITY_VIDEO_CALLING)
             .setHighlightColor(Color.RED)
             .setShortDescription(ACCOUNT_LABEL)
-            .setSupportedUriSchemes(Arrays.asList("tel"))
+            .setSupportedUriSchemes(Arrays.asList(
+                    PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL))
+            .build();
+
+    public static final PhoneAccount TEST_CALL_MANAGER_PHONE_ACCOUNT = PhoneAccount.builder(
+            TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL)
+            .setAddress(Uri.parse("tel:555-TEST"))
+            .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
+            .setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                    PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+            .setHighlightColor(Color.RED)
+            .setShortDescription(ACCOUNT_LABEL)
+            .setSupportedUriSchemes(Arrays.asList(
+                    PhoneAccount.SCHEME_TEL, PhoneAccount.SCHEME_VOICEMAIL))
             .build();
 
     private Context mContext;
@@ -154,9 +168,33 @@
         final List<PhoneAccountHandle> newAccounts = mTelecomManager.getCallCapablePhoneAccounts();
         assertNotNull("No enabled Phone account found.", newAccounts);
         assertEquals("1 new enabled Phone account expected.", newAccounts.size(),
-                oldAccountsListSize+1);
+                oldAccountsListSize + 1);
         assertTrue("Enabled Phone accounts do not contain the test account.",
                 newAccounts.contains(TEST_PHONE_ACCOUNT_HANDLE));
     }
 
+    public void testRegisterPhoneAccount_CheckCapabilities() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+        mTelecomManager.registerPhoneAccount(TEST_NO_SIM_PHONE_ACCOUNT);
+        PhoneAccount retrievedPhoneAccount = mTelecomManager.getPhoneAccount(
+                TEST_PHONE_ACCOUNT_HANDLE);
+        assertTrue("Phone account should have call provider & video calling capability.",
+                retrievedPhoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER |
+                        PhoneAccount.CAPABILITY_VIDEO_CALLING));
+    }
+
+    public void testRegisterPhoneAccount_CheckURISchemeSupported() throws Exception {
+        if (!shouldTestTelecom(mContext)) {
+            return;
+        }
+        mTelecomManager.registerPhoneAccount(TEST_NO_SIM_PHONE_ACCOUNT);
+        PhoneAccount retrievedPhoneAccount = mTelecomManager.getPhoneAccount(
+                TEST_PHONE_ACCOUNT_HANDLE);
+        assertTrue("Phone account should support tel URI scheme.",
+                retrievedPhoneAccount.supportsUriScheme(PhoneAccount.SCHEME_TEL));
+        assertTrue("Phone account should support voicemail URI scheme.",
+                retrievedPhoneAccount.supportsUriScheme(PhoneAccount.SCHEME_VOICEMAIL));
+    }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
new file mode 100644
index 0000000..a7961c3
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/SimCallManagerTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.ACCOUNT_ID;
+import static android.telecom.cts.TestUtils.ACCOUNT_LABEL;
+import static android.telecom.cts.TestUtils.COMPONENT;
+import static android.telecom.cts.TestUtils.PACKAGE;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.PersistableBundle;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.test.InstrumentationTestCase;
+import android.text.TextUtils;
+
+import java.util.Arrays;
+
+/**
+ * Verifies the behavior of TelecomManager.getSimCallManager() with respect to the default dialer
+ */
+public class SimCallManagerTest extends InstrumentationTestCase {
+    public static final PhoneAccountHandle TEST_PHONE_ACCOUNT_HANDLE =
+            new PhoneAccountHandle(new ComponentName(PACKAGE, COMPONENT), ACCOUNT_ID);
+
+    public static final PhoneAccount TEST_SIM_CALL_MANAGER_ACCOUNT = PhoneAccount.builder(
+            TEST_PHONE_ACCOUNT_HANDLE, ACCOUNT_LABEL)
+            .setAddress(Uri.parse("tel:555-TEST"))
+            .setSubscriptionAddress(Uri.parse("tel:555-TEST"))
+            .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+            .setHighlightColor(Color.RED)
+            .setShortDescription(ACCOUNT_LABEL)
+            .setSupportedUriSchemes(Arrays.asList("tel"))
+            .build();
+
+    private Context mContext;
+    private TelecomManager mTelecomManager;
+    private String mPreviousDefaultDialer = null;
+    private String mSystemDialer = null;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+        mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
+        // Reset the current dialer to the system dialer, to ensure that we start each test
+        // without being the default dialer.
+        mSystemDialer = TestUtils.getSystemDialer(getInstrumentation());
+        if (!TextUtils.isEmpty(mSystemDialer)) {
+            TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
+        }
+        mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
+            // Restore the default dialer to whatever the default dialer was before the tests
+            // were started. This may or may not be the system dialer.
+            TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
+        }
+        super.tearDown();
+    }
+
+    public void testGetSimCallManager() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
+
+        // By default, getSimCallManager should return either the carrier configured sim call
+        // manager or the system dialer's sim call manager.
+        assertEquals(mSystemDialer, mTelecomManager.getDefaultDialerPackage());
+        assertNotSame(TEST_PHONE_ACCOUNT_HANDLE, mTelecomManager.getSimCallManager());
+
+        ComponentName carrierConfigSimCallManager = null;
+        CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
+                Context.CARRIER_CONFIG_SERVICE);
+        PersistableBundle configBundle = configManager.getConfig();
+        if (configBundle != null) {
+            final String componentString = configBundle.getString(
+                    CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING);
+            if (!TextUtils.isEmpty(componentString)) {
+                carrierConfigSimCallManager = ComponentName.unflattenFromString(componentString);
+            }
+        }
+
+        // If the default dialer has not registered a sim call manager, getSimCallManager should
+        // return the carrier configured sim call manager (which can be null).
+        PhoneAccountHandle simCallManager = mTelecomManager.getSimCallManager();
+        TestUtils.setDefaultDialer(getInstrumentation(), TestUtils.PACKAGE);
+        assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
+        assertNotSame(TEST_PHONE_ACCOUNT_HANDLE, mTelecomManager.getSimCallManager());
+        assertEquals("Sim call manager should be the carrier configured value if no default-dialer"
+                + " provided value",
+                carrierConfigSimCallManager,
+                simCallManager == null ? null : simCallManager.getComponentName());
+
+        // Once the default dialer has registered a sim call manager, getSimCallManager should
+        // return the new sim call manager.
+        mTelecomManager.registerPhoneAccount(TEST_SIM_CALL_MANAGER_ACCOUNT);
+        assertEquals("Sim call manager should be default dialer's sim call manager if provided"
+                + " by default dialer",
+                TEST_PHONE_ACCOUNT_HANDLE,
+                mTelecomManager.getSimCallManager());
+
+        // If the dialer is no longer the default dialer, it is no longer the sim call manager.
+        TestUtils.setDefaultDialer(getInstrumentation(), mSystemDialer);
+        assertNotSame(TEST_PHONE_ACCOUNT_HANDLE, mTelecomManager.getSimCallManager());
+    }
+}
diff --git a/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java b/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
index 4ca6bcd..b3044a2 100644
--- a/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
+++ b/tests/tests/telecom2/src/android/telecom/cts/DefaultDialerOperationsNoPermissionsTest.java
@@ -119,6 +119,9 @@
     }
 
     public void testIsVoicemailNumber() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
         verifyForReadPhoneStateOrDefaultDialer(new Runnable() {
             @Override
             public void run() {
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewTest.java b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
index 6c62be4..838f7a8 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -427,26 +427,23 @@
 
         final Drawable d = mActivity.getResources().getDrawable(R.drawable.scenery);
 
-        Rect r2 = d.getBounds();
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
                 mListView.setDivider(d);
-                mListView.requestLayout();
             }
         });
         mInstrumentation.waitForIdleSync();
         assertSame(d, mListView.getDivider());
-        assertEquals(r2.bottom - r2.top, mListView.getDividerHeight());
+        assertEquals(d.getBounds().height(), mListView.getDividerHeight());
 
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
                 mListView.setDividerHeight(10);
-                mListView.requestLayout();
             }
         });
         mInstrumentation.waitForIdleSync();
         assertEquals(10, mListView.getDividerHeight());
-        assertEquals(10, r2.bottom - r2.top);
+        assertEquals(10, d.getBounds().height());
     }
 
     public void testSetSelection() {
diff --git a/tools/cts-media/copy_media.sh b/tools/cts-media/copy_media.sh
index 3998dc3..cf0d099 100755
--- a/tools/cts-media/copy_media.sh
+++ b/tools/cts-media/copy_media.sh
@@ -45,24 +45,24 @@
 
 if [ $max_resolution -ge 3 ]; then
   echo "copying 1920x1080"
-  adb $adb_options push bbb_short/1920x1080 /mnt/sdcard/test/bbb_short/1920x1080
-  adb $adb_options push bbb_full/1920x1080 /mnt/sdcard/test/bbb_full/1920x1080
+  adb $adb_options push bbb_short/1920x1080 /sdcard/test/bbb_short/1920x1080
+  adb $adb_options push bbb_full/1920x1080 /sdcard/test/bbb_full/1920x1080
 fi
 
 if [ $max_resolution -ge 2 ]; then
   echo "copying 1280x720"
-  adb $adb_options push bbb_short/1280x720 /mnt/sdcard/test/bbb_short/1280x720
-  adb $adb_options push bbb_full/1280x720 /mnt/sdcard/test/bbb_full/1280x720
+  adb $adb_options push bbb_short/1280x720 /sdcard/test/bbb_short/1280x720
+  adb $adb_options push bbb_full/1280x720 /sdcard/test/bbb_full/1280x720
 fi
 
 if [ $max_resolution -ge 1 ]; then
   echo "copying 720x480"
-  adb $adb_options push bbb_short/720x480 /mnt/sdcard/test/bbb_short/720x480
-  adb $adb_options push bbb_full/720x480 /mnt/sdcard/test/bbb_full/720x480
+  adb $adb_options push bbb_short/720x480 /sdcard/test/bbb_short/720x480
+  adb $adb_options push bbb_full/720x480 /sdcard/test/bbb_full/720x480
 fi
 
 echo "copying all others"
-adb $adb_options push bbb_short/176x144 /mnt/sdcard/test/bbb_short/176x144
-adb $adb_options push bbb_full/176x144 /mnt/sdcard/test/bbb_full/176x144
-adb $adb_options push bbb_short/480x360 /mnt/sdcard/test/bbb_short/480x360
-adb $adb_options push bbb_full/480x360 /mnt/sdcard/test/bbb_full/480x360
+adb $adb_options push bbb_short/176x144 /sdcard/test/bbb_short/176x144
+adb $adb_options push bbb_full/176x144 /sdcard/test/bbb_full/176x144
+adb $adb_options push bbb_short/480x360 /sdcard/test/bbb_short/480x360
+adb $adb_options push bbb_full/480x360 /sdcard/test/bbb_full/480x360
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
index 62c268d..8fb61bf 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
@@ -46,6 +46,7 @@
     public static final String SCREEN_SIZE = "screen_size";
     public static final String SCREEN_DENSITY_BUCKET = "screen_density_bucket";
     public static final String SCREEN_DENSITY = "screen_density";
+    public static final String SMALLEST_SCREEN_WIDTH_DP = "smallest_screen_width_dp";
     public static final String RESOLUTION = "resolution";
     public static final String VERSION_SDK = "androidPlatformVersion";
     public static final String VERSION_RELEASE = "buildVersion";
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
index 52ddfe9..5828259 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
@@ -97,6 +97,9 @@
         String screenSize = getScreenSize();
         addResult(SCREEN_SIZE, screenSize);
 
+        Configuration configuration = getContext().getResources().getConfiguration();
+        addResult(SMALLEST_SCREEN_WIDTH_DP, configuration.smallestScreenWidthDp);
+
         Intent intent = new Intent();
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
         intent.setClass(this.getContext(), DeviceInfoActivity.class);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index ca67746..fa930df 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
     @Option(name="cts-install-path", description="the path to the cts installation to use")
     private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
 
-    public static final String CTS_BUILD_VERSION = "5.0_r1.91";
+    public static final String CTS_BUILD_VERSION = "6.0_r0";
     public static final String CTS_PACKAGE = "com.android.cts.tradefed.testtype";
 
     /**
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index 973d943..51b457d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -25,7 +25,6 @@
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.build.IFolderBuildInfo;
 import com.android.tradefed.config.Option;
-import com.android.tradefed.config.Option.Importance;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.result.ILogSaver;
 import com.android.tradefed.result.ILogSaverListener;
@@ -42,6 +41,7 @@
 import org.kxml2.io.KXmlSerializer;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
@@ -98,6 +98,9 @@
     @Option(name = "include-test-log-tags", description = "Include test log tags in XML report.")
     private boolean mIncludeTestLogTags = false;
 
+    @Option(name = "use-log-saver", description = "Also saves generated result XML with log saver")
+    private boolean mUseLogSaver = false;
+
     protected IBuildInfo mBuildInfo;
     private String mStartTime;
     private String mDeviceSerial;
@@ -110,6 +113,7 @@
     private File mLogDir;
     private String mSuiteName;
     private String mReferenceUrl;
+    private ILogSaver mLogSaver;
 
     public void setReportDir(File reportDir) {
         mReportDir = reportDir;
@@ -253,7 +257,7 @@
 
     @Override
     public void setLogSaver(ILogSaver logSaver) {
-      // Don't need to keep a reference to logSaver, because we don't save extra logs in this class.
+        mLogSaver = logSaver;
     }
 
     @Override
@@ -351,6 +355,18 @@
 
         File reportFile = getResultFile(mReportDir);
         createXmlResult(reportFile, mStartTime, elapsedTime);
+        if (mUseLogSaver) {
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(reportFile);
+                mLogSaver.saveLogData("cts-result", LogDataType.XML, fis);
+            } catch (IOException ioe) {
+                CLog.e("error saving XML with log saver");
+                CLog.e(ioe);
+            } finally {
+                StreamUtil.close(fis);
+            }
+        }
         copyFormattingFiles(mReportDir);
         zipResults(mReportDir);
 
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java
index 0c947c3..96145e9 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/DeviceInfoResult.java
@@ -95,6 +95,8 @@
                 getMetric(metricsCopy, DeviceInfoConstants.SCREEN_DENSITY_BUCKET));
         serializer.attribute(ns, DeviceInfoConstants.SCREEN_SIZE,
                 getMetric(metricsCopy, DeviceInfoConstants.SCREEN_SIZE));
+        serializer.attribute(ns, DeviceInfoConstants.SMALLEST_SCREEN_WIDTH_DP,
+                getMetric(metricsCopy, DeviceInfoConstants.SMALLEST_SCREEN_WIDTH_DP));
         serializer.endTag(ns, SCREEN_TAG);
 
         serializer.startTag(ns, PHONE_TAG);
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 9490eaf..2b7e093 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -461,35 +461,6 @@
   """ Construct a defaultdict that maps package name to a list of tests
       that are known failures during dev cycle but expected to be fixed before launch """
   return {
-      'android.content' : [
-          'android.content.cts.ContentResolverTest#testAndroidTestCaseSetupProperly',
-          'android.content.cts.ContentResolverTest#testBulkInsert',
-          'android.content.cts.ContentResolverTest#testCancelableQuery_WhenCanceledBeforeQuery_ThrowsImmediately',
-          'android.content.cts.ContentResolverTest#testCancelableQuery_WhenCanceledDuringLongRunningQuery_CancelsQueryAndThrows',
-          'android.content.cts.ContentResolverTest#testCancelableQuery_WhenNotCanceled_ReturnsResultSet',
-          'android.content.cts.ContentResolverTest#testConstructor',
-          'android.content.cts.ContentResolverTest#testCrashOnLaunch',
-          'android.content.cts.ContentResolverTest#testCrashingOpenAssetFileDescriptor',
-          'android.content.cts.ContentResolverTest#testCrashingOpenTypedAssetFileDescriptor',
-          'android.content.cts.ContentResolverTest#testCrashingQuery',
-          'android.content.cts.ContentResolverTest#testDelete',
-          'android.content.cts.ContentResolverTest#testGetType',
-          'android.content.cts.ContentResolverTest#testInsert',
-          'android.content.cts.ContentResolverTest#testNotifyChange1',
-          'android.content.cts.ContentResolverTest#testNotifyChange2',
-          'android.content.cts.ContentResolverTest#testOpenAssetFileDescriptor',
-          'android.content.cts.ContentResolverTest#testOpenFileDescriptor',
-          'android.content.cts.ContentResolverTest#testOpenInputStream',
-          'android.content.cts.ContentResolverTest#testOpenOutputStream',
-          'android.content.cts.ContentResolverTest#testQuery',
-          'android.content.cts.ContentResolverTest#testRegisterContentObserver',
-          'android.content.cts.ContentResolverTest#testStableToUnstableRefs',
-          'android.content.cts.ContentResolverTest#testStartCancelSync',
-          'android.content.cts.ContentResolverTest#testStartSyncFailure',
-          'android.content.cts.ContentResolverTest#testUnstableGetType',
-          'android.content.cts.ContentResolverTest#testUnstableToStableRefs',
-          'android.content.cts.ContentResolverTest#testUpdate',
-          'android.content.cts.ContentResolverTest#testValidateSyncExtrasBundle',],
       'android.bluetooth' : [
           'android.bluetooth.cts.BluetoothLeScanTest#testBasicBleScan',
           'android.bluetooth.cts.BluetoothLeScanTest#testBatchScan',