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) : "";
+ }
}