Merge "Revert "Apply requested DRM info test changes"" into nougat-cts-dev
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
index abc8033..142ffff 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
@@ -1,18 +1,11 @@
 <?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.
--->
+<!-- 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"
@@ -24,54 +17,285 @@
     <ScrollView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:id="@+id/scrollView"
-    >
+        android:id="@+id/scrollView">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical"
-        >
+            android:orientation="vertical">
 
-        <TextView
+            <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:scrollbars="vertical"
                 android:gravity="bottom"
-                android:id="@+id/audio_frequency_unprocessed_defined"/>
-
-                <ProgressBar
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_weight="1"
-                    android:id="@+id/audio_frequency_unprocessed_progress_bar" />
+                android:id="@+id/audio_frequency_unprocessed_defined" />
 
             <LinearLayout
-                android:layout_width="wrap_content"
+                android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="vertical"
-                android:id="@+id/audio_frequency_unprocessed_layout_test1"
+                android:id="@+id/unprocessed_layout_test_tone"
             >
 
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_instructions2"
-                    android:id="@+id/audio_frequency_unprocessed_instructions2" />
-
-                <Button
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_test1_btn"
-                    android:id="@+id/audio_frequency_unprocessed_test1_btn" />
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
 
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/audio_frequency_unprocessed_results_text"
-                    android:id="@+id/audio_frequency_unprocessed_results1_text" />
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_tone_instructions"
+                    android:id="@+id/unprocessed_test_tone_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_tone_btn"
+                            android:id="@+id/unprocessed_test_tone_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_tone_progress_bar" />
+
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_tone_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_tone_result"
+                    android:id="@+id/unprocessed_test_tone_result" />
             </LinearLayout>
 
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_noise_instructions"
+                    android:id="@+id/unprocessed_test_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_noise_btn"
+                            android:id="@+id/unprocessed_test_noise_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_noise_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_noise_result"
+                    android:id="@+id/unprocessed_test_noise_result" />
+            </LinearLayout>
+
+        <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_usb_background">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_usb_background_instructions"
+                    android:id="@+id/unprocessed_test_usb_background_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_usb_background_btn"
+                            android:id="@+id/unprocessed_test_usb_background_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_usb_background_progress_bar" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_usb_background_result"
+                    android:id="@+id/unprocessed_test_usb_background_result" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"
+                android:id="@+id/unprocessed_layout_test_usb_noise">
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="1dp"
+                    android:background="?android:colorAccent" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:scrollbars="vertical"
+                    android:gravity="bottom"
+                    android:text="@string/unprocessed_test_usb_noise_instructions"
+                    android:id="@+id/unprocessed_test_usb_noise_instructions" />
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="2">
+
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_test_usb_noise_btn"
+                            android:id="@+id/unprocessed_test_usb_noise_btn" />
+                        <ProgressBar
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_weight="1"
+                            android:id="@+id/unprocessed_test_usb_noise_progress_bar" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="1dp"
+                        android:layout_height="match_parent"
+                        android:background="?android:colorAccent" />
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="wrap_content"
+                        android:orientation="vertical"
+                        android:layout_weight="1">
+                        <Button
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:soundEffectsEnabled="false"
+                            android:text="@string/unprocessed_play"
+                            android:id="@+id/unprocessed_play_usb_noise_btn" />
+                    </LinearLayout>
+                </LinearLayout>
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_usb_noise_result"
+                    android:id="@+id/unprocessed_test_usb_noise_result" />
+            </LinearLayout>
+             <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="?android:colorAccent" />
+
+            <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:text="@string/unprocessed_test_global_result"
+                    android:id="@+id/unprocessed_test_global_result" />
 
             <include layout="@layout/pass_fail_buttons" />
         </LinearLayout>
diff --git a/apps/CtsVerifier/res/raw/onekhztone.mp3 b/apps/CtsVerifier/res/raw/onekhztone.mp3
new file mode 100644
index 0000000..c0e6660
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/onekhztone.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 84076bc..50703d9 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2738,7 +2738,7 @@
     <string name="audio_general_headset_yes">Yes</string>
     <string name="audio_general_deficiency_found">WARNING: Some results show potential deficiencies on the system.
     Please consider addressing them for a future release.</string>
-    <string name="audio_general_test_passed">Test Successful</string>
+    <string name="audio_general_test_passed">Test Result: Successful</string>
     <string name="audio_general_test_failed">Test Result: Not Optimal</string>
     <string name="audio_general_default_false_string">false</string>
     <string name="audio_general_default_true_string">true</string>
@@ -2832,17 +2832,39 @@
      <!-- Audio Frequency Unprocessed Test -->
     <string name="audio_frequency_unprocessed_test">Audio Frequency Unprocessed Test</string>
     <string name="audio_frequency_unprocessed_info">
-   This test requires an external broadband noise source (or click/impulse).
-   Please be prepared to activate the noise source when asked to.
-   The system will measure frequency response of the built in microphone using the UNPROCESSED
-   audio source.
+    This test requires an external USB reference microphone, external speakers and a Sound Pressure Level meter.
+    You can play the test signals from the device under test or from a secondary device.
+    Follow the instructions on the screen to measure the frequency response for the built in microphone
+    using UNPROCESSED audio source.
+    If the Audio Frequency Unprocessed feature is defined in this system, success in all tests is mandatory to pass.
+    If the feature is not defined, measurements are still needed, but success in all of them is not mandatory to pass.
        </string>
-    <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Test is mandatory</string>
-    <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Test is optional</string>
-     <string name="audio_frequency_unprocessed_instructions2">
-          Once you press the [TEST] button, you have 5 seconds to play a broadband sound (click or white noise).
-    </string>
-    <string name="audio_frequency_unprocessed_test1_btn">Test 1</string>
-    <string name="audio_frequency_unprocessed_results_text">Results...</string>
+    <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Success in all tests is mandatory to pass</string>
+    <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Success in all test is NOT mandatory to pass</string>
+
+    <string name="unprocessed_play">Play</string>
+    <string name="unprocessed_stop">Stop</string>
+
+    <string name="unprocessed_test_tone_instructions">TEST TONE: Press [PLAY] to play tone at 1 Khz. Measure sound SPL to be 94 dB
+    right next to microphone under test. Press [TEST]</string>
+    <string name="unprocessed_test_tone_btn">Test</string>
+    <string name="unprocessed_test_tone_result">Results...</string>
+
+    <string name="unprocessed_test_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
+    Press [PLAY] to play broadband white noise. Press [TEST]</string>
+    <string name="unprocessed_test_noise_btn">Test</string>
+    <string name="unprocessed_test_noise_result">Results...</string>
+
+    <string name="unprocessed_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
+    No source of noise should be active during this test. Press [TEST]</string>
+    <string name="unprocessed_test_usb_background_btn">Test</string>
+    <string name="unprocessed_test_usb_background_result">Results...</string>
+
+    <string name="unprocessed_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test. 
+    Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
+    <string name="unprocessed_test_usb_noise_btn">Test</string>
+    <string name="unprocessed_test_usb_noise_result">Results...</string>
+
+    <string name="unprocessed_test_global_result">Global Results...</string>
 
 </resources>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 56275c5..009dd58 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -22,11 +22,11 @@
 import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+
 import android.content.Context;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
-
 import android.media.AudioDeviceCallback;
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
@@ -34,17 +34,13 @@
 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;
@@ -59,25 +55,63 @@
     private static final String TAG = "AudioFrequencyUnprocessedActivity";
 
     private static final int TEST_STARTED = 900;
-    private static final int TEST_ENDED = 901;
-    private static final int TEST_MESSAGE = 902;
-    private static final int TEST1_MESSAGE = 903;
-    private static final int TEST1_ENDED = 904;
-    private static final double MIN_ENERGY_BAND_1 = -50.0;          //dB Full Scale
-    private static final double MAX_ENERGY_BAND_1_BASE = -60.0;     //dB Full Scale
-    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+    private static final int TEST_MESSAGE = 903;
+    private static final int TEST_ENDED = 904;
+    private static final int TEST_ENDED_ERROR = 905;
+    private static final double MIN_FRACTION_POINTS_IN_BAND = 0.5;
+
+    private static final double TONE_RMS_EXPECTED = -36.0;
+    private static final double TONE_RMS_MAX_ERROR = 3.0;
+
     private static final double MAX_VAL = Math.pow(2, 15);
     private static final double CLIP_LEVEL = (MAX_VAL-10) / MAX_VAL;
 
+    private static final int SOURCE_TONE = 0;
+    private static final int SOURCE_NOISE = 1;
+
+    private static final int TEST_NONE = -1;
+    private static final int TEST_TONE = 0;
+    private static final int TEST_NOISE = 1;
+    private static final int TEST_USB_BACKGROUND = 2;
+    private static final int TEST_USB_NOISE = 3;
+    private static final int TEST_COUNT = 4;
+    private int mCurrentTest = TEST_NONE;
+    private boolean mTestsDone[] = new boolean[TEST_COUNT];
+
+    private static final int TEST_DURATION_DEFAULT = 2000;
+    private static final int TEST_DURATION_TONE = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_NOISE = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_USB_BACKGROUND = TEST_DURATION_DEFAULT;
+    private static final int TEST_DURATION_USB_NOISE = TEST_DURATION_DEFAULT;
+
     final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
     Context mContext;
 
-    Button mTest1Button;                //execute test 1
-    Button mTest2Button;                 //user to start test
-    String mUsbDevicesInfo;             //usb device info for report
-    LinearLayout mLayoutTest1;
-    TextView mTest1Result;
-    ProgressBar mProgressBar;
+    LinearLayout mLayoutTestTone;
+    Button mButtonTestTone;
+    ProgressBar mProgressTone;
+    TextView mResultTestTone;
+    Button mButtonPlayTone;
+
+    LinearLayout mLayoutTestNoise;
+    Button mButtonTestNoise;
+    ProgressBar mProgressNoise;
+    TextView mResultTestNoise;
+    Button mButtonPlayNoise;
+
+    LinearLayout mLayoutTestUsbBackground;
+    Button mButtonTestUsbBackground;
+    ProgressBar mProgressUsbBackground;
+    TextView mResultTestUsbBackground;
+
+    LinearLayout mLayoutTestUsbNoise;
+    Button mButtonTestUsbNoise;
+    ProgressBar mProgressUsbNoise;
+    TextView mResultTestUsbNoise;
+    Button mButtonPlayUsbNoise;
+
+    TextView mGlobalResultText;
+    TextView mTextViewUnprocessedStatus;
 
     private boolean mIsRecording = false;
     private final Object mRecordingLock = new Object();
@@ -95,6 +129,8 @@
 
     PipeShort mPipe = new PipeShort(65536);
 
+    SoundPlayerObject mSPlayer;
+
     private boolean mSupportsUnprocessed = false;
 
     private DspBufferComplex mC;
@@ -102,25 +138,27 @@
 
     private DspWindow mWindow;
     private DspFftServer mFftServer;
-    private VectorAverage mFreqAverageMain = new VectorAverage();
-    private VectorAverage mFreqAverageBuiltIn = new VectorAverage();
+    private VectorAverage mFreqAverageTone = new VectorAverage();
+    private VectorAverage mFreqAverageNoise = new VectorAverage();
+    private VectorAverage mFreqAverageUsbBackground = new VectorAverage();
+    private VectorAverage mFreqAverageUsbNoise = new VectorAverage();
 
-    int mBands = 4;
-    AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
-    private TextView mTextViewUnprocessedStatus;
+    //RMS for tone:
+    private double mRMS;
+    private double mRMSMax;
 
-    private class OnBtnClickListener implements OnClickListener {
-        @Override
-        public void onClick(View v) {
-            switch (v.getId()) {
-            case R.id.audio_frequency_unprocessed_test1_btn:
-                setMaxLevel();
-                testMaxLevel();
-                startTest1();
-                break;
-            }
-        }
-    }
+    private double mRMSTone;
+    private double mRMSMaxTone;
+
+    int mBands = 3;
+    int mBandsTone = 3;
+    int mBandsBack = 3;
+    AudioBandSpecs[] mBandSpecsMic = new AudioBandSpecs[mBands];
+    AudioBandSpecs[] mBandSpecsTone = new AudioBandSpecs[mBandsTone];
+    AudioBandSpecs[] mBandSpecsBack = new AudioBandSpecs[mBandsBack];
+    private Results mResultsMic;
+    private Results mResultsTone;
+    private Results mResultsBack;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
@@ -139,13 +177,51 @@
                     getResources().getText(R.string.audio_frequency_unprocessed_not_defined));
         }
 
-        mTest1Button = (Button)findViewById(R.id.audio_frequency_unprocessed_test1_btn);
-        mTest1Button.setOnClickListener(mBtnClickListener);
-        mTest1Result = (TextView)findViewById(R.id.audio_frequency_unprocessed_results1_text);
-        mLayoutTest1 = (LinearLayout) findViewById(R.id.audio_frequency_unprocessed_layout_test1);
-        mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_unprocessed_progress_bar);
-        showWait(false);
-        enableLayout(mLayoutTest1, true);
+        mSPlayer = new SoundPlayerObject();
+        playerSetSource(SOURCE_TONE);
+
+        // Test tone
+        mLayoutTestTone = (LinearLayout) findViewById(R.id.unprocessed_layout_test_tone);
+        mButtonTestTone = (Button) findViewById(R.id.unprocessed_test_tone_btn);
+        mButtonTestTone.setOnClickListener(mBtnClickListener);
+        mProgressTone = (ProgressBar) findViewById(R.id.unprocessed_test_tone_progress_bar);
+        mResultTestTone = (TextView) findViewById(R.id.unprocessed_test_tone_result);
+        mButtonPlayTone = (Button) findViewById(R.id.unprocessed_play_tone_btn);
+        mButtonPlayTone.setOnClickListener(mBtnClickListener);
+        showWait(mProgressTone, false);
+
+        //Test Noise
+        mLayoutTestNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_noise);
+        mButtonTestNoise = (Button) findViewById(R.id.unprocessed_test_noise_btn);
+        mButtonTestNoise.setOnClickListener(mBtnClickListener);
+        mProgressNoise = (ProgressBar) findViewById(R.id.unprocessed_test_noise_progress_bar);
+        mResultTestNoise = (TextView) findViewById(R.id.unprocessed_test_noise_result);
+        mButtonPlayNoise = (Button) findViewById(R.id.unprocessed_play_noise_btn);
+        mButtonPlayNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressNoise, false);
+
+        //USB Background
+        mLayoutTestUsbBackground = (LinearLayout)
+                findViewById(R.id.unprocessed_layout_test_usb_background);
+        mButtonTestUsbBackground = (Button) findViewById(R.id.unprocessed_test_usb_background_btn);
+        mButtonTestUsbBackground.setOnClickListener(mBtnClickListener);
+        mProgressUsbBackground = (ProgressBar)
+                findViewById(R.id.unprocessed_test_usb_background_progress_bar);
+        mResultTestUsbBackground = (TextView)
+                findViewById(R.id.unprocessed_test_usb_background_result);
+        showWait(mProgressUsbBackground, false);
+
+        mLayoutTestUsbNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_usb_noise);
+        mButtonTestUsbNoise = (Button) findViewById(R.id.unprocessed_test_usb_noise_btn);
+        mButtonTestUsbNoise.setOnClickListener(mBtnClickListener);
+        mProgressUsbNoise = (ProgressBar)findViewById(R.id.unprocessed_test_usb_noise_progress_bar);
+        mResultTestUsbNoise = (TextView) findViewById(R.id.unprocessed_test_usb_noise_result);
+        mButtonPlayUsbNoise = (Button) findViewById(R.id.unprocessed_play_usb_noise_btn);
+        mButtonPlayUsbNoise.setOnClickListener(mBtnClickListener);
+        showWait(mProgressUsbNoise, false);
+
+        setButtonPlayStatus(-1);
+        mGlobalResultText = (TextView) findViewById(R.id.unprocessed_test_global_result);
 
         //Init FFT stuff
         mAudioShortArray2 = new short[mBlockSizeSamples*2];
@@ -162,29 +238,141 @@
         setInfoResources(R.string.audio_frequency_unprocessed_test,
                 R.string.audio_frequency_unprocessed_info, -1);
 
-        //Init bands for BuiltIn/Reference test
-        bandSpecsArray[0] = new AudioBandSpecs(
-                2, 500,         /* frequency start,stop */
-                30.0, -50,     /* start top,bottom value */
-                30.0, -4.0       /* stop top,bottom value */);
+        //Init bands for Mic test
+        mBandSpecsMic[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                20.0, -20.0,     /* start top,bottom value */
+                20.0, -20.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 */);
+        mBandSpecsMic[1] = new AudioBandSpecs(
+                100, 7000,       /* frequency start,stop */
+                10.0, -10.0,     /* start top,bottom value */
+                10.0, -10.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 */);
+        mBandSpecsMic[2] = new AudioBandSpecs(
+                7000, 20000,     /* frequency start,stop */
+                30.0, -30.0,     /* start top,bottom value */
+                30.0, -30.0      /* stop top,bottom value */);
 
-        bandSpecsArray[3] = new AudioBandSpecs(
-                12000, 20000,   /* frequency start,stop */
-                5.0, -5.0,      /* start top,bottom value */
-                5.0, -30.0      /* stop top,bottom value */);
+        //Init bands for Tone test
+        mBandSpecsTone[0] = new AudioBandSpecs(
+                5, 900,          /* frequency start,stop */
+                -10.0, -100.0,     /* start top,bottom value */
+                -10.0, -100.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[1] = new AudioBandSpecs(
+                900, 1100,       /* frequency start,stop */
+                10.0, -50.0,     /* start top,bottom value */
+                10.0, -10.0      /* stop top,bottom value */);
+
+        mBandSpecsTone[2] = new AudioBandSpecs(
+                1100, 20000,     /* frequency start,stop */
+                -30.0, -120.0,     /* start top,bottom value */
+                -30.0, -120.0      /* stop top,bottom value */);
+
+      //Init bands for Background test
+        mBandSpecsBack[0] = new AudioBandSpecs(
+                5, 100,          /* frequency start,stop */
+                10.0, -120.0,     /* start top,bottom value */
+                -10.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[1] = new AudioBandSpecs(
+                100, 7000,       /* frequency start,stop */
+                -10.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
+
+        mBandSpecsBack[2] = new AudioBandSpecs(
+                7000, 20000,     /* frequency start,stop */
+                -50.0, -120.0,     /* start top,bottom value */
+                -50.0, -120.0      /* stop top,bottom value */);
 
         mSupportsUnprocessed = supportsUnprocessed();
         Log.v(TAG, "Supports unprocessed: " + mSupportsUnprocessed);
+
+        mResultsMic =  new Results("mic_response", mBands);
+        mResultsTone = new Results("tone_response", mBandsTone);
+        mResultsBack = new Results("background_response", mBandsBack);
+    }
+
+    private void playerToggleButton(int buttonId, int sourceId) {
+        if (playerIsPlaying()) {
+            playerStopAll();
+        } else {
+            playerSetSource(sourceId);
+            playerTransport(true);
+            setButtonPlayStatus(buttonId);
+        }
+    }
+
+    private class OnBtnClickListener implements OnClickListener {
+        @Override
+        public void onClick(View v) {
+            int id = v.getId();
+            switch (id) {
+            case R.id.unprocessed_test_tone_btn:
+                startTest(TEST_TONE);
+                break;
+            case R.id.unprocessed_play_tone_btn:
+                playerToggleButton(id, SOURCE_TONE);
+                break;
+            case R.id.unprocessed_test_noise_btn:
+                startTest(TEST_NOISE);
+                break;
+            case R.id.unprocessed_play_noise_btn:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            case R.id.unprocessed_test_usb_background_btn:
+                startTest(TEST_USB_BACKGROUND);
+                break;
+            case R.id.unprocessed_test_usb_noise_btn:
+                startTest(TEST_USB_NOISE);
+                break;
+            case R.id.unprocessed_play_usb_noise_btn:
+                playerToggleButton(id, SOURCE_NOISE);
+                break;
+            }
+        }
+    }
+
+    private void setButtonPlayStatus(int playResId) {
+        String play = getResources().getText(R.string.unprocessed_play).toString();
+        String stop = getResources().getText(R.string.unprocessed_stop).toString();
+
+        mButtonPlayTone.setText(playResId == R.id.unprocessed_play_tone_btn ? stop : play);
+        mButtonPlayNoise.setText(playResId == R.id.unprocessed_play_noise_btn ? stop : play);
+        mButtonPlayUsbNoise.setText(playResId ==
+                R.id.unprocessed_play_usb_noise_btn ? stop : play);
+    }
+
+    private void playerSetSource(int sourceIndex) {
+        switch (sourceIndex) {
+            case SOURCE_TONE:
+                mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.onekhztone);
+                break;
+            default:
+            case SOURCE_NOISE:
+                mSPlayer.setSoundWithResId(getApplicationContext(),
+                        R.raw.stereo_mono_white_noise_48);
+                break;
+        }
+    }
+
+    private void playerTransport(boolean play) {
+        if (!mSPlayer.isAlive()) {
+            mSPlayer.start();
+        }
+        mSPlayer.play(play);
+    }
+
+    private boolean playerIsPlaying() {
+       return mSPlayer.isPlaying();
+    }
+
+    private void playerStopAll() {
+        if (mSPlayer.isAlive() && mSPlayer.isPlaying()) {
+            mSPlayer.play(false);
+            setButtonPlayStatus(-1);
+        }
     }
 
     /**
@@ -197,14 +385,66 @@
         }
     }
 
-    /**
-     * show active progress bar
-     */
-    private void showWait(boolean show) {
+    private void showWait(ProgressBar pb, boolean show) {
         if (show) {
-            mProgressBar.setVisibility(View.VISIBLE);
+            pb.setVisibility(View.VISIBLE);
         } else {
-            mProgressBar.setVisibility(View.INVISIBLE);
+            pb.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    private String getTestString(int testId) {
+        String name = "undefined";
+        switch(testId) {
+            case TEST_TONE:
+                name = "BuiltIn_tone";
+                break;
+            case TEST_NOISE:
+                name = "BuiltIn_noise";
+                break;
+            case TEST_USB_BACKGROUND:
+                name = "USB_background";
+                break;
+            case TEST_USB_NOISE:
+                name = "USB_noise";
+                break;
+        }
+        return name;
+    }
+
+    private void showWait(int testId, boolean show) {
+        switch(testId) {
+            case TEST_TONE:
+                showWait(mProgressTone, show);
+                break;
+            case TEST_NOISE:
+                showWait(mProgressNoise, show);
+                break;
+            case TEST_USB_BACKGROUND:
+                showWait(mProgressUsbBackground, show);
+                break;
+            case TEST_USB_NOISE:
+                showWait(mProgressUsbNoise, show);
+                break;
+        }
+    }
+
+    private void showMessage(int testId, String msg) {
+        if (msg != null && msg.length() > 0) {
+            switch(testId) {
+                case TEST_TONE:
+                    mResultTestTone.setText(msg);
+                    break;
+                case TEST_NOISE:
+                    mResultTestNoise.setText(msg);
+                    break;
+                case TEST_USB_BACKGROUND:
+                    mResultTestUsbBackground.setText(msg);
+                    break;
+                case TEST_USB_NOISE:
+                    mResultTestUsbNoise.setText(msg);
+                    break;
+            }
         }
     }
 
@@ -224,47 +464,320 @@
         return unprocessedSupport;
     }
 
-    /**
-     *  Start the loopback audio test
-     */
-    private void startTest1() {
+    private void computeAllResults() {
+        StringBuilder sb = new StringBuilder();
+
+        boolean allDone = true;
+
+        for (int i=0; i<TEST_COUNT; i++) {
+            allDone = allDone & mTestsDone[i];
+            sb.append(String.format("%s : %s\n", getTestString(i),
+                    mTestsDone[i] ? "DONE" :" NOT DONE"));
+        }
+
+        if (allDone) {
+            sb.append(computeResults());
+        } else {
+            sb.append("Please execute all tests for results\n");
+        }
+        mGlobalResultText.setText(sb.toString());
+    }
+
+    private void processSpectrum(Results results, AudioBandSpecs[] bandsSpecs, int anchorBand) {
+        int points = results.mValuesLog.length;
+        int bandCount = bandsSpecs.length;
+        int currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+            if (freq > bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+                results.mPointsPerBand[currentBand]++;
+            }
+        }
+
+        for (int b = 0; b < bandCount; b++) {
+            if (results.mPointsPerBand[b] > 0) {
+                results.mAverageEnergyPerBand[b] =
+                        results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+            }
+        }
+
+        //set offset relative to band anchor band level
+        for (int b = 0; b < bandCount; b++) {
+            if (anchorBand > -1 && anchorBand < bandCount) {
+                bandsSpecs[b].setOffset(results.mAverageEnergyPerBand[anchorBand]);
+            } else {
+                bandsSpecs[b].setOffset(0);
+            }
+        }
+
+        //test points in band.
+        currentBand = 0;
+        for (int i = 0; i < points; i++) {
+            double freq = (double) mSamplingRate * i / (double) mBlockSizeSamples;
+            if (freq >  bandsSpecs[currentBand].mFreqStop) {
+                currentBand++;
+                if (currentBand >= bandCount)
+                    break;
+            }
+
+            if (freq >= bandsSpecs[currentBand].mFreqStart) {
+                double value = results.mValuesLog[i];
+                if (bandsSpecs[currentBand].isInBounds(freq, value)) {
+                    results.mInBoundPointsPerBand[currentBand]++;
+                }
+            }
+        }
+    }
+
+    private String computeResults() {
+        StringBuilder sb = new StringBuilder();
+
+        int points = mFreqAverageNoise.getSize();
+        //mFreqAverageNoise size is determined by the latest data writen to it.
+        //Currently, this data is always mBlockSizeSamples/2.
+        if (points < 1) {
+            return "error: not enough points";
+        }
+
+        double[] tone = new double[points];
+        double[] noise = new double[points];
+        double[] reference = new double[points];
+        double[] background = new double[points];
+
+        mFreqAverageTone.getData(tone, false);
+        mFreqAverageNoise.getData(noise, false);
+        mFreqAverageUsbNoise.getData(reference, false);
+        mFreqAverageUsbBackground.getData(background, false);
+
+        //Convert to dB
+        double[] toneDb = new double[points];
+        double[] noiseDb = new double[points];
+        double[] referenceDb = new double[points];
+        double[] backgroundDb = new double[points];
+
+        double[] compensatedNoiseDb = new double[points];
+
+        for (int i = 0; i < points; i++) {
+            toneDb[i] = 20 * Math.log10(tone[i]);
+            noiseDb[i] = 20 * Math.log10(noise[i]);
+            referenceDb[i] = 20 * Math.log10(reference[i]);
+            backgroundDb[i] = 20 * Math.log10(background[i]);
+
+            compensatedNoiseDb[i] = noiseDb[i] - referenceDb[i];
+        }
+
+        mResultsMic.reset();
+        mResultsTone.reset();
+        mResultsBack.reset();
+
+        mResultsMic.mValuesLog = compensatedNoiseDb;
+        mResultsTone.mValuesLog = toneDb;
+        mResultsBack.mValuesLog = backgroundDb;
+
+        processSpectrum(mResultsMic, mBandSpecsMic, 1);
+        processSpectrum(mResultsTone, mBandSpecsTone, 1);
+        processSpectrum(mResultsBack, mBandSpecsBack, -1); //no reference for offset
+
+        //Tone test
+        boolean toneTestSuccess = true;
+        {
+            //rms level should be -36 dbfs +/- 3 db?
+            double rmsMaxDb =  20 * Math.log10(mRMSMaxTone);
+            sb.append(String.format("RMS level of tone: %.2f dBFS\n", rmsMaxDb));
+            sb.append(String.format("Target RMS level: %.2f dBFS +/- %.2f dB\n",
+                    TONE_RMS_EXPECTED,
+                    TONE_RMS_MAX_ERROR));
+            if (Math.abs(rmsMaxDb - TONE_RMS_EXPECTED) > TONE_RMS_MAX_ERROR) {
+                toneTestSuccess = false;
+                sb.append("RMS level test FAILED\n");
+            } else {
+                sb.append(" RMS level test SUCCESSFUL\n");
+            }
+            //check the spectrum is really a tone around 1 khz
+        }
+
+        sb.append("\n");
+        sb.append(mResultsTone.toString());
+        if (mResultsTone.testAll()) {
+            sb.append(" 1 Khz Tone Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" 1 Khz Tone Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        sb.append("\n");
+        sb.append(mResultsBack.toString());
+        if (mResultsBack.testAll()) {
+            sb.append(" Background environment Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Background environment Test FAILED\n");
+        }
+
+        sb.append("\n");
+        sb.append(mResultsMic.toString());
+        if (mResultsMic.testAll()) {
+            sb.append(" Frequency Response Test SUCCESSFUL\n");
+        } else {
+            sb.append(" Frequency Response Test FAILED\n");
+        }
+        sb.append("\n");
+
+        recordTestResults(mResultsTone);
+        recordTestResults(mResultsMic);
+
+        boolean allTestsPassed = false;
+        if (mResultsMic.testAll() && mResultsTone.testAll() && toneTestSuccess &&
+                mResultsBack.testAll()) {
+            allTestsPassed = true;
+            String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+            sb.append(strSuccess);
+        } else {
+            String strFailed = getResources().getString(R.string.audio_general_test_failed);
+            sb.append(strFailed);
+        }
+
+        sb.append("\n");
+        if (mSupportsUnprocessed) { //test is mandatory
+            sb.append(getResources().getText(
+                    R.string.audio_frequency_unprocessed_defined).toString());
+            if (allTestsPassed) {
+                getPassButton().setEnabled(true);
+            } else {
+                getPassButton().setEnabled(false);
+            }
+        } else {
+            //test optional
+            sb.append(getResources().getText(
+                    R.string.audio_frequency_unprocessed_not_defined).toString());
+            getPassButton().setEnabled(true);
+        }
+        return sb.toString();
+    }
+
+    Thread mTestThread;
+    private void startTest(int testId) {
         if (mTestThread != null && !mTestThread.isAlive()) {
             mTestThread = null; //kill it.
         }
 
         if (mTestThread == null) {
+            mRMS = 0;
+            mRMSMax = 0;
             Log.v(TAG,"Executing test Thread");
-            mTestThread = new Thread(mTest1Runnable);
+            switch(testId) {
+                case TEST_TONE:
+                    mTestThread = new Thread(new TestRunnable(TEST_TONE) {
+                        public void run() {
+                            super.run();
+                            if (!mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing Built in Microphone: Tone");
+                                mRMSTone = 0;
+                                mRMSMaxTone = 0;
+                                mFreqAverageTone.reset();
+                                mFreqAverageTone.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_TONE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "Please Unplug USB Microphone");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_NOISE:
+                    mTestThread = new Thread(new TestRunnable(TEST_NOISE) {
+                        public void run() {
+                            super.run();
+                            if (!mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing Built in Microphone: Noise");
+                                mFreqAverageNoise.reset();
+                                mFreqAverageNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_NOISE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "Please Unplug USB Microphone");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_USB_BACKGROUND:
+                    playerStopAll();
+                    mTestThread = new Thread(new TestRunnable(TEST_USB_BACKGROUND) {
+                        public void run() {
+                            super.run();
+                            if (mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE,
+                                        "Testing USB Microphone: background");
+                                mFreqAverageUsbBackground.reset();
+                                mFreqAverageUsbBackground.setCaptureType(
+                                        VectorAverage.CAPTURE_TYPE_AVERAGE);
+                                record(TEST_DURATION_USB_BACKGROUND);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "USB Microphone not detected.");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+                case TEST_USB_NOISE:
+                    mTestThread = new Thread(new TestRunnable(TEST_USB_NOISE) {
+                        public void run() {
+                            super.run();
+                            if (mUsbMicConnected) {
+                                sendMessage(mTestId, TEST_MESSAGE, "Testing USB Microphone: Noise");
+                                mFreqAverageUsbNoise.reset();
+                                mFreqAverageUsbNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+                                record(TEST_DURATION_USB_NOISE);
+                                sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+                                mTestsDone[mTestId] = true;
+                            } else {
+                                sendMessage(mTestId, TEST_ENDED_ERROR,
+                                        "USB Microphone not detected.");
+                                mTestsDone[mTestId] = false;
+                            }
+                        }
+                    });
+                break;
+            }
             mTestThread.start();
         } else {
             Log.v(TAG,"test Thread already running.");
         }
     }
-
-    Thread mTestThread;
-    Runnable mTest1Runnable = new Runnable() {
-        public void run() {
-            Message msg = Message.obtain();
-            msg.what = TEST_STARTED;
-            mMessageHandler.sendMessage(msg);
-
-            sendMessage("Testing Built in Microphone");
-            mFreqAverageBuiltIn.reset();
-            mFreqAverageBuiltIn.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
-            play();
-
-            sendMessage("Testing Completed");
-
-            Message msg2 = Message.obtain();
-            msg2.what = TEST1_ENDED;
-            mMessageHandler.sendMessage(msg2);
+    public class TestRunnable implements Runnable {
+        public int mTestId;
+        public boolean mUsbMicConnected;
+        TestRunnable(int testId) {
+            Log.v(TAG,"New TestRunnable");
+            mTestId = testId;
         }
-
-        private void play() {
+        public void run() {
+            mCurrentTest = mTestId;
+            sendMessage(mTestId, TEST_STARTED,"");
+            mUsbMicConnected =
+                    UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+        };
+        public void record(int durationMs) {
             startRecording();
-
             try {
-                Thread.sleep(5000);
+                Thread.sleep(durationMs);
             } catch (InterruptedException e) {
                 e.printStackTrace();
                 //restore interrupted status
@@ -272,41 +785,40 @@
             }
             stopRecording();
         }
-
-        private void sendMessage(String str) {
+        public void sendMessage(int testId, int msgType, String str) {
             Message msg = Message.obtain();
-            msg.what = TEST1_MESSAGE;
+            msg.what = msgType;
             msg.obj = str;
+            msg.arg1 = testId;
             mMessageHandler.sendMessage(msg);
         }
-    };
+    }
 
     private Handler mMessageHandler = new Handler() {
         public void handleMessage(Message msg) {
             super.handleMessage(msg);
+            int testId = msg.arg1; //testId
+            String str = (String) msg.obj;
             switch (msg.what) {
             case TEST_STARTED:
-                showWait(true);
-                getPassButton().setEnabled(false);
+                showWait(testId, true);
+//                getPassButton().setEnabled(false);
+                break;
+            case TEST_MESSAGE:
+                    showMessage(testId, str);
                 break;
             case TEST_ENDED:
-                showWait(false);
-//                computeTest2Results();
+                showWait(testId, false);
+                playerStopAll();
+                showMessage(testId, str);
+                appendResultsToScreen(testId, "test finished");
+                computeAllResults();
                 break;
-            case TEST1_MESSAGE: {
-                    String str = (String)msg.obj;
-                    if (str != null) {
-                        mTest1Result.setText(str);
-                    }
-                }
-                break;
-            case TEST1_ENDED:
-                showWait(false);
-                computeTest1Results();
-                break;
-            case TEST_MESSAGE: {
-                }
-                break;
+            case TEST_ENDED_ERROR:
+                showWait(testId, false);
+                playerStopAll();
+                showMessage(testId, str);
+                computeAllResults();
             default:
                 Log.e(TAG, String.format("Unknown message: %d", msg.what));
             }
@@ -314,21 +826,32 @@
     };
 
     private class Results {
+        private int mBandCount;
         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) {
+        int[] mPointsPerBand; // = new int[mBands];
+        double[] mAverageEnergyPerBand;// = new double[mBands];
+        int[] mInBoundPointsPerBand;// = new int[mBands];
+        public Results(String label, int bandCount) {
             mLabel = label;
+            mBandCount = bandCount;
+            mPointsPerBand = new int[mBandCount];
+            mAverageEnergyPerBand = new double[mBandCount];
+            mInBoundPointsPerBand = new int[mBandCount];
+        }
+        public void reset() {
+            for (int i = 0; i < mBandCount; i++) {
+                mPointsPerBand[i] = 0;
+                mAverageEnergyPerBand[i] = 0;
+                mInBoundPointsPerBand[i] = 0;
+            }
         }
 
         //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" :"Not Optimal") + "\n");
-            for (int b = 0; b < mBands; b++) {
+            for (int b = 0; b < mBandCount; b++) {
                 double percent = 0;
                 if (mPointsPerBand[b] > 0) {
                     percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
@@ -344,15 +867,8 @@
             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 (b >= 0 && b < mBandCount && mPointsPerBand[b] > 0) {
                 if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
                     MIN_FRACTION_POINTS_IN_BAND) {
                         return true;
@@ -362,10 +878,7 @@
         }
 
         public boolean testAll() {
-            if (!testLevel()) {
-                return false;
-            }
-            for (int b = 0; b < mBands; b++) {
+            for (int b = 0; b < mBandCount; b++) {
                 if (!testInBand(b)) {
                     return false;
                 }
@@ -375,98 +888,13 @@
     }
 
 
-    /**
-     * compute test1 results
-     */
-    private void computeTest1Results() {
-        Results resultsBuiltIn = new Results("BuiltIn");
-        if (computeResultsForVector(mFreqAverageBuiltIn, resultsBuiltIn, bandSpecsArray)) {
-            appendResultsToScreen(resultsBuiltIn.toString(), mTest1Result);
-            recordTestResults(resultsBuiltIn);
-        }
-        if (mSupportsUnprocessed) { //test is mandatory
-            appendResultsToScreen(getResources().getText(
-                    R.string.audio_frequency_unprocessed_defined).toString(), mTest1Result);
-            if (resultsBuiltIn.testAll()) {
-                //tst passed
-                getPassButton().setEnabled(true);
-                String strSuccess = getResources().getString(R.string.audio_general_test_passed);
-                appendResultsToScreen(strSuccess, mTest1Result);
-            } else {
-                getPassButton().setEnabled(false);
-                String strFailed = getResources().getString(R.string.audio_general_test_failed);
-                appendResultsToScreen(strFailed, mTest1Result);
-            }
-        } else {
-            //test optional
-            appendResultsToScreen(getResources().getText(
-                    R.string.audio_frequency_unprocessed_not_defined).toString(), mTest1Result);
-            getPassButton().setEnabled(true);
-        }
-    }
-
-    private boolean computeResultsForVector(VectorAverage freqAverage, Results results,
-            AudioBandSpecs[] bandSpecs) {
-
-        int points = freqAverage.getSize();
-        if (points > 0) {
-            //compute vector in db
-            double[] values = new double[points];
-            freqAverage.getData(values, false);
-            results.mValuesLog = new double[points];
-            for (int i = 0; i < points; i++) {
-                results.mValuesLog[i] = 20 * Math.log10(values[i]);
-            }
-
-            int currentBand = 0;
-            for (int i = 0; i < points; i++) {
-                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
-                if (freq > bandSpecs[currentBand].mFreqStop) {
-                    currentBand++;
-                    if (currentBand >= mBands)
-                        break;
-                }
-
-                if (freq >= bandSpecs[currentBand].mFreqStart) {
-                    results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
-                    results.mPointsPerBand[currentBand]++;
-                }
-            }
-
-            for (int b = 0; b < mBands; b++) {
-                if (results.mPointsPerBand[b] > 0) {
-                    results.mAverageEnergyPerBand[b] =
-                            results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
-                }
-            }
-
-            //set offset relative to band 1 level
-            for (int b = 0; b < mBands; b++) {
-                bandSpecs[b].setOffset(results.mAverageEnergyPerBand[1]);
-            }
-
-            //test points in band.
-            currentBand = 0;
-            for (int i = 0; i < points; i++) {
-                double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
-                if (freq >  bandSpecs[currentBand].mFreqStop) {
-                    currentBand++;
-                    if (currentBand >= mBands)
-                        break;
-                }
-
-                if (freq >= bandSpecs[currentBand].mFreqStart) {
-                    double value = results.mValuesLog[i];
-                    if (bandSpecs[currentBand].isInBounds(freq, value)) {
-                        results.mInBoundPointsPerBand[currentBand]++;
-                    }
-                }
-            }
-            return true;
-        } else {
-            return false;
-        }
-    }
+//    /**
+//     * compute test results
+//     */
+//    private void computeTestResults(int testId) {
+//        String testName = getTestString(testId);
+//        appendResultsToScreen(testId, "test finished");
+//    }
 
     //append results
     private void appendResultsToScreen(String str, TextView text) {
@@ -474,6 +902,24 @@
         text.setText(currentText + "\n" + str);
     }
 
+    private void appendResultsToScreen(int testId, String str) {
+        switch(testId) {
+            case TEST_TONE:
+                appendResultsToScreen(str, mResultTestTone);
+                showToneRMS();
+                break;
+            case TEST_NOISE:
+                appendResultsToScreen(str, mResultTestNoise);
+                break;
+            case TEST_USB_BACKGROUND:
+                appendResultsToScreen(str, mResultTestUsbBackground);
+                break;
+            case TEST_USB_NOISE:
+                appendResultsToScreen(str, mResultTestUsbNoise);
+                break;
+        }
+    }
+
     /**
      * Store test results in log
      */
@@ -615,6 +1061,12 @@
         mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
         return true;
     }
+    private void showToneRMS() {
+        String str = String.format("RMS: %.3f dBFS. Max RMS: %.3f dBFS",
+                20 * Math.log10(mRMSTone),
+                20 * Math.log10(mRMSMaxTone));
+        showMessage(TEST_TONE, str);
+    }
 
     // ---------------------------------------------------------
     // Implementation of AudioRecord.OnPeriodicNotificationListener
@@ -627,9 +1079,10 @@
 
             //compute stuff.
             int clipcount = 0;
-            double sum = 0;
+//            double sum = 0;
             double maxabs = 0;
             int i;
+            double rmsTempSum = 0;
 
             for (i = 0; i < samplesNeeded; i++) {
                 double value = mAudioShortArray2[i] / MAX_VAL;
@@ -643,10 +1096,18 @@
                     clipcount++;
                 }
 
-                sum += value * value;
+                rmsTempSum += value * value;
                 //fft stuff
                 mData.mData[i] = value;
             }
+            double rms = Math.sqrt(rmsTempSum / samplesNeeded);
+
+            double alpha = 0.9;
+            double total_rms = rms * alpha + mRMS *(1-alpha);
+            mRMS = total_rms;
+            if (mRMS > mRMSMax) {
+                mRMSMax = mRMS;
+            }
 
             //for the current frame, compute FFT and send to the viewer.
 
@@ -660,8 +1121,25 @@
                 halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
             }
 
-            mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
-            mFreqAverageBuiltIn.setData(halfMagnitude, false);
+            switch(mCurrentTest) {
+                case TEST_TONE: {
+                    mFreqAverageTone.setData(halfMagnitude, false);
+                    //Update realtime info on screen
+                    mRMSTone = mRMS;
+                    mRMSMaxTone = mRMSMax;
+                   showToneRMS();
+                }
+                    break;
+                case TEST_NOISE:
+                    mFreqAverageNoise.setData(halfMagnitude, false);
+                    break;
+                case TEST_USB_BACKGROUND:
+                    mFreqAverageUsbBackground.setData(halfMagnitude, false);
+                    break;
+                case TEST_USB_NOISE:
+                    mFreqAverageUsbNoise.setData(halfMagnitude, false);
+                    break;
+            }
         }
     }
 
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 6aacea8..9af0840 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -399,7 +399,6 @@
         adapter.add(mCredSettingsVisibleTest);
         adapter.add(mAppSettingsVisibleTest);
         adapter.add(mLocationSettingsVisibleTest);
-        adapter.add(mWiFiDataUsageSettingsVisibleTest);
         adapter.add(mCellularDataUsageSettingsVisibleTest);
         adapter.add(mPrintSettingsVisibleTest);
 
@@ -420,6 +419,10 @@
         adapter.add(mParentProfilePassword);
         adapter.add(mPolicyTransparencyTest);
 
+        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+            adapter.add(mWiFiDataUsageSettingsVisibleTest);
+        }
+
         if (canResolveIntent(new Intent(Settings.ACTION_APPLICATION_SETTINGS))) {
             adapter.add(mDisallowAppsControlTest);
         }
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
index ff28263..6b9b5e4 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
@@ -57,12 +57,20 @@
     public static final String FAILED = "failed";
     public static final String NOT_EXECUTED = "not_executed";
     // static mapping of result types to TestStatuses
-    private static final Map<String, TestStatus> mStatusMap;
+    private static final Map<String, TestStatus> STATUS_MAP;
     static {
         Map<String, TestStatus> statusMap = new HashMap<String, TestStatus>();
         statusMap.put(PASSED, TestStatus.PASS);
         statusMap.put(FAILED, TestStatus.FAIL);
-        mStatusMap = Collections.unmodifiableMap(statusMap);
+        STATUS_MAP = Collections.unmodifiableMap(statusMap);
+    }
+
+    // TODO(aaronholden): remove this temporary workaround for b/33090757
+    private static final Set<String> MULTITEST_MODULES;
+    static {
+        Set<String> multiTestModuleSet = new HashSet<String>();
+        multiTestModuleSet.add("CtsDeqpTestCases");
+        MULTITEST_MODULES = Collections.unmodifiableSet(multiTestModuleSet);
     }
 
     @Option (name = "name", shortName = 'n', description = "the name of the subplan to create",
@@ -183,10 +191,51 @@
         if (mModuleName != null) {
             subPlan.addIncludeFilter(new TestFilter(mAbiName, mModuleName, mTestName).toString());
         }
+        Set<TestStatus> statusesToRun = getStatusesToRun();
 
         for (IModuleResult module : mResult.getModules()) {
+
+            // TODO(aaronholden): remove this special case from SubPlanCreator, and filter
+            // individual tests only when the module should run. Tracked by b/33211104
+            if (MULTITEST_MODULES.contains(module.getName())) {
+                // cannot check module.isDone() since this value is not accurate for modules
+                // with multiple test configs. If we should run not-executed tests, include module
+                // and exclude tests with status not in mResultTypes.
+                TestFilter moduleFilter =
+                            new TestFilter(module.getAbi(), module.getName(), null /*test*/);
+                if (mResultTypes.contains(NOT_EXECUTED)) {
+                    subPlan.addIncludeFilter(moduleFilter.toString());
+                    for (ICaseResult caseResult : module.getResults()) {
+                        for (ITestResult testResult : caseResult.getResults()) {
+                            if (!statusesToRun.contains(testResult.getResultStatus())) {
+                                TestFilter testExclude = new TestFilter(module.getAbi(),
+                                        module.getName(), testResult.getFullName());
+                                subPlan.addExcludeFilter(testExclude.toString());
+                            }
+                        }
+                    }
+                } else {
+                    // not running not-executed tests, only include executed tests
+                    if (shouldRunModule(module)) {
+                        // at least some executed tests will be included
+                        for (ICaseResult caseResult : module.getResults()) {
+                            for (ITestResult testResult : caseResult.getResults()) {
+                                if (statusesToRun.contains(testResult.getResultStatus())) {
+                                    TestFilter testInclude = new TestFilter(module.getAbi(),
+                                            module.getName(), testResult.getFullName());
+                                    subPlan.addIncludeFilter(testInclude.toString());
+                                }
+                            }
+                        }
+                    } else {
+                        // no executed tests will be included, so exclude entire module
+                        subPlan.addExcludeFilter(moduleFilter.toString());
+                    }
+                }
+                continue;
+            }
+
             if (shouldRunModule(module)) {
-                Set<TestStatus> statusesToRun = getStatusesToRun();
                 TestFilter moduleInclude =
                             new TestFilter(module.getAbi(), module.getName(), null /*test*/);
                 if (shouldRunEntireModule(module)) {
@@ -280,7 +329,7 @@
         for (String resultType : mResultTypes) {
             // no test status exists for not-executed tests
             if (resultType != NOT_EXECUTED) {
-                statusesToRun.add(mStatusMap.get(resultType));
+                statusesToRun.add(STATUS_MAP.get(resultType));
             }
         }
         return statusesToRun;
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
index 068ce45..0646385 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.compatibility.common.tradefed.result;
 
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
 import com.android.compatibility.common.tradefed.result.ResultReporter;
 import com.android.compatibility.common.util.ChecksumReporter;
@@ -25,6 +26,7 @@
 import com.android.compatibility.common.util.ITestResult;
 import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.TestStatus;
+import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.OptionSetter;
 import com.android.tradefed.util.FileUtil;
@@ -44,10 +46,13 @@
     private static final String SUITE_PLAN = "cts";
     private static final String BASE_DIR_NAME = "android-tests";
     private static final String TESTCASES = "testcases";
+    private static final String DYNAMIC_CONFIG_URL = "";
+    private static final long START_TIME = 123456L;
 
     private ChecksumReporter mReporter;
     private File mRoot = null;
     private IBuildInfo mBuildInfo;
+    private CompatibilityBuildHelper mBuildHelper;
     private ReportLog mReportLog = null;
     private IInvocationResult mInvocationResult;
     private IModuleResult mModuleResult;
@@ -64,25 +69,10 @@
         System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
 
         ResultReporter resultReporter = new ResultReporter();
-        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
-            @Override
-            protected String getSuiteInfoName() {
-                return SUITE_NAME;
-            }
-            @Override
-            protected String getSuiteInfoBuildNumber() {
-                return BUILD_NUMBER;
-            }
-            @Override
-            protected String getSuiteInfoVersion() {
-                return BUILD_NUMBER;
-            }
-        };
-        OptionSetter setter = new OptionSetter(provider);
-        setter.setOptionValue("plan", SUITE_PLAN);
-        setter.setOptionValue("dynamic-config-url", "");
-        mBuildInfo = provider.getBuild();
-
+        OptionSetter setter = new OptionSetter(resultReporter);
+        mBuildInfo = new BuildInfo(BUILD_NUMBER, "", "");
+        mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
+        mBuildHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL, START_TIME);
         resultReporter.invocationStarted(mBuildInfo);
         mInvocationResult = resultReporter.getResult();
         mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
@@ -146,7 +136,7 @@
         ChecksumReporter storedChecksum = ChecksumReporter.load(mRoot);
         VerifyInvocationResults(mInvocationResult, storedChecksum);
         assertTrue("Serializing checksum maintains file hash",
-                storedChecksum.containsFile(file1, ""));
+                storedChecksum.containsFile(file1, mRoot.getName()));
     }
 
     public void testFileCRCOperations() throws IOException {
@@ -163,18 +153,18 @@
         }
 
         mReporter.addDirectory(mRoot);
-
-        assertTrue(mReporter.containsFile(file1, ""));
-        assertTrue(mReporter.containsFile(file2, "/child"));
+        String folderName = mRoot.getName();
+        assertTrue(mReporter.containsFile(file1, folderName));
+        assertTrue(mReporter.containsFile(file2, folderName + "/child"));
         assertFalse("Should not contain non-existent file",
-                mReporter.containsFile(new File(mRoot, "fake.txt"), ""));
+                mReporter.containsFile(new File(mRoot, "fake.txt"), folderName));
 
         File file3 = new File(mRoot, "file3.txt");
         try (FileWriter fileWriter = new FileWriter(file3, false)) {
             fileWriter.append("This is a test file added after crc calculated");
         }
         assertFalse("Should not contain file created after crc calculated",
-                mReporter.containsFile(file3, ""));
+                mReporter.containsFile(file3, folderName));
 
     }
 
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
index a6f990e..d04ed8e 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -180,7 +180,7 @@
                     int notExecuted =
                             Integer.parseInt(parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
                     module.setNotExecuted(notExecuted);
-                    int runtime = Integer.parseInt(parser.getAttributeValue(NS, RUNTIME_ATTR));
+                    long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
                     module.addRuntime(runtime);
                     while (parser.nextTag() == XmlPullParser.START_TAG) {
                         parser.require(XmlPullParser.START_TAG, NS, CASE_TAG);
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
index a0e9a3b..4a78835 100644
--- a/common/host-side/util/tests/Android.mk
+++ b/common/host-side/util/tests/Android.mk
@@ -18,7 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := compatibility-host-util junit json-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util junit json-prebuilt tradefed-prebuilt
 
 LOCAL_MODULE := compatibility-host-util-tests
 
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
index 4b47bf3..169cfdb 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/HostUnitTests.java
@@ -28,6 +28,7 @@
     public HostUnitTests() {
         super();
         addTestSuite(DynamicConfigHandlerTest.class);
+        addTestSuite(ResultHandlerTest.class);
     }
 
     public static Test suite() {
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
similarity index 100%
rename from common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
rename to common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
diff --git a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
index 967b8a8..e6c6a87 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/UnitTests.java
@@ -37,7 +37,6 @@
         addTestSuite(StatTest.class);
         addTestSuite(TestFilterTest.class);
         addTestSuite(TestResultTest.class);
-        addTestSuite(ResultHandlerTest.class);
     }
 
     public static Test suite() {
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index cc04431..418ce38 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -18,6 +18,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_JAVA_RESOURCE_DIRS := res
+
 LOCAL_MODULE_TAGS := optional
 
 # tag this module as a cts test artifact
diff --git a/hostsidetests/security/res/add-debug.apk b/hostsidetests/security/res/add-debug.apk
new file mode 100644
index 0000000..dff9cb6
--- /dev/null
+++ b/hostsidetests/security/res/add-debug.apk
Binary files differ
diff --git a/hostsidetests/security/res/crash_mod.apk b/hostsidetests/security/res/crash_mod.apk
new file mode 100644
index 0000000..4991294
--- /dev/null
+++ b/hostsidetests/security/res/crash_mod.apk
Binary files differ
diff --git a/hostsidetests/security/res/poc b/hostsidetests/security/res/poc
new file mode 100644
index 0000000..8b6f012
--- /dev/null
+++ b/hostsidetests/security/res/poc
Binary files differ
diff --git a/hostsidetests/security/res/test-case b/hostsidetests/security/res/test-case
new file mode 100644
index 0000000..bac4af1
--- /dev/null
+++ b/hostsidetests/security/res/test-case
Binary files differ
diff --git a/hostsidetests/security/src/android/security/cts/AdbUtils.java b/hostsidetests/security/src/android/security/cts/AdbUtils.java
new file mode 100644
index 0000000..a3018fa
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/AdbUtils.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.platform.test.annotations.RootPermissionTest;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Scanner;
+
+public class AdbUtils {
+
+    /** Runs a commandline on the specified device
+     *
+     * @param command the command to be ran
+     * @param device device for the command to be ran on
+     * @return the console output from running the command
+     */
+    public static String runCommandLine(String command, ITestDevice device) throws Exception
+    {
+        return device.executeShellCommand(command);
+    }
+
+    /**
+     * Pushes and runs a binary to the selected device
+     *
+     * @param pathToPoc a string path to poc from the /res folder
+     * @param device device to be ran on
+     * @return the console output from the binary
+     */
+    public static String runPoc(String pathToPoc, ITestDevice device) throws Exception {
+        String fullResourceName = pathToPoc;
+        File pocFile = File.createTempFile("poc", "");
+        try {
+            pocFile = extractResource(fullResourceName, pocFile);
+            device.pushFile(pocFile, "/data/local/tmp/poc");
+            device.executeShellCommand("chmod +x /data/local/tmp/poc");
+            return device.executeShellCommand("/data/local/tmp/poc");
+        } finally {
+            pocFile.delete();
+        }
+    }
+
+    /**
+     * Pushes and installs an apk to the selected device
+     *
+     * @param pathToApk a string path to apk from the /res folder
+     * @param device device to be ran on
+     * @return the output from attempting to install the apk
+     */
+    public static String installApk(String pathToApk, ITestDevice device) throws Exception {
+
+        String fullResourceName = pathToApk;
+        File apkFile = File.createTempFile("apkFile", ".apk");
+        try {
+            apkFile = extractResource(fullResourceName, apkFile);
+            return device.installPackage(apkFile, true);
+        } finally {
+            apkFile.delete();
+        }
+    }
+
+   /**
+     * Extracts the binary data from a resource and writes it to a temp file
+     */
+    private static File extractResource(String fullResourceName, File file) throws Exception {
+        try (InputStream in = AdbUtils.class.getResourceAsStream(fullResourceName);
+            OutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
+            if (in == null) {
+                throw new IllegalArgumentException("Resource not found: " + fullResourceName);
+            }
+            byte[] buf = new byte[65536];
+            int chunkSize;
+            while ((chunkSize = in.read(buf)) != -1) {
+                out.write(buf, 0, chunkSize);
+            }
+            return file;
+        }
+
+    }
+}
diff --git a/hostsidetests/security/src/android/security/cts/SampleRootTestCase.java b/hostsidetests/security/src/android/security/cts/SampleRootTestCase.java
new file mode 100644
index 0000000..1988721
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/SampleRootTestCase.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.platform.test.annotations.RootPermissionTest;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Scanner;
+
+public class SampleRootTestCase extends SecurityTestCase {
+
+    /**
+     * Sample where we use a commandline to check for a vulnerability
+     */
+    public void testHelperCmdLine() throws Exception {
+        enableAdbRoot(getDevice());
+        String command = "cd /sys/kernel/slab; ls -l 2>/dev/null | grep ffffffc0";
+        assertEquals("Lines do not match:", "", AdbUtils.runCommandLine(command, getDevice()));
+    }
+
+    /**
+     * Sample of running a binary poc that requires root and properly attains it
+     */
+    public void testHelperPocRoot() throws Exception {
+        enableAdbRoot(getDevice());
+        AdbUtils.runPoc("/test-case", getDevice());
+    }
+
+    /**
+     * Sample of running a binary poc that requires root and does not attain it
+     */
+    public void testHelperPoc() throws Exception {
+        AdbUtils.runPoc("/test-case", getDevice());
+    }
+
+    /**
+     * Sample of running an apk
+     */
+    public void testHelperApk() throws Exception {
+        String installResult = AdbUtils.installApk("/crash_mod.apk", getDevice());
+        assertNull("failed to install apk", installResult);
+    }
+}
diff --git a/hostsidetests/security/src/android/security/cts/SecurityTestCase.java b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
new file mode 100644
index 0000000..b6599c1
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/SecurityTestCase.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import android.platform.test.annotations.RootPermissionTest;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Scanner;
+
+public class SecurityTestCase extends DeviceTestCase {
+
+    private long kernelStartTime;
+
+    /**
+     * Waits for device to be online, marks the most recent boottime of the device
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        kernelStartTime = System.currentTimeMillis()/1000 -
+            Integer.parseInt(getDevice().executeShellCommand("cut -f1 -d. /proc/uptime").trim());
+        //TODO:(badash@): Watch for other things to track.
+        //     Specifically time when app framework starts
+    }
+
+    /**
+     * Takes a device and runs a root command.  There is a more robust version implemented by
+     * NativeDevice, but due to some other changes it isnt trivially acessible, but I can get
+     * that implementation fairly easy if we think it is a better idea.
+     */
+    public void enableAdbRoot(ITestDevice mDevice) throws DeviceNotAvailableException {
+        boolean isUserDebug =
+            "userdebug".equals(mDevice.executeShellCommand("getprop ro.build.type").trim());
+        if (!isUserDebug) {
+            //TODO(badash@): This would Noop once cl: ag/1594311 is in
+            return;
+        }
+        mDevice.executeAdbCommand("root");
+    }
+
+    /**
+     * Makes sure the phone is online, and the ensure the current boottime is within 2 seconds
+     * (due to rounding) of the previous boottime to check if The phone has crashed.
+     */
+    @Override
+    public void tearDown() throws Exception {
+        getDevice().waitForDeviceOnline(60 * 1000);
+        assertTrue("Phone has had a hard reset",
+            (System.currentTimeMillis()/1000 -
+                Integer.parseInt(getDevice().executeShellCommand("cut -f1 -d. /proc/uptime").trim())
+                    - kernelStartTime < 2));
+        //TODO(badash@): add ability to catch runtime restart
+        getDevice().executeAdbCommand("unroot");
+    }
+}
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index cad4922..38443b9 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -457,6 +457,10 @@
     }
 
     public void testUsbAccessory() {
+        // USB accessory mode is only a requirement for devices with USB ports supporting
+        // peripheral mode. As there is no public API to distinguish a device with only host
+        // mode support from having both peripheral and host support, the test may have
+        // false negatives.
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) &&
                 !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
@@ -464,23 +468,18 @@
         }
     }
 
-    public void testWifiFeature() throws Exception {
+  public void testWifiFeature() throws Exception {
         if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
             // no WiFi, skip the test
             return;
         }
         boolean enabled = mWifiManager.isWifiEnabled();
         try {
-            // WifiManager is hard-coded to return true,
-            // the case without WiFi is already handled,
-            // so this case MUST have WiFi.
-            if (mWifiManager.setWifiEnabled(true)) {
-                assertAvailable(PackageManager.FEATURE_WIFI);
-            }
+            // assert wifimanager can toggle wifi from current sate
+            assertTrue(mWifiManager.setWifiEnabled(!enabled));
+
         } finally {
-            if (!enabled) {
-                mWifiManager.setWifiEnabled(false);
-            }
+            mWifiManager.setWifiEnabled(enabled);
         }
     }
 
diff --git a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
index 0f4775e..32c54c9 100644
--- a/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssMeasurementWhenNoLocationTest.java
@@ -135,7 +135,13 @@
         List<GnssMeasurementsEvent> events = mMeasurementListener.getEvents();
         Log.i(TAG, "Number of GPS measurement events received = " + events.size());
 
-        // Ensure that after getting a few (at least 2) measurements, that we still don't have
+        if (events.isEmpty()) {
+            SoftAssert.failOrWarning(isMeasurementTestStrict(), "No measurement events received",
+                    false);
+            return;  // All of the following checks rely on there being measurements
+        }
+
+        // Ensure that after getting a few (at least 2) measurement events, that we still don't have
         // location (i.e. that we got measurements before location.)  Fail, if strict, warn, if not.
         SoftAssert.failOrWarning(isMeasurementTestStrict(),
                 "Location was received before " + events.size() +
@@ -149,9 +155,8 @@
             return; // allow a (passing) return, if not strict, otherwise continue
         }
 
-        // If device is not indoors, verify
-        // 1) that we receive GPS measurements before being able to calculate the position solution
-        // 2) that mandatory fields of GnssMeasurement are in expected ranges.
+        // If device has received measurements also verify
+        // that mandatory fields of GnssMeasurement are in expected ranges.
         GnssMeasurementsEvent firstEvent = events.get(0);
         Collection<GnssMeasurement> gpsMeasurements = firstEvent.getMeasurements();
         int satelliteCount = gpsMeasurements.size();
diff --git a/tests/tests/location/src/android/location/cts/SoftAssert.java b/tests/tests/location/src/android/location/cts/SoftAssert.java
index 3913149..4349f07 100644
--- a/tests/tests/location/src/android/location/cts/SoftAssert.java
+++ b/tests/tests/location/src/android/location/cts/SoftAssert.java
@@ -156,7 +156,9 @@
         if (testIsStrict) {
             Assert.assertTrue(message, condition);
         } else {
-            failAsWarning("", message);
+            if (!condition) {
+                failAsWarning("", message);
+            }
         }
     }
 
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index ec0ceae..662a1fd 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -28,8 +28,11 @@
 
 import junit.framework.Assert;
 
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.Set;
 
 /**
  * Helper class for GnssMeasurement Tests.
@@ -54,6 +57,21 @@
 
     private static final int YEAR_2016 = 2016;
 
+    // The valid Gnss navigation message type as listed in
+    // android/hardware/libhardware/include/hardware/gps.h
+    public static final Set<Integer> GNSS_NAVIGATION_MESSAGE_TYPE =
+        new HashSet<Integer>(Arrays.asList(
+            GnssNavigationMessage.TYPE_GPS_L1CA,
+            GnssNavigationMessage.TYPE_GPS_L2CNAV,
+            GnssNavigationMessage.TYPE_GPS_L5CNAV,
+            GnssNavigationMessage.TYPE_GPS_CNAV2,
+            GnssNavigationMessage.TYPE_GLO_L1CA,
+            GnssNavigationMessage.TYPE_BDS_D1,
+            GnssNavigationMessage.TYPE_BDS_D2,
+            GnssNavigationMessage.TYPE_GAL_I,
+            GnssNavigationMessage.TYPE_GAL_F
+        ));
+
     /**
      * Check if test can be run on the current device.
      *
@@ -65,15 +83,12 @@
                                                     String testTag,
                                                     int minHardwareYear,
                                                     boolean isCtsVerifier) {
-       // TODO(sumitk): Enable this check once api 24 for N is avaiable.
-       /*
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
             Log.i(TAG, "This test is designed to work on N or newer. " +
                     "Test is being skipped because the platform version is being run in " +
                     Build.VERSION.SDK_INT);
             return false;
         }
-        */
 
         // If device does not have a GPS, skip the test.
         PackageManager pm = testLocationManager.getContext().getPackageManager();
@@ -674,9 +689,9 @@
         SoftAssert softAssert = new SoftAssert(TAG);
         for (GnssNavigationMessage message : events) {
             int type = message.getType();
-            softAssert.assertTrue("Gnss Navigation Message Type:expected [0x0101 - 0x0104]," +
-                            " actual = " + type,
-                    type >= 0x0101 && type <= 0x0104);
+            softAssert.assertTrue("Gnss Navigation Message Type:expected [" +
+                getGnssNavMessageTypes() + "] actual = " + type,
+                    GNSS_NAVIGATION_MESSAGE_TYPE.contains(type));
 
             int gnssYearOfHardware = testLocationManager.getLocationManager().getGnssYearOfHardware();
             if (gnssYearOfHardware >= YEAR_2016) {
@@ -701,4 +716,14 @@
         }
         softAssert.assertAll();
     }
+
+    private static String getGnssNavMessageTypes() {
+        StringBuilder typesStr = new StringBuilder();
+        for (int type : GNSS_NAVIGATION_MESSAGE_TYPE) {
+            typesStr.append(String.format("0x%04X", type));
+            typesStr.append(", ");
+        }
+
+        return typesStr.length() > 2 ? typesStr.substring(0, typesStr.length() - 2) : "";
+    }
 }