Merge "update attention management test for M release" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index beb9895..0950994 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -172,6 +172,7 @@
     CtsNativeOpenGLTestCases \
     CtsNdefTestCases \
     CtsNetTestCases \
+    CtsNetTestCasesLegacyApi22 \
     CtsOpenGLTestCases \
     CtsOpenGlPerfTestCases \
     CtsOsTestCases \
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index f4f0d56..2c8d73b 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -116,7 +116,11 @@
             # Verify MINIMAL(3) is not better than HQ(2)
             assert(variances[j][3] >
                    variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
-        if its.caps.noise_reduction_mode(props, 4):
+            if its.caps.noise_reduction_mode(props, 4):
+                # Verify ZSL(4) is close to MINIMAL(3)
+                assert(numpy.isclose(variances[j][4], variances[j][3],
+                                     RELATIVE_ERROR_TOLERANCE))
+        elif its.caps.noise_reduction_mode(props, 4):
             # Verify ZSL(4) is close to OFF(0)
             assert(numpy.isclose(variances[j][4], variances[j][0],
                                  RELATIVE_ERROR_TOLERANCE))
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index aeeae33..757dfeb 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -107,10 +107,12 @@
             print "Variances with NR mode [0,1,2,3,4]:", variances
 
             # Draw a plot.
-            for nr_mode in range(5):
-                if not its.caps.noise_reduction_mode(props, nr_mode):
-                    continue
-                pylab.plot(range(3), variances[nr_mode], "rgbcm"[nr_mode])
+            for chan in range(3):
+                line = []
+                for nr_mode in range(5):
+                    line.append(variances[nr_mode][chan])
+                pylab.plot(range(5), line, "rgb"[chan])
+
             matplotlib.pyplot.savefig("%s_plot_%s_variances.png" %
                                       (NAME, reprocess_format))
 
@@ -133,9 +135,13 @@
                     # Verify MINIMAL(3) is not better than HQ(2)
                     assert(variances[3][j] >
                            variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
-                # Verify ZSL(4) is close to OFF(0)
-                assert(numpy.isclose(variances[4][j], variances[0][j],
-                                     RELATIVE_ERROR_TOLERANCE))
+                    # Verify ZSL(4) is close to MINIMAL(3)
+                    assert(numpy.isclose(variances[4][j], variances[3][j],
+                                         RELATIVE_ERROR_TOLERANCE))
+                else:
+                    # Verify ZSL(4) is close to OFF(0)
+                    assert(numpy.isclose(variances[4][j], variances[0][j],
+                                         RELATIVE_ERROR_TOLERANCE))
 
 if __name__ == '__main__':
     main()
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 47eb16f..272e192 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1369,7 +1369,12 @@
                 android:theme="@android:style/Theme.NoDisplay"
                 android:noHistory="true"
                 android:autoRemoveFromRecents="true"
-                android:stateNotNeeded="true"/>
+                android:stateNotNeeded="true">
+        </activity>
+
+        <activity android:name=".managedprovisioning.KeyguardDisabledFeaturesActivity"
+                android:label="@string/provisioning_byod_keyguard_disabled_features">
+        </activity>
 
         <activity android:name=".managedprovisioning.WifiLockdownTestActivity"
                 android:label="@string/device_owner_wifi_lockdown_test">
@@ -1416,6 +1421,8 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO" />
                 <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" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
         </activity>
@@ -1455,6 +1462,7 @@
         <activity android:name=".managedprovisioning.WorkNotificationTestActivity">
             <intent-filter>
                 <action android:name="com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
@@ -1632,6 +1640,18 @@
             <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
         </activity>
 
+        <activity android:name=".audio.AudioFrequencyLineActivity"
+                  android:label="@string/audio_frequency_line_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_excluded_features" android:value="android.hardware.type.watch" />
+            <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
+        </activity>
+
         <service android:name=".tv.MockTvInputService"
             android:permission="android.permission.BIND_TV_INPUT">
             <intent-filter>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
new file mode 100644
index 0000000..69e3bc7
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
@@ -0,0 +1,72 @@
+<?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">
+
+  <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_line_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_line_plug_ready_btn"
+          android:text="@string/audio_frequency_line_plug_ready_btn"/>
+
+    <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_line_layout">
+            <Button
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/audio_frequency_line_test_btn"
+                android:id="@+id/audio_frequency_line_test_btn"/>
+
+            <ProgressBar
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:id="@+id/audio_frequency_line_progress_bar"/>
+        </LinearLayout>
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/audio_frequency_line_results_text"
+            android:id="@+id/audio_frequency_line_results_text"/>
+
+    </LinearLayout>
+    </LinearLayout>
+
+  <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3 b/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3
new file mode 100644
index 0000000..e877fc1
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 3b26458..b8bd395 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1448,6 +1448,42 @@
         \n
         Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
     </string>
+    <string name="provisioning_byod_keyguard_disabled_features">Keyguard disabled features</string>
+    <string name="provisioning_byod_keyguard_disabled_features_info">
+        This test exercises Keyguard Disabled Features. Follow instructions above.
+    </string>
+    <string name="provisioning_byod_keyguard_disabled_features_instruction">
+        Please press the \"Prepare test\" button to disable trust agents.\n
+        Then please press through the following verification steps.\n
+        Note: Device password will be set to \"testpassword\". After leaving the screen device password be cleared.
+    </string>
+    <string name="provisioning_byod_keyguard_disabled_features_prepare_button">Prepare test</string>
+    <string name="provisioning_byod_disable_trust_agents">Disable trust agents</string>
+    <string name="provisioning_byod_disable_trust_agents_instruction">
+        Please press the Go button to go to Settings > Security. Then go to Trusted agents and\n
+        check if the agents are shown as disabled by the administrator.
+        Then please press Back and mark the test as \"Pass\" or \"Fail\".
+    </string>
+    <string name="provisioning_byod_fingerprint_disabled_in_settings">Fingerprint is disabled in Settings</string>
+    <string name="provisioning_byod_fingerprint_disabled_in_settings_instruction">
+        Please press the Go button to go to Settings > Security. Then go to Fingerprint and\n
+        check if the screen is shown as disabled by the administrator.
+        Then please press Back and mark the test as \"Pass\" or \"Fail\".
+    </string>
+    <string name="provisioning_byod_disable_fingerprint">Fingerprint disabled on keyguard</string>
+    <string name="provisioning_byod_disable_fingerprint_instruction">
+        Please press the Go button to lock the screen. Then try to log in using the fingerprint reader.\n
+        Expected result is you cannot log in using your fingerprint.\n
+        After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
+    </string>
+    <string name="provisioning_byod_disable_notifications">Notifications disabled on keyguard</string>
+    <string name="provisioning_byod_disable_notifications_instruction">
+        Please press the Go button to lock the screen. Wait a couple of seconds and look out for a
+        notification from CtsVerifier.\n
+        Expected result is the notification is shown as \"Contents hidden\", you can not see the contents
+        (Which would read \"This is a work notification\").\n
+        After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
+    </string>
     <string name="provisioning_byod_work_notification">Work notification is badged</string>
     <string name="provisioning_byod_work_notification_instruction">
         Please press the Go button to trigger a notification.\n
@@ -1690,6 +1726,40 @@
     <string name="activity_not_found">No activity found to handle intent: %s</string>
     <string name="open_settings_button_label">Open Application Settings</string>
     <string name="finish_button_label">Finish</string>
+    <string name="device_owner_device_admin_visible">Device administrator settings</string>
+    <string name="device_owner_device_admin_visible_info">
+        Please press the Go button to open the Security page in Settings.
+        Navigate to Device administrators and confirm that:\n
+        \n
+        - \"CTS Verifier - AfW Admin\" exists and is activated.\n
+        - \"CTS Verifier - AfW Admin\" cannot be disabled.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="device_owner_disallow_config_bt">Disallow configuring Bluetooth</string>
+    <string name="device_owner_disallow_config_bt_info">
+        Please press the Set restriction button to set the user restriction.
+        Then press Go to open the Bluetooth page in Settings.
+        Confirm that:\n
+        \n
+        - You cannot view Bluetooth devices in range.\n
+        - You cannot edit, add or remove any already paired devices.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="device_owner_disallow_config_wifi">Disallow configuring WiFi</string>
+    <string name="device_owner_disallow_config_wifi_info">
+        Please press the Set restriction button to set the user restriction.
+        Then press Go to open the WiFi page in Settings.
+        Confirm that:\n
+        \n
+        - You cannot view WiFi networks in range.\n
+        - You cannot edit, add or remove any existing WiFi configs.\n
+        \n
+        Use the Back button to return to this page.
+    </string>
+    <string name="device_owner_user_restriction_set">Set restriction</string>
+    <string name="device_owner_settings_go">Go</string>
 
     <!-- Strings for JobScheduler Tests -->
     <string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
@@ -1911,4 +1981,22 @@
     <string name="audio_loopback_test_btn">Test</string>
     <string name="audio_loopback_results_text">Results...</string>
 
+   <!-- Audio Frequency Line Test -->
+    <string name="audio_frequency_line_test">Audio Frequency Line Test</string>
+    <string name="audio_frequency_line_info">
+        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 name="audio_frequency_line_instructions">
+          Please connect a "Loopback Plug" and press "Loopback Plug Ready".
+    </string>
+    <string name="audio_frequency_line_plug_ready_btn">Loopback Plug Ready</string>
+
+    <string name="audio_frequency_line_test_btn">Test</string>
+    <string name="audio_frequency_line_results_text">Results...</string>
+
 </resources>
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
index 61238aa..ce44794 100644
--- a/apps/CtsVerifier/res/xml/device_admin_byod.xml
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -20,6 +20,8 @@
         <encrypted-storage />
         <wipe-data />
         <reset-password />
+        <disable-keyguard-features />
+        <force-lock />
     </uses-policies>
 </device-admin>
 <!-- END_INCLUDE(meta_data) -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java
new file mode 100644
index 0000000..9af4af1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+public class AudioBandSpecs {
+    double mFreqStart;
+    double mFreqStop;
+    double mRippleStartTop;
+    double mRippleStartBottom;
+
+    double mRippleStopTop;
+    double mRippleStopBottom;
+
+    double mOffset;
+
+    public AudioBandSpecs(double fStart, double fStop, double startTop, double startBottom,
+            double stopTop, double stopBottom) {
+        initFreq(fStart, fStop);
+        initRipple(startTop, startBottom, stopTop, stopBottom);
+        setOffset(0);
+    }
+
+    public void initRipple(double startTop, double startBottom, double stopTop, double stopBottom) {
+        mRippleStartTop = startTop;
+        mRippleStartBottom = startBottom;
+        mRippleStopTop = stopTop;
+        mRippleStopBottom = stopBottom;
+        // note: top should be >= bottom, but no check is done here.
+    }
+
+    public void initFreq(double fStart, double fStop) {
+        mFreqStart = fStart;
+        mFreqStop = fStop;
+    }
+
+    public void setOffset(double offset) {
+        mOffset = offset;
+    }
+
+    /**
+     * Check if the given point is in bounds in this band.
+     */
+    public boolean isInBounds(double freq, double value) {
+        if (freq < mFreqStart || freq > mFreqStop) {
+            return false;
+        }
+
+        double d = mFreqStop - mFreqStart;
+        if (d <= 0) {
+            return false;
+        }
+
+        double e = freq - mFreqStart;
+        double vTop = (e / d) * (mRippleStopTop - mRippleStartTop) + mRippleStartTop + mOffset;
+        if (value > vTop) {
+            return false;
+        }
+
+        double vBottom = (e / d) * (mRippleStopBottom - mRippleStartBottom) + mRippleStartBottom
+                + mOffset;
+
+        if (value < vBottom) {
+            return false;
+        }
+        return true;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(String.format("Freq %.1f - %.1f |", mFreqStart, mFreqStop));
+        sb.append(String.format("start [%.1f : %.1f] |", mRippleStartTop, mRippleStartBottom));
+        sb.append(String.format("stop  [%.1f : %.1f] |", mRippleStopTop, mRippleStopBottom));
+        sb.append(String.format("offset %.1f", mOffset));
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
new file mode 100644
index 0000000..d3e2571
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -0,0 +1,664 @@
+/*
+ * 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.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 AudioFrequencyLineActivity extends PassFailButtons.Activity implements Runnable,
+    AudioRecord.OnRecordPositionUpdateListener {
+    private static final String TAG = "AudioFrequencyLineActivity";
+
+    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 = -20.0;
+    static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+
+    OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+    Context mContext;
+
+    Button mLoopbackPlugReady;
+    LinearLayout mLinearLayout;
+    Button mTestButton;
+    TextView mResultText;
+    ProgressBar mProgressBar;
+    //recording
+    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 volatile 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 mFreqAverage0 = new VectorAverage();
+    private VectorAverage mFreqAverage1 = new VectorAverage();
+
+    private int mCurrentTest = -1;
+    int mBands = 4;
+    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
+
+    int mMaxLevel;
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            switch (v.getId()) {
+                case R.id.audio_frequency_line_plug_ready_btn:
+                    Log.i(TAG, "audio loopback plug ready");
+                    //enable all the other views.
+                    enableLayout(true);
+                    break;
+                case R.id.audio_frequency_line_test_btn:
+                    Log.i(TAG, "audio loopback test");
+                    startAudioTest();
+                    break;
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.audio_frequency_line_activity);
+
+        mContext = this;
+
+        mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_line_plug_ready_btn);
+        mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+        mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_line_layout);
+        mTestButton = (Button)findViewById(R.id.audio_frequency_line_test_btn);
+        mTestButton.setOnClickListener(mBtnClickListener);
+        mResultText = (TextView)findViewById(R.id.audio_frequency_line_results_text);
+        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_line_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_line_test,
+                R.string.audio_frequency_line_info, -1);
+
+        //Init bands
+        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 */);
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     *  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);
+            setMaxLevel();
+
+            sendMessage("Testing Left Capture");
+            mCurrentTest = 0;
+            mFreqAverage0.reset();
+            mSPlayer.setBalance(0.0f);
+            play();
+
+            sendMessage("Testing Right Capture");
+            mCurrentTest = 1;
+            mFreqAverage1.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 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") +"\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 (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 resultsLeft = new Results("Left");
+        computeResultsForVector(mFreqAverage0, resultsLeft);
+        Results resultsRight = new Results("Right");
+        computeResultsForVector(mFreqAverage1, resultsRight);
+        if (resultsLeft.testAll() && resultsRight.testAll()) {
+            //enable button
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    private void computeResultsForVector(VectorAverage freqAverage,Results results) {
+
+        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 > bandSpecsArray[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecsArray[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++) {
+                bandSpecsArray[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 >  bandSpecsArray[currentBand].mFreqStop) {
+                    currentBand++;
+                    if (currentBand >= mBands)
+                        break;
+                }
+
+                if (freq >= bandSpecsArray[currentBand].mFreqStart) {
+                    double value = results.mValuesLog[i];
+                    if (bandSpecsArray[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(AudioFrequencyLineActivity.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:
+                    mFreqAverage0.setData(halfMagnitude, false);
+                    break;
+                case 1:
+                    mFreqAverage1.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);
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
new file mode 100644
index 0000000..23b71c0
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
@@ -0,0 +1,215 @@
+/*
+ * 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.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.net.rtp.AudioStream;
+import android.util.Log;
+
+import com.android.cts.verifier.audio.wavelib.PipeShort;
+
+import java.io.IOException;
+
+public class SoundPlayerObject extends Thread {
+    private static final String LOGTAG = "SoundPlayerObject";
+    private MediaPlayer mMediaPlayer;
+    private boolean isInitialized = false;
+    private boolean isRunning = false;
+
+    public PipeShort mPipe = new PipeShort(65536);
+    private short[] mAudioShortArray;
+
+    public AudioTrack mAudioTrack;
+    public int mSamplingRate = 48000;
+    private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
+    private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+    int mMinPlayBufferSizeInBytes = 0;
+    int mMinBufferSizeInSamples = 0;
+
+    private int mStreamType = AudioManager.STREAM_MUSIC;
+    private int mResId = -1;
+    private boolean mUseMediaPlayer = true;
+    private float mBalance = 0.5f; //0 left, 1 right
+
+    public int getCurrentResId() {
+        return mResId;
+    }
+
+    public int getStreamType () {
+        return mStreamType;
+    }
+
+    public void run() {
+        setPriority(Thread.MAX_PRIORITY);
+        isRunning = true;
+        while (isRunning) {
+
+            if (!mUseMediaPlayer && isInitialized && isPlaying()) {
+                int valuesAvailable = mPipe.availableToRead();
+                if (valuesAvailable > 0) {
+
+                    int valuesOfInterest = valuesAvailable;
+                    if (mMinBufferSizeInSamples < valuesOfInterest) {
+                        valuesOfInterest = mMinBufferSizeInSamples;
+                    }
+                    mPipe.read(mAudioShortArray, 0,valuesOfInterest);
+                    //inject into output.
+                    mAudioTrack.write(mAudioShortArray, 0, valuesOfInterest);
+                }
+            } else {
+                try {
+                    sleep(10);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    public void setBalance(float balance) {
+        mBalance = balance;
+        if (mUseMediaPlayer) {
+            if (mMediaPlayer != null) {
+                float left = Math.min(2.0f * (1.0f - mBalance), 1.0f);
+                float right = Math.min(2.0f * mBalance, 1.0f);
+                mMediaPlayer.setVolume(left, right);
+                log(String.format("Setting balance to %f", mBalance));
+            }
+        }
+    }
+
+    public void setStreamType(int streamType) {
+        mStreamType = streamType;
+    }
+
+    public void rewind() {
+        if (mUseMediaPlayer) {
+            if (mMediaPlayer != null) {
+                mMediaPlayer.seekTo(0);
+            }
+        }
+    }
+
+    public void setSoundWithResId(Context context, int resId) {
+        boolean playing = isPlaying();
+        //release player
+        releasePlayer();
+        mResId = resId;
+        if (mUseMediaPlayer) {
+            mMediaPlayer = new MediaPlayer();
+            try {
+                log("opening resource with stream type: " + mStreamType);
+                mMediaPlayer.setAudioStreamType(mStreamType);
+                mMediaPlayer.setDataSource(context.getApplicationContext(),
+                        Uri.parse("android.resource://com.android.cts.verifier/" + resId));
+                mMediaPlayer.prepare();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            mMediaPlayer.setLooping(true);
+            setBalance(mBalance);
+        } else {
+            mMinPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
+                    mChannelConfigOut, mAudioFormat);
+
+            mMinBufferSizeInSamples = mMinPlayBufferSizeInBytes / 2;
+            mAudioShortArray = new short[mMinBufferSizeInSamples * 4];
+
+            mAudioTrack = new AudioTrack(mStreamType,
+                    mSamplingRate,
+                    mChannelConfigOut,
+                    mAudioFormat,
+                    mMinPlayBufferSizeInBytes,
+                    AudioTrack.MODE_STREAM /* FIXME runtime test for API level 9 ,
+                mSessionId */);
+            mPipe.flush();
+            isInitialized = true;
+        }
+
+        log("done preparing media player");
+        if (playing)
+            play(true); //start playing if it was playing before
+    }
+
+    public boolean isPlaying() {
+        boolean result = false;
+        if (mUseMediaPlayer) {
+            if (mMediaPlayer != null) {
+                result = mMediaPlayer.isPlaying();
+            }
+        } else {
+            if (mAudioTrack != null) {
+                result = mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
+            }
+        }
+        return result;
+    }
+
+    public void play(boolean play) {
+        if (mUseMediaPlayer) {
+            if (mMediaPlayer != null) {
+                if (play) {
+                    mMediaPlayer.start();
+                } else {
+                    mMediaPlayer.pause();
+                }
+            }
+        } else {
+            if (mAudioTrack != null && isInitialized) {
+                if (play) {
+                    mPipe.flush();
+                    mAudioTrack.flush();
+                    mAudioTrack.play();
+                } else {
+                    mAudioTrack.pause();
+                }
+            }
+        }
+    }
+
+    public void finish() {
+        play(false);
+        releasePlayer();
+    }
+
+    private void releasePlayer() {
+        if (mMediaPlayer != null) {
+            mMediaPlayer.stop();
+            mMediaPlayer.release();
+            mMediaPlayer = null;
+        }
+
+        if (mAudioTrack != null) {
+            mAudioTrack.stop();
+            mAudioTrack.release();
+            mAudioTrack = null;
+        }
+        isInitialized = false;
+    }
+
+    /*
+       Misc
+    */
+    private static void log(String msg) {
+        Log.v(LOGTAG, msg);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java
new file mode 100644
index 0000000..0a8bdde
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java
@@ -0,0 +1,46 @@
+/*
+ * 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.wavelib;
+
+public abstract class DspBufferBase {
+    private int mSize;
+
+    public DspBufferBase() {
+        setSize(0);
+    }
+
+    public DspBufferBase(int size) {
+        setSize(size);
+    }
+
+    public int getSize() {
+        return mSize;
+    }
+
+    public void setSize(int size) {
+        mSize = size;
+    }
+
+    public abstract void setValue(int index, double value);
+
+    public abstract void setValues(int index, double... values);
+
+    @Override
+    public String toString() {
+        return String.format("Size: %d", mSize);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java
new file mode 100644
index 0000000..2b71343
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java
@@ -0,0 +1,61 @@
+/*
+ * 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.wavelib;
+
+public class DspBufferComplex extends DspBufferBase {
+    public double[] mReal;
+    public double[] mImag;
+
+    public DspBufferComplex(int size) {
+        super(size);
+    }
+
+    @Override
+    public void setSize(int size) {
+        if (size == getSize()) {
+            return;
+        }
+        mReal = new double[size];
+        mImag = new double[size];
+        super.setSize(size);
+    }
+
+    // Warning, these methods don't check for bounds!
+    @Override
+    public void setValues(int index, double... values) {
+        mReal[index] = values[0];
+        mImag[index] = values[1];
+    }
+
+    @Override
+    public void setValue(int index, double value) {
+        mReal[index] = value;
+        mImag[index] = 0;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int size = getSize();
+        sb.append(String.format("Size: %d { ", size));
+        for (int i = 0; i < size; i++) {
+            sb.append(String.format("(%.3f, %3f) ", mReal[i], mImag[i]));
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java
new file mode 100644
index 0000000..1b75da6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java
@@ -0,0 +1,61 @@
+/*
+ * 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.wavelib;
+
+public class DspBufferDouble extends DspBufferBase {
+    public double[] mData;
+
+    public DspBufferDouble(int size) {
+        super(size);
+    }
+
+    @Override
+    public void setSize(int size) {
+        if (size == getSize()) {
+            return;
+        }
+        mData = new double[size];
+        super.setSize(size);
+    }
+
+    // Warning, these methods don't check for bounds!
+    @Override
+    public void setValues(int index, double... values) {
+        mData[index] = values[0];
+    }
+
+    @Override
+    public void setValue(int index, double value) {
+        mData[index] = value;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        int size = getSize();
+        sb.append(String.format("Size: %d { ", size));
+        int i = 0;
+        for (; i < size - 1; i++) {
+            sb.append(String.format("%.3f, ", mData[i]));
+        }
+        for(; i < size; i++) {
+            sb.append(String.format("%.3f", mData[i]));
+        }
+        sb.append(" }");
+        return sb.toString();
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
new file mode 100644
index 0000000..a9cbbd0
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
@@ -0,0 +1,329 @@
+/*
+ * 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.wavelib;
+
+import android.util.Log;
+
+public class DspBufferMath {
+    private static final String TAG = "DspBufferMath";
+    public static final int OPERANDS_TYPE_UNKNOWN  = -1;
+    public static final int OPERANDS_TYPE_REAL     = 0;
+    public static final int OPERANDS_TYPE_COMPLEX  = 1;
+    public static final int OPERANDS_TYPE_MIXED    = 2;
+
+    public static final int MATH_RESULT_UNDEFINED  = -1;
+    public static final int MATH_RESULT_SUCCESS    = 0;
+    public static final int MATH_RESULT_ERROR      = 1;
+
+    static private<T extends DspBufferBase> int estimateOperandsType(T a, T b) {
+        if (a instanceof DspBufferComplex) {
+            if (b instanceof DspBufferComplex) {
+                return OPERANDS_TYPE_COMPLEX;
+            } else if (b instanceof DspBufferDouble) {
+                return OPERANDS_TYPE_MIXED;
+            }
+        } else if (a instanceof DspBufferDouble) {
+            if (b instanceof DspBufferComplex) {
+                return OPERANDS_TYPE_MIXED;
+            } else if (b instanceof DspBufferDouble) {
+                return OPERANDS_TYPE_REAL;
+            }
+        }
+        return OPERANDS_TYPE_UNKNOWN;
+    }
+
+    /**
+     * adds r = a + b; element by element
+     *
+     * If the result is double vector, the imaginary part of complex operations is ignored.
+     */
+    static public <T extends DspBufferBase> int add(T r, T a, T b) {
+        int size = Math.min(a.getSize(), b.getSize());
+        r.setSize(size);
+
+        T x = a;
+        T y = b;
+        int opType = estimateOperandsType(a, b);
+
+        if (opType == OPERANDS_TYPE_MIXED) {
+            if (a instanceof  DspBufferDouble)  {
+                x = b; //Complex first
+                y = a;
+            }
+        }
+
+        if (opType == OPERANDS_TYPE_UNKNOWN) {
+            return MATH_RESULT_UNDEFINED;
+        }
+
+        if (r instanceof DspBufferComplex) {
+            switch (opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] =
+                                ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
+                        ((DspBufferComplex) r).mImag[i] = 0;
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] =
+                                ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
+                        ((DspBufferComplex) r).mImag[i] =
+                                ((DspBufferComplex) x).mImag[i] + ((DspBufferComplex) y).mImag[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] =
+                                ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
+                        ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        } else if (r instanceof DspBufferDouble) {
+            switch (opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] =
+                                ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] =
+                                ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] =
+                                ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        }
+        return MATH_RESULT_ERROR;
+    }
+
+    /**
+     * mult r = a * b; element by element
+     */
+    static public <T extends DspBufferBase> int mult(T r, T a, T b) {
+        int size = Math.min(a.getSize(), b.getSize());
+        r.setSize(size);
+
+        T x = a;
+        T y = b;
+        int opType = estimateOperandsType(a, b);
+
+        if (opType == OPERANDS_TYPE_MIXED) {
+            if (a instanceof  DspBufferDouble)  {
+                x = b; //Complex first
+                y = a;
+            }
+        }
+
+        if (opType == OPERANDS_TYPE_UNKNOWN) {
+            return MATH_RESULT_UNDEFINED;
+        }
+
+        if (r instanceof DspBufferComplex) {
+            switch (opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] =
+                                ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
+                        ((DspBufferComplex) r).mImag[i] = 0;
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        double A = ((DspBufferComplex) x).mReal[i];
+                        double B = ((DspBufferComplex) x).mImag[i];
+                        double C = ((DspBufferComplex) y).mReal[i];
+                        double D = ((DspBufferComplex) y).mImag[i];
+                        ((DspBufferComplex) r).mReal[i] = (C * A) - (B * D);
+                        ((DspBufferComplex) r).mImag[i] = (C * B) + (A * D);
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        double A = ((DspBufferComplex) x).mReal[i];
+                        double B = ((DspBufferComplex) x).mImag[i];
+                        double C = ((DspBufferDouble) y).mData[i];
+                        //double D = 0;
+                        ((DspBufferComplex) r).mReal[i] = C * A;
+                        ((DspBufferComplex) r).mImag[i] = C * B;
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        } else if (r instanceof DspBufferDouble) {
+            switch (opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] =
+                                ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        double A = ((DspBufferComplex) x).mReal[i];
+                        double B = ((DspBufferComplex) x).mImag[i];
+                        double C = ((DspBufferComplex) y).mReal[i];
+                        double D = ((DspBufferComplex) y).mImag[i];
+                        ((DspBufferDouble) r).mData[i] = (C * A) - (B * D);
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        double A = ((DspBufferComplex) x).mReal[i];
+                        double B = ((DspBufferComplex) x).mImag[i];
+                        double C = ((DspBufferDouble) y).mData[i];
+                        //double D = 0;
+                        ((DspBufferDouble) r).mData[i] = C * A;
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        }
+        return MATH_RESULT_ERROR;
+    }
+
+    /**
+     * mult r = a * v; element by element
+     */
+    static public <T extends DspBufferBase> int mult(T r, T a, double v) {
+        int size = a.getSize();
+        r.setSize(size);
+
+        T x = a;
+        int opType = estimateOperandsType(r, a);
+
+        if (opType == OPERANDS_TYPE_UNKNOWN) {
+            return MATH_RESULT_UNDEFINED;
+        }
+
+        if (r instanceof DspBufferComplex) {
+            switch (opType) {
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i] * v;
+                        ((DspBufferComplex) r).mImag[i] = 0;
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i] * v;
+                        ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i] * v;
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        } else if (r instanceof DspBufferDouble) {
+            switch (opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i] * v;
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i] * v;
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        }
+        return MATH_RESULT_ERROR;
+    }
+
+    /**
+     * set r = a ; element by element
+     */
+    static public <T extends DspBufferBase> int set(T r, T a) {
+        int size = a.getSize();
+        r.setSize(size);
+
+        T x = a;
+        int opType = estimateOperandsType(r, a);
+
+        if (opType == OPERANDS_TYPE_UNKNOWN) {
+            return MATH_RESULT_UNDEFINED;
+        }
+
+        if (r instanceof DspBufferComplex) {
+            switch (opType) {
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i];
+                        ((DspBufferComplex) r).mImag[i] = 0;
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_COMPLEX:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i];
+                        ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        } else if (r instanceof DspBufferDouble) {
+            switch(opType) {
+                case OPERANDS_TYPE_REAL:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+                case OPERANDS_TYPE_MIXED:
+                    for (int i = 0; i < size; i++) {
+                        ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i];
+                    }
+                    return MATH_RESULT_SUCCESS;
+            }
+        }
+        return MATH_RESULT_ERROR;
+    }
+
+
+    /**
+     * set r = v ; all elements the same
+     * It keeps the size of the return vector
+     */
+    static public <T extends DspBufferBase> int set(T r, double ...values) {
+        int size = r.getSize();
+
+        double a = 0;
+        double b = 0;
+        if (values.length > 0) {
+            a = values[0];
+        }
+        if (values.length > 1) {
+            b = values[1];
+        }
+
+        if (r instanceof DspBufferComplex) {
+            for (int i = 0; i < size; i++) {
+                ((DspBufferComplex) r).mReal[i] = a;
+                ((DspBufferComplex) r).mImag[i] = b;
+            }
+            return MATH_RESULT_SUCCESS;
+        } else if (r instanceof DspBufferDouble) {
+            for (int i = 0; i < size; i++) {
+                ((DspBufferDouble) r).mData[i] = a;
+            }
+            return MATH_RESULT_SUCCESS;
+        }
+        return MATH_RESULT_ERROR;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java
new file mode 100644
index 0000000..09337f1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public class DspFftServer {
+    private int mN = 0;
+    private int mOrder = 0;
+
+    DspBufferDouble mCos;
+    DspBufferDouble mSin;
+    public boolean isInitialized = false;
+
+    public DspFftServer(int size) {
+        init(size);
+    }
+
+    public boolean init(int size) {
+        boolean status = false;
+        mN=size;
+
+        mOrder = (int) (Math.log(mN) / Math.log(2));
+        if (mN == (1 << mOrder)) {
+            mCos = new DspBufferDouble(mN / 2);
+            mSin = new DspBufferDouble(mN / 2);
+            for (int i = 0; i < mN / 2; i++) {
+                mCos.mData[i] = Math.cos(-2 * Math.PI * i / mN);
+                mSin.mData[i] = Math.sin(-2 * Math.PI * i / mN);
+            }
+            status = true;
+        } else {
+            mN = 0;
+            throw new RuntimeException("FFT must be power of 2");
+        }
+        isInitialized = status;
+        return status;
+    }
+
+    public void fft(DspBufferComplex r, int sign) {
+        int ii, jj, kk, n1, n2, aa;
+        double cc, ss, t1, t2;
+
+        // Bit-reverse
+        jj = 0;
+        n2 = mN / 2;
+        for (ii = 1; ii < mN - 1; ii++) {
+            n1 = n2;
+            while (jj >= n1) {
+                jj = jj - n1;
+                n1 = n1 / 2;
+            }
+            jj = jj + n1;
+
+            if (ii < jj) {
+                t1 =  r.mReal[ii];
+                r.mReal[ii] = r.mReal[jj];
+                r.mReal[jj] = t1;
+                t1 = r.mImag[ii];
+                r.mImag[ii] = r.mImag[jj];
+                r.mImag[jj] = t1;
+            }
+        }
+
+        // FFT
+        n1 = 0;
+        n2 = 1;
+        for (ii = 0; ii < mOrder; ii++) {
+            n1 = n2;
+            n2 = n2 + n2;
+            aa = 0;
+
+            for (jj = 0; jj < n1; jj++) {
+                cc = mCos.mData[aa];
+                ss = sign * mSin.mData[aa];
+                aa += 1 << (mOrder - ii - 1);
+                for (kk = jj; kk < mN; kk = kk + n2) {
+                    t1 = cc * r.mReal[kk + n1] - ss * r.mImag[kk + n1];
+                    t2 = ss * r.mReal[kk + n1] + cc * r.mImag[kk + n1];
+                    r.mReal[kk + n1] = r.mReal[kk] - t1;
+                    r.mImag[kk + n1] = r.mImag[kk] - t2;
+                    r.mReal[kk] = r.mReal[kk] + t1;
+                    r.mImag[kk] = r.mImag[kk] + t2;
+                }
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java
new file mode 100644
index 0000000..3ccca43
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java
@@ -0,0 +1,201 @@
+/*
+ * 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.wavelib;
+
+public class DspWindow {
+    public DspBufferDouble mBuffer;
+    private int mWindowType = WINDOW_RECTANGULAR;
+    private int mSize;
+    private int mOverlap;
+
+    private static final double TWOPI = Math.PI * 2;
+
+    public static final int WINDOW_RECTANGULAR = 0;
+    public static final int WINDOW_TRIANGULAR = 1;
+    public static final int WINDOW_TRIANGULAR_FLAT_TOP = 2;
+    public static final int WINDOW_HAMMING = 3;
+    public static final int WINDOW_HAMMING_FLAT_TOP = 4;
+    public static final int WINDOW_HANNING = 5;
+    public static final int WINDOW_HANNING_FLAT_TOP = 6;
+
+    public DspWindow(int windowType, int size, int overlap) {
+        init(windowType, size, overlap);
+    }
+
+    public DspWindow(int windowType, int size)  {
+        init(windowType, size, size / 2);
+    }
+
+    public void init(int windowType, int size, int overlap) {
+        if (size > 0 && overlap > 0) {
+            mSize = size;
+            mOverlap = overlap;
+            if (mOverlap > mSize / 2) {
+                mOverlap = mSize / 2;
+            }
+
+            mBuffer = new DspBufferDouble(mSize);
+            if (fillWindow(mBuffer, windowType, mOverlap)) {
+                mWindowType = windowType;
+            }
+        }
+    }
+
+    public void scale(double scale) {
+        DspBufferMath.mult(mBuffer, mBuffer, scale);
+    }
+
+    public static boolean fillWindow(DspBufferDouble r, int type, int overlap) {
+        boolean status = false;
+        int size = r.getSize();
+        if (overlap > size / 2) {
+            overlap = size / 2;
+        }
+
+        switch(type) {
+            case WINDOW_RECTANGULAR:
+                status = fillRectangular(r);
+                break;
+            case WINDOW_TRIANGULAR:
+                status = fillTriangular(r, size / 2);
+                break;
+            case WINDOW_TRIANGULAR_FLAT_TOP:
+                status = fillTriangular(r, overlap);
+                break;
+            case WINDOW_HAMMING:
+                status = fillHamming(r, size / 2);
+                break;
+            case WINDOW_HAMMING_FLAT_TOP:
+                status = fillHamming(r, overlap);
+                break;
+            case WINDOW_HANNING:
+                status = fillHanning(r, size / 2);
+                break;
+            case WINDOW_HANNING_FLAT_TOP:
+                status = fillHanning(r, overlap);
+                break;
+        }
+        return status;
+    }
+
+    private static boolean fillRectangular(DspBufferDouble r) {
+        if (DspBufferMath.set(r, 1.0) == DspBufferMath.MATH_RESULT_SUCCESS) {
+            return true;
+        }
+        return false;
+    }
+
+    private static boolean fillTriangular(DspBufferDouble b, int overlap) {
+        int size = b.getSize();
+        if (overlap > size / 2) {
+            overlap = size / 2;
+        }
+
+        double value;
+        //ramp up
+        int i = 0;
+        if (overlap > 0) {
+            for (i = 0; i < overlap; i++) {
+                value = (2.0 * i + 1) / (2 * overlap);
+                b.mData[i] = value;
+            }
+        }
+
+        //flat top
+        for (; i < size - overlap; i++) {
+            b.mData[i] = 1.0;
+        }
+
+        //ramp down
+        if (overlap > 0) {
+            for (; i < size; i++) {
+                value = (2.0 * (size - i) - 1) / (2 * overlap);
+                b.mData[i] = value;
+            }
+        }
+        return true;
+    }
+
+    private static boolean fillHamming(DspBufferDouble b, int overlap) {
+        int size = b.getSize();
+        if (overlap > size / 2)
+            overlap = size / 2;
+
+        //create window, then copy
+        double value;
+
+        int twoOverlap = 2 * overlap;
+        //ramp up
+        int i = 0;
+        if (overlap > 0) {
+            for (i = 0; i < overlap; i++) {
+                value = 0.54 - 0.46 * Math.cos(TWOPI * i / (twoOverlap - 1));
+                b.mData[i] = value;
+            }
+        }
+
+        //flat top
+        for (; i < size - overlap; i++) {
+            b.mData[i] = 1.0;
+        }
+
+        //ramp down
+        int k;
+        if (overlap > 0) {
+            for (; i < size; i++) {
+                k = i - (size - 2 * overlap);
+                value = 0.54 - 0.46 * Math.cos(TWOPI * k / (twoOverlap - 1));
+                b.mData[i] = value;
+            }
+        }
+        return true;
+    }
+
+    private static boolean fillHanning(DspBufferDouble b, int overlap) {
+        int size = b.getSize();
+        if (overlap > size / 2)
+            overlap = size / 2;
+
+        //create window, then copy
+        double value;
+
+        int twoOverlap = 2*overlap;
+        //ramp up
+        int i = 0;
+        if (overlap > 0) {
+            for (i = 0; i < overlap; i++) {
+                value = 0.5 * (1.0 - Math.cos(TWOPI * i / (twoOverlap - 1)));
+                b.mData[i] = value;
+            }
+        }
+
+        //flat top
+        for (; i < size - overlap; i++) {
+            b.mData[i] = 1.0;
+        }
+
+        //ramp down
+        if (overlap > 0) {
+            for (; i < size; i++) {
+                int k = i - (size - 2 * overlap);
+                value = 0.5 * (1.0 - Math.cos(TWOPI * k / (twoOverlap - 1)));
+                b.mData[i] = value;
+            }
+        }
+        return true;
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java
new file mode 100644
index 0000000..83b171f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+// Non-blocking pipe supports a single writer and single reader.
+// The write side of a pipe permits overruns; flow control is the caller's responsibility.
+
+public class PipeShort {
+    private int mFront;
+    private int mRear;
+    private short mBuffer[];
+    private volatile int mVolatileRear; // written by write(), read by read()
+    private int mMaxValues;
+    private int mBytesOverrun;
+    private int mOverruns;
+    public static final int OVERRUN = -2;
+
+    // maxBytes will be rounded up to a power of 2, and all slots are available. Must be >= 2.
+    public PipeShort(int maxValues)
+    {
+        mMaxValues = roundup(maxValues);
+        mBuffer = new short[mMaxValues];
+    }
+
+    // buffer must != null.
+    // offset must be >= 0.
+    // count is maximum number of bytes to copy, and must be >= 0.
+    // offset + count must be <= buffer.length.
+    // Returns actual number of bytes copied >= 0.
+    public int write(short[] buffer, int offset, int count)
+    {
+        int rear = mRear & (mMaxValues - 1);
+        int written = mMaxValues - rear;
+        if (written > count) {
+            written = count;
+        }
+        System.arraycopy(buffer, offset, mBuffer, rear, written);
+        if (rear + written == mMaxValues) {
+            if ((count -= written) > rear) {
+                count = rear;
+            }
+            if (count > 0) {
+                System.arraycopy(buffer, offset + written, mBuffer, 0, count);
+                written += count;
+            }
+        }
+        mRear += written;
+        mVolatileRear = mRear;
+        return written;
+    }
+
+    public int availableToRead()
+    {
+        int rear = mVolatileRear;
+        int avail = rear - mFront;
+        if (avail > mMaxValues) {
+            // Discard 1/16 of the most recent data in pipe to avoid another overrun immediately
+            int oldFront = mFront;
+            mFront = rear - mMaxValues + (mMaxValues >> 4);
+            mBytesOverrun += mFront - oldFront;
+            ++mOverruns;
+            return OVERRUN;
+        }
+        return avail;
+    }
+
+    // buffer must != null.
+    // offset must be >= 0.
+    // count is maximum number of bytes to copy, and must be >= 0.
+    // offset + count must be <= buffer.length.
+    // Returns actual number of bytes copied >= 0.
+    public int read(short[] buffer, int offset, int count)
+    {
+        int avail = availableToRead();
+        if (avail <= 0) {
+            return avail;
+        }
+        // An overrun can occur from here on and be silently ignored,
+        // but it will be caught at next read()
+        if (count > avail) {
+            count = avail;
+        }
+        int front = mFront & (mMaxValues - 1);
+        int red = mMaxValues - front;
+        if (red > count) {
+            red = count;
+        }
+        // In particular, an overrun during the System.arraycopy will result in reading corrupt data
+        System.arraycopy(mBuffer, front, buffer, offset, red);
+        // We could re-read the rear pointer here to detect the corruption, but why bother?
+        if (front + red == mMaxValues) {
+            if ((count -= red) > front) {
+                count = front;
+            }
+            if (count > 0) {
+                System.arraycopy(mBuffer, 0, buffer, offset + red, count);
+                red += count;
+            }
+        }
+        mFront += red;
+        return red;
+    }
+
+    public void flush()
+    {
+        mRear = mFront;
+        mVolatileRear = mFront;
+    }
+
+    // Round up to the next highest power of 2
+    private static int roundup(int v)
+    {
+        // Integer.numberOfLeadingZeros() returns 32 for zero input
+        if (v == 0) {
+            v = 1;
+        }
+        int lz = Integer.numberOfLeadingZeros(v);
+        int rounded = 0x80000000 >>> lz;
+        // 0x800000001 and higher are actually rounded _down_ to prevent overflow
+        if (v > rounded && lz > 0) {
+            rounded <<= 1;
+        }
+        return rounded;
+    }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.java
new file mode 100644
index 0000000..41f0411
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.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.audio.wavelib;
+
+import android.util.Log;
+
+public class VectorAverage {
+    private static final String LOGTAG = "VectorAverage";
+    private static final int mVersion = 0;
+    private double[] mData;
+    private int mValueCount = 0;
+
+    public void setData(double[] data, boolean replace) {
+        int size = data.length;
+        if (mData == null || mData.length != size) {
+            mData = new double[size];
+            mValueCount = 0;
+        }
+        if (replace || mValueCount == 0) {
+            System.arraycopy(data, 0, mData, 0, size);
+            mValueCount = 1;
+        } else {
+            for (int i = 0; i < size; i++) {
+                mData[i] += data[i];
+            }
+            mValueCount++;
+        }
+    }
+
+    public int getData(double[] data, boolean raw) {
+        int nCount = 0;
+        if (mData != null && mData.length <= data.length) {
+            nCount = mData.length;
+            if (mValueCount == 0) {
+                for (int i = 0; i < nCount; i++) {
+                    data[i] = 0;
+                }
+            } else if (!raw && mValueCount > 1) {
+                for (int i = 0; i < nCount; i++) {
+                    data[i] = mData[i] / mValueCount;
+                }
+            } else {
+                for (int i = 0; i < nCount; i++) {
+                    data[i] = mData[i];
+                }
+            }
+        }
+        return nCount;
+    }
+
+    public int getCount() {
+        return mValueCount;
+    }
+
+    public int getSize() {
+        if (mData != null) {
+            return mData.length;
+        }
+        return 0;
+    }
+
+    public void reset() {
+        mValueCount = 0;
+    }
+
+    private final String SERIALIZED_VERSION = "VECTOR_AVERAGE_VERSION";
+    private final String SERIALIZED_COUNT = "COUNT";
+
+    public String toString() {
+        StringBuffer sb = new StringBuffer();
+
+        //version
+        sb.append(SERIALIZED_VERSION +"="+ mVersion +"\n");
+
+        double[] data = new double[getSize()];
+        getData(data,false);
+
+        //element count
+        int nCount = data.length;
+        sb.append(SERIALIZED_COUNT + "=" + nCount +"\n");
+
+        for (int i = 0; i < nCount; i++) {
+            sb.append(String.format("%f\n",data[i]));
+        }
+
+        return sb.toString();
+    }
+
+    public boolean initFromString(String string) {
+        boolean success = false;
+
+        String[] lines = string.split(System.getProperty("line.separator"));
+
+        int lineCount = lines.length;
+        if (lineCount > 3) {
+            int nVersion = -1;
+            int nCount = -1;
+            int nIndex = 0;
+
+            //search for version:
+            while (nIndex < lineCount) {
+                String[] separated = lines[nIndex].split("=");
+                nIndex++;
+                if (separated.length > 1 && separated[0].equalsIgnoreCase(SERIALIZED_VERSION)) {
+                    nVersion = Integer.parseInt(separated[1]);
+                    break;
+                }
+            }
+
+            if (nVersion >= 0) {
+                //get count
+
+                while (nIndex < lineCount) {
+                    String[] separated = lines[nIndex].split("=");
+                    nIndex++;
+                    if (separated.length > 1 && separated[0].equalsIgnoreCase(SERIALIZED_COUNT)) {
+                        nCount = Integer.parseInt(separated[1]);
+                        break;
+                    }
+                }
+
+                if (nCount > 0 && nCount <= lineCount-2 && nCount < 20000) { //foolproof
+                    //now add nCount to the vector.
+                    double[] data = new double[nCount];
+                    int dataIndex=0;
+
+                    while (nIndex < lineCount) {
+                        double value = Double.parseDouble(lines[nIndex]);
+                        data[dataIndex++] = value;
+                        nIndex++;
+                    }
+                    setData(data, true);
+                    success = true;
+                }
+            }
+        }
+
+        return success;
+    }
+
+    private static void log(String msg) {
+        Log.v(LOGTAG, msg);
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index a76bb7f..3037376 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -1295,8 +1295,8 @@
                         CaptureRequest.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR));
 
                 inputReqest.set(CaptureRequest.NOISE_REDUCTION_MODE,
-                        CaptureRequest.NOISE_REDUCTION_MODE_OFF);
-                inputReqest.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_OFF);
+                        CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
+                inputReqest.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
                 inputReqest.set(CaptureRequest.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR, null);
                 inputReqest.addTarget(mInputImageReader.getSurface());
                 mSession.capture(inputReqest.build(), captureCallbackWaiter, mResultHandler);
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 a463937..bee1241 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -32,6 +32,7 @@
 import com.android.cts.verifier.DialogTestListActivity;
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListActivity;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
 import com.android.cts.verifier.TestResult;
 
 /**
@@ -73,6 +74,7 @@
     private DialogTestListItem mCrossProfileImageCaptureSupportTest;
     private DialogTestListItem mCrossProfileVideoCaptureSupportTest;
     private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
+    private TestListItem mKeyguardDisabledFeaturesTest;
 
     public ByodFlowTestActivity() {
         super(R.layout.provisioning_byod,
@@ -256,6 +258,11 @@
                 R.string.provisioning_byod_cross_profile_instruction,
                 chooser);
 
+        mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
+                R.string.provisioning_byod_keyguard_disabled_features,
+                KeyguardDisabledFeaturesActivity.class.getName(),
+                new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
+
         // Test for checking if the required intent filters are set during managed provisioning.
         mIntentFiltersTest = new DialogTestListItem(this,
                 R.string.provisioning_byod_cross_profile_intent_filters,
@@ -295,6 +302,7 @@
         adapter.add(mEnableNonMarketTest);
         adapter.add(mIntentFiltersTest);
         adapter.add(mPermissionLockdownTest);
+        adapter.add(mKeyguardDisabledFeaturesTest);
 
         if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
             // Capture image 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 4d1a92a..09e6393 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -67,8 +67,13 @@
     public static final String ACTION_CAPTURE_AND_CHECK_VIDEO = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO";
     // Primage -> managed intent: request to capture and check an audio recording
     public static final String ACTION_CAPTURE_AND_CHECK_AUDIO = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_AUDIO";
+    public static final String ACTION_KEYGUARD_DISABLED_FEATURES =
+            "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 EXTRA_PROVISIONED = "extra_provisioned";
+    public static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
 
     // Primary -> managed intent: set unknown sources restriction and install package
     public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK";
@@ -187,6 +192,14 @@
                 finish();
             }
             return;
+        } else if (ACTION_KEYGUARD_DISABLED_FEATURES.equals(action)) {
+            final int value = intent.getIntExtra(EXTRA_PARAMETER_1,
+                    DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE);
+            ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
+            mDevicePolicyManager.setKeyguardDisabledFeatures(admin, value);
+        } else if (ACTION_LOCKNOW.equals(action)) {
+            mDevicePolicyManager.lockNow();
+            setResult(RESULT_OK);
         }
         // This activity has no UI and is only used to respond to CtsVerifier in the primary side.
         finish();
@@ -267,6 +280,10 @@
         return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
     }
 
+    public static Intent createLockIntent() {
+        return new Intent(ACTION_LOCKNOW);
+    }
+
     private Uri getTempUri(String fileName) {
         final File file = new File(getFilesDir() + File.separator + "images"
                 + File.separator + fileName);
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 4987f86..b18e816 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -61,8 +61,11 @@
             filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE);
             filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_VIDEO);
             filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_AUDIO);
+            filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
+            filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
             filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
             filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
+            filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
             filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
             filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_TOAST);
             filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index e6bbdee..a6a5e5a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -25,6 +25,7 @@
 import android.content.pm.PackageManager;
 import android.database.DataSetObserver;
 import android.os.Bundle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.view.View;
@@ -66,11 +67,14 @@
     static final String EXTRA_SETTING = "extra-setting";
 
     private static final String CHECK_DEVICE_OWNER_TEST_ID = "CHECK_DEVICE_OWNER";
+    private static final String DEVICE_ADMIN_SETTINGS_ID = "DEVICE_ADMIN_SETTINGS";
     private static final String WIFI_LOCKDOWN_TEST_ID = WifiLockdownTestActivity.class.getName();
     private static final String DISABLE_STATUS_BAR_TEST_ID = "DISABLE_STATUS_BAR";
     private static final String DISABLE_KEYGUARD_TEST_ID = "DISABLE_KEYGUARD";
     private static final String CHECK_PERMISSION_LOCKDOWN_TEST_ID =
             PermissionLockdownTestActivity.class.getName();
+    private static final String DISALLOW_CONFIG_BT_ID = "DISALLOW_CONFIG_BT";
+    private static final String DISALLOW_CONFIG_WIFI_ID = "DISALLOW_CONFIG_WIFI";
     private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
 
     @Override
@@ -132,11 +136,49 @@
                 new Intent(this, CommandReceiver.class)
                         .putExtra(EXTRA_COMMAND, COMMAND_CHECK_DEVICE_OWNER)
                         ));
+
+        // device admin settings
+        adapter.add(createInteractiveTestItem(this, DEVICE_ADMIN_SETTINGS_ID,
+                R.string.device_owner_device_admin_visible,
+                R.string.device_owner_device_admin_visible_info,
+                new ButtonInfo(
+                        R.string.device_owner_settings_go,
+                        new Intent(Settings.ACTION_SECURITY_SETTINGS))));
+
         PackageManager packageManager = getPackageManager();
         if (packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            // WiFi Lock down tests
             adapter.add(createTestItem(this, WIFI_LOCKDOWN_TEST_ID,
                     R.string.device_owner_wifi_lockdown_test,
                     new Intent(this, WifiLockdownTestActivity.class)));
+
+            // DISALLOW_CONFIG_WIFI
+            adapter.add(createInteractiveTestItem(this, DISALLOW_CONFIG_WIFI_ID,
+                    R.string.device_owner_disallow_config_wifi,
+                    R.string.device_owner_disallow_config_wifi_info,
+                    new ButtonInfo[] {
+                            new ButtonInfo(
+                                    R.string.device_owner_user_restriction_set,
+                                    createSetUserRestrictionIntent(
+                                            UserManager.DISALLOW_CONFIG_WIFI)),
+                            new ButtonInfo(
+                                    R.string.device_owner_settings_go,
+                                    new Intent(Settings.ACTION_WIFI_SETTINGS))}));
+        }
+
+        // DISALLOW_CONFIG_BLUETOOTH
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
+            adapter.add(createInteractiveTestItem(this, DISALLOW_CONFIG_BT_ID,
+                    R.string.device_owner_disallow_config_bt,
+                    R.string.device_owner_disallow_config_bt_info,
+                    new ButtonInfo[] {
+                            new ButtonInfo(
+                                    R.string.device_owner_user_restriction_set,
+                                    createSetUserRestrictionIntent(
+                                            UserManager.DISALLOW_CONFIG_BLUETOOTH)),
+                            new ButtonInfo(
+                                    R.string.device_owner_settings_go,
+                                    new Intent(Settings.ACTION_BLUETOOTH_SETTINGS))}));
         }
 
         // setStatusBarDisabled
@@ -215,6 +257,12 @@
                 .putExtra(EXTRA_PARAMETER_1, value);
     }
 
+    private Intent createSetUserRestrictionIntent(String restriction) {
+        return new Intent(this, CommandReceiver.class)
+                .putExtra(EXTRA_COMMAND, COMMAND_ADD_USER_RESTRICTION)
+                .putExtra(EXTRA_RESTRICTION, restriction);
+    }
+
     public static class CommandReceiver extends Activity {
         @Override
         public void onCreate(Bundle savedInstanceState) {
@@ -276,6 +324,8 @@
 
             dpm.setStatusBarDisabled(admin, false);
             dpm.setKeyguardDisabled(admin, false);
+            dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_BLUETOOTH);
+            dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_WIFI);
             dpm.clearDeviceOwnerApp(getPackageName());
         }
     }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
new file mode 100644
index 0000000..0fdc498
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
@@ -0,0 +1,123 @@
+/*
+ * 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.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+
+public class KeyguardDisabledFeaturesActivity extends DialogTestListActivity {
+
+    public KeyguardDisabledFeaturesActivity() {
+        super(R.layout.provisioning_byod,
+                R.string.provisioning_byod_keyguard_disabled_features,
+                R.string.provisioning_byod_keyguard_disabled_features_info,
+                R.string.provisioning_byod_keyguard_disabled_features_instruction);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPrepareTestButton.setText(
+                R.string.provisioning_byod_keyguard_disabled_features_prepare_button);
+        mPrepareTestButton.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    resetPassword("testpassword");
+                    setKeyguardDisabledFeatures(DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS |
+                            DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
+                            DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+                }
+            });
+    }
+
+    @Override
+    public void finish() {
+        // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
+        // clear the password.
+        resetPassword(null);
+        super.finish();
+    }
+
+    private void setKeyguardDisabledFeatures(final int flags) {
+        Intent setKeyguardDisabledFeaturesIntent =
+                new Intent(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES)
+                .putExtra(ByodHelperActivity.EXTRA_PARAMETER_1, flags);
+        startActivity(setKeyguardDisabledFeaturesIntent);
+    }
+
+    /**
+     * Reset device password
+     * @param password password to reset to (may be null)
+     */
+    private void resetPassword(String password) {
+        DevicePolicyManager dpm = (DevicePolicyManager)
+                getSystemService(Context.DEVICE_POLICY_SERVICE);
+        dpm.resetPassword(password, 0);
+    }
+
+    @Override
+    protected void setupTests(ArrayTestListAdapter adapter) {
+        adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_trust_agents,
+                "BYOD_DisableTrustAgentsTest",
+                R.string.provisioning_byod_disable_trust_agents_instruction,
+                new Intent(Settings.ACTION_SECURITY_SETTINGS)));
+        adapter.add(new DialogTestListItemWithIcon(this,
+                R.string.provisioning_byod_disable_notifications,
+                "BYOD_DisableUnredactedNotifications",
+                R.string.provisioning_byod_disable_notifications_instruction,
+                new Intent(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN),
+                R.drawable.ic_corp_icon));
+        FingerprintManager fpm = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
+        if (fpm.isHardwareDetected()) {
+            adapter.add(new DialogTestListItem(this,
+                    R.string.provisioning_byod_fingerprint_disabled_in_settings,
+                    "BYOD_FingerprintDisabledInSettings",
+                    R.string.provisioning_byod_fingerprint_disabled_in_settings_instruction,
+                    new Intent(Settings.ACTION_SECURITY_SETTINGS)));
+            adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_fingerprint,
+                    "BYOD_DisableFingerprint",
+                    R.string.provisioning_byod_disable_fingerprint_instruction,
+                    ByodHelperActivity.createLockIntent()));
+        }
+    }
+
+    @Override
+    protected void clearRemainingState(final DialogTestListItem test) {
+        super.clearRemainingState(test);
+        if (WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(
+                test.getManualTestIntent().getAction())) {
+            try {
+                startActivity(new Intent(
+                        WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION));
+            } catch (ActivityNotFoundException e) {
+                // User shouldn't run this test before work profile is set up.
+            }
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
index c85ccf5..a912d2c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
@@ -19,7 +19,9 @@
 import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.Intent;
 import android.os.Bundle;
 
 import com.android.cts.verifier.R;
@@ -30,26 +32,37 @@
 public class WorkNotificationTestActivity extends Activity {
     public static final String ACTION_WORK_NOTIFICATION =
             "com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION";
+    public static final String ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN =
+            "com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION";
     public static final String ACTION_CLEAR_WORK_NOTIFICATION =
             "com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION";
     private static final int NOTIFICATION_ID = 7;
+    private NotificationManager mNotificationManager;
+
+    private void showWorkNotification(int visibility) {
+        final Notification notification = new Notification.Builder(this)
+                .setSmallIcon(R.drawable.icon)
+                .setContentTitle(getString(R.string.provisioning_byod_work_notification_title))
+                .setVisibility(visibility)
+                .setAutoCancel(true)
+                .build();
+        mNotificationManager.notify(NOTIFICATION_ID, notification);
+    }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         final String action = getIntent().getAction();
-        final NotificationManager notificationManager = (NotificationManager)
-                getSystemService(Context.NOTIFICATION_SERVICE);
+        mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
         if (ACTION_WORK_NOTIFICATION.equals(action)) {
-            final Notification notification = new Notification.Builder(this)
-                .setSmallIcon(R.drawable.icon)
-                .setContentTitle(getString(R.string.provisioning_byod_work_notification_title))
-                .setVisibility(Notification.VISIBILITY_PUBLIC)
-                .setAutoCancel(true)
-                .build();
-            notificationManager.notify(NOTIFICATION_ID, notification);
+            showWorkNotification(Notification.VISIBILITY_PUBLIC);
+        } else if (ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(action)) {
+            DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
+                    Context.DEVICE_POLICY_SERVICE);
+            dpm.lockNow();
+            showWorkNotification(Notification.VISIBILITY_PRIVATE);
         } else if (ACTION_CLEAR_WORK_NOTIFICATION.equals(action)) {
-            notificationManager.cancel(NOTIFICATION_ID);
+            mNotificationManager.cancel(NOTIFICATION_ID);
         }
         finish();
     }
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
index d74ec52..cb67c63 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
@@ -215,6 +215,10 @@
             // Verify they both have isolated view of storage
             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", owner);
             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testReadIsolatedStorage", secondary);
+
+            // Verify they can't poke at each other
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", owner);
+            runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testUserIsolation", secondary);
         } finally {
             getDevice().uninstallPackage(MULTIUSER_PKG);
             removeUsersForTest(users);
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index f01db4f..7fe0b80 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -26,12 +26,14 @@
 import android.test.AndroidTestCase;
 import android.util.Log;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -166,6 +168,21 @@
         return paths;
     }
 
+    public static List<File> getMountPaths() throws IOException {
+        final List<File> paths = new ArrayList<>();
+        final BufferedReader br = new BufferedReader(new FileReader("/proc/self/mounts"));
+        try {
+            String line;
+            while ((line = br.readLine()) != null) {
+                final String[] fields = line.split(" ");
+                paths.add(new File(fields[1]));
+            }
+        } finally {
+            br.close();
+        }
+        return paths;
+    }
+
     private static File[] dropFirst(File[] before) {
         final File[] after = new File[before.length - 1];
         System.arraycopy(before, 1, after, 0, after.length);
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
index 7dc462a..6030f1c 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
@@ -17,8 +17,10 @@
 package com.android.cts.externalstorageapp;
 
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
 
 import android.app.DownloadManager;
 import android.app.DownloadManager.Query;
@@ -34,7 +36,9 @@
 import android.test.AndroidTestCase;
 import android.text.format.DateUtils;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -76,6 +80,25 @@
     }
 
     /**
+     * Verify that we don't have read access to any storage mountpoints.
+     */
+    public void testMountPointsNotReadable() throws Exception {
+        final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+        final List<File> mountPaths = getMountPaths();
+        for (File path : mountPaths) {
+            if (path.getAbsolutePath().startsWith("/mnt/")
+                    || path.getAbsolutePath().startsWith("/storage/")) {
+                // Mount points could be multi-user aware, so try probing both
+                // top level and user-specific directory.
+                final File userPath = new File(path, userId);
+
+                assertDirNoAccess(path);
+                assertDirNoAccess(userPath);
+            }
+        }
+    }
+
+    /**
      * Verify that we can't download things outside package directory.
      */
     public void testDownloadManager() throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/src/com/android/cts/multiuserstorageapp/MultiUserStorageTest.java b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/src/com/android/cts/multiuserstorageapp/MultiUserStorageTest.java
index ed84a66..d9f00d2 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/src/com/android/cts/multiuserstorageapp/MultiUserStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/src/com/android/cts/multiuserstorageapp/MultiUserStorageTest.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.multiuserstorageapp;
 
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPathsExceptObb;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
@@ -119,6 +120,24 @@
                 readInt(buildRawObbPath(FILE_OBB_SINGLETON)));
     }
 
+    /**
+     * Verify that we can't poke at storage of other users.
+     */
+    public void testUserIsolation() throws Exception {
+        final File myPath = Environment.getExternalStorageDirectory();
+        final int myId = android.os.Process.myUid() / 100000;
+        assertEquals(String.valueOf(myId), myPath.getName());
+
+        Log.d(TAG, "My path is " + myPath);
+        final File basePath = myPath.getParentFile();
+        for (int i = 0; i < 128; i++) {
+            if (i == myId) continue;
+
+            final File otherPath = new File(basePath, String.valueOf(i));
+            assertDirNoAccess(otherPath);
+        }
+    }
+
     private File buildApiObbPath(String file) {
         return new File(getContext().getObbDir(), file);
     }
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
index 71faab2..995da90 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
@@ -16,9 +16,11 @@
 
 package com.android.cts.readexternalstorageapp;
 
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
 
 import android.os.Environment;
 import android.test.AndroidTestCase;
@@ -64,4 +66,23 @@
             }
         }
     }
+
+    /**
+     * Verify that we don't have write access to any mountpoints.
+     */
+    public void testMountPointsNotWritable() throws Exception {
+        final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+        final List<File> mountPaths = getMountPaths();
+        for (File path : mountPaths) {
+            if (path.getAbsolutePath().startsWith("/mnt/")
+                    || path.getAbsolutePath().startsWith("/storage/")) {
+                // Mount points could be multi-user aware, so try probing both
+                // top level and user-specific directory.
+                final File userPath = new File(path, userId);
+
+                assertDirNoWriteAccess(path);
+                assertDirNoWriteAccess(userPath);
+            }
+        }
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index badc852..5e6aa3e 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -24,6 +24,7 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildProbeFile;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getPrimaryPackageSpecificPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getSecondaryPackageSpecificPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
@@ -35,9 +36,7 @@
 
 import com.android.cts.externalstorageapp.CommonExternalStorageTest;
 
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
 import java.util.List;
 import java.util.Random;
 
@@ -273,28 +272,29 @@
      * {@link CommonExternalStorageTest#testAllPackageDirsWritable()}.
      */
     public void testSecondaryMountPointsNotWritable() throws Exception {
+        // Probe path could be /storage/emulated/0 or /storage/1234-5678
         final File probe = buildProbeFile(Environment.getExternalStorageDirectory());
         assertTrue(probe.createNewFile());
 
-        final BufferedReader br = new BufferedReader(new FileReader("/proc/self/mounts"));
-        try {
-            String line;
-            while ((line = br.readLine()) != null) {
-                final String[] fields = line.split(" ");
-                final File testMount = new File(fields[1]);
-                final File testProbe = new File(testMount, probe.getName());
-                if (testProbe.exists()) {
-                    Log.d(TAG, "Primary external mountpoint " + testMount);
-                } else {
-                    // This mountpoint is not primary external storage; we must
-                    // not be able to write.
-                    Log.d(TAG, "Other mountpoint " + testMount);
-                    assertDirNoWriteAccess(testProbe.getParentFile());
-                }
+        final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+        final List<File> mountPaths = getMountPaths();
+        for (File path : mountPaths) {
+            // Mount points could be multi-user aware, so try probing both top
+            // level and user-specific directory.
+            final File userPath = new File(path, userId);
+
+            final File testProbe = new File(path, probe.getName());
+            final File testUserProbe = new File(userPath, probe.getName());
+
+            if (testProbe.exists() || testUserProbe.exists()) {
+                Log.d(TAG, "Primary external mountpoint " + path);
+            } else {
+                // This mountpoint is not primary external storage; we must
+                // not be able to write.
+                Log.d(TAG, "Other mountpoint " + path);
+                assertDirNoWriteAccess(path);
+                assertDirNoWriteAccess(userPath);
             }
-       } finally {
-           br.close();
-           probe.delete();
-       }
+        }
     }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
index 07b6953..ed920e9 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/AndroidManifest.xml
@@ -18,6 +18,9 @@
     package="com.android.cts.deviceandprofileowner">
 
     <uses-sdk android:minSdkVersion="23"/>
+    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -50,6 +53,15 @@
             </intent-filter>
         </activity>
 
+        <service android:name=".MockAccountService" android:exported="true">
+            <intent-filter>
+                <action android:name="android.accounts.AccountAuthenticator" />
+            </intent-filter>
+
+            <meta-data android:name="android.accounts.AccountAuthenticator"
+                       android:resource="@xml/authenticator" />
+        </service>
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/values/strings.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/values/strings.xml
new file mode 100644
index 0000000..4aca824
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/values/strings.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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Label for this package -->
+    <string name="authenticator_label">Android CTS - Device and Profile Owner</string>
+</resources>
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/xml/authenticator.xml b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/xml/authenticator.xml
new file mode 100644
index 0000000..0d8ecd8
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/res/xml/authenticator.xml
@@ -0,0 +1,22 @@
+<!-- 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.
+-->
+
+<!-- The attributes in this XML file provide configuration information -->
+<!-- for the Account Manager. -->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="com.android.cts.deviceandprofileowner.account.type"
+    android:label="@string/authenticator_label"
+/>
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
new file mode 100644
index 0000000..c40539b8
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementTest.java
@@ -0,0 +1,179 @@
+/*
+ * 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.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Bundle;
+
+import java.io.IOException;
+
+/**
+ * Functionality tests for {@link DevicePolicyManager#setAccountManagementDisabled}
+ *
+ * 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}
+ */
+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_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);
+
+    private AccountManager mAccountManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
+        clearAllAccountManagementDisabled();
+        removeAllAccounts();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        clearAllAccountManagementDisabled();
+        removeAllAccounts();
+        super.tearDown();
+    }
+
+    public void testAccountManagementDisabled_setterAndGetter() {
+        // Some local tests: adding and removing disabled accounts and make sure
+        // DevicePolicyManager keeps track of the disabled set correctly
+        assertEquals(0, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                true);
+        assertEquals(1, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+        assertEquals(ACCOUNT_TYPE_1,
+                mDevicePolicyManager.getAccountTypesWithManagementDisabled()[0]);
+
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                false);
+        assertEquals(0, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+    }
+
+    public void testAccountManagementDisabled_addAccount() throws AuthenticatorException,
+            IOException, OperationCanceledException {
+        // Test for restriction on addAccount()
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                true);
+        // Test if disabling ACCOUNT_TYPE_2 affects ACCOUNT_TYPE_1
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_2,
+                false);
+        assertEquals(1, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+
+        assertEquals(0, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+        // Management is disabled, adding account should fail.
+        try {
+            mAccountManager.addAccount(ACCOUNT_TYPE_1, null, null, null, null, null, null)
+                    .getResult();
+            fail("Expected OperationCanceledException is not thrown.");
+        } catch (OperationCanceledException e) {
+            // Expected
+        }
+        assertEquals(0, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+
+        // Management is re-enabled, adding account should succeed.
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                false);
+        assertEquals(0, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+        Bundle result = mAccountManager.addAccount(ACCOUNT_TYPE_1,
+                null, null, null, null, null, null).getResult();
+
+        // Normally the expected result of addAccount() is AccountManager returning
+        // an intent to start the authenticator activity for adding new accounts.
+        // But MockAccountAuthenticator returns a new account straightway.
+        assertEquals(ACCOUNT_TYPE_1, result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+    }
+
+    public void testAccountManagementDisabled_removeAccount() throws AuthenticatorException,
+            IOException, OperationCanceledException {
+        // Test for restriction on removeAccount()
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                true);
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_2,
+                false);
+        assertEquals(1, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+
+        assertEquals(0, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+        // First prepare some accounts by manually adding them,
+        // setAccountManagementDisabled(true) should not stop addAccountExplicitly().
+        assertTrue(mAccountManager.addAccountExplicitly(ACCOUNT_0, "password", null));
+        assertTrue(mAccountManager.addAccountExplicitly(ACCOUNT_1, "password", null));
+        assertEquals(2, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+
+        // Removing account should fail, as we just disabled it.
+        try {
+            mAccountManager.removeAccount(ACCOUNT_0, null, null).getResult();
+            fail("Expected OperationCanceledException is not thrown.");
+        } catch (OperationCanceledException e) {
+            // Expected
+        }
+        assertEquals(2, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+
+        // Re-enable management, so we can successfully remove account this time.
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_1,
+                false);
+        assertEquals(0, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+        assertTrue(mAccountManager.removeAccount(ACCOUNT_0, null, null).getResult());
+
+        // Make sure the removal actually succeeds.
+        Account[] accounts = mAccountManager.getAccountsByType(ACCOUNT_TYPE_1);
+        assertEquals(1, accounts.length);
+        assertEquals(ACCOUNT_1, accounts[0]);
+
+        // Disable account type 2, we should still be able to remove from type 1.
+        mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, ACCOUNT_TYPE_2,
+                true);
+        assertEquals(1, mDevicePolicyManager.getAccountTypesWithManagementDisabled().length);
+        assertTrue(mAccountManager.removeAccount(ACCOUNT_1, null, null).getResult());
+
+        // Make sure the removal actually succeeds.
+        assertEquals(0, mAccountManager.getAccountsByType(ACCOUNT_TYPE_1).length);
+    }
+
+    private void clearAllAccountManagementDisabled() {
+        for (String accountType : mDevicePolicyManager.getAccountTypesWithManagementDisabled()) {
+            mDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT, accountType,
+                    false);
+        }
+        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/MockAccountAuthenticator.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java
new file mode 100644
index 0000000..161410f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountAuthenticator.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.os.Bundle;
+
+/* 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";
+    private static final String AUTH_TOKEN = "mockAuthToken";
+    private static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
+
+    private MockAccountAuthenticator(Context context) {
+        super(context);
+    }
+
+    private Bundle createResultBundle() {
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, ACCOUNT_NAME);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+        result.putString(AccountManager.KEY_AUTHTOKEN, AUTH_TOKEN);
+
+        return result;
+    }
+
+    @Override
+    public Bundle addAccount(AccountAuthenticatorResponse response, String accountType,
+            String authTokenType, String[] requiredFeatures, Bundle options)
+            throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account,
+            String authTokenType, Bundle options) throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account,
+            Bundle options) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        return result;
+    }
+
+    @Override
+    public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account,
+            String authTokenType, Bundle options) throws NetworkErrorException {
+        return createResultBundle();
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        return AUTH_TOKEN_LABEL;
+    }
+
+    @Override
+    public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account,
+            String[] features) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        return result;
+    }
+
+    public static synchronized MockAccountAuthenticator getMockAuthenticator(Context context) {
+        if (null == sMockAuthenticator) {
+            sMockAuthenticator = new MockAccountAuthenticator(context);
+        }
+        return sMockAuthenticator;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountService.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountService.java
new file mode 100644
index 0000000..dfedccb
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/MockAccountService.java
@@ -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.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a basic Mock Service for wrapping the MockAccountAuthenticator
+ */
+public class MockAccountService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return MockAccountAuthenticator.getMockAuthenticator(this).getIBinder();
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
new file mode 100644
index 0000000..c74211d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class NfcTest extends AndroidTestCase {
+    private static final String SAMPLE_TEXT = "This is my text to send.";
+    private static final String TEXT_MIME_TYPE = "text/plain";
+    private static final String NFC_BEAM_ACTIVITY = "com.android.nfc.BeamShareActivity";
+
+    public void testNfcShareDisabled() throws Exception {
+        Intent intent = getTextShareIntent();
+        assertFalse("Nfc beam activity should not be resolved", isNfcBeamActivityResolved(intent));
+    }
+
+    public void testNfcShareEnabled() throws Exception {
+        Intent intent = getTextShareIntent();
+        assertTrue("Nfc beam activity should be resolved", isNfcBeamActivityResolved(intent));
+    }
+
+    private Intent getTextShareIntent() {
+        Intent intent = new Intent();
+        intent.setAction(Intent.ACTION_SEND);
+        intent.putExtra(Intent.EXTRA_TEXT, SAMPLE_TEXT);
+        intent.setType(TEXT_MIME_TYPE);
+        return intent;
+    }
+
+    private boolean isNfcBeamActivityResolved(Intent intent) {
+        PackageManager pm = mContext.getPackageManager();
+        for (ResolveInfo resolveInfo : pm.queryIntentActivities(intent, 0)) {
+            if (NFC_BEAM_ACTIVITY.equals(resolveInfo.activityInfo.name)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
+
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index adf81a3..e6351c5 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -37,6 +37,24 @@
 
     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);
+        }
+
+        super.tearDown();
+    }
 
     public void testOwnerChangedBroadcast() throws Exception {
         if (!mHasFeature) {
@@ -44,7 +62,6 @@
         }
         try {
             installApp(INTENT_RECEIVER_APK);
-            installApp(DEVICE_OWNER_APK);
 
             String testClass = INTENT_RECEIVER_PKG + ".OwnerChangedBroadcastTest";
 
@@ -54,15 +71,27 @@
                     "testOwnerChangedBroadcastNotReceived", 0));
 
             // Setting the device owner should send the owner changed broadcast.
-            setDeviceOwner(DEVICE_OWNER_PKG + "/" + ADMIN_RECEIVER_TEST_CLASS);
+            assertTrue(setDeviceOwner(ADMIN_RECEIVER_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));
-            getDevice().uninstallPackage(DEVICE_OWNER_PKG);
-            getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
+        }
+    }
+
+    public void testCannotSetDeviceOwnerWhenSecondaryUserPresent() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        int userId = -1;
+        try {
+            userId = createUser();
+            assertFalse(setDeviceOwner(ADMIN_RECEIVER_COMPONENT));
+        } finally {
+            removeUser(userId);
         }
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index 45f3618..36dab2c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -16,12 +16,6 @@
 
 package com.android.cts.devicepolicy;
 
-import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import junit.framework.AssertionFailedError;
-
 /**
  * Set of tests for usecases that apply to profile and device owner.
  * This class is the base class of MixedProfileOwnerTest and MixedDeviceOwnerTest and is abstract
@@ -46,6 +40,7 @@
     // is the user id of the created profile.
     protected int mUserId;
 
+    @Override
     protected void tearDown() throws Exception {
         if (mHasFeature) {
             getDevice().uninstallPackage(DEVICE_ADMIN_PKG);
@@ -164,6 +159,15 @@
         executeDeviceTestClass(".ApplicationHiddenTest");
     }
 
+    // TODO: Remove AccountManagementTest from XTS after GTS is released for MNC.
+    public void testAccountManagement() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        executeDeviceTestClass(".AccountManagementTest");
+    }
+
     protected void executeDeviceTestClass(String className) throws Exception {
         assertTrue(runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId));
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index a1ae9b9..54b535a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -62,6 +62,8 @@
     private int mUserId;
     private String mPackageVerifier;
 
+    private boolean mHasNfcFeature;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -69,6 +71,7 @@
         // We need multi user to be supported in order to create a profile of the user owner.
         mHasFeature = mHasFeature && hasDeviceFeature(
                 "android.software.managed_users");
+        mHasNfcFeature = hasDeviceFeature("android.hardware.nfc");
 
         if (mHasFeature) {
             removeTestUsers();
@@ -563,6 +566,30 @@
         }
     }
 
+    public void testNfcRestriction() throws Exception {
+        if (!mHasFeature || !mHasNfcFeature) {
+            return;
+        }
+
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", mUserId));
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", 0));
+
+        String restriction = "no_outgoing_beam";  // UserManager.DISALLOW_OUTGOING_BEAM
+        String command = "add-restriction";
+
+        String addRestrictionCommandOutput =
+                changeUserRestrictionForUser(restriction, command, mUserId);
+        assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
+                addRestrictionCommandOutput.contains("Status: ok"));
+
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareDisabled", mUserId));
+        assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+                "testNfcShareEnabled", 0));
+    }
+
     private void disableActivityForUser(String activityName, int userId)
             throws DeviceNotAvailableException {
         String command = "am start -W --user " + userId
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index c04a2cf..c595e10 100644
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -459,12 +459,13 @@
         return avgs;
     }
 
-    public static void logResults(ReportLog log, String prefix,
+    public static String logResults(ReportLog log, String prefix,
             double min, double max, double avg, double stdev) {
         String msg = prefix;
         msg += " min=" + Math.round(min / 1000) + " max=" + Math.round(max / 1000) +
                 " avg=" + Math.round(avg / 1000) + " stdev=" + Math.round(stdev / 1000);
         log.printValue(msg, 1000000000 / min, ResultType.HIGHER_BETTER, ResultUnit.FPS);
+        return msg;
     }
 
     public static VideoCapabilities getVideoCapabilities(String codecName, String mime) {
@@ -512,4 +513,17 @@
         return (measured >= lowerBoundary1 && measured <= upperBoundary1 &&
                 measured >= lowerBoundary2 && measured <= upperBoundary2);
     }
+
+    public static String getErrorMessage(
+            Range<Double> reportedRange, double[] measuredFps, String[] rawData) {
+        String msg = "";
+        if (reportedRange == null) {
+            msg += "Failed to get achievable frame rate.\n";
+        } else {
+            msg += "Expected achievable frame rate range: " + reportedRange + ".\n";
+        }
+        msg += "Measured frame rate: " + Arrays.toString(measuredFps) + ".\n";
+        msg += "Raw data: " + Arrays.toString(rawData) + ".\n";
+        return msg;
+    }
 }
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
index 8fc5a44..62f37c5 100644
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
+++ b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
@@ -516,6 +516,8 @@
 
         boolean encTestPassed = false;
         boolean decTestPassed = false;
+        double[] measuredFps = new double[mTestConfig.mNumberOfRepeat];
+        String[] resultRawData = new String[mTestConfig.mNumberOfRepeat];
         for (int i = 0; i < mTestConfig.mNumberOfRepeat; i++) {
             // make sure that rms error is not too big.
             if (decoderRmsErrorResults[i] >= mRmsErrorMargain) {
@@ -542,8 +544,11 @@
                 String prefix = "codec=" + encoderName + " round=" + i +
                         " EncInputFormat=" + mEncInputFormat +
                         " EncOutputFormat=" + mEncOutputFormat;
-                MediaUtils.logResults(mReportLog, prefix, encMin, encMax, encAvg, encStdev);
+                String result =
+                        MediaUtils.logResults(mReportLog, prefix, encMin, encMax, encAvg, encStdev);
                 double measuredEncFps = 1000000000 / encMin;
+                resultRawData[i] = result;
+                measuredFps[i] = measuredEncFps;
                 if (!encTestPassed) {
                     encTestPassed = MediaUtils.verifyResults(
                             encoderName, mimeType, w, h, measuredEncFps);
@@ -565,10 +570,14 @@
                 }
             }
         }
+
         if (mTestConfig.mTestResult) {
             if (!encTestPassed) {
-                fail("Measured fps for " + encoderName +
-                        " doesn't match with reported achievable frame rates.");
+                Range<Double> reportedRange =
+                    MediaUtils.getAchievableFrameRatesFor(encoderName, mimeType, w, h);
+                String failMessage =
+                    MediaUtils.getErrorMessage(reportedRange, measuredFps, resultRawData);
+                fail(failMessage);
             }
             // Decoder result will be verified in VideoDecoderPerfTest
             // if (!decTestPassed) {
@@ -576,6 +585,8 @@
             //             " doesn't match with reported achievable frame rates.");
             // }
         }
+        measuredFps = null;
+        resultRawData = null;
     }
 
     /**
diff --git a/tests/deviceadmin/res/xml/device_admin.xml b/tests/deviceadmin/res/xml/device_admin.xml
index 263fda6..f7d394e 100644
--- a/tests/deviceadmin/res/xml/device_admin.xml
+++ b/tests/deviceadmin/res/xml/device_admin.xml
@@ -22,6 +22,7 @@
         <force-lock />
         <wipe-data />
         <expire-password />
+        <disable-keyguard-features />
     </uses-policies>
 </device-admin>
 
diff --git a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 04e2ba3..66e12c0 100644
--- a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -526,6 +526,23 @@
         }
     }
 
+    public void testKeyguardDisabledFeatures() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testKeyguardDisabledFeatures");
+            return;
+        }
+        int originalValue = mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent);
+        try {
+            for (int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+                    which < 2 * DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; ++which) {
+                mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, which);
+                assertEquals(which, mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent));
+            }
+        } finally {
+            mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, originalValue);
+        }
+    }
+
     public void testCreateUser_failIfNotDeviceOwner() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testCreateUser_failIfNotDeviceOwner");
diff --git a/tests/tests/assist/AndroidManifest.xml b/tests/tests/assist/AndroidManifest.xml
index c5772ad..b6cd684 100644
--- a/tests/tests/assist/AndroidManifest.xml
+++ b/tests/tests/assist/AndroidManifest.xml
@@ -28,6 +28,7 @@
           <intent-filter>
               <action android:name="android.intent.action.TEST_START_ACTIVITY_ASSIST_STRUCTURE" />
               <action android:name="android.intent.action.TEST_START_ACTIVITY_DISABLE_CONTEXT" />
+              <action android:name="android.intent.action.TEST_START_ACTIVITY_FLAG_SECURE" />
               <category android:name="android.intent.category.LAUNCHER" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
diff --git a/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
similarity index 61%
rename from tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
rename to tests/tests/assist/common/src/android/assist/common/Utils.java
index b9fb7cf..bf051c0 100644
--- a/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -15,23 +15,13 @@
  */
 package android.assist.common;
 
-import android.app.VoiceInteractor;
-import android.app.VoiceInteractor.PickOptionRequest.Option;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
+import android.R;
+import android.content.ComponentName;
 import android.os.Bundle;
-import android.util.Log;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.concurrent.CountDownLatch;
 
 public class Utils {
-    public enum TestCaseType {
-        ASSIST_STRUCTURE,
-        DISABLE_CONTEXT,
-    }
     public static final String TESTCASE_TYPE = "testcase_type";
     public static final String TESTINFO = "testinfo";
     public static final String BROADCAST_INTENT = "android.intent.action.ASSIST_TESTAPP";
@@ -40,17 +30,46 @@
 
     public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
     public static final String ASSIST_CONTENT_KEY = "assist_content";
-    public static final String ASSIST_BUNDLE = "assist_bundle";
+    public static final String ASSIST_BUNDLE_KEY = "assist_bundle";
+    public static final String ASSIST_SCREENSHOT_KEY = "assist_screenshot";
 
     public static final int TIMEOUT_MS = 2 * 1000; // TODO(awlee): what is the timeout
 
+    /** Test name suffixes */
+    public static final String ASSIST_STRUCTURE = "ASSIST_STRUCTURE";
+    public static final String DISABLE_CONTEXT = "DISABLE_CONTEXT";
+    public static final String FLAG_SECURE = "FLAG_SECURE";
+
+    /**
+     * The shim activity that starts the service associated with each test.
+     */
     public static final String getTestActivity(String testCaseType) {
-        if (testCaseType.equals("ASSIST_STRUCTURE")) {
-            return "service.AssistStructureActivity";
-        } else if (testCaseType.equals("DISABLE_CONTEXT")) {
-            return "service.DisableContextActivity";
+        switch (testCaseType) {
+            case ASSIST_STRUCTURE:
+            case FLAG_SECURE:
+                return "service.AssistStructureActivity";
+            case DISABLE_CONTEXT:
+                return "service.DisableContextActivity";
+            default:
+                return "";
         }
-        return "";
+    }
+
+    /**
+     * The test app associated with each test.
+     */
+    public static final ComponentName getTestAppComponent(String testCaseType) {
+        switch (testCaseType) {
+            case ASSIST_STRUCTURE:
+            case DISABLE_CONTEXT:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.TestApp");
+            case FLAG_SECURE:
+                return new ComponentName(
+                        "android.assist.testapp", "android.assist.testapp.SecureActivity");
+            default:
+                return new ComponentName("","");
+        }
     }
 
     public static final String toBundleString(Bundle bundle) {
@@ -71,19 +90,6 @@
         return buf.toString();
     }
 
-    public static final String toOptionsString(Option[] options) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("{");
-        for (int i = 0; i < options.length; i++) {
-            if (i >= 1) {
-                sb.append(", ");
-            }
-            sb.append(options[i].getLabel());
-        }
-        sb.append("}");
-        return sb.toString();
-    }
-
     public static final void addErrorResult(final Bundle testinfo, final String msg) {
         testinfo.getStringArrayList(testinfo.getString(Utils.TESTCASE_TYPE))
             .add(TEST_ERROR + " " + msg);
diff --git a/tests/tests/assist/service/AndroidManifest.xml b/tests/tests/assist/service/AndroidManifest.xml
index 543568d..2c5206a 100644
--- a/tests/tests/assist/service/AndroidManifest.xml
+++ b/tests/tests/assist/service/AndroidManifest.xml
@@ -34,6 +34,7 @@
       <activity android:name=".AssistStructureActivity" >
           <intent-filter>
               <action android:name="android.intent.action.START_TEST_ASSIST_STRUCTURE" />
+              <action android:name="android.intent.action.START_TEST_FLAG_SECURE" />
               <category android:name="android.intent.category.DEFAULT" />
           </intent-filter>
       </activity>
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
index 8b63b25..784d63b 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
@@ -35,8 +35,8 @@
         super.onStart();
         Intent intent = new Intent();
         intent.setComponent(new ComponentName(this, MainInteractionService.class));
-        ComponentName serviceName = startService(intent);
-        Log.i(TAG, "Started service: " + serviceName);
-        getLayoutInflater().inflate(R.layout.voice_interaction_main, null);
+        Log.i(TAG, "Starting service.");
+        finish();
+        startService(intent);
     }
 }
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java
index 0db7ec1..52ba7ac 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/DisableContextActivity.java
@@ -38,6 +38,7 @@
         super.onStart();
         Intent intent = new Intent();
         intent.setComponent(new ComponentName(this, MainInteractionService.class));
+        finish();
         ComponentName serviceName = startService(intent);
         Log.i(TAG, "Started service: " + serviceName);
     }
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
index 56017ce..85bd6ea 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -17,7 +17,6 @@
 package android.assist.service;
 
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionService;
@@ -48,14 +47,9 @@
             Log.wtf(TAG, "Can't start session because either intent is null or onReady() "
                     + "has not been called yet. mIntent = " + mIntent + ", mReady = " + mReady);
         } else {
-            Log.i(TAG, "Yay! about to start session with TestApp");
+            Log.i(TAG, "Yay! about to start session");
             if (isActiveService(this, new ComponentName(this, getClass()))) {
-                Bundle args = new Bundle();
-                Intent intent = new Intent();
-                intent.setComponent(new ComponentName("android.assist.testapp",
-                        "android.assist.testapp.TestApp"));
-                args.putParcelable("intent", intent);
-                showSession(args, VoiceInteractionSession.SHOW_WITH_ASSIST |
+                showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
                         VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
             } else {
                 Log.wtf(TAG, "**** Not starting MainInteractionService because" +
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
index d19c6f8..9a835c2 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -16,26 +16,19 @@
 
 package android.assist.service;
 
-import android.app.VoiceInteractor;
-import android.app.VoiceInteractor.Prompt;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.service.voice.VoiceInteractionSession;
-import android.service.voice.VoiceInteractionSession.ConfirmationRequest;
-import android.service.voice.VoiceInteractionSession.PickOptionRequest;
 import android.util.Log;
 
-import java.util.ArrayList;
-import java.util.List;
+import java.io.ByteArrayOutputStream;
 
 import android.assist.common.Utils;
-import android.webkit.URLUtil;
 
 public class MainInteractionSession extends VoiceInteractionSession {
     static final String TAG = "MainInteractionSession";
@@ -44,6 +37,9 @@
     Context mContext;
     Bundle mAssistData = new Bundle();
 
+    private boolean hasReceivedAssistData = false;
+    private boolean hasReceivedScreenshot = false;
+
     MainInteractionSession(Context context) {
         super(context);
         mContext = context;
@@ -64,8 +60,6 @@
     public void onShow(Bundle args, int showFlags) {
         // set some content view.
         // TODO: check that the view takes up the whole screen.
-        mStartIntent = args.getParcelable("intent");
-        startVoiceActivity(mStartIntent); // remove
         // check that interactor mode is for assist
         if ((showFlags & SHOW_WITH_ASSIST) == 0) {
             return;
@@ -73,32 +67,52 @@
         super.onShow(args, showFlags);
     }
 
-
     @Override
     public void onHandleAssist(/*@Nullable */Bundle data, /*@Nullable*/ AssistStructure structure,
         /*@Nullable*/ AssistContent content) {
         Log.i(TAG, "onHandleAssist");
-        Log.i(TAG, String.format("Bundle: %s, Structure: %s, Content: %s", data, structure, content));
+        Log.i(TAG,
+            String.format("Bundle: %s, Structure: %s, Content: %s", data, structure, content));
         super.onHandleAssist(data, structure, content);
 
         // send to test to verify that this is accurate.
         mAssistData.putParcelable(Utils.ASSIST_STRUCTURE_KEY, structure);
         mAssistData.putParcelable(Utils.ASSIST_CONTENT_KEY, content);
-        mAssistData.putBundle(Utils.ASSIST_BUNDLE, data);
-        broadcastResults();
+        mAssistData.putBundle(Utils.ASSIST_BUNDLE_KEY, data);
+        hasReceivedAssistData = true;
+        maybeBroadcastResults();
     }
 
     @Override
     public void onHandleScreenshot(/*@Nullable*/ Bitmap screenshot) {
+        Log.i(TAG, String.format("onHandleScreenshot - Screenshot: %s", screenshot));
         super.onHandleScreenshot(screenshot);
-        // add this to mAssistData?
+        ByteArrayOutputStream bs = new ByteArrayOutputStream();
+        if (screenshot != null) {
+            screenshot.compress(Bitmap.CompressFormat.PNG, 50, bs);
+            mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, bs.toByteArray());
+        } else {
+            mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, null);
+        }
+        hasReceivedScreenshot = true;
+        maybeBroadcastResults();
     }
 
-    private void broadcastResults() {
-        Intent intent = new Intent(Utils.BROADCAST_ASSIST_DATA_INTENT);
-        intent.putExtras(mAssistData);
-        Log.i(TAG, "broadcasting: " + intent.toString() + ", Bundle = " + mAssistData.toString());
-        mContext.sendBroadcast(intent);
+    private void maybeBroadcastResults() {
+        if (!hasReceivedAssistData) {
+            Log.i(TAG, "waiting for assist data before broadcasting results");
+        } else if (!hasReceivedScreenshot) {
+            Log.i(TAG, "waiting for screenshot before broadcasting results");
+        } else {
+            Intent intent = new Intent(Utils.BROADCAST_ASSIST_DATA_INTENT);
+            intent.putExtras(mAssistData);
+            Log.i(TAG,
+                    "broadcasting: " + intent.toString() + ", Bundle = " + mAssistData.toString());
+            mContext.sendBroadcast(intent);
+
+            hasReceivedAssistData = false;
+            hasReceivedScreenshot = false;
+        }
     }
 
     class DoneReceiver extends BroadcastReceiver {
diff --git a/tests/tests/assist/src/android/assist/TestStartActivity.java b/tests/tests/assist/src/android/assist/TestStartActivity.java
index 06bf5aa..df9b534 100644
--- a/tests/tests/assist/src/android/assist/TestStartActivity.java
+++ b/tests/tests/assist/src/android/assist/TestStartActivity.java
@@ -21,12 +21,9 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.content.ComponentName;
-import android.content.Context;
 import android.os.Bundle;
 import android.util.Log;
 
-import android.assist.common.Utils;
-
 public class TestStartActivity extends Activity {
     static final String TAG = "TestStartActivity";
 
@@ -42,13 +39,20 @@
         Log.i(TAG, " in onResume");
     }
 
-    public void startTest(String testCaseType) {
-        Log.i(TAG, "Starting test activity for TestCaseType = " + testCaseType);
+    public void startTest(String testCaseName) {
+        Log.i(TAG, "Starting test activity for TestCaseType = " + testCaseName);
         Intent intent = new Intent();
-        intent.putExtra(Utils.TESTCASE_TYPE, testCaseType);
-        intent.setAction("android.intent.action.START_TEST_" + testCaseType);
+        intent.putExtra(Utils.TESTCASE_TYPE, testCaseName);
+        intent.setAction("android.intent.action.START_TEST_" + testCaseName);
         intent.setComponent(new ComponentName("android.assist.service",
-                "android.assist." + Utils.getTestActivity(testCaseType)));
+                "android.assist." + Utils.getTestActivity(testCaseName)));
+        startActivity(intent);
+    }
+
+    public void start3pApp(String testCaseName) {
+        Intent intent = new Intent();
+        intent.setAction("android.intent.action.TEST_APP_" + testCaseName);
+        intent.setComponent(Utils.getTestAppComponent(testCaseName));
         startActivity(intent);
     }
 
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index 3c93c8a..97ab290 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -16,24 +16,10 @@
 
 package android.assist.cts;
 
-import android.assist.TestStartActivity;
 import android.assist.common.Utils;
 
-import android.app.assist.AssistContent;
-import android.app.assist.AssistStructure;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
+import android.provider.Settings;
 
-import java.lang.Exception;
-import java.lang.Override;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
 
 /**
  *  Test that the AssistStructure returned is properly formatted.
@@ -42,7 +28,7 @@
 public class AssistStructureTest extends AssistTestBase {
     static final String TAG = "AssistStructureTest";
 
-    private static final String TEST_CASE_TYPE = "ASSIST_STRUCTURE";
+    private static final String TEST_CASE_TYPE = Utils.ASSIST_STRUCTURE;
 
     public AssistStructureTest() {
         super();
@@ -52,38 +38,15 @@
     protected void setUp() throws Exception {
         super.setUp();
         startTestActivity(TEST_CASE_TYPE);
-        waitForBroadcast(Utils.TestCaseType.ASSIST_STRUCTURE);
+        waitForBroadcast();
     }
 
     public void testAssistStructure() throws Exception {
-        // verify assist data contains what we want.
-        // go through all things in the bundle, verify not null, verify contains what we want.
+        assertEquals("1", Settings.Secure.getString(
+            mContext.getContentResolver(), "assist_structure_enabled"));
 
-        // TODO(awlee): verify that the context is not off by default.
-        if (mAssistContent == null || mAssistBundle == null) {
-            fail("Received null assistBundle or assistContent.");
-            return;
-        }
-
-        if (mAssistStructure == null) {
-            fail("Received null assistStructure");
-            return;
-        } else {
-            verifyAssistStructure(new ComponentName("android.assist.service",
-                    "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
-        }
-    }
-
-    private void verifyAssistStructure(ComponentName backgroundApp,
-            boolean isSecureWindow) {
-        // Check component name matches
-        assertEquals(backgroundApp.flattenToString(),
-                mAssistStructure.getActivityComponent().flattenToString());
-
-        int numWindows = mAssistStructure.getWindowNodeCount();
-        assertEquals(1, numWindows);
-        for (int i = 0; i < numWindows; i++) {
-            AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
-        }
+        verifyAssistDataNullness(false, false, false, false);
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+                    false /*FLAG_SECURE set*/);
     }
 }
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index a4f4cbc..e6d08cf 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -19,7 +19,6 @@
 import android.assist.TestStartActivity;
 import android.assist.common.Utils;
 
-import android.app.Activity;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.content.BroadcastReceiver;
@@ -27,11 +26,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.os.Bundle;
+import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
-import java.lang.Override;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -41,11 +43,11 @@
     protected TestStartActivity mTestActivity;
     protected AssistContent mAssistContent;
     protected AssistStructure mAssistStructure;
+    protected Bitmap mScreenshot;
     protected BroadcastReceiver mReceiver;
     protected Bundle mAssistBundle;
     protected Context mContext;
     protected CountDownLatch mLatch;
-    protected Utils.TestCaseType mTestCaseType;
     private String mTestName;
 
     public AssistTestBase() {
@@ -56,6 +58,11 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getTargetContext();
+        assertEquals("1", Settings.Secure.getString(
+            mContext.getContentResolver(), "assist_structure_enabled"));
+        assertEquals("1", Settings.Secure.getString(
+            mContext.getContentResolver(), "assist_screenshot_enabled"));
+        logContextAndScreenshotSetting();
     }
 
     @Override
@@ -70,7 +77,7 @@
         mTestName = testName;
         intent.setAction("android.intent.action.TEST_START_ACTIVITY_" + testName);
         intent.setComponent(new ComponentName(getInstrumentation().getContext(),
-                TestStartActivity.class));
+            TestStartActivity.class));
         setActivityIntent(intent);
         mTestActivity = getActivity();
     }
@@ -78,16 +85,16 @@
     /**
      * Called after startTestActivity
      */
-    protected boolean waitForBroadcast(Utils.TestCaseType testCaseType) throws Exception {
-        mTestCaseType = testCaseType;
+    protected boolean waitForBroadcast() throws Exception {
         mLatch = new CountDownLatch(1);
         if (mReceiver != null) {
             mContext.unregisterReceiver(mReceiver);
         }
         mReceiver = new TestResultsReceiver();
         mContext.registerReceiver(mReceiver,
-                new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
+            new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
 
+        mTestActivity.start3pApp(mTestName);
         mTestActivity.startTest(mTestName);
         if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
@@ -96,18 +103,84 @@
         return true;
     }
 
+    /**
+     * Checks that the nullness of values are what we expect.
+     * @param isBundleNull True if assistBundle should be null.
+     * @param isStructureNull True if assistStructure should be null.
+     * @param isContentNull True if assistContent should be null.
+     * @param isScreenshotNull True if screenshot should be null.
+     */
+    protected void verifyAssistDataNullness(boolean isBundleNull, boolean isStructureNull,
+            boolean isContentNull, boolean isScreenshotNull) {
+
+        if ((mAssistContent == null) != isContentNull) {
+            fail(String.format("Should %s have been null - AssistContent: %s",
+                    isContentNull? "":"not", mAssistContent));
+        }
+
+        if ((mAssistStructure == null) != isStructureNull) {
+            fail(String.format("Should %s have been null - AssistStructure: %s",
+                isStructureNull ? "" : "not", mAssistStructure));
+        }
+
+        if ((mAssistBundle == null) != isBundleNull) {
+            fail(String.format("Should %s have been null - AssistBundle: %s",
+                    isBundleNull? "":"not", mAssistBundle));
+        }
+
+        if ((mScreenshot == null) != isScreenshotNull) {
+            fail(String.format("Should %s have been null - Screenshot: %s",
+                    isScreenshotNull? "":"not", mScreenshot));
+        }
+    }
+
+    /**
+     * Traverses and compares the view heirarchy of the backgroundApp and the view we expect.
+     *
+     * @param backgroundApp ComponentName of app the assistant is invoked upon
+     * @param isSecureWindow Denotes whether the activity has FLAG_SECURE set
+     */
+    protected void verifyAssistStructure(ComponentName backgroundApp, boolean isSecureWindow) {
+        // Check component name matches
+        assertEquals(backgroundApp.flattenToString(),
+            mAssistStructure.getActivityComponent().flattenToString());
+
+        int numWindows = mAssistStructure.getWindowNodeCount();
+        assertEquals(1, numWindows);
+        for (int i = 0; i < numWindows; i++) {
+            AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+            // TODO: Actually traverse the view heirarchy and verify it matches what we expect
+            // If isSecureWindow, will not have any children.
+        }
+    }
+
+    protected void logContextAndScreenshotSetting() {
+        Log.i(TAG, "Context is: " + Settings.Secure.getString(
+            mContext.getContentResolver(), "assist_structure_enabled"));
+        Log.i(TAG, "Screenshot is: " + Settings.Secure.getString(
+            mContext.getContentResolver(), "assist_screenshot_enabled"));
+    }
+
     class TestResultsReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (intent.getAction().equalsIgnoreCase(Utils.BROADCAST_ASSIST_DATA_INTENT)) { // not necessary?
-                Log.i(TAG, "received broadcast with results ");
+                Log.i(TAG, "Received broadcast with assist data.");
                 Bundle assistData = intent.getExtras();
+                AssistTestBase.this.mAssistBundle = assistData.getBundle(Utils.ASSIST_BUNDLE_KEY);
                 AssistTestBase.this.mAssistStructure = assistData.getParcelable(
                         Utils.ASSIST_STRUCTURE_KEY);
-                AssistTestBase.this.mAssistBundle = assistData.getBundle(Utils.ASSIST_BUNDLE);
                 AssistTestBase.this.mAssistContent = assistData.getParcelable(
                         Utils.ASSIST_CONTENT_KEY);
 
+                byte[] bitmapArray = assistData.getByteArray(Utils.ASSIST_SCREENSHOT_KEY);
+                if (bitmapArray != null) {
+                    AssistTestBase.this.mScreenshot = BitmapFactory.decodeByteArray(
+                            bitmapArray, 0, bitmapArray.length);
+                } else {
+                    AssistTestBase.this.mScreenshot = null;
+                }
+
                 if (mLatch != null) {
                     mLatch.countDown();
                 }
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index f3da32b..9407ec5 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -27,7 +27,9 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
 import android.os.Bundle;
+import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
 import android.util.Log;
 
@@ -39,7 +41,7 @@
 public class DisableContextTest extends AssistTestBase {
     static final String TAG = "DisableContextTest";
 
-    private static final String TEST_CASE_TYPE = "DISABLE_CONTEXT";
+    private static final String TEST_CASE_TYPE = Utils.DISABLE_CONTEXT;
 
     public DisableContextTest() {
         super();
@@ -48,43 +50,49 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-        // need to set action/component/activityintent for the test activity?
+        SystemUtil.runShellCommand(getInstrumentation(),
+                "settings put secure assist_structure_enabled 0");
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_screenshot_enabled 0");
+        logContextAndScreenshotSetting();
         startTestActivity(TEST_CASE_TYPE);
-        waitForBroadcast(Utils.TestCaseType.DISABLE_CONTEXT);
+        waitForBroadcast();
     }
 
-    public void testContextOnAndOff() throws Exception {
-        // filler
-
-
-        // verify assist data contains what we want.
-        // go through all things in the bundle, verify not null, verify contains what we want.
-
-        // TODO(awlee): verify that the context is not off by default.
-        if (mAssistContent == null || mAssistBundle == null) {
-            fail("Received null assistBundle or assistContent.");
-            return;
-        }
-
-        if (mAssistStructure == null) {
-            fail("Received null assistStructure");
-            return;
-        } else {
-            verifyAssistStructure(new ComponentName("android.assist.service",
-                    "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
-        }
+    @Override
+    public void tearDown() throws Exception {
+        SystemUtil.runShellCommand(getInstrumentation(),
+                "settings put secure assist_structure_enabled 1");
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_screenshot_enabled 1");
+        logContextAndScreenshotSetting();
+        super.tearDown();
     }
 
-    private void verifyAssistStructure(ComponentName backgroundApp,
-            boolean isSecureWindow) {
-        // Check component name matches
-        assertEquals(backgroundApp.flattenToString(),
-                mAssistStructure.getActivityComponent().flattenToString());
+    public void testContextAndScreenshotOff() throws Exception {
+        // Both settings off
+        verifyAssistDataNullness(true, true, true, true);
 
-        int numWindows = mAssistStructure.getWindowNodeCount();
-        assertEquals(1, numWindows);
-        for (int i = 0; i < numWindows; i++) {
-            AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
-        }
+        // Screenshot off, context on
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_structure_enabled 1");
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_screenshot_enabled 0");
+        waitForBroadcast();
+
+        logContextAndScreenshotSetting();
+
+        verifyAssistDataNullness(false, false, false, true);
+
+        // Context off, screenshot on
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_structure_enabled 0");
+        SystemUtil.runShellCommand(getInstrumentation(),
+            "settings put secure assist_screenshot_enabled 1");
+        waitForBroadcast();
+
+        logContextAndScreenshotSetting();
+
+        verifyAssistDataNullness(true, true, true, false);
     }
 }
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
new file mode 100644
index 0000000..0e79d9d
--- /dev/null
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.assist.cts;
+
+import android.assist.common.Utils;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Test we receive proper assist data (root assistStructure with no children) when the assistant is
+ * invoked on an app with FLAG_SECURE set.
+ */
+public class FlagSecureTest extends AssistTestBase {
+
+    static final String TAG = "DisableContextTest";
+
+    private static final String TEST_CASE_TYPE = Utils.FLAG_SECURE;
+
+    public FlagSecureTest() {
+        super();
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        startTestActivity(TEST_CASE_TYPE);
+        waitForBroadcast();
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    public void testSecureActivity() throws Exception {
+        verifyAssistDataNullness(false, false, false, true);
+
+        // verify that we have only the root window and not its children.
+        verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE), true);
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/AndroidManifest.xml b/tests/tests/assist/testapp/AndroidManifest.xml
index 5b16ed7..371ae7b 100644
--- a/tests/tests/assist/testapp/AndroidManifest.xml
+++ b/tests/tests/assist/testapp/AndroidManifest.xml
@@ -19,16 +19,25 @@
     package="android.assist.testapp">
 
     <application>
-      <uses-library android:name="android.test.runner" />
+        <uses-library android:name="android.test.runner" />
 
-      <activity android:name="TestApp"
+        <activity android:name="TestApp"
                 android:label="Assist Test App"
                 android:theme="@android:style/Theme.Material.Light">
           <intent-filter>
-              <action android:name="android.intent.action.TEST_APP" />
+              <action android:name="android.intent.action.TEST_APP_ASSIST_STRUCTURE" />
               <category android:name="android.intent.category.DEFAULT" />
               <category android:name="android.intent.category.VOICE" />
           </intent-filter>
-      </activity>
+        </activity>
+        <activity android:name="SecureActivity"
+                  android:label="Secure Test App"
+                  android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.TEST_APP_FLAG_SECURE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.VOICE" />
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/tests/assist/service/res/layout/voice_interaction_main.xml b/tests/tests/assist/testapp/res/layout/secure_app.xml
similarity index 100%
rename from tests/tests/assist/service/res/layout/voice_interaction_main.xml
rename to tests/tests/assist/testapp/res/layout/secure_app.xml
diff --git a/tests/tests/assist/service/res/layout/voice_interaction_main.xml b/tests/tests/assist/testapp/res/layout/test_app.xml
similarity index 100%
copy from tests/tests/assist/service/res/layout/voice_interaction_main.xml
copy to tests/tests/assist/testapp/res/layout/test_app.xml
diff --git a/tests/tests/assist/service/res/values/strings.xml b/tests/tests/assist/testapp/res/values/strings.xml
similarity index 100%
rename from tests/tests/assist/service/res/values/strings.xml
rename to tests/tests/assist/testapp/res/values/strings.xml
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java
new file mode 100644
index 0000000..83f7549
--- /dev/null
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/SecureActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.assist.testapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+
+import android.view.WindowManager;
+
+public class SecureActivity extends Activity {
+    static final String TAG = "SecureActivity";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "SecureActivity created");
+        setContentView(R.layout.secure_app);
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE,
+            WindowManager.LayoutParams.FLAG_SECURE);
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
index 9083cda..85a9342 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -17,26 +17,24 @@
 package android.assist.testapp;
 
 import android.app.Activity;
-import android.app.VoiceInteractor;
-import android.app.VoiceInteractor.AbortVoiceRequest;
-import android.app.VoiceInteractor.CommandRequest;
-import android.app.VoiceInteractor.CompleteVoiceRequest;
-import android.app.VoiceInteractor.ConfirmationRequest;
-import android.app.VoiceInteractor.PickOptionRequest;
-import android.app.VoiceInteractor.PickOptionRequest.Option;
-import android.app.VoiceInteractor.Prompt;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
-import android.service.voice.VoiceInteractionService;
 import android.util.Log;
 
-import java.util.ArrayList;
-
-import android.assist.common.Utils;
-
 public class TestApp extends Activity {
+    static final String TAG = "TestApp";
 
-}
+    Bundle mTestinfo = new Bundle();
+    Bundle mTotalInfo = new Bundle();
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Log.i(TAG, "TestApp created");
+        getLayoutInflater().inflate(R.layout.test_app, null);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+}
\ No newline at end of file
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 9523d87..9c26d8a 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -34,7 +34,7 @@
     src/android/hardware/cts/SensorIntegrationTests.java \
     src/android/hardware/cts/SensorBatchingTests.java \
     src/android/hardware/cts/SensorTest.java \
-    src/android/hardware/cts/SensorManagerStaticTest.java \
+    src/android/hardware/cts/SensorManagerStaticTest.java
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil
 
@@ -57,4 +57,4 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
new file mode 100644
index 0000000..4750b09
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorParameterRangeTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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 java.util.concurrent.TimeUnit;
+
+/**
+ * Test min-max frequency, max range parameters for sensors.
+ *
+ * <p>To execute these test cases, the following command can be used:</p>
+ * <pre>
+ * adb shell am instrument -e class android.hardware.cts.SensorParameterRangeTest \
+ *     -w com.android.cts.hardware/android.test.AndroidJUnitRunner
+ * </pre>
+ */
+public class SensorParameterRangeTest extends SensorTestCase {
+
+    private static final double ACCELEROMETER_MAX_RANGE = 8 * 9.81; // 8G
+    private static final int ACCELEROMETER_MIN_FREQUENCY = 5;
+    private static final int ACCELEROMETER_MAX_FREQUENCY = 200;
+
+    private static final double GYRO_MAX_RANGE = 1000/57.295; // 1000 degrees per sec.
+    private static final int GYRO_MIN_FREQUENCY = 5;
+    private static final int GYRO_MAX_FREQUENCY = 200;
+
+    private static final int MAGNETOMETER_MAX_RANGE = 900;   // micro telsa
+    private static final int MAGNETOMETER_MIN_FREQUENCY = 5;
+    private static final int MAGNETOMETER_MAX_FREQUENCY = 50;
+
+    private static final int PRESSURE_MAX_RANGE = 1100;     // hecto-pascal
+    private static final int PRESSURE_MIN_FREQUENCY = 1;
+    private static final int PRESSURE_MAX_FREQUENCY = 10;
+
+    private boolean mHasHifiSensors;
+    private SensorManager mSensorManager;
+
+    @Override
+    public void setUp() {
+        mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+        mHasHifiSensors = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_HIFI_SENSORS);
+    }
+
+    public void testAccelerometerRange() {
+        checkSensorRangeAndFrequency(
+                mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+                ACCELEROMETER_MAX_RANGE,
+                ACCELEROMETER_MIN_FREQUENCY,
+                ACCELEROMETER_MAX_FREQUENCY);
+  }
+
+  public void testGyroscopeRange() {
+        checkSensorRangeAndFrequency(
+                mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
+                GYRO_MAX_RANGE,
+                GYRO_MIN_FREQUENCY,
+                GYRO_MAX_FREQUENCY);
+  }
+
+    public void testMagnetometerRange() {
+        checkSensorRangeAndFrequency(
+                mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
+                MAGNETOMETER_MAX_RANGE,
+                MAGNETOMETER_MIN_FREQUENCY,
+                MAGNETOMETER_MAX_FREQUENCY);
+    }
+
+    public void testPressureRange() {
+        checkSensorRangeAndFrequency(
+                mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
+                PRESSURE_MAX_RANGE,
+                PRESSURE_MIN_FREQUENCY,
+                PRESSURE_MAX_FREQUENCY);
+    }
+
+    private void checkSensorRangeAndFrequency(
+          Sensor sensor, double maxRange, int minFrequency, int maxFrequency) {
+        if (!mHasHifiSensors) return;
+        assertTrue(String.format("%s Range actual=%.2f expected=%.2f %s",
+                    sensor.getName(), sensor.getMaximumRange(), maxRange,
+                    SensorCtsHelper.getUnitsForSensor(sensor)),
+                sensor.getMaximumRange() >= maxRange);
+        double actualMinFrequency = SensorCtsHelper.getFrequency(sensor.getMaxDelay(),
+                TimeUnit.MICROSECONDS);
+        assertTrue(String.format("%s Min Frequency actual=%.2f expected=%dHz",
+                    sensor.getName(), actualMinFrequency, minFrequency), actualMinFrequency <=
+                minFrequency);
+
+        double actualMaxFrequency = SensorCtsHelper.getFrequency(sensor.getMinDelay(),
+                TimeUnit.MICROSECONDS);
+        assertTrue(String.format("%s Max Frequency actual=%.2f expected=%dHz",
+                    sensor.getName(), actualMaxFrequency, maxFrequency), actualMaxFrequency >=
+                maxFrequency);
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorSupportTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorSupportTest.java
new file mode 100644
index 0000000..2f25c8d
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorSupportTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.test.AndroidTestCase;
+
+/**
+ * Checks if Hifi sensors are supported. When supported, checks individual support for
+ * Accelerometer, Gyroscope, Gyroscope_uncal, GeoMagneticField, MagneticField_uncal
+ * Pressure, RotationVector, SignificantMotion, StepDetector, StepCounter, TiltDetector.
+ *
+ * <p>To execute these test cases, the following command can be used:</p>
+ * <pre>
+ * adb shell am instrument -e class android.hardware.cts.SensorSupportTest \
+ *     -w com.android.cts.hardware/android.test.AndroidJUnitRunner
+ * </pre>
+ */
+public class SensorSupportTest extends AndroidTestCase {
+    private SensorManager mSensorManager;
+    private boolean mAreHifiSensorsSupported;
+
+    @Override
+    public void setUp() {
+        // Tests will only run if HIFI_SENSORS are supported.
+        mAreHifiSensorsSupported = getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_HIFI_SENSORS);
+        if (mAreHifiSensorsSupported) {
+            mSensorManager =
+                    (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+        }
+    }
+
+    public void testSupportsAccelerometer() {
+        checkSupportsSensor(Sensor.TYPE_ACCELEROMETER);
+    }
+
+    public void testSupportsGyroscope() {
+        checkSupportsSensor(Sensor.TYPE_GYROSCOPE);
+    }
+
+    public void testSupportsGyroscopeUncalibrated() {
+        checkSupportsSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
+    }
+
+    public void testSupportsGeoMagneticField() {
+        checkSupportsSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);
+    }
+
+    public void testSupportsMagneticFieldUncalibrated() {
+        checkSupportsSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
+    }
+
+    public void testSupportsPressure() {
+        checkSupportsSensor(Sensor.TYPE_PRESSURE);
+    }
+
+    public void testSupportsRotationVector() {
+        checkSupportsSensor(Sensor.TYPE_ROTATION_VECTOR);
+    }
+
+    public void testSupportsSignificantMotion() {
+        checkSupportsSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
+    }
+
+    public void testSupportsStepDetector() {
+        checkSupportsSensor(Sensor.TYPE_STEP_DETECTOR);
+    }
+
+    public void testSupportsStepCounter() {
+        checkSupportsSensor(Sensor.TYPE_STEP_COUNTER);
+    }
+
+    public void testSupportsTiltDetector() {
+        final int TYPE_TILT_DETECTOR = 22;
+        checkSupportsSensor(TYPE_TILT_DETECTOR);
+    }
+
+    private void checkSupportsSensor(int sensorType) {
+        if (mAreHifiSensorsSupported) {
+            assertTrue(mSensorManager.getDefaultSensor(sensorType) != null);
+        }
+    }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
index 490e965..55465ac 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCtsHelper.java
@@ -15,6 +15,7 @@
  */
 package android.hardware.cts.helpers;
 
+import android.hardware.Sensor;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -259,4 +260,20 @@
             throw new IllegalStateException("Collection cannot be null or empty");
         }
     }
+
+    public static String getUnitsForSensor(Sensor sensor) {
+        switch(sensor.getType()) {
+            case Sensor.TYPE_ACCELEROMETER:
+                return "m/s^2";
+            case Sensor.TYPE_MAGNETIC_FIELD:
+            case Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+                return "uT";
+            case Sensor.TYPE_GYROSCOPE:
+            case Sensor.TYPE_GYROSCOPE_UNCALIBRATED:
+                return "radians/sec";
+            case Sensor.TYPE_PRESSURE:
+                return "hPa";
+        };
+        return "";
+    }
 }
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
index 6f17e7b..687e63b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
@@ -62,7 +62,7 @@
     public void testVerify_missing_events() {
         // Timestamps in ns, expected in us
         long[] timestamps = {1000000, 2000000, 3000000, 5000000, 6000000};
-        runVerification(1000, timestamps, false, new int[]{3});
+        runVerification(1000, timestamps, true, new int[]{3});
     }
 
     private void runVerification(int expected, long[] timestamps, boolean pass,
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
index 6633903..e5a5053 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerification.java
@@ -18,6 +18,10 @@
 
 import junit.framework.Assert;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import android.util.Log;
 import android.hardware.Sensor;
 import android.hardware.cts.helpers.SensorCtsHelper;
 import android.hardware.cts.helpers.SensorStats;
@@ -39,6 +43,8 @@
 
     // sensorType: threshold (% of expected period)
     private static final SparseIntArray DEFAULTS = new SparseIntArray(12);
+    // Max allowed jitter (in percentage).
+    private static final int THRESHOLD_PERCENT_FOR_HIFI_SENSORS = 1;
     static {
         // Use a method so that the @deprecation warning can be set for that method only
         setDefaults();
@@ -68,6 +74,11 @@
         if (threshold == -1) {
             return null;
         }
+        boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_HIFI_SENSORS);
+        if (hasHifiSensors) {
+           threshold = THRESHOLD_PERCENT_FOR_HIFI_SENSORS;
+        }
         return new JitterVerification(threshold);
     }
 
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
index f7c2c53..20dd2d2 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerification.java
@@ -18,10 +18,13 @@
 
 import junit.framework.Assert;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.hardware.Sensor;
 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.HashMap;
 import java.util.Map;
@@ -66,7 +69,21 @@
         if (!DEFAULTS.containsKey(sensorType)) {
             return null;
         }
+        boolean hasHifiSensors = environment.getContext().getPackageManager().hasSystemFeature(
+                PackageManager.FEATURE_HIFI_SENSORS);
 
+        if (hasHifiSensors) {
+            // Max accelerometer deviation: 400uG/√Hz
+            DEFAULTS.put(Sensor.TYPE_ACCELEROMETER, new float[]{0.004f, 0.004f, 0.004f});
+            // Max gyro deviation: 0.014°/s/√Hz
+            float deviationInRadians = (float) (0.014f * (Math.PI / 180));
+            DEFAULTS.put(Sensor.TYPE_GYROSCOPE,
+                    new float[]{deviationInRadians,deviationInRadians, deviationInRadians});
+            // Max magnetometer deviation: 0.1uT/√Hz
+            DEFAULTS.put(Sensor.TYPE_MAGNETIC_FIELD, new float[]{0.1f, 0.1f, 0.1f});
+            // Max pressure deviation: 2Pa/√Hz
+            DEFAULTS.put(Sensor.TYPE_PRESSURE, new float[]{2.0f, 2.0f, 2.0f});
+        }
         return new StandardDeviationVerification(DEFAULTS.get(sensorType));
     }
 
@@ -107,9 +124,9 @@
             if (stdDevs[i] > mThreshold[i]) {
                 failed = true;
             }
-            stddevSb.append(String.format("%.2f", stdDevs[i]));
+            stddevSb.append(String.format("%.3f", stdDevs[i]));
             if (i != stdDevs.length - 1) stddevSb.append(", ");
-            expectedSb.append(String.format("<%.2f", mThreshold[i]));
+            expectedSb.append(String.format("<%.3f", mThreshold[i]));
             if (i != stdDevs.length - 1) expectedSb.append(", ");
         }
         if (stdDevs.length > 1) {
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index ded0539..a0163e5 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -45,23 +45,27 @@
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.System;
-import android.test.AndroidTestCase;
+import android.test.InstrumentationTestCase;
 import android.view.SoundEffectConstants;
 
 import java.util.TreeMap;
 
-public class AudioManagerTest extends AndroidTestCase {
+public class AudioManagerTest extends InstrumentationTestCase {
 
     private final static int MP3_TO_PLAY = R.raw.testmp3;
     private final static long TIME_TO_PLAY = 2000;
+    private final static String APPOPS_OP_STR = "android:write_settings";
     private AudioManager mAudioManager;
     private boolean mHasVibrator;
     private boolean mUseFixedVolume;
     private boolean mIsTelevision;
+    private Context mContext;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        mContext = getInstrumentation().getContext();
+        Utils.enableAppOps(mContext.getPackageName(), APPOPS_OP_STR, getInstrumentation());
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = (vibrator != null) && vibrator.hasVibrator();
diff --git a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
index f513709..94af087 100644
--- a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
+++ b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
@@ -115,29 +115,31 @@
             // Sample Rates
             int[] sampleRates = deviceInfo.getSampleRates();
             assertNotNull(sampleRates);
-            // "analog" devices won't list any sample rates
+            // Note: an empty array indicates that the device supports arbitrary sample rates.
 
             // Channel Masks
             int[] channelMasks = deviceInfo.getChannelMasks();
             assertNotNull(channelMasks);
-            // "analog" devices won't list any channel masks
+            // Note: an empty array indicates that the device supports arbitrary channel masks.
 
             // Channel Index Masks
             int[] indexMasks = deviceInfo.getChannelIndexMasks();
-            assertNotNull(channelMasks);
+            assertNotNull(indexMasks);
+            // Note: an empty array indicates that the device supports arbitrary channel index
+            // masks.
 
             // Channel Counts
             int[] channelCounts = deviceInfo.getChannelCounts();
             assertNotNull(channelCounts);
-            // "analog" devices won't list any channel Counts
+            // Note: an empty array indicates that the device supports arbitrary channel counts.
 
             // Encodings
             int[] encodings = deviceInfo.getEncodings();
             assertNotNull(encodings);
-            // "analog" devices won't list any encodings
+            // Note: an empty array indicates that the device supports arbitrary encodings.
 
             int type = deviceInfo.getType();
-            assert(type > AudioDeviceInfo.TYPE_UNKNOWN);
+            assertTrue(type != AudioDeviceInfo.TYPE_UNKNOWN);
         }
     }
 
@@ -167,7 +169,7 @@
         }
         return myLooper;
     }
-    
+
     public void test_deviceCallback() {
         // null callback?
         mAudioManager.registerAudioDeviceCallback(null,null);
@@ -187,7 +189,7 @@
         mAudioManager.unregisterAudioDeviceCallback(callback);
 
         Looper myLooper = prepareIfNeededLooper();
-        
+
         mAudioManager.registerAudioDeviceCallback(callback, new Handler());
         // unregister null callback
         mAudioManager.unregisterAudioDeviceCallback(null);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index b3fcce1..813af0f2 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -19,6 +19,7 @@
 import android.cts.util.MediaUtils;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.AudioCapabilities;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.media.MediaCodecInfo.VideoCapabilities;
@@ -530,24 +531,35 @@
         }
     }
 
-    private static MediaFormat createMinFormat(String mime, VideoCapabilities vcaps, int color) {
-        int minWidth = vcaps.getSupportedWidths().getLower();
-        int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
-        int minBitrate = vcaps.getBitrateRange().getLower();
+    private static MediaFormat createMinFormat(String mime, CodecCapabilities caps) {
+        MediaFormat format;
+        if (caps.getVideoCapabilities() != null) {
+            VideoCapabilities vcaps = caps.getVideoCapabilities();
+            int minWidth = vcaps.getSupportedWidths().getLower();
+            int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
+            int minBitrate = vcaps.getBitrateRange().getLower();
+            format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
+            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
+            format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
+            format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
+            format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
+        } else {
+            AudioCapabilities acaps = caps.getAudioCapabilities();
+            int minSampleRate = acaps.getSupportedSampleRateRanges()[0].getLower();
+            int minChannelCount = 1;
+            int minBitrate = acaps.getBitrateRange().getLower();
+            format = MediaFormat.createAudioFormat(mime, minSampleRate, minChannelCount);
+            format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
+        }
 
-        MediaFormat format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
-        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, color);
-        format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
-        format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
-        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
         return format;
     }
 
     private static int getActualMax(
             boolean isEncoder, String name, String mime, CodecCapabilities caps, int max) {
         int flag = isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0;
-        MediaFormat format =
-                createMinFormat(mime, caps.getVideoCapabilities(), caps.colorFormats[0]);
+        MediaFormat format = createMinFormat(mime, caps);
+        Log.d(TAG, "Test format " + format);
         Vector<MediaCodec> codecs = new Vector<MediaCodec>();
         MediaCodec codec = null;
         for (int i = 0; i < max; ++i) {
@@ -588,14 +600,6 @@
         return actualMax;
     }
 
-    private static boolean shouldTestActual(CodecCapabilities caps) {
-        if (caps.getVideoCapabilities() == null) {
-            // TODO: test audio codecs.
-            return false;
-        }
-        return true;
-    }
-
     public void testGetMaxSupportedInstances() {
         final int MAX_INSTANCES = 32;
         StringBuilder xmlOverrides = new StringBuilder();
@@ -612,21 +616,19 @@
                 Log.d(TAG, "getMaxSupportedInstances returns " + max);
                 assertTrue(max > 0);
 
-                if (shouldTestActual(caps)) {
-                    int actualMax = getActualMax(
-                            info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES);
-                    Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
-                    if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
-                        String codec = "<MediaCodec name=\"" + info.getName() +
-                                "\" type=\"" + types[j] + "\" >";
-                        String limit = "    <Limit name=\"concurrent-instances\" max=\"" +
-                                actualMax + "\" />";
-                        xmlOverrides.append(codec);
-                        xmlOverrides.append("\n");
-                        xmlOverrides.append(limit);
-                        xmlOverrides.append("\n");
-                        xmlOverrides.append("</MediaCodec>\n");
-                    }
+                int actualMax = getActualMax(
+                        info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES);
+                Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
+                if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
+                    String codec = "<MediaCodec name=\"" + info.getName() +
+                            "\" type=\"" + types[j] + "\" >";
+                    String limit = "    <Limit name=\"concurrent-instances\" max=\"" +
+                            actualMax + "\" />";
+                    xmlOverrides.append(codec);
+                    xmlOverrides.append("\n");
+                    xmlOverrides.append(limit);
+                    xmlOverrides.append("\n");
+                    xmlOverrides.append("</MediaCodec>\n");
                 }
             }
         }
diff --git a/tests/tests/media/src/android/media/cts/MidiSoloTest.java b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
index 4c1a5e8..d198ee8 100644
--- a/tests/tests/media/src/android/media/cts/MidiSoloTest.java
+++ b/tests/tests/media/src/android/media/cts/MidiSoloTest.java
@@ -97,9 +97,7 @@
         MidiManager.DeviceCallback callback = new MidiManager.DeviceCallback();
 
         // These should not crash.
-        midiManager.unregisterDeviceCallback(null);
         midiManager.unregisterDeviceCallback(callback);
-        midiManager.registerDeviceCallback(null, null);
         midiManager.registerDeviceCallback(callback, null);
         midiManager.unregisterDeviceCallback(callback);
         midiManager.registerDeviceCallback(callback, new Handler(Looper.getMainLooper()));
@@ -107,9 +105,6 @@
         midiManager.unregisterDeviceCallback(callback);
         midiManager.unregisterDeviceCallback(callback);
         midiManager.unregisterDeviceCallback(callback);
-        midiManager.registerDeviceCallback(null, new Handler(Looper.getMainLooper()));
-        midiManager.unregisterDeviceCallback(callback);
-        midiManager.unregisterDeviceCallback(null);
     }
 
     public void testMidiReceiver() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
index bf47a27..4693036 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
@@ -55,6 +55,7 @@
         mActivity = getActivity();
         mInstrumentation = getInstrumentation();
         mContext = mInstrumentation.getContext();
+        Utils.enableAppOps(mContext.getPackageName(), "android:write_settings", mInstrumentation);
         mRingtoneManager = new RingtoneManager(mActivity);
         mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
         // backup ringer settings
@@ -74,6 +75,7 @@
         }
         RingtoneManager.setActualDefaultRingtoneUri(mContext, RingtoneManager.TYPE_RINGTONE,
                 mDefaultUri);
+        Utils.disableAppOps(mContext.getPackageName(), "android:write_settings", mInstrumentation);
         super.tearDown();
     }
 
diff --git a/tests/tests/media/src/android/media/cts/Utils.java b/tests/tests/media/src/android/media/cts/Utils.java
new file mode 100644
index 0000000..bb9cf78
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/Utils.java
@@ -0,0 +1,70 @@
+/*
+ * 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.media.cts;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Scanner;
+
+public class Utils {
+    public static void enableAppOps(String packageName, String operation,
+            Instrumentation instrumentation) {
+        setAppOps(packageName, operation, instrumentation, true);
+    }
+
+    public static void disableAppOps(String packageName, String operation,
+            Instrumentation instrumentation) {
+        setAppOps(packageName, operation, instrumentation, false);
+    }
+
+    public static String convertStreamToString(InputStream is) {
+        try (Scanner scanner = new Scanner(is).useDelimiter("\\A")) {
+            return scanner.hasNext() ? scanner.next() : "";
+        }
+    }
+
+    private static void setAppOps(String packageName, String operation,
+            Instrumentation instrumentation, boolean enable) {
+        StringBuilder cmd = new StringBuilder();
+        cmd.append("appops set ");
+        cmd.append(packageName);
+        cmd.append(" ");
+        cmd.append(operation);
+        cmd.append(enable ? " allow" : " deny");
+        instrumentation.getUiAutomation().executeShellCommand(cmd.toString());
+
+        StringBuilder query = new StringBuilder();
+        query.append("appops get ");
+        query.append(packageName);
+        query.append(" ");
+        query.append(operation);
+        String queryStr = query.toString();
+
+        String expectedResult = enable ? "allow" : "deny";
+        String result = "";
+        while(!result.contains(expectedResult)) {
+            ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(
+                                                            queryStr);
+            InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
+            result = convertStreamToString(inputStream);
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
index ede5040..f5680f6 100644
--- a/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoDecoderPerfTest.java
@@ -31,6 +31,7 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.util.Log;
+import android.util.Range;
 import android.view.Surface;
 
 import com.android.cts.util.ResultType;
@@ -58,6 +59,8 @@
     LinkedList<ByteBuffer> mSamplesInMemory = new LinkedList<ByteBuffer>();
     private static final int MOVING_AVERAGE_NUM = 10;
     private MediaFormat mDecOutputFormat;
+    private double[] mMeasuredFps;
+    private String[] mResultRawData;
 
     private Resources mResources;
     private DeviceReportLog mReportLog;
@@ -104,6 +107,8 @@
             }
 
             boolean pass = false;
+            mMeasuredFps = new double[NUMBER_OF_REPEAT];
+            mResultRawData = new String[NUMBER_OF_REPEAT];
             Log.d(TAG, "testing " + name);
             for (int i = 0; i < NUMBER_OF_REPEAT; ++i) {
                 // Decode to Surface.
@@ -118,7 +123,16 @@
                 Log.d(TAG, "round #" + i + " decode to buffer");
                 doDecode(name, video, width, height, null, i);
             }
-            assertTrue("Measured fps doesn't match with reported achievable frame rates.", pass);
+
+            if (!pass) {
+                Range<Double> reportedRange =
+                    MediaUtils.getAchievableFrameRatesFor(name, mime, width, height);
+                String failMessage =
+                    MediaUtils.getErrorMessage(reportedRange, mMeasuredFps, mResultRawData);
+                fail(failMessage);
+            }
+            mMeasuredFps = null;
+            mResultRawData = null;
         }
         // use 0 for summary line, detail for each test config is in the report.
         mReportLog.printSummary("average fps", 0, ResultType.HIGHER_BETTER, ResultUnit.FPS);
@@ -276,9 +290,15 @@
         double decMax = Stat.getMax(avgs);
         double decAvg = Stat.getAverage(avgs);
         double decStdev = MediaUtils.getStdev(avgs);
-        MediaUtils.logResults(mReportLog, testConfig, decMin, decMax, decAvg, decStdev);
+        String result =
+                MediaUtils.logResults(mReportLog, testConfig, decMin, decMax, decAvg, decStdev);
+        fps = 1000000000 / decMin;
+        if (surface != null) {
+            mMeasuredFps[round] = fps;
+            mResultRawData[round] = result;
+        }
 
-        return MediaUtils.verifyResults(name, mime, w, h, 1000000000 / decMin);
+        return MediaUtils.verifyResults(name, mime, w, h, fps);
     }
 
     public void testH2640320x0240Other() throws Exception {
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index e4d77b1..88dbd7c 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -67,7 +67,6 @@
     private PackageManager mPackageManager;
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
-    private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
 
     @Override
     protected void setUp() throws Exception {
@@ -90,13 +89,6 @@
                 mNetworks.put(n.type, n);
             } catch (Exception e) {}
         }
-
-        // Get com.android.internal.R.array.config_protectedNetworks
-        resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
-        int[] protectedNetworks = getContext().getResources().getIntArray(resId);
-        for (int p : protectedNetworks) {
-            mProtectedNetworks.add(p);
-        }
     }
 
     public void testIsNetworkTypeValid() {
@@ -190,6 +182,27 @@
         }
     }
 
+    private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
+        try {
+            mCm.startUsingNetworkFeature(networkType, feature);
+            fail("startUsingNetworkFeature is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
+        try {
+            mCm.startUsingNetworkFeature(networkType, feature);
+            fail("stopUsingNetworkFeature is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
+    private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
+        try {
+            mCm.requestRouteToHost(networkType, hostAddress);
+            fail("requestRouteToHost is no longer supported in the current API version");
+        } catch (UnsupportedOperationException expected) {}
+    }
+
     public void testStartUsingNetworkFeature() {
 
         final String invalidateFeature = "invalidateFeature";
@@ -198,27 +211,9 @@
         final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED;
         final int wifiOnlyStopFailureCode = -1;
 
-        NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
-        if (ni != null) {
-            assertEquals(PhoneConstants.APN_REQUEST_FAILED,
-                    mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature));
-            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-        } else {
-            assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-            assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
-                    invalidateFeature));
-        }
-
-        ni = mCm.getNetworkInfo(TYPE_WIFI);
-        if (ni != null) {
-            // Should return failure because MMS is not supported on WIFI.
-            assertEquals(PhoneConstants.APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
-                    mmsFeature));
-            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
-                    mmsFeature));
-        }
+        assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+        assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+        assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
     }
 
     private boolean isSupported(int networkType) {
@@ -229,11 +224,6 @@
                (networkType == ConnectivityManager.TYPE_VPN);
     }
 
-    // true if only the system can turn it on
-    private boolean isNetworkProtected(int networkType) {
-        return mProtectedNetworks.contains(networkType);
-    }
-
     public void testIsNetworkSupported() {
         for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
             boolean supported = mCm.isNetworkSupported(type);
@@ -247,82 +237,14 @@
 
     public void testRequestRouteToHost() {
         for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            NetworkInfo ni = mCm.getNetworkInfo(type);
-            boolean expectToWork = isSupported(type) && !isNetworkProtected(type) &&
-                    ni != null && ni.isConnected();
-
-            try {
-                assertTrue("Network type " + type,
-                        mCm.requestRouteToHost(type, HOST_ADDRESS) == expectToWork);
-            } catch (Exception e) {
-                Log.d(TAG, "got exception in requestRouteToHost for type " + type);
-                assertFalse("Exception received for type " + type, expectToWork);
-            }
-
-            //TODO verify route table
+            assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
         }
-
-        assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS));
     }
 
     public void testTest() {
         mCm.getBackgroundDataSetting();
     }
 
-    /** Test that hipri can be brought up when Wifi is enabled. */
-    public void testStartUsingNetworkFeature_enableHipri() throws Exception {
-        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
-                || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
-            // This test requires a mobile data connection and WiFi.
-            return;
-        }
-
-        boolean isWifiEnabled = mWifiManager.isWifiEnabled();
-        boolean isWifiConnected = false;
-
-        NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
-        if (nwInfo != null) {
-            isWifiConnected = nwInfo.isConnected();
-        }
-        try {
-            // Make sure WiFi is connected to an access point.
-            if (!isWifiConnected) {
-                connectToWifi();
-            }
-
-            // Register a receiver that will capture the connectivity change for hipri.
-            ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
-                    ConnectivityManager.TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED);
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-            mContext.registerReceiver(receiver, filter);
-
-            // Try to start using the hipri feature...
-            int result = mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                    FEATURE_ENABLE_HIPRI);
-            assertTrue("Couldn't start using the HIPRI feature.", result != -1);
-
-            // Check that the ConnectivityManager reported that it connected using hipri...
-            assertTrue("Couldn't connect using hipri...", receiver.waitForState());
-
-            assertTrue("Couldn't requestRouteToHost using HIPRI.",
-                    mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS));
-            // TODO check dns selection
-            // TODO check routes
-        } catch (InterruptedException e) {
-            fail("Broadcast receiver waiting for ConnectivityManager interrupted.");
-        } finally {
-            mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
-                    FEATURE_ENABLE_HIPRI);
-            // TODO wait for HIPRI to go
-            // TODO check dns selection
-            // TODO check routes
-            if (!isWifiEnabled) {
-                disconnectFromWifi();
-            }
-        }
-    }
-
     /**
      * Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
      * see if we get a callback for the TRANSPORT_WIFI transport type being available.
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/netlegacy22/Android.mk
new file mode 100644
index 0000000..68fd6f8
--- /dev/null
+++ b/tests/tests/netlegacy22/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)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsNetTestCasesLegacyApi22
+
+LOCAL_SDK_VERSION := 22
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netlegacy22/AndroidManifest.xml b/tests/tests/netlegacy22/AndroidManifest.xml
new file mode 100644
index 0000000..d243e45
--- /dev/null
+++ b/tests/tests/netlegacy22/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 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.net.legacy22">
+
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.INTERNET" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.net.legacy22"
+                     android:label="CTS tests of legacy android.net APIs as of API 22">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
new file mode 100644
index 0000000..8a9002b
--- /dev/null
+++ b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts.legacy.api22;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_VPN;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+
+public class ConnectivityManagerLegacyTest extends AndroidTestCase {
+    private static final String TAG = ConnectivityManagerLegacyTest.class.getSimpleName();
+    private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
+    private static final String HOST_ADDRESS1 = "192.0.2.1";
+    private static final String HOST_ADDRESS2 = "192.0.2.2";
+    private static final String HOST_ADDRESS3 = "192.0.2.3";
+
+    // These are correct as of API level 22, which is what we target here.
+    private static final int APN_REQUEST_FAILED = 3;
+    private static final int MAX_NETWORK_TYPE = TYPE_VPN;
+
+    private ConnectivityManager mCm;
+    private WifiManager mWifiManager;
+    private PackageManager mPackageManager;
+
+    private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+        mPackageManager = getContext().getPackageManager();
+
+        // Get com.android.internal.R.array.config_protectedNetworks
+        int resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
+        int[] protectedNetworks = getContext().getResources().getIntArray(resId);
+        for (int p : protectedNetworks) {
+            mProtectedNetworks.add(p);
+        }
+    }
+
+    // true if only the system can turn it on
+    private boolean isNetworkProtected(int networkType) {
+        return mProtectedNetworks.contains(networkType);
+    }
+
+    private int ipv4AddrToInt(String addrString) throws Exception {
+        byte[] addr = ((Inet4Address) InetAddress.getByName(addrString)).getAddress();
+        return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
+                ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
+    }
+
+    private void checkSourceAddress(String addrString, int type) throws Exception {
+        DatagramSocket d = new DatagramSocket();
+        d.connect(InetAddress.getByName(addrString), 7);
+        InetAddress localAddress = d.getLocalAddress();
+
+        Network[] networks = mCm.getAllNetworks();
+        for (int i = 0; i < networks.length; i++) {
+            NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
+            if (ni != null && ni.getType() == type) {
+                LinkProperties lp = mCm.getLinkProperties(networks[i]);
+                for (LinkAddress address : lp.getLinkAddresses()) {
+                    if (address.getAddress().equals(localAddress)) {
+                        return;
+                    }
+                }
+            }
+        }
+        fail("Local address " + localAddress + " not assigned to any network of type " + type);
+    }
+
+    /** Test that hipri can be brought up when Wifi is enabled. */
+    public void testStartUsingNetworkFeature_enableHipri() throws Exception {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+                || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            // This test requires a mobile data connection and WiFi.
+            return;
+        }
+
+        // Make sure WiFi is connected to an access point.
+        connectToWifi();
+
+        expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED,
+                new Runnable() {
+                    public void run() {
+                        int ret = mCm.startUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+                        assertTrue("Couldn't start using the HIPRI feature.", ret != -1);
+                    }
+                });
+
+        assertTrue("Couldn't requestRouteToHost using HIPRI.",
+                mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
+
+        try { Thread.sleep(1000); } catch(Exception e) {}
+        checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
+        checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
+
+        // TODO check dns selection
+
+        expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.DISCONNECTED,
+                new Runnable() {
+                    public void run() {
+                        int ret = mCm.stopUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+                        assertTrue("Couldn't stop using the HIPRI feature.", ret != -1);
+                    }
+                });
+
+
+        // TODO check dns selection
+        disconnectFromWifi();
+    }
+
+    public void testStartUsingNetworkFeature() {
+
+        final String invalidFeature = "invalidFeature";
+        final String mmsFeature = "enableMMS";
+        final int failureCode = -1;
+        final int wifiOnlyStartFailureCode = APN_REQUEST_FAILED;
+        final int wifiOnlyStopFailureCode = -1;
+
+        NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
+        if (ni != null) {
+            assertEquals(APN_REQUEST_FAILED,
+                    mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+        } else {
+            assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
+                    invalidFeature));
+            assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
+                    invalidFeature));
+        }
+
+        ni = mCm.getNetworkInfo(TYPE_WIFI);
+        if (ni != null) {
+            // Should return failure because MMS is not supported on WIFI.
+            assertEquals(APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
+                    mmsFeature));
+            assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
+                    mmsFeature));
+        }
+    }
+
+    private void expectNetworkBroadcast(final int type, final NetworkInfo.State state,
+            Runnable afterWhat) {
+        final int TIMEOUT_MS = 30 * 1000;
+        final ConditionVariable var = new ConditionVariable();
+
+        Log.d(TAG, "Waiting for " + state + " broadcast for type " + type);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            public void onReceive(Context context, Intent intent) {
+                NetworkInfo ni = intent.getExtras()
+                        .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
+                assertNotNull("CONNECTIVITY_ACTION with null EXTRA_NETWORK_INFO", ni);
+                if (ni.getType() == type && ni.getState().equals(state)) {
+                    Log.d(TAG, "Received expected " + state + " broadcast for type " + type);
+                    var.open();
+                }
+            }
+        };
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(CONNECTIVITY_ACTION);
+        mContext.registerReceiver(receiver, filter);
+
+        try {
+            afterWhat.run();
+            final String msg = "Did not receive expected " + state + " broadcast for type " + type +
+                    " after " + TIMEOUT_MS + " ms";
+            assertTrue(msg, var.block(TIMEOUT_MS));
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+
+    private boolean isWifiConnected() {
+        NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI);
+        return ni != null && ni.isConnected();
+    }
+
+    private void setWifiState(final boolean enabled) {
+        if (enabled != isWifiConnected()) {
+            final NetworkInfo.State desiredState = enabled ?
+                    NetworkInfo.State.CONNECTED :
+                    NetworkInfo.State.DISCONNECTED;
+            expectNetworkBroadcast(TYPE_WIFI, desiredState, new Runnable() {
+                public void run() {
+                    mWifiManager.setWifiEnabled(enabled);
+                }
+            });
+        }
+    }
+
+    private void connectToWifi() {
+        setWifiState(true);
+    }
+
+    private void disconnectFromWifi() {
+        setWifiState(false);
+    }
+
+    private boolean isNetworkSupported(int networkType) {
+        return mCm.getNetworkInfo(networkType) != null;
+    }
+
+    public void testRequestRouteToHost() throws Exception {
+        for (int type = -1 ; type <= MAX_NETWORK_TYPE; type++) {
+            NetworkInfo ni = mCm.getNetworkInfo(type);
+            boolean expectToWork = isNetworkSupported(type) && !isNetworkProtected(type) &&
+                    ni != null && ni.isConnected();
+
+            try {
+                assertTrue("Network type " + type,
+                        mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS3)) == expectToWork);
+            } catch (Exception e) {
+                Log.d(TAG, "got exception in requestRouteToHost for type " + type);
+                assertFalse("Exception received for type " + type, expectToWork);
+            }
+
+            //TODO verify route table
+        }
+
+        assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS1)));
+    }
+}
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
new file mode 100644
index 0000000..a4d68cb
--- /dev/null
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -0,0 +1,64 @@
+/*
+* 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.permission2.cts;
+
+import android.Manifest;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.Set;
+
+/**
+ * Tests for permission policy on the platform.
+ */
+public class PermissionPolicyTest extends AndroidTestCase {
+    private static final String PLATFORM_PACKAGE_NAME = "android";
+
+    private static final Set<String> PERMISSION_GROUPS = new ArraySet<>();
+    static {
+        PERMISSION_GROUPS.add(Manifest.permission_group.CALENDAR);
+        PERMISSION_GROUPS.add(Manifest.permission_group.CAMERA);
+        PERMISSION_GROUPS.add(Manifest.permission_group.CONTACTS);
+        PERMISSION_GROUPS.add(Manifest.permission_group.LOCATION);
+        PERMISSION_GROUPS.add(Manifest.permission_group.MICROPHONE);
+        PERMISSION_GROUPS.add(Manifest.permission_group.PHONE);
+        PERMISSION_GROUPS.add(Manifest.permission_group.SENSORS);
+        PERMISSION_GROUPS.add(Manifest.permission_group.SMS);
+        PERMISSION_GROUPS.add(Manifest.permission_group.STORAGE);
+    }
+
+    public void testPlatformDefinedRuntimePermissionValid() throws Exception {
+        PackageManager packageManager = getContext().getPackageManager();
+        PackageInfo packageInfo = packageManager.getPackageInfo(PLATFORM_PACKAGE_NAME,
+                PackageManager.GET_PERMISSIONS);
+        for (PermissionInfo permission : packageInfo.permissions) {
+            if ((permission.protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) == 0) {
+                continue;
+            }
+            assertTrue(permission.name + " must be in one of these groups: " + PERMISSION_GROUPS,
+                    PERMISSION_GROUPS.contains(permission.group));
+            assertFalse(permission.name + " must have non-empty label",
+                    TextUtils.isEmpty(permission.loadLabel(packageManager)));
+            assertFalse(permission.name + " must have non-empty description",
+                    TextUtils.isEmpty(permission.loadDescription(packageManager)));
+        }
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index 323190c..31ca09b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -86,13 +86,16 @@
     String mPreviousDefaultDialer = null;
     MockConnectionService connectionService = null;
 
+    boolean mShouldTestTelecom = true;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
         mTelecomManager = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
 
-        if (shouldTestTelecom(mContext)) {
+        mShouldTestTelecom = shouldTestTelecom(mContext);
+        if (mShouldTestTelecom) {
             mPreviousDefaultDialer = TestUtils.getDefaultDialer(getInstrumentation());
             TestUtils.setDefaultDialer(getInstrumentation(), PACKAGE);
             setupCallbacks();
@@ -101,7 +104,7 @@
 
     @Override
     protected void tearDown() throws Exception {
-        if (shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             cleanupCalls();
             if (!TextUtils.isEmpty(mPreviousDefaultDialer)) {
                 TestUtils.setDefaultDialer(getInstrumentation(), mPreviousDefaultDialer);
@@ -319,8 +322,6 @@
 
         assertThat("Telecom should create outgoing connection for outgoing call",
                 connectionService.outgoingConnections.size(), not(equalTo(0)));
-        assertEquals("Telecom should not create incoming connections for outgoing calls",
-                0, connectionService.incomingConnections.size());
         MockConnection connection = connectionService.outgoingConnections.get(connectionIndex);
         return connection;
     }
@@ -342,8 +343,6 @@
 
         assertThat("Telecom should create incoming connections for incoming calls",
                 connectionService.incomingConnections.size(), not(equalTo(0)));
-        assertEquals("Telecom should not create outgoing connections for incoming calls",
-                0, connectionService.outgoingConnections.size());
         MockConnection connection = connectionService.incomingConnections.get(connectionIndex);
         setAndVerifyConnectionForIncomingCall(connection);
         return connection;
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index dd93573..879c995 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -65,7 +65,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (TestUtils.shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             PhoneAccount account = setupConnectionService(
                     new MockConnectionService() {
                         @Override
@@ -93,23 +93,27 @@
                         }
                     }, FLAG_REGISTER | FLAG_ENABLE);
 
+            /** Place a call as a part of the setup before we test the various
+             *  Call details.
+             */
+            placeAndVerifyCall();
+            verifyConnectionForOutgoingCall();
+
+            mInCallService = mInCallCallbacks.getService();
+            mCall = mInCallService.getLastCall();
+
+            assertCallState(mCall, Call.STATE_DIALING);
         }
-        /** Place a call as a part of the setup before we test the various
-         *  Call details.
-         */
-        placeAndVerifyCall();
-        verifyConnectionForOutgoingCall();
-
-        mInCallService = mInCallCallbacks.getService();
-        mCall = mInCallService.getLastCall();
-
-        assertCallState(mCall, Call.STATE_DIALING);
     }
 
     /**
      * Tests whether the getAccountHandle() getter returns the correct object.
      */
     public void testAccountHandle() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getAccountHandle(), is(PhoneAccountHandle.class));
         assertEquals(TEST_PHONE_ACCOUNT_HANDLE, mCall.getDetails().getAccountHandle());
     }
@@ -118,6 +122,10 @@
      * Tests whether the getCallCapabilities() getter returns the correct object.
      */
     public void testCallCapabilities() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getCallCapabilities(), is(Integer.class));
         assertEquals(CALL_CAPABILITIES, mCall.getDetails().getCallCapabilities());
         assertTrue(mCall.getDetails().can(Call.Details.CAPABILITY_HOLD));
@@ -130,6 +138,10 @@
      * Tests whether the getCallerDisplayName() getter returns the correct object.
      */
     public void testCallerDisplayName() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getCallerDisplayName(), is(String.class));
         assertEquals(CALLER_DISPLAY_NAME, mCall.getDetails().getCallerDisplayName());
     }
@@ -138,6 +150,10 @@
      * Tests whether the getCallerDisplayNamePresentation() getter returns the correct object.
      */
     public void testCallerDisplayNamePresentation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getCallerDisplayNamePresentation(), is(Integer.class));
         assertEquals(CALLER_DISPLAY_NAME_PRESENTATION, mCall.getDetails().getCallerDisplayNamePresentation());
     }
@@ -146,6 +162,10 @@
      * Tests whether the getCallProperties() getter returns the correct object.
      */
     public void testCallProperties() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getCallProperties(), is(Integer.class));
         assertEquals(CALL_PROPERTIES, mCall.getDetails().getCallProperties());
     }
@@ -154,6 +174,10 @@
      * Tests whether the getConnectTimeMillis() getter returns the correct object.
      */
     public void testConnectTimeMillis() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getConnectTimeMillis(), is(Long.class));
     }
 
@@ -161,6 +185,10 @@
      * Tests whether the getDisconnectCause() getter returns the correct object.
      */
     public void testDisconnectCause() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getDisconnectCause(), is(DisconnectCause.class));
     }
 
@@ -168,6 +196,10 @@
      * Tests whether the getExtras() getter returns the correct object.
      */
     public void testExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         if (mCall.getDetails().getExtras() != null) {
             assertThat(mCall.getDetails().getExtras(), is(Bundle.class));
         }
@@ -177,6 +209,10 @@
      * Tests whether the getIntentExtras() getter returns the correct object.
      */
     public void testIntentExtras() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getIntentExtras(), is(Bundle.class));
     }
 
@@ -184,6 +220,10 @@
      * Tests whether the getGatewayInfo() getter returns the correct object.
      */
     public void testGatewayInfo() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         if (mCall.getDetails().getGatewayInfo() != null) {
             assertThat(mCall.getDetails().getGatewayInfo(), is(GatewayInfo.class));
         }
@@ -193,6 +233,10 @@
      * Tests whether the getHandle() getter returns the correct object.
      */
     public void testHandle() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getHandle(), is(Uri.class));
         assertEquals(getTestNumber(), mCall.getDetails().getHandle());
     }
@@ -201,6 +245,10 @@
      * Tests whether the getHandlePresentation() getter returns the correct object.
      */
     public void testHandlePresentation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getHandlePresentation(), is(Integer.class));
         assertEquals(MockConnectionService.CONNECTION_PRESENTATION, mCall.getDetails().getHandlePresentation());
     }
@@ -209,6 +257,10 @@
      * Tests whether the getStatusHints() getter returns the correct object.
      */
     public void testStatusHints() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getStatusHints(), is(StatusHints.class));
         assertEquals(mStatusHints.getLabel(), mCall.getDetails().getStatusHints().getLabel());
         assertEquals(
@@ -221,6 +273,10 @@
      * Tests whether the getVideoState() getter returns the correct object.
      */
     public void testVideoState() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         assertThat(mCall.getDetails().getVideoState(), is(Integer.class));
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index 989045c..121d559 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -51,17 +51,17 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
-        if (shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             addOutgoingCalls();
             addConferenceCall(mCall1, mCall2);
             // Use vanilla conference object so that the CTS coverage tool detects the useage.
-            mConferenceObject = (Conference)verifyConferenceForOutgoingCall();
+            mConferenceObject = verifyConferenceForOutgoingCall();
             verifyConferenceObject(mConferenceObject, mConnection1, mConnection2);
         }
     }
 
     public void testConferenceCreate() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -81,7 +81,7 @@
     }
 
     public void testConferenceSplit() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -101,7 +101,7 @@
     }
 
     public void testConferenceHoldAndUnhold() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -119,7 +119,7 @@
     }
 
     public void testConferenceMergeAndSwap() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -144,7 +144,7 @@
     }
 
     public void testConferenceSetters() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -215,7 +215,7 @@
     }
 
     public void testConferenceAddAndRemoveConnection() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
@@ -240,7 +240,7 @@
     }
 
     public void testConferenceDTMFTone() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call conf = mInCallService.getLastConferenceCall();
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
new file mode 100644
index 0000000..afaa3eb
--- /dev/null
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telecom.cts;
+
+import static android.telecom.cts.TestUtils.*;
+
+import android.telecom.Call;
+import android.telecom.Connection;
+import android.telecom.ConnectionService;
+import android.util.Log;
+
+import java.util.Collection;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Test some additional {@link ConnectionService} APIs not already covered by other tests.
+ */
+public class ConnectionServiceTest extends BaseTelecomTestWithMockServices {
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+        if (mShouldTestTelecom) {
+            setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
+        }
+    }
+
+    public void testAddExistingConnection() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        placeAndVerifyCall();
+        verifyConnectionForOutgoingCall();
+
+        final MockConnection connection = new MockConnection();
+        connection.setOnHold();
+        CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
+
+        try {
+            if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
+                fail("No call added to InCallService.");
+            }
+        } catch (InterruptedException e) {
+            Log.i(TAG, "Test interrupted!");
+        }
+
+        final MockInCallService inCallService = mInCallCallbacks.getService();
+        final Call call = inCallService.getLastCall();
+        assertCallState(call, Call.STATE_HOLDING);
+    }
+
+    public void testGetAllConnections() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        // Add first connection (outgoing call)
+        placeAndVerifyCall();
+        final Connection connection1 = verifyConnectionForOutgoingCall();
+
+        Collection<Connection> connections = CtsConnectionService.getAllConnectionsFromTelecom();
+        assertEquals(1, connections.size());
+        assertTrue(connections.contains(connection1));
+
+        // Add second connection (add existing connection)
+        final Connection connection2 = new MockConnection();
+        CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection2);
+
+        connections = CtsConnectionService.getAllConnectionsFromTelecom();
+        assertEquals(2, connections.size());
+        assertTrue(connections.contains(connection2));
+
+        // Add third connection (incoming call)
+        addAndVerifyNewIncomingCall(getTestNumber(), null);
+        final Connection connection3 = verifyConnectionForIncomingCall();
+        connections = CtsConnectionService.getAllConnectionsFromTelecom();
+        assertEquals(3, connections.size());
+        assertTrue(connections.contains(connection3));
+    }
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
index f7e08ed6f..3c30e6b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsConnectionService.java
@@ -24,6 +24,8 @@
 import android.telecom.RemoteConference;
 import android.telecom.RemoteConnection;
 
+import java.util.Collection;
+
 /**
  * This is the official ConnectionService for Telecom's CTS App. Since telecom requires that a
  * CS be registered in the AndroidManifest.xml file, we have to have a single implementation
@@ -135,6 +137,19 @@
         }
     }
 
+    public static void addExistingConnectionToTelecom(
+            PhoneAccountHandle phoneAccountHandle, Connection connection) {
+        synchronized(sLock) {
+            sTelecomConnectionService.addExistingConnection(phoneAccountHandle, connection);
+        }
+    }
+
+    public static Collection<Connection> getAllConnectionsFromTelecom() {
+        synchronized(sLock) {
+            return sTelecomConnectionService.getAllConnections();
+        }
+    }
+
     public static RemoteConnection createRemoteOutgoingConnectionToTelecom(
             PhoneAccountHandle connectionManagerPhoneAccount,
             ConnectionRequest request) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 74fc143..216ba97 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -36,13 +36,13 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (TestUtils.shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         }
     }
 
     public void testAddNewOutgoingCallAndThenDisconnect() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -56,7 +56,7 @@
     }
 
     public void testMuteAndUnmutePhone() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -83,7 +83,7 @@
     }
 
     public void testSwitchAudioRoutes() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -122,7 +122,7 @@
      * @see {@link Call#stopDtmfTone()}
      */
     public void testPlayAndStopDtmfTones() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -155,7 +155,7 @@
     }
 
     public void testHoldAndUnholdCall() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -182,6 +182,10 @@
     }
 
     public void testAnswerIncomingCallAudioOnly() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         addAndVerifyNewIncomingCall(getTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
@@ -199,6 +203,10 @@
     }
 
     public void testAnswerIncomingCallAsVideo_SendsCorrectVideoState() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         addAndVerifyNewIncomingCall(getTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
@@ -218,6 +226,10 @@
     }
 
     public void testRejectIncomingCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         addAndVerifyNewIncomingCall(getTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
@@ -235,7 +247,7 @@
     }
 
     public void testCanAddCall_CannotAddForExistingDialingCall() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -252,7 +264,7 @@
     }
 
     public void testCanAddCall_CanAddForExistingActiveCall() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -273,7 +285,7 @@
     }
 
     public void testCanAddCall_CannotAddIfTooManyCalls() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -308,7 +320,7 @@
     }
 
     public void testOnBringToForeground() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -340,7 +352,7 @@
     }
 
     public void testOnPostDialWaitAndContinue() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -354,7 +366,7 @@
         assertCallState(call, Call.STATE_ACTIVE);
 
         final String postDialString = "12345";
-        connection.setPostDialWait(postDialString);
+        ((Connection) connection).setPostDialWait(postDialString);
         mOnPostDialWaitCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
 
         assertEquals(postDialString, mOnPostDialWaitCounter.getArgs(0)[1]);
@@ -372,7 +384,7 @@
     }
 
     public void testOnCannedTextResponsesLoaded() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
index 8d6d114..8ffcf48 100644
--- a/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/NumberDialingTest.java
@@ -35,7 +35,7 @@
     private static final int CS_WAIT_MILLIS = 2000;
 
     public void testEndInPound() throws Exception {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
index b1c77fd..f2422c9 100644
--- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
@@ -30,7 +30,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (TestUtils.shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         }
     }
@@ -52,6 +52,10 @@
      * @see {@link TelecomManager#EXTRA_START_CALL_WITH_SPEAKERPHONE}
      */
     public void testStartCallWithSpeakerphoneTrue_SpeakerphoneOnInCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         final Bundle extras = new Bundle();
         extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, true);
         placeAndVerifyCall(extras);
@@ -60,6 +64,10 @@
     }
 
     public void testStartCallWithSpeakerphoneFalse_SpeakerphoneOffInCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         final Bundle extras = new Bundle();
         extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
         placeAndVerifyCall(extras);
@@ -68,6 +76,10 @@
     }
 
     public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         verifyConnectionForOutgoingCall();
         assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
diff --git a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
index 27c8cf4..cfa8e9f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/PhoneAccountOperationsTest.java
@@ -74,6 +74,9 @@
 
     @Override
     protected void tearDown() throws Exception {
+        if (!TestUtils.shouldTestTelecom(mContext)) {
+            return;
+        }
         mTelecomManager.unregisterPhoneAccount(TEST_PHONE_ACCOUNT_HANDLE);
         PhoneAccount retrievedPhoneAccount = mTelecomManager.getPhoneAccount(
                 TEST_PHONE_ACCOUNT_HANDLE);
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index d14372e..3fc65ea 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -62,14 +62,14 @@
     protected void setUp() throws Exception {
         super.setUp();
         mContext = getInstrumentation().getContext();
-        if (shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             addRemoteConferenceCall();
             verifyRemoteConferenceObject(mRemoteConferenceObject, mRemoteConference, mConference);
         }
     }
 
     public void testRemoteConferenceCreate() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call confCall = mInCallCallbacks.getService().getLastConferenceCall();
@@ -92,7 +92,7 @@
     }
 
     public void testRemoteConferenceSplit() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call confCall = mInCallCallbacks.getService().getLastConferenceCall();
@@ -114,7 +114,7 @@
     }
 
     public void testRemoteConferenceHoldAndUnhold() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call confCall = mInCallCallbacks.getService().getLastConferenceCall();
@@ -146,7 +146,7 @@
     }
 
     public void testRemoteConferenceMergeAndSwap() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call confCall = mInCallCallbacks.getService().getLastConferenceCall();
@@ -178,7 +178,7 @@
     }
 
     public void testRemoteConferenceDTMFTone() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         final Call confCall = mInCallCallbacks.getService().getLastConferenceCall();
@@ -201,7 +201,7 @@
     }
 
     public void testRemoteConferenceCallbacks_StateChange() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -227,7 +227,7 @@
     }
 
     public void testRemoteConferenceCallbacks_Disconnect() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -254,7 +254,7 @@
     }
 
     public void testRemoteConferenceCallbacks_ConnectionAdd() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -285,7 +285,7 @@
     }
 
     public void testRemoteConferenceCallbacks_ConnectionRemove() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -317,7 +317,7 @@
     }
 
     public void testRemoteConferenceCallbacks_ConnectionCapabilities() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -345,7 +345,7 @@
     }
 
     public void testRemoteConferenceCallbacks_ConferenceableConnections() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -380,7 +380,7 @@
     }
 
     public void testRemoteConferenceCallbacks_Destroy() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
@@ -404,7 +404,7 @@
     }
 
     public void testRemoteConferenceCallbacks_Extras() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         Handler handler = setupRemoteConferenceCallbacksTest();
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index 9863c11..79fb592 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -55,7 +55,7 @@
     RemoteConnection mRemoteConnectionObject;
 
     public void testRemoteConnectionOutgoingCall() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         addRemoteConnectionOutgoingCall();
@@ -92,7 +92,7 @@
     }
 
     public void testRemoteConnectionIncomingCallAccept() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         addRemoteConnectionIncomingCall();
@@ -113,7 +113,7 @@
     }
 
     public void testRemoteConnectionIncomingCallReject() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         addRemoteConnectionIncomingCall();
@@ -134,7 +134,7 @@
     }
 
     public void testRemoteConnectionDTMFTone() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
         addRemoteConnectionIncomingCall();
@@ -160,7 +160,7 @@
     }
 
     public void testRemoteConnectionCallbacks_StateChange() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -186,7 +186,7 @@
     }
 
     public void testRemoteConnectionCallbacks_RingbackRequest() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -212,7 +212,7 @@
     }
 
     public void testRemoteConnectionCallbacks_ConnectionCapabilities() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -242,7 +242,7 @@
     }
 
     public void testRemoteConnectionCallbacks_PostDialWait() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -270,7 +270,7 @@
     }
 
     public void testRemoteConnectionCallbacks_PostDialChar() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -289,7 +289,7 @@
         };
         mRemoteConnectionObject.registerCallback(callback, handler);
         char postDialChar = '3';
-        mRemoteConnection.setNextPostDialChar(postDialChar);
+        ((Connection) mRemoteConnection).setNextPostDialChar(postDialChar);
         callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
         assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
         assertEquals(postDialChar, callbackInvoker.getArgs(0)[1]);
@@ -297,7 +297,7 @@
     }
 
     public void testRemoteConnectionCallbacks_VoipAudio() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -323,7 +323,7 @@
     }
 
     public void testRemoteConnectionCallbacks_StatusHints() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -350,7 +350,7 @@
     }
 
     public void testRemoteConnectionCallbacks_AddressChange() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -379,7 +379,7 @@
     }
 
     public void testRemoteConnectionCallbacks_CallerDisplayName() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -408,7 +408,7 @@
     }
 
     public void testRemoteConnectionCallbacks_VideoState() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -434,7 +434,7 @@
     }
 
     public void testRemoteConnectionCallbacks_ConferenceableConnections() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -474,7 +474,7 @@
     }
 
     public void testRemoteConnectionCallbacks_VideoProvider() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -502,7 +502,7 @@
     }
 
     public void testRemoteConnectionCallbacks_Extras() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -531,7 +531,7 @@
     }
 
     public void testRemoteConnectionCallbacks_Disconnect() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -560,7 +560,7 @@
     }
 
     public void testRemoteConnectionCallbacks_Destroy() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -585,7 +585,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_SessionModify() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -627,7 +627,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_SessionEvent() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -655,7 +655,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_PeerDimensions() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -686,7 +686,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_CallDataUsage() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -715,7 +715,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_CameraCapabilities() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -746,7 +746,7 @@
     }
 
     public void testRemoteConnectionVideoCallbacks_VideoQuality() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -775,7 +775,7 @@
     }
 
     public void testRemoteConnectionVideo_RequestCallDataUsage() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -810,7 +810,7 @@
     }
 
     public void testRemoteConnectionVideo_RequestCameraCapabilities() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -848,7 +848,7 @@
     }
 
     public void testRemoteConnectionVideo_SendSessionModifyRequest() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -889,7 +889,7 @@
     }
 
     public void testRemoteConnectionVideo_SendSessionModifyResponse() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -935,7 +935,7 @@
     }
 
     public void testRemoteConnectionVideo_SetCamera() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -975,7 +975,7 @@
     }
 
     public void testRemoteConnectionVideo_SetDeviceOrientation() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -998,7 +998,7 @@
     }
 
     public void testRemoteConnectionVideo_SetDisplaySurface() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -1021,7 +1021,7 @@
     }
 
     public void testRemoteConnectionVideo_SetPauseImage() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -1044,7 +1044,7 @@
     }
 
     public void testRemoteConnectionVideo_SetPreviewSurface() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
@@ -1067,7 +1067,7 @@
     }
 
     public void testRemoteConnectionVideo_SetZoom() {
-        if (!shouldTestTelecom(mContext)) {
+        if (!mShouldTestTelecom) {
             return;
         }
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
index e3ba6ef..fbfa998 100644
--- a/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/VideoCallTest.java
@@ -47,7 +47,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (TestUtils.shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         }
     }
@@ -56,6 +56,9 @@
      * Tests ability to start a 2-way video call and retrieve its video state.
      */
     public void testMakeTwoWayVideoCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
 
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
@@ -75,6 +78,10 @@
      * Tests ability to start a 1-way video call and retrieve its video state.
      */
     public void testMakeOneWayVideoCall() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_TX_ENABLED);
         verifyConnectionForOutgoingCall();
 
@@ -89,6 +96,10 @@
      * Tests ability to upgrade an audio-only call to a video call.
      */
     public void testUpgradeToVideo() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
         verifyConnectionForOutgoingCall();
 
@@ -109,6 +120,10 @@
      * Tests ability to receive a session modification request.
      */
     public void testReceiveSessionModifyRequest() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -134,6 +149,10 @@
      * Tests ability to send a session modification response.
      */
     public void testSendSessionModifyResponse() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_AUDIO_ONLY);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -156,6 +175,10 @@
      * the call.
      */
     public void testVideoCallDelayProvider() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         // Don't create video provider when call is created initially; we will do this later.
         try {
             connectionService.setCreateVideoProvider(false);
@@ -187,6 +210,10 @@
      * back in response.
      */
     public void testChangeCamera() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         verifyConnectionForOutgoingCall();
 
@@ -208,6 +235,10 @@
      * Tests ability to request the camera capabilities from the video provider.
      */
     public void testRequestCameraCapabilities() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         verifyConnectionForOutgoingCall();
 
@@ -232,6 +263,10 @@
      * Tests ability to request data usage from the video provider.
      */
     public void testRequestDataUsage() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         verifyConnectionForOutgoingCall();
 
@@ -249,6 +284,10 @@
      * Tests ability to receive changes to the video quality from the video provider.
      */
     public void testReceiveVideoQuality() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -281,6 +320,10 @@
      * Tests ability to receive call session events from the video provider.
      */
     public void testReceiveCallSessionEvent() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -303,6 +346,10 @@
      * Tests ability to receive changes to the peer dimensions from the video provider.
      */
     public void testReceivePeerDimensionChange() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -324,6 +371,10 @@
      * Tests ability to set the device orientation via the provider.
      */
     public void testSetDeviceOrientation() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -342,6 +393,10 @@
      * Tests ability to set the preview surface via the provider.
      */
     public void testSetPreviewSurface() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -365,6 +420,10 @@
      * Tests ability to set the display surface via the provider.
      */
     public void testSetDisplaySurface() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -388,6 +447,10 @@
      * Tests ability to set the camera zoom via the provider.
      */
     public void testSetZoom() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall(VideoProfile.STATE_BIDIRECTIONAL);
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index 697b191..466a90b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -30,7 +30,7 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        if (TestUtils.shouldTestTelecom(mContext)) {
+        if (mShouldTestTelecom) {
             setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE);
         }
     }
@@ -45,6 +45,10 @@
     }
 
     public void testIncomingCallShortPress_acceptsCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         addAndVerifyNewIncomingCall(getTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
@@ -58,6 +62,10 @@
     }
 
     public void testIncomingCallLongPress_rejectsCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         addAndVerifyNewIncomingCall(getTestNumber(), null);
         final MockConnection connection = verifyConnectionForIncomingCall();
 
@@ -71,6 +79,10 @@
     }
 
     public void testInCallShortPress_togglesMute() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
         final MockInCallService incallService = mInCallCallbacks.getService();
@@ -89,6 +101,10 @@
     }
 
     public void testInCallLongPress_hangupCall() throws Exception {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         final MockConnection connection = verifyConnectionForOutgoingCall();
 
@@ -104,6 +120,10 @@
     }
 
     public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
         placeAndVerifyCall();
         verifyConnectionForOutgoingCall();
         assertAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_EARPIECE);
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index ce3fe78..41fe996 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -177,7 +177,7 @@
                 assertTrue("Phone count should be > 0", phoneCount > 0);
                 break;
             case TelephonyManager.PHONE_TYPE_NONE:
-                assertTrue("Phone count should be 0", phoneCount == 0);
+                assertTrue("Phone count should be 0", phoneCount == 0 || phoneCount == 1);
                 break;
             default:
                 throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index e6b656f..592e308 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -95,7 +95,7 @@
      * brackets are optional):
      * <p/>
      * Mozilla/5.0 (Linux;[ U;] Android <version>;[ <language>-<country>;]
-     * [<devicemodel>;] Build/<buildID>[; wv]) AppleWebKit/<major>.<minor> (KHTML, like Gecko)
+     * [<devicemodel>;] Build/<buildID>; wv) AppleWebKit/<major>.<minor> (KHTML, like Gecko)
      * Version/<major>.<minor> Chrome/<major>.<minor>.<branch>.<build>[ Mobile]
      * Safari/<major>.<minor>
      */
@@ -107,7 +107,7 @@
         Log.i(LOG_TAG, String.format("Checking user agent string %s", actualUserAgentString));
         final String patternString =
                 "Mozilla/5\\.0 \\(Linux;( U;)? Android ([^;]+);( (\\w+)-(\\w+);)?" +
-                "\\s?(.*)\\sBuild/(.+?)(; wv)?\\) AppleWebKit/(\\d+)\\.(\\d+) " +
+                "\\s?(.*)\\sBuild/(.+); wv\\) AppleWebKit/(\\d+)\\.(\\d+) " +
                 "\\(KHTML, like Gecko\\) " +
                 "Version/\\d+\\.\\d+ Chrome/\\d+\\.\\d+\\.\\d+\\.\\d+( Mobile)? " +
                 "Safari/(\\d+)\\.(\\d+)";
@@ -119,12 +119,11 @@
         //  5   - language
         //  6 - device model (optional)
         //  7 - build ID
-        //  8 - WebView identifier "; wv" (optional)
-        //  9 - AppleWebKit major version number
-        // 10 - AppleWebKit minor version number
-        // 11 - " Mobile" string (optional)
-        // 12 - Safari major version number
-        // 13 - Safari minor version number
+        //  8 - AppleWebKit major version number
+        //  9 - AppleWebKit minor version number
+        // 10 - " Mobile" string (optional)
+        // 11 - Safari major version number
+        // 12 - Safari minor version number
         Log.i(LOG_TAG, String.format("Trying to match pattern %s", patternString));
         final Pattern userAgentExpr = Pattern.compile(patternString);
         Matcher patternMatcher = userAgentExpr.matcher(actualUserAgentString);
diff --git a/tests/tests/widget/src/android/widget/cts/ListViewTest.java b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
index f6f490f..6c62be4 100644
--- a/tests/tests/widget/src/android/widget/cts/ListViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ListViewTest.java
@@ -431,6 +431,7 @@
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
                 mListView.setDivider(d);
+                mListView.requestLayout();
             }
         });
         mInstrumentation.waitForIdleSync();
@@ -440,6 +441,7 @@
         mInstrumentation.runOnMainSync(new Runnable() {
             public void run() {
                 mListView.setDividerHeight(10);
+                mListView.requestLayout();
             }
         });
         mInstrumentation.waitForIdleSync();
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
index 01f148ae..d74cce5 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/CtsTest.java
@@ -289,9 +289,8 @@
         @Override
         public void testFailed(TestIdentifier test, String trace) {
             super.testFailed(test, trace);
-            // sleep a small amount of time to ensure test failure stack trace makes it into logcat
-            // capture
-            RunUtil.getDefault().sleep(10);
+            // sleep 2s to ensure test failure stack trace makes it into logcat capture
+            RunUtil.getDefault().sleep(2 * 1000);
             InputStreamSource logSource = mDevice.getLogcat(mNumLogcatBytes);
             super.testLog(String.format("logcat-%s_%s", test.getClassName(), test.getTestName()),
                     LogDataType.TEXT, logSource);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 12adb9f..43aaf98 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -64,7 +64,6 @@
         new BatchRunConfiguration("rgba8888d24s8", "unspecified", "window");
 
     private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 60000; // one minute
-    private static final int FILE_REMOVE_RETRY_INTERVAL = 2000; // 2 seconds
 
     private final String mPackageName;
     private final String mName;
@@ -79,7 +78,6 @@
     private Set<String> mDeviceFeatures;
     private Map<String, Boolean> mConfigQuerySupportCache = new HashMap<>();
     private IRunUtil mRunUtil = RunUtil.getDefault();
-    private ISleepProvider mSleepProvider = new SleepProvider();
 
     private IRecovery mDeviceRecovery = new Recovery();
     {
@@ -154,15 +152,6 @@
     }
 
     /**
-     * Sets the sleep provider DeqpTestRunner works on.
-     *
-     * Exposed for unit testing.
-     */
-    public void setSleepProvider(ISleepProvider sleepProvider) {
-        mSleepProvider = sleepProvider;
-    }
-
-    /**
      * Set IRunUtil.
      *
      * Exposed for unit testing.
@@ -777,12 +766,12 @@
         public void recoverConnectionRefused() throws DeviceNotAvailableException;
 
         /**
-         * Tries to recover device after abnormal termination of a command or a test run execution
-         * or link failure.
+         * Tries to recover device after abnormal execution termination or link failure.
          *
+         * @param progressedSinceLastCall true if test execution has progressed since last call
          * @throws DeviceNotAvailableException if recovery did not succeed
          */
-        public void recoverCommandNotCompleted() throws DeviceNotAvailableException;
+        public void recoverComLinkKilled() throws DeviceNotAvailableException;
     };
 
     /**
@@ -875,7 +864,7 @@
          * {@inheritDoc}
          */
         @Override
-        public void recoverCommandNotCompleted() throws DeviceNotAvailableException {
+        public void recoverComLinkKilled() throws DeviceNotAvailableException {
             switch (mState) {
                 case WAIT:
                     // First failure, just try to wait and try again
@@ -890,10 +879,10 @@
                         killDeqpProcess();
                     } catch (DeviceNotAvailableException ex) {
                         // chain forward
-                        recoverCommandNotCompleted();
+                        recoverComLinkKilled();
                     } catch (ProcessKillFailureException ex) {
                         // chain forward
-                        recoverCommandNotCompleted();
+                        recoverComLinkKilled();
                     }
                     break;
 
@@ -907,10 +896,10 @@
                         killDeqpProcess();
                     } catch (DeviceNotAvailableException ex) {
                         // chain forward
-                        recoverCommandNotCompleted();
+                        recoverComLinkKilled();
                     } catch (ProcessKillFailureException ex) {
                         // chain forward
-                        recoverCommandNotCompleted();
+                        recoverComLinkKilled();
                     }
                     break;
 
@@ -923,7 +912,7 @@
                         rebootDevice();
                     } catch (DeviceNotAvailableException ex) {
                         // chain forward
-                        recoverCommandNotCompleted();
+                        recoverComLinkKilled();
                     }
                     break;
 
@@ -1408,51 +1397,6 @@
         }
     }
 
-    private static final class FileRecreateFailedException extends Exception {
-    };
-
-    /**
-     * Creates a log file suitable for writing.
-     *
-     * Creates an empty file that is suitable for writing. If target file already exists, it will
-     * first be removed and then recreated. This delete-recreate cycle should guarantee that the
-     * target file is always writable and is not affected by file-access flags of the pre-existing
-     * file.
-     *
-     * Precreating a file in the runner makes detecting file-access issues faster and more
-     * reliable. It also avoids issues caused by sdcard FUSE spuriously preventing file creation.
-     */
-    private void precreateLogFile() throws DeviceNotAvailableException,
-            FileRecreateFailedException {
-        final int NUM_ATTEMPTS = 4;
-        int attemptNum = 0;
-        for (;;) {
-            mDevice.executeShellCommand("rm " + LOG_FILE_NAME);
-            ++attemptNum;
-
-            if (!mDevice.doesFileExist(LOG_FILE_NAME)) {
-                // yay, remove works like it should
-                break;
-            } else if (attemptNum < NUM_ATTEMPTS) {
-                // wait if we failed
-                CLog.w("Remote file removal failed, retrying...");
-                mSleepProvider.sleep(FILE_REMOVE_RETRY_INTERVAL);
-            } else {
-                // Bail
-                CLog.e("Could not delete a remote file.");
-                throw new FileRecreateFailedException();
-            }
-        }
-
-        // create & truncate and make world read-writable
-        mDevice.pushString("", LOG_FILE_NAME);
-
-        if (!mDevice.doesFileExist(LOG_FILE_NAME)) {
-            CLog.e("Could not precreate log file.");
-            throw new FileRecreateFailedException();
-        }
-    }
-
     /**
      * Runs one execution pass over the given batch.
      *
@@ -1468,8 +1412,8 @@
 
         final String testCases = generateTestCaseTrie(batch.tests);
 
-        // Caselist file cannot linger.
         mDevice.executeShellCommand("rm " + CASE_LIST_FILE_NAME);
+        mDevice.executeShellCommand("rm " + LOG_FILE_NAME);
         mDevice.pushString(testCases + "\n", CASE_LIST_FILE_NAME);
 
         final String instrumentationName =
@@ -1499,9 +1443,6 @@
         Throwable interruptingError = null;
 
         try {
-            // we might have lingering log file from a previous dirty run and it might be somehow
-            // locked (details unknown). Make sure it's writable when test is run.
-            precreateLogFile();
             executeShellCommandAndReadOutput(command, parser);
         } catch (Throwable ex) {
             interruptingError = ex;
@@ -1521,9 +1462,7 @@
             if (interruptingError instanceof AdbComLinkOpenError) {
                 mDeviceRecovery.recoverConnectionRefused();
             } else if (interruptingError instanceof AdbComLinkKilledError) {
-                mDeviceRecovery.recoverCommandNotCompleted();
-            } else if (interruptingError instanceof FileRecreateFailedException) {
-                mDeviceRecovery.recoverCommandNotCompleted();
+                mDeviceRecovery.recoverComLinkKilled();
             } else if (interruptingError instanceof RunInterruptedException) {
                 // external run interruption request. Terminate immediately.
                 throw (RunInterruptedException)interruptingError;
@@ -1534,7 +1473,7 @@
 
             // recoverXXX did not throw => recovery succeeded
         } else if (!parser.wasSuccessful()) {
-            mDeviceRecovery.recoverCommandNotCompleted();
+            mDeviceRecovery.recoverComLinkKilled();
             // recoverXXX did not throw => recovery succeeded
         }
 
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
index f276f1d..12c3ddd 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/TestPackageDef.java
@@ -308,9 +308,6 @@
         instrTest.setRunName(mAppPackageName);
         instrTest.setPackageName(mAppNameSpace);
         instrTest.setRunnerName(mRunner);
-        instrTest.setTestPackageName(mTestPackageName);
-        instrTest.setClassName(mClassName);
-        instrTest.setMethodName(mMethodName);
         instrTest.setAbi(mAbi);
         instrTest.setTestsToRun(mTests, false
             /* force batch mode off to always run using testFile */);
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
index 4c879b4..7ec09c9 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
@@ -106,7 +106,7 @@
          * {@inheritDoc}
          */
         @Override
-        public void recoverCommandNotCompleted() throws DeviceNotAvailableException {
+        public void recoverComLinkKilled() throws DeviceNotAvailableException {
         }
     };
 
@@ -1717,14 +1717,11 @@
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
                 .andReturn("").once();
 
-        EasyMock.expect(mockDevice.pushString("{dEQP-GLES3{loss{instance}}}\n", CASE_LIST_FILE_NAME))
-                .andReturn(true).once();
-
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
                 .andReturn("").once();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(false).once();
-        EasyMock.expect(mockDevice.pushString("", LOG_FILE_NAME)).andReturn(true).once();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
+
+        EasyMock.expect(mockDevice.pushString("{dEQP-GLES3{loss{instance}}}\n", CASE_LIST_FILE_NAME))
+                .andReturn(true).once();
 
         String command = String.format(
                 "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
@@ -1756,10 +1753,10 @@
         });
 
         if (!recoverySuccessful) {
-            mockRecovery.recoverCommandNotCompleted();
+            mockRecovery.recoverComLinkKilled();
             EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()).once();
         } else {
-            mockRecovery.recoverCommandNotCompleted();
+            mockRecovery.recoverComLinkKilled();
             EasyMock.expectLastCall().once();
 
             // retry running config B
@@ -1863,7 +1860,7 @@
                     recovery.recoverConnectionRefused();
                     break;
                 case FAIL_LINK_KILLED:
-                    recovery.recoverCommandNotCompleted();
+                    recovery.recoverComLinkKilled();
                     break;
             }
         }
@@ -2144,7 +2141,7 @@
         orderedControl.replay();
         recovery.setDevice(mockDevice);
         recovery.setSleepProvider(mockSleepProvider);
-        recovery.recoverCommandNotCompleted();
+        recovery.recoverComLinkKilled();
         orderedControl.verify();
     }
 
@@ -2315,216 +2312,16 @@
         EasyMock.verify(mockDevice, mockIDevice);
     }
 
-    /**
-     * Test log file precreate persistent failure
-     */
-    public void testPrecreate_persistentFailure() throws Exception {
-        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.precreate", "test");
-        final String testTrie = "{dEQP-GLES3{precreate{test}}}";
-
-        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
-        tests.add(testId);
-
-        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
-        instance.put(testId, DEFAULT_INSTANCE_ARGS);
-
-        ITestInvocationListener mockListener
-                = EasyMock.createStrictMock(ITestInvocationListener.class);
-        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
-        IDevice mockIDevice = EasyMock.createMock(IDevice.class);
-        DeqpTestRunner.ISleepProvider mockSleepProvider =
-                EasyMock.createMock(DeqpTestRunner.ISleepProvider.class);
-        DeqpTestRunner.IRecovery mockRecovery =
-                EasyMock.createMock(DeqpTestRunner.IRecovery.class);
-
-        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
-        deqpTest.setAbi(UnitTests.ABI);
-        deqpTest.setDevice(mockDevice);
-        deqpTest.setBuildHelper(new StubCtsBuildHelper());
-        deqpTest.setSleepProvider(mockSleepProvider);
-        deqpTest.setRecovery(mockRecovery);
-
-        mockRecovery.setDevice(mockDevice);
-        EasyMock.expectLastCall().atLeastOnce();
-
-        int version = 3 << 16;
-        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
-                .andReturn(Integer.toString(version)).atLeastOnce();
-
-        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
-            andReturn("").once();
-
-        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
-                EasyMock.eq(true),
-                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
-                .once();
-
-        expectRenderConfigQuery(mockDevice,
-                "--deqp-gl-config-name=rgba8888d24s8 --deqp-screen-rotation=unspecified "
-                + "--deqp-surface-type=window --deqp-gl-major-version=3 "
-                + "--deqp-gl-minor-version=0");
-
-        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
-                .andReturn("").once();
-
-        EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
-                .andReturn(true).once();
-
-        // fail persistently...
-        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
-                .andReturn("").anyTimes();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).anyTimes();
-        mockSleepProvider.sleep(EasyMock.gt(0));
-        EasyMock.expectLastCall().anyTimes();
-
-        // ..and when retries won't help, trigger recovery tactics
-        mockRecovery.recoverCommandNotCompleted();
-        EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()).once();
-
-        mockListener.testRunStarted(ID, 1);
-        EasyMock.expectLastCall().once();
-
-        EasyMock.replay(mockDevice, mockIDevice);
-        EasyMock.replay(mockListener);
-        EasyMock.replay(mockSleepProvider);
-        EasyMock.replay(mockRecovery);
-        try {
-            deqpTest.run(mockListener);
-            fail("expected DeviceNotAvailableException");
-        } catch (DeviceNotAvailableException ex) {
-            // expected
-        }
-        EasyMock.verify(mockRecovery);
-        EasyMock.verify(mockSleepProvider);
-        EasyMock.verify(mockListener);
-        EasyMock.verify(mockDevice, mockIDevice);
-    }
-
-    /**
-     * Test log file precreate transient failure
-     */
-    public void testPrecreate_transientFailure() throws Exception {
-        final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.precreate", "test");
-        final String testPath = "dEQP-GLES3.precreate.test";
-        final String testTrie = "{dEQP-GLES3{precreate{test}}}";
-        final String output = "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=" + testPath + "\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=DetailPass\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
-                + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
-                + "INSTRUMENTATION_CODE: 0\r\n";
-
-        Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
-        tests.add(testId);
-
-        Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
-        instance.put(testId, DEFAULT_INSTANCE_ARGS);
-
-        ITestInvocationListener mockListener
-                = EasyMock.createStrictMock(ITestInvocationListener.class);
-        ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
-        IDevice mockIDevice = EasyMock.createMock(IDevice.class);
-        DeqpTestRunner.ISleepProvider mockSleepProvider =
-                EasyMock.createMock(DeqpTestRunner.ISleepProvider.class);
-
-        DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
-        deqpTest.setAbi(UnitTests.ABI);
-        deqpTest.setDevice(mockDevice);
-        deqpTest.setBuildHelper(new StubCtsBuildHelper());
-        deqpTest.setSleepProvider(mockSleepProvider);
-
-        int version = 3 << 16;
-        EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
-                .andReturn(Integer.toString(version)).atLeastOnce();
-
-        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
-            andReturn("").once();
-
-        EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
-                EasyMock.eq(true),
-                EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
-                .once();
-
-        expectRenderConfigQuery(mockDevice,
-                "--deqp-gl-config-name=rgba8888d24s8 --deqp-screen-rotation=unspecified "
-                + "--deqp-surface-type=window --deqp-gl-major-version=3 "
-                + "--deqp-gl-minor-version=0");
-
-        // fail once
-        EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
-                .andReturn("").once();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
-        mockSleepProvider.sleep(EasyMock.gt(0));
-        EasyMock.expectLastCall().once();
-
-        String commandLine = String.format(
-                "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
-                + "--deqp-screen-rotation=unspecified "
-                + "--deqp-surface-type=window "
-                + "--deqp-log-images=disable "
-                + "--deqp-watchdog=enable",
-                CASE_LIST_FILE_NAME);
-
-        runInstrumentationLineAndAnswer(mockDevice, mockIDevice, testTrie, commandLine,
-                output);
-
-        EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
-            andReturn("").once();
-
-        mockListener.testRunStarted(ID, 1);
-        EasyMock.expectLastCall().once();
-
-        mockListener.testStarted(EasyMock.eq(testId));
-        EasyMock.expectLastCall().once();
-
-        mockListener.testEnded(EasyMock.eq(testId), EasyMock.<Map<String, String>>notNull());
-        EasyMock.expectLastCall().once();
-
-        mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
-        EasyMock.expectLastCall().once();
-
-        EasyMock.replay(mockDevice, mockIDevice);
-        EasyMock.replay(mockListener);
-        EasyMock.replay(mockSleepProvider);
-        deqpTest.run(mockListener);
-        EasyMock.verify(mockSleepProvider);
-        EasyMock.verify(mockListener);
-        EasyMock.verify(mockDevice, mockIDevice);
-    }
-
     private void runInstrumentationLineAndAnswer(ITestDevice mockDevice, IDevice mockIDevice,
             final String testTrie, final String cmd, final String output) throws Exception {
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
                 .andReturn("").once();
 
-        EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
-                .andReturn(true).once();
-
         EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
                 .andReturn("").once();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(false).once();
-        EasyMock.expect(mockDevice.pushString("", LOG_FILE_NAME)).andReturn(true).once();
-        EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
+
+        EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
+                .andReturn(true).once();
 
         String command = String.format(
                 "am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \"%s\" "