Merge "Make sure to skip Telecom CTS tests on unsupported devices" into mnc-dev
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index beb9895..0950994 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -172,6 +172,7 @@
CtsNativeOpenGLTestCases \
CtsNdefTestCases \
CtsNetTestCases \
+ CtsNetTestCasesLegacyApi22 \
CtsOpenGLTestCases \
CtsOpenGlPerfTestCases \
CtsOsTestCases \
diff --git a/apps/CameraITS/pymodules/its/device.py b/apps/CameraITS/pymodules/its/device.py
index dec37db..756f959 100644
--- a/apps/CameraITS/pymodules/its/device.py
+++ b/apps/CameraITS/pymodules/its/device.py
@@ -58,6 +58,7 @@
# Seconds timeout on each socket operation.
SOCK_TIMEOUT = 10.0
+ SEC_TO_NSEC = 1000*1000*1000.0
PACKAGE = 'com.android.cts.verifier.camera.its'
INTENT_START = 'com.android.cts.verifier.camera.its.START'
@@ -580,6 +581,18 @@
"dng" in formats and "raw10" in formats or \
"raw" in formats and "raw10" in formats:
raise its.error.Error('Different raw formats not supported')
+
+ # Detect long exposure time and set timeout accordingly
+ longest_exp_time = 0
+ for req in cmd["captureRequests"]:
+ if "android.sensor.exposureTime" in req and \
+ req["android.sensor.exposureTime"] > longest_exp_time:
+ longest_exp_time = req["android.sensor.exposureTime"]
+
+ extended_timeout = longest_exp_time / self.SEC_TO_NSEC + \
+ self.SOCK_TIMEOUT
+ self.sock.settimeout(extended_timeout)
+
print "Capturing %d frame%s with %d format%s [%s]" % (
ncap, "s" if ncap>1 else "", nsurf, "s" if nsurf>1 else "",
",".join(formats))
@@ -621,6 +634,7 @@
obj["metadata"] = mds[i]
objs.append(obj)
rets.append(objs if ncap>1 else objs[0])
+ self.sock.settimeout(self.SOCK_TIMEOUT)
return rets if len(rets)>1 else rets[0]
def get_device_id():
diff --git a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
index f4f0d56..2c8d73b 100644
--- a/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_param_noise_reduction.py
@@ -116,7 +116,11 @@
# Verify MINIMAL(3) is not better than HQ(2)
assert(variances[j][3] >
variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
- if its.caps.noise_reduction_mode(props, 4):
+ if its.caps.noise_reduction_mode(props, 4):
+ # Verify ZSL(4) is close to MINIMAL(3)
+ assert(numpy.isclose(variances[j][4], variances[j][3],
+ RELATIVE_ERROR_TOLERANCE))
+ elif its.caps.noise_reduction_mode(props, 4):
# Verify ZSL(4) is close to OFF(0)
assert(numpy.isclose(variances[j][4], variances[j][0],
RELATIVE_ERROR_TOLERANCE))
diff --git a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
index aeeae33..757dfeb 100644
--- a/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
+++ b/apps/CameraITS/tests/scene1/test_reprocess_noise_reduction.py
@@ -107,10 +107,12 @@
print "Variances with NR mode [0,1,2,3,4]:", variances
# Draw a plot.
- for nr_mode in range(5):
- if not its.caps.noise_reduction_mode(props, nr_mode):
- continue
- pylab.plot(range(3), variances[nr_mode], "rgbcm"[nr_mode])
+ for chan in range(3):
+ line = []
+ for nr_mode in range(5):
+ line.append(variances[nr_mode][chan])
+ pylab.plot(range(5), line, "rgb"[chan])
+
matplotlib.pyplot.savefig("%s_plot_%s_variances.png" %
(NAME, reprocess_format))
@@ -133,9 +135,13 @@
# Verify MINIMAL(3) is not better than HQ(2)
assert(variances[3][j] >
variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE))
- # Verify ZSL(4) is close to OFF(0)
- assert(numpy.isclose(variances[4][j], variances[0][j],
- RELATIVE_ERROR_TOLERANCE))
+ # Verify ZSL(4) is close to MINIMAL(3)
+ assert(numpy.isclose(variances[4][j], variances[3][j],
+ RELATIVE_ERROR_TOLERANCE))
+ else:
+ # Verify ZSL(4) is close to OFF(0)
+ assert(numpy.isclose(variances[4][j], variances[0][j],
+ RELATIVE_ERROR_TOLERANCE))
if __name__ == '__main__':
main()
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 47eb16f..272e192 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1369,7 +1369,12 @@
android:theme="@android:style/Theme.NoDisplay"
android:noHistory="true"
android:autoRemoveFromRecents="true"
- android:stateNotNeeded="true"/>
+ android:stateNotNeeded="true">
+ </activity>
+
+ <activity android:name=".managedprovisioning.KeyguardDisabledFeaturesActivity"
+ android:label="@string/provisioning_byod_keyguard_disabled_features">
+ </activity>
<activity android:name=".managedprovisioning.WifiLockdownTestActivity"
android:label="@string/device_owner_wifi_lockdown_test">
@@ -1416,6 +1421,8 @@
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO" />
<action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_AUDIO" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>
@@ -1455,6 +1462,7 @@
<activity android:name=".managedprovisioning.WorkNotificationTestActivity">
<intent-filter>
<action android:name="com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION" />
<action android:name="com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
@@ -1632,6 +1640,18 @@
<meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
</activity>
+ <activity android:name=".audio.AudioFrequencyLineActivity"
+ android:label="@string/audio_frequency_line_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+ <meta-data android:name="test_required_features" android:value="android.hardware.microphone" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.watch" />
+ <meta-data android:name="test_excluded_features" android:value="android.hardware.type.television" />
+ </activity>
+
<service android:name=".tv.MockTvInputService"
android:permission="android.permission.BIND_TV_INPUT">
<intent-filter>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
new file mode 100644
index 0000000..69e3bc7
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/audio_frequency_line_activity.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:orientation="vertical">
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:id="@+id/info_text"
+ android:text="@string/audio_frequency_line_instructions" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <Button
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_line_plug_ready_btn"
+ android:text="@string/audio_frequency_line_plug_ready_btn"/>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:id="@+id/audio_frequency_line_layout">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_line_test_btn"
+ android:id="@+id/audio_frequency_line_test_btn"/>
+
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:id="@+id/audio_frequency_line_progress_bar"/>
+ </LinearLayout>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/audio_frequency_line_results_text"
+ android:id="@+id/audio_frequency_line_results_text"/>
+
+ </LinearLayout>
+ </LinearLayout>
+
+ <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3 b/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3
new file mode 100644
index 0000000..e877fc1
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/stereo_mono_white_noise_48.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 91a62ba..43afa87 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1449,6 +1449,42 @@
\n
Verify that you are prompted with the above choices and both options work as intended. Then mark this test accordingly.
</string>
+ <string name="provisioning_byod_keyguard_disabled_features">Keyguard disabled features</string>
+ <string name="provisioning_byod_keyguard_disabled_features_info">
+ This test exercises Keyguard Disabled Features. Follow instructions above.
+ </string>
+ <string name="provisioning_byod_keyguard_disabled_features_instruction">
+ Please press the \"Prepare test\" button to disable trust agents.\n
+ Then please press through the following verification steps.\n
+ Note: Device password will be set to \"testpassword\". After leaving the screen device password be cleared.
+ </string>
+ <string name="provisioning_byod_keyguard_disabled_features_prepare_button">Prepare test</string>
+ <string name="provisioning_byod_disable_trust_agents">Disable trust agents</string>
+ <string name="provisioning_byod_disable_trust_agents_instruction">
+ Please press the Go button to go to Settings > Security. Then go to Trusted agents and\n
+ check if the agents are shown as disabled by the administrator.
+ Then please press Back and mark the test as \"Pass\" or \"Fail\".
+ </string>
+ <string name="provisioning_byod_fingerprint_disabled_in_settings">Fingerprint is disabled in Settings</string>
+ <string name="provisioning_byod_fingerprint_disabled_in_settings_instruction">
+ Please press the Go button to go to Settings > Security. Then go to Fingerprint and\n
+ check if the screen is shown as disabled by the administrator.
+ Then please press Back and mark the test as \"Pass\" or \"Fail\".
+ </string>
+ <string name="provisioning_byod_disable_fingerprint">Fingerprint disabled on keyguard</string>
+ <string name="provisioning_byod_disable_fingerprint_instruction">
+ Please press the Go button to lock the screen. Then try to log in using the fingerprint reader.\n
+ Expected result is you cannot log in using your fingerprint.\n
+ After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
+ </string>
+ <string name="provisioning_byod_disable_notifications">Notifications disabled on keyguard</string>
+ <string name="provisioning_byod_disable_notifications_instruction">
+ Please press the Go button to lock the screen. Wait a couple of seconds and look out for a
+ notification from CtsVerifier.\n
+ Expected result is the notification is shown as \"Contents hidden\", you can not see the contents
+ (Which would read \"This is a work notification\").\n
+ After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
+ </string>
<string name="provisioning_byod_work_notification">Work notification is badged</string>
<string name="provisioning_byod_work_notification_instruction">
Please press the Go button to trigger a notification.\n
@@ -1912,4 +1948,22 @@
<string name="audio_loopback_test_btn">Test</string>
<string name="audio_loopback_results_text">Results...</string>
+ <!-- Audio Frequency Line Test -->
+ <string name="audio_frequency_line_test">Audio Frequency Line Test</string>
+ <string name="audio_frequency_line_info">
+ This test requires the Loopback Plug. Please connect a Loopback Plug on the headset
+ connector, and proceed with the instructions on the screen.
+ The system will measure the input-output audio latency by injecting a pulse on the output,
+ and computing the distance between replicas of the pulse.
+ You can vary the Audio Level slider to ensure the pulse will feed back at adecuate levels.
+ Repeat until a confidence level >= 0.6 is achieved.
+ </string>
+ <string name="audio_frequency_line_instructions">
+ Please connect a "Loopback Plug" and press "Loopback Plug Ready".
+ </string>
+ <string name="audio_frequency_line_plug_ready_btn">Loopback Plug Ready</string>
+
+ <string name="audio_frequency_line_test_btn">Test</string>
+ <string name="audio_frequency_line_results_text">Results...</string>
+
</resources>
diff --git a/apps/CtsVerifier/res/xml/device_admin_byod.xml b/apps/CtsVerifier/res/xml/device_admin_byod.xml
index 61238aa..ce44794 100644
--- a/apps/CtsVerifier/res/xml/device_admin_byod.xml
+++ b/apps/CtsVerifier/res/xml/device_admin_byod.xml
@@ -20,6 +20,8 @@
<encrypted-storage />
<wipe-data />
<reset-password />
+ <disable-keyguard-features />
+ <force-lock />
</uses-policies>
</device-admin>
<!-- END_INCLUDE(meta_data) -->
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java
new file mode 100644
index 0000000..9af4af1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioBandSpecs.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+public class AudioBandSpecs {
+ double mFreqStart;
+ double mFreqStop;
+ double mRippleStartTop;
+ double mRippleStartBottom;
+
+ double mRippleStopTop;
+ double mRippleStopBottom;
+
+ double mOffset;
+
+ public AudioBandSpecs(double fStart, double fStop, double startTop, double startBottom,
+ double stopTop, double stopBottom) {
+ initFreq(fStart, fStop);
+ initRipple(startTop, startBottom, stopTop, stopBottom);
+ setOffset(0);
+ }
+
+ public void initRipple(double startTop, double startBottom, double stopTop, double stopBottom) {
+ mRippleStartTop = startTop;
+ mRippleStartBottom = startBottom;
+ mRippleStopTop = stopTop;
+ mRippleStopBottom = stopBottom;
+ // note: top should be >= bottom, but no check is done here.
+ }
+
+ public void initFreq(double fStart, double fStop) {
+ mFreqStart = fStart;
+ mFreqStop = fStop;
+ }
+
+ public void setOffset(double offset) {
+ mOffset = offset;
+ }
+
+ /**
+ * Check if the given point is in bounds in this band.
+ */
+ public boolean isInBounds(double freq, double value) {
+ if (freq < mFreqStart || freq > mFreqStop) {
+ return false;
+ }
+
+ double d = mFreqStop - mFreqStart;
+ if (d <= 0) {
+ return false;
+ }
+
+ double e = freq - mFreqStart;
+ double vTop = (e / d) * (mRippleStopTop - mRippleStartTop) + mRippleStartTop + mOffset;
+ if (value > vTop) {
+ return false;
+ }
+
+ double vBottom = (e / d) * (mRippleStopBottom - mRippleStartBottom) + mRippleStartBottom
+ + mOffset;
+
+ if (value < vBottom) {
+ return false;
+ }
+ return true;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("Freq %.1f - %.1f |", mFreqStart, mFreqStop));
+ sb.append(String.format("start [%.1f : %.1f] |", mRippleStartTop, mRippleStartBottom));
+ sb.append(String.format("stop [%.1f : %.1f] |", mRippleStopTop, mRippleStopBottom));
+ sb.append(String.format("offset %.1f", mOffset));
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
new file mode 100644
index 0000000..d3e2571
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -0,0 +1,664 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.audio.wavelib.*;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultType;
+import com.android.compatibility.common.util.ResultUnit;
+import android.content.Context;
+
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.AudioRecord;
+import android.media.MediaRecorder;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+
+import android.util.Log;
+
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.SeekBar;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+
+/**
+ * Tests Audio Device roundtrip latency by using a loopback plug.
+ */
+public class AudioFrequencyLineActivity extends PassFailButtons.Activity implements Runnable,
+ AudioRecord.OnRecordPositionUpdateListener {
+ private static final String TAG = "AudioFrequencyLineActivity";
+
+ static final int TEST_STARTED = 900;
+ static final int TEST_ENDED = 901;
+ static final int TEST_MESSAGE = 902;
+ static final double MIN_ENERGY_BAND_1 = -20.0;
+ static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+
+ OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
+ Context mContext;
+
+ Button mLoopbackPlugReady;
+ LinearLayout mLinearLayout;
+ Button mTestButton;
+ TextView mResultText;
+ ProgressBar mProgressBar;
+ //recording
+ private boolean mIsRecording = false;
+ private final Object mRecordingLock = new Object();
+ private AudioRecord mRecorder;
+ private int mMinRecordBufferSizeInSamples = 0;
+ private short[] mAudioShortArray;
+ private short[] mAudioShortArray2;
+
+ private final int mBlockSizeSamples = 1024;
+ private final int mSamplingRate = 48000;
+ private final int mSelectedRecordSource = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+ private final int mChannelConfig = AudioFormat.CHANNEL_IN_MONO;
+ private final int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ private volatile Thread mRecordThread;
+ private boolean mRecordThreadShutdown = false;
+
+ PipeShort mPipe = new PipeShort(65536);
+ SoundPlayerObject mSPlayer;
+
+ private DspBufferComplex mC;
+ private DspBufferDouble mData;
+
+ private DspWindow mWindow;
+ private DspFftServer mFftServer;
+ private VectorAverage mFreqAverageMain = new VectorAverage();
+
+ private VectorAverage mFreqAverage0 = new VectorAverage();
+ private VectorAverage mFreqAverage1 = new VectorAverage();
+
+ private int mCurrentTest = -1;
+ int mBands = 4;
+ AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
+
+ int mMaxLevel;
+ private class OnBtnClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.audio_frequency_line_plug_ready_btn:
+ Log.i(TAG, "audio loopback plug ready");
+ //enable all the other views.
+ enableLayout(true);
+ break;
+ case R.id.audio_frequency_line_test_btn:
+ Log.i(TAG, "audio loopback test");
+ startAudioTest();
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.audio_frequency_line_activity);
+
+ mContext = this;
+
+ mLoopbackPlugReady = (Button)findViewById(R.id.audio_frequency_line_plug_ready_btn);
+ mLoopbackPlugReady.setOnClickListener(mBtnClickListener);
+ mLinearLayout = (LinearLayout)findViewById(R.id.audio_frequency_line_layout);
+ mTestButton = (Button)findViewById(R.id.audio_frequency_line_test_btn);
+ mTestButton.setOnClickListener(mBtnClickListener);
+ mResultText = (TextView)findViewById(R.id.audio_frequency_line_results_text);
+ mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_line_progress_bar);
+ showWait(false);
+ enableLayout(false); //disabled all content
+
+ mSPlayer = new SoundPlayerObject();
+ mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.stereo_mono_white_noise_48);
+ mSPlayer.setBalance(0.5f);
+
+ //Init FFT stuff
+ mAudioShortArray2 = new short[mBlockSizeSamples*2];
+ mData = new DspBufferDouble(mBlockSizeSamples);
+ mC = new DspBufferComplex(mBlockSizeSamples);
+ mFftServer = new DspFftServer(mBlockSizeSamples);
+
+ int overlap = mBlockSizeSamples / 2;
+
+ mWindow = new DspWindow(DspWindow.WINDOW_HANNING, mBlockSizeSamples, overlap);
+
+ setPassFailButtonClickListeners();
+ getPassButton().setEnabled(false);
+ setInfoResources(R.string.audio_frequency_line_test,
+ R.string.audio_frequency_line_info, -1);
+
+ //Init bands
+ bandSpecsArray[0] = new AudioBandSpecs(
+ 50, 500, /* frequency start,stop */
+ -20.0, -50, /* start top,bottom value */
+ 4.0, -4.0 /* stop top,bottom value */);
+
+ bandSpecsArray[1] = new AudioBandSpecs(
+ 500,4000, /* frequency start,stop */
+ 4.0, -4.0, /* start top,bottom value */
+ 4.0, -4.0 /* stop top,bottom value */);
+
+ bandSpecsArray[2] = new AudioBandSpecs(
+ 4000, 12000, /* frequency start,stop */
+ 4.0, -4.0, /* start top,bottom value */
+ 5.0, -5.0 /* stop top,bottom value */);
+
+ bandSpecsArray[3] = new AudioBandSpecs(
+ 12000, 20000, /* frequency start,stop */
+ 5.0, -5.0, /* start top,bottom value */
+ 5.0, -30.0 /* stop top,bottom value */);
+ }
+
+ /**
+ * enable test ui elements
+ */
+ private void enableLayout(boolean enable) {
+ for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
+ View view = mLinearLayout.getChildAt(i);
+ view.setEnabled(enable);
+ }
+ }
+
+ /**
+ * show active progress bar
+ */
+ private void showWait(boolean show) {
+ if (show) {
+ mProgressBar.setVisibility(View.VISIBLE);
+ } else {
+ mProgressBar.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private void setMaxLevel() {
+ AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ mMaxLevel = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ am.setStreamVolume(AudioManager.STREAM_MUSIC, (int)(mMaxLevel), 0);
+ }
+
+ /**
+ * Start the loopback audio test
+ */
+ private void startAudioTest() {
+ if (mTestThread != null && !mTestThread.isAlive()) {
+ mTestThread = null; //kill it.
+ }
+
+ if (mTestThread == null) {
+ Log.v(TAG,"Executing test Thread");
+ mTestThread = new Thread(mPlayRunnable);
+ getPassButton().setEnabled(false);
+ if (!mSPlayer.isAlive())
+ mSPlayer.start();
+ mTestThread.start();
+ } else {
+ Log.v(TAG,"test Thread already running.");
+ }
+ }
+
+ Thread mTestThread;
+ Runnable mPlayRunnable = new Runnable() {
+ public void run() {
+ Message msg = Message.obtain();
+ msg.what = TEST_STARTED;
+ mMessageHandler.sendMessage(msg);
+ setMaxLevel();
+
+ sendMessage("Testing Left Capture");
+ mCurrentTest = 0;
+ mFreqAverage0.reset();
+ mSPlayer.setBalance(0.0f);
+ play();
+
+ sendMessage("Testing Right Capture");
+ mCurrentTest = 1;
+ mFreqAverage1.reset();
+ mSPlayer.setBalance(1.0f);
+ play();
+
+ mCurrentTest = -1;
+ sendMessage("Testing Completed");
+
+ Message msg2 = Message.obtain();
+ msg2.what = TEST_ENDED;
+ mMessageHandler.sendMessage(msg2);
+ }
+
+ private void play() {
+ startRecording();
+ mSPlayer.play(true);
+
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ mSPlayer.play(false);
+ stopRecording();
+ }
+
+ private void sendMessage(String str) {
+ Message msg = Message.obtain();
+ msg.what = TEST_MESSAGE;
+ msg.obj = str;
+ mMessageHandler.sendMessage(msg);
+ }
+ };
+
+ private Handler mMessageHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case TEST_STARTED:
+ showWait(true);
+ getPassButton().setEnabled(false);
+ break;
+ case TEST_ENDED:
+ showWait(false);
+ computeResults();
+ break;
+ case TEST_MESSAGE:
+ String str = (String)msg.obj;
+ if (str != null) {
+ mResultText.setText(str);
+ }
+ break;
+ default:
+ Log.e(TAG, String.format("Unknown message: %d", msg.what));
+ }
+ }
+ };
+
+ private class Results {
+ private String mLabel;
+ public double[] mValuesLog;
+ int[] mPointsPerBand = new int[mBands];
+ double[] mAverageEnergyPerBand = new double[mBands];
+ int[] mInBoundPointsPerBand = new int[mBands];
+ public Results(String label) {
+ mLabel = label;
+ }
+
+ //append results
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(String.format("Channel %s\n", mLabel));
+ sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"FAILED") +"\n");
+ for (int b = 0; b < mBands; b++) {
+ double percent = 0;
+ if (mPointsPerBand[b] > 0) {
+ percent = 100.0 * (double)mInBoundPointsPerBand[b] / mPointsPerBand[b];
+ }
+ sb.append(String.format(
+ " Band %d: Av. Level: %.1f dB InBand: %d/%d (%.1f%%) %s\n",
+ b, mAverageEnergyPerBand[b],
+ mInBoundPointsPerBand[b],
+ mPointsPerBand[b],
+ percent,
+ (testInBand(b) ? "OK" : "FAILED")));
+ }
+ return sb.toString();
+ }
+
+ public boolean testLevel() {
+ if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
+ return true;
+ }
+ return false;
+ }
+
+ public boolean testInBand(int b) {
+ if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
+ if ((double)mInBoundPointsPerBand[b] / mPointsPerBand[b] >
+ MIN_FRACTION_POINTS_IN_BAND)
+ return true;
+ }
+ return false;
+ }
+
+ public boolean testAll() {
+ if (!testLevel()) {
+ return false;
+ }
+ for (int b = 0; b < mBands; b++) {
+ if (!testInBand(b)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * compute test results
+ */
+ private void computeResults() {
+ Results resultsLeft = new Results("Left");
+ computeResultsForVector(mFreqAverage0, resultsLeft);
+ Results resultsRight = new Results("Right");
+ computeResultsForVector(mFreqAverage1, resultsRight);
+ if (resultsLeft.testAll() && resultsRight.testAll()) {
+ //enable button
+ getPassButton().setEnabled(true);
+ }
+ }
+
+ private void computeResultsForVector(VectorAverage freqAverage,Results results) {
+
+ int points = freqAverage.getSize();
+ if (points > 0) {
+ //compute vector in db
+ double[] values = new double[points];
+ freqAverage.getData(values, false);
+ results.mValuesLog = new double[points];
+ for (int i = 0; i < points; i++) {
+ results.mValuesLog[i] = 20 * Math.log10(values[i]);
+ }
+
+ int currentBand = 0;
+ for (int i = 0; i < points; i++) {
+ double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+ if (freq > bandSpecsArray[currentBand].mFreqStop) {
+ currentBand++;
+ if (currentBand >= mBands)
+ break;
+ }
+
+ if (freq >= bandSpecsArray[currentBand].mFreqStart) {
+ results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+ results.mPointsPerBand[currentBand]++;
+ }
+ }
+
+ for (int b = 0; b < mBands; b++) {
+ if (results.mPointsPerBand[b] > 0) {
+ results.mAverageEnergyPerBand[b] =
+ results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+ }
+ }
+
+ //set offset relative to band 1 level
+ for (int b = 0; b < mBands; b++) {
+ bandSpecsArray[b].setOffset(results.mAverageEnergyPerBand[1]);
+ }
+
+ //test points in band.
+ currentBand = 0;
+ for (int i = 0; i < points; i++) {
+ double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+ if (freq > bandSpecsArray[currentBand].mFreqStop) {
+ currentBand++;
+ if (currentBand >= mBands)
+ break;
+ }
+
+ if (freq >= bandSpecsArray[currentBand].mFreqStart) {
+ double value = results.mValuesLog[i];
+ if (bandSpecsArray[currentBand].isInBounds(freq, value)) {
+ results.mInBoundPointsPerBand[currentBand]++;
+ }
+ }
+ }
+
+ appendResultsToScreen(results.toString());
+ //store results
+ recordTestResults(results);
+ } else {
+ appendResultsToScreen("Failed testing channel " + results.mLabel);
+ }
+ }
+
+ //append results
+ private void appendResultsToScreen(String str) {
+ String currentText = mResultText.getText().toString();
+ mResultText.setText(currentText + "\n" + str);
+ }
+
+ /**
+ * Store test results in log
+ */
+ private void recordTestResults(Results results) {
+ String channelLabel = "channel_" + results.mLabel;
+
+ for (int b = 0; b < mBands; b++) {
+ String bandLabel = String.format(channelLabel + "_%d", b);
+ getReportLog().addValue(
+ bandLabel + "_Level",
+ results.mAverageEnergyPerBand[b],
+ ResultType.HIGHER_BETTER,
+ ResultUnit.NONE);
+
+ getReportLog().addValue(
+ bandLabel + "_pointsinbound",
+ results.mInBoundPointsPerBand[b],
+ ResultType.HIGHER_BETTER,
+ ResultUnit.COUNT);
+
+ getReportLog().addValue(
+ bandLabel + "_pointstotal",
+ results.mPointsPerBand[b],
+ ResultType.NEUTRAL,
+ ResultUnit.COUNT);
+ }
+
+ getReportLog().addValues(channelLabel + "_magnitudeSpectrumLog",
+ results.mValuesLog,
+ ResultType.NEUTRAL,
+ ResultUnit.NONE);
+
+ Log.v(TAG, "Results Recorded");
+ }
+
+ private void startRecording() {
+ synchronized (mRecordingLock) {
+ mIsRecording = true;
+ }
+
+ boolean successful = initRecord();
+ if (successful) {
+ startRecordingForReal();
+ } else {
+ Log.v(TAG, "Recorder initialization error.");
+ synchronized (mRecordingLock) {
+ mIsRecording = false;
+ }
+ }
+ }
+
+ private void startRecordingForReal() {
+ // start streaming
+ if (mRecordThread == null) {
+ mRecordThread = new Thread(AudioFrequencyLineActivity.this);
+ mRecordThread.setName("FrequencyAnalyzerThread");
+ mRecordThreadShutdown = false;
+ }
+ if (!mRecordThread.isAlive()) {
+ mRecordThread.start();
+ }
+
+ mPipe.flush();
+
+ long startTime = SystemClock.uptimeMillis();
+ mRecorder.startRecording();
+ if (mRecorder.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
+ stopRecording();
+ return;
+ }
+ Log.v(TAG, "Start time: " + (long) (SystemClock.uptimeMillis() - startTime) + " ms");
+ }
+
+ private void stopRecording() {
+ synchronized (mRecordingLock) {
+ stopRecordingForReal();
+ mIsRecording = false;
+ }
+ }
+
+ private void stopRecordingForReal() {
+
+ // stop streaming
+ Thread zeThread = mRecordThread;
+ mRecordThread = null;
+ mRecordThreadShutdown = true;
+ if (zeThread != null) {
+ zeThread.interrupt();
+ try {
+ zeThread.join();
+ } catch(InterruptedException e) {
+ Log.v(TAG,"Error shutting down recording thread " + e);
+ //we don't really care about this error, just logging it.
+ }
+ }
+ // release recording resources
+ if (mRecorder != null) {
+ mRecorder.stop();
+ mRecorder.release();
+ mRecorder = null;
+ }
+ }
+
+ private boolean initRecord() {
+ int minRecordBuffSizeInBytes = AudioRecord.getMinBufferSize(mSamplingRate,
+ mChannelConfig, mAudioFormat);
+ Log.v(TAG,"FrequencyAnalyzer: min buff size = " + minRecordBuffSizeInBytes + " bytes");
+ if (minRecordBuffSizeInBytes <= 0) {
+ return false;
+ }
+
+ mMinRecordBufferSizeInSamples = minRecordBuffSizeInBytes / 2;
+ // allocate the byte array to read the audio data
+
+ mAudioShortArray = new short[mMinRecordBufferSizeInSamples];
+
+ Log.v(TAG, "Initiating record:");
+ Log.v(TAG, " using source " + mSelectedRecordSource);
+ Log.v(TAG, " at " + mSamplingRate + "Hz");
+
+ try {
+ mRecorder = new AudioRecord(mSelectedRecordSource, mSamplingRate,
+ mChannelConfig, mAudioFormat, 2 * minRecordBuffSizeInBytes);
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ if (mRecorder.getState() != AudioRecord.STATE_INITIALIZED) {
+ mRecorder.release();
+ mRecorder = null;
+ return false;
+ }
+ mRecorder.setRecordPositionUpdateListener(this);
+ mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
+ return true;
+ }
+
+ // ---------------------------------------------------------
+ // Implementation of AudioRecord.OnPeriodicNotificationListener
+ // --------------------
+ public void onPeriodicNotification(AudioRecord recorder) {
+ int samplesAvailable = mPipe.availableToRead();
+ int samplesNeeded = mBlockSizeSamples;
+ if (samplesAvailable >= samplesNeeded) {
+ mPipe.read(mAudioShortArray2, 0, samplesNeeded);
+
+ //compute stuff.
+ double maxval = Math.pow(2, 15);
+ int clipcount = 0;
+ double cliplevel = (maxval-10) / maxval;
+ double sum = 0;
+ double maxabs = 0;
+ int i;
+ int index = 0;
+
+ for (i = 0; i < samplesNeeded; i++) {
+ double value = mAudioShortArray2[i] / maxval;
+ double valueabs = Math.abs(value);
+
+ if (valueabs > maxabs) {
+ maxabs = valueabs;
+ }
+
+ if (valueabs > cliplevel) {
+ clipcount++;
+ }
+
+ sum += value * value;
+ //fft stuff
+ if (index < mBlockSizeSamples) {
+ mData.mData[index] = value;
+ }
+ index++;
+ }
+
+ //for the current frame, compute FFT and send to the viewer.
+
+ //apply window and pack as complex for now.
+ DspBufferMath.mult(mData, mData, mWindow.mBuffer);
+ DspBufferMath.set(mC, mData);
+ mFftServer.fft(mC, 1);
+
+ double[] halfMagnitude = new double[mBlockSizeSamples / 2];
+ for (i = 0; i < mBlockSizeSamples / 2; i++) {
+ halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
+ }
+
+ mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
+
+ switch(mCurrentTest) {
+ case 0:
+ mFreqAverage0.setData(halfMagnitude, false);
+ break;
+ case 1:
+ mFreqAverage1.setData(halfMagnitude, false);
+ break;
+ }
+ }
+ }
+
+ public void onMarkerReached(AudioRecord track) {
+ }
+
+ // ---------------------------------------------------------
+ // Implementation of Runnable for the audio recording + playback
+ // --------------------
+ public void run() {
+ int nSamplesRead = 0;
+
+ Thread thisThread = Thread.currentThread();
+ while (mRecordThread == thisThread && !mRecordThreadShutdown) {
+ // read from native recorder
+ nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBufferSizeInSamples);
+ if (nSamplesRead > 0) {
+ mPipe.write(mAudioShortArray, 0, nSamplesRead);
+ }
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
new file mode 100644
index 0000000..23b71c0
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/SoundPlayerObject.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import android.content.Context;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.net.rtp.AudioStream;
+import android.util.Log;
+
+import com.android.cts.verifier.audio.wavelib.PipeShort;
+
+import java.io.IOException;
+
+public class SoundPlayerObject extends Thread {
+ private static final String LOGTAG = "SoundPlayerObject";
+ private MediaPlayer mMediaPlayer;
+ private boolean isInitialized = false;
+ private boolean isRunning = false;
+
+ public PipeShort mPipe = new PipeShort(65536);
+ private short[] mAudioShortArray;
+
+ public AudioTrack mAudioTrack;
+ public int mSamplingRate = 48000;
+ private int mChannelConfigOut = AudioFormat.CHANNEL_OUT_MONO;
+ private int mAudioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ int mMinPlayBufferSizeInBytes = 0;
+ int mMinBufferSizeInSamples = 0;
+
+ private int mStreamType = AudioManager.STREAM_MUSIC;
+ private int mResId = -1;
+ private boolean mUseMediaPlayer = true;
+ private float mBalance = 0.5f; //0 left, 1 right
+
+ public int getCurrentResId() {
+ return mResId;
+ }
+
+ public int getStreamType () {
+ return mStreamType;
+ }
+
+ public void run() {
+ setPriority(Thread.MAX_PRIORITY);
+ isRunning = true;
+ while (isRunning) {
+
+ if (!mUseMediaPlayer && isInitialized && isPlaying()) {
+ int valuesAvailable = mPipe.availableToRead();
+ if (valuesAvailable > 0) {
+
+ int valuesOfInterest = valuesAvailable;
+ if (mMinBufferSizeInSamples < valuesOfInterest) {
+ valuesOfInterest = mMinBufferSizeInSamples;
+ }
+ mPipe.read(mAudioShortArray, 0,valuesOfInterest);
+ //inject into output.
+ mAudioTrack.write(mAudioShortArray, 0, valuesOfInterest);
+ }
+ } else {
+ try {
+ sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ public void setBalance(float balance) {
+ mBalance = balance;
+ if (mUseMediaPlayer) {
+ if (mMediaPlayer != null) {
+ float left = Math.min(2.0f * (1.0f - mBalance), 1.0f);
+ float right = Math.min(2.0f * mBalance, 1.0f);
+ mMediaPlayer.setVolume(left, right);
+ log(String.format("Setting balance to %f", mBalance));
+ }
+ }
+ }
+
+ public void setStreamType(int streamType) {
+ mStreamType = streamType;
+ }
+
+ public void rewind() {
+ if (mUseMediaPlayer) {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.seekTo(0);
+ }
+ }
+ }
+
+ public void setSoundWithResId(Context context, int resId) {
+ boolean playing = isPlaying();
+ //release player
+ releasePlayer();
+ mResId = resId;
+ if (mUseMediaPlayer) {
+ mMediaPlayer = new MediaPlayer();
+ try {
+ log("opening resource with stream type: " + mStreamType);
+ mMediaPlayer.setAudioStreamType(mStreamType);
+ mMediaPlayer.setDataSource(context.getApplicationContext(),
+ Uri.parse("android.resource://com.android.cts.verifier/" + resId));
+ mMediaPlayer.prepare();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ mMediaPlayer.setLooping(true);
+ setBalance(mBalance);
+ } else {
+ mMinPlayBufferSizeInBytes = AudioTrack.getMinBufferSize(mSamplingRate,
+ mChannelConfigOut, mAudioFormat);
+
+ mMinBufferSizeInSamples = mMinPlayBufferSizeInBytes / 2;
+ mAudioShortArray = new short[mMinBufferSizeInSamples * 4];
+
+ mAudioTrack = new AudioTrack(mStreamType,
+ mSamplingRate,
+ mChannelConfigOut,
+ mAudioFormat,
+ mMinPlayBufferSizeInBytes,
+ AudioTrack.MODE_STREAM /* FIXME runtime test for API level 9 ,
+ mSessionId */);
+ mPipe.flush();
+ isInitialized = true;
+ }
+
+ log("done preparing media player");
+ if (playing)
+ play(true); //start playing if it was playing before
+ }
+
+ public boolean isPlaying() {
+ boolean result = false;
+ if (mUseMediaPlayer) {
+ if (mMediaPlayer != null) {
+ result = mMediaPlayer.isPlaying();
+ }
+ } else {
+ if (mAudioTrack != null) {
+ result = mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING;
+ }
+ }
+ return result;
+ }
+
+ public void play(boolean play) {
+ if (mUseMediaPlayer) {
+ if (mMediaPlayer != null) {
+ if (play) {
+ mMediaPlayer.start();
+ } else {
+ mMediaPlayer.pause();
+ }
+ }
+ } else {
+ if (mAudioTrack != null && isInitialized) {
+ if (play) {
+ mPipe.flush();
+ mAudioTrack.flush();
+ mAudioTrack.play();
+ } else {
+ mAudioTrack.pause();
+ }
+ }
+ }
+ }
+
+ public void finish() {
+ play(false);
+ releasePlayer();
+ }
+
+ private void releasePlayer() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.stop();
+ mMediaPlayer.release();
+ mMediaPlayer = null;
+ }
+
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack.release();
+ mAudioTrack = null;
+ }
+ isInitialized = false;
+ }
+
+ /*
+ Misc
+ */
+ private static void log(String msg) {
+ Log.v(LOGTAG, msg);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java
new file mode 100644
index 0000000..0a8bdde
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferBase.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public abstract class DspBufferBase {
+ private int mSize;
+
+ public DspBufferBase() {
+ setSize(0);
+ }
+
+ public DspBufferBase(int size) {
+ setSize(size);
+ }
+
+ public int getSize() {
+ return mSize;
+ }
+
+ public void setSize(int size) {
+ mSize = size;
+ }
+
+ public abstract void setValue(int index, double value);
+
+ public abstract void setValues(int index, double... values);
+
+ @Override
+ public String toString() {
+ return String.format("Size: %d", mSize);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java
new file mode 100644
index 0000000..2b71343
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferComplex.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public class DspBufferComplex extends DspBufferBase {
+ public double[] mReal;
+ public double[] mImag;
+
+ public DspBufferComplex(int size) {
+ super(size);
+ }
+
+ @Override
+ public void setSize(int size) {
+ if (size == getSize()) {
+ return;
+ }
+ mReal = new double[size];
+ mImag = new double[size];
+ super.setSize(size);
+ }
+
+ // Warning, these methods don't check for bounds!
+ @Override
+ public void setValues(int index, double... values) {
+ mReal[index] = values[0];
+ mImag[index] = values[1];
+ }
+
+ @Override
+ public void setValue(int index, double value) {
+ mReal[index] = value;
+ mImag[index] = 0;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ int size = getSize();
+ sb.append(String.format("Size: %d { ", size));
+ for (int i = 0; i < size; i++) {
+ sb.append(String.format("(%.3f, %3f) ", mReal[i], mImag[i]));
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java
new file mode 100644
index 0000000..1b75da6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferDouble.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public class DspBufferDouble extends DspBufferBase {
+ public double[] mData;
+
+ public DspBufferDouble(int size) {
+ super(size);
+ }
+
+ @Override
+ public void setSize(int size) {
+ if (size == getSize()) {
+ return;
+ }
+ mData = new double[size];
+ super.setSize(size);
+ }
+
+ // Warning, these methods don't check for bounds!
+ @Override
+ public void setValues(int index, double... values) {
+ mData[index] = values[0];
+ }
+
+ @Override
+ public void setValue(int index, double value) {
+ mData[index] = value;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ int size = getSize();
+ sb.append(String.format("Size: %d { ", size));
+ int i = 0;
+ for (; i < size - 1; i++) {
+ sb.append(String.format("%.3f, ", mData[i]));
+ }
+ for(; i < size; i++) {
+ sb.append(String.format("%.3f", mData[i]));
+ }
+ sb.append(" }");
+ return sb.toString();
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
new file mode 100644
index 0000000..a9cbbd0
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspBufferMath.java
@@ -0,0 +1,329 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+import android.util.Log;
+
+public class DspBufferMath {
+ private static final String TAG = "DspBufferMath";
+ public static final int OPERANDS_TYPE_UNKNOWN = -1;
+ public static final int OPERANDS_TYPE_REAL = 0;
+ public static final int OPERANDS_TYPE_COMPLEX = 1;
+ public static final int OPERANDS_TYPE_MIXED = 2;
+
+ public static final int MATH_RESULT_UNDEFINED = -1;
+ public static final int MATH_RESULT_SUCCESS = 0;
+ public static final int MATH_RESULT_ERROR = 1;
+
+ static private<T extends DspBufferBase> int estimateOperandsType(T a, T b) {
+ if (a instanceof DspBufferComplex) {
+ if (b instanceof DspBufferComplex) {
+ return OPERANDS_TYPE_COMPLEX;
+ } else if (b instanceof DspBufferDouble) {
+ return OPERANDS_TYPE_MIXED;
+ }
+ } else if (a instanceof DspBufferDouble) {
+ if (b instanceof DspBufferComplex) {
+ return OPERANDS_TYPE_MIXED;
+ } else if (b instanceof DspBufferDouble) {
+ return OPERANDS_TYPE_REAL;
+ }
+ }
+ return OPERANDS_TYPE_UNKNOWN;
+ }
+
+ /**
+ * adds r = a + b; element by element
+ *
+ * If the result is double vector, the imaginary part of complex operations is ignored.
+ */
+ static public <T extends DspBufferBase> int add(T r, T a, T b) {
+ int size = Math.min(a.getSize(), b.getSize());
+ r.setSize(size);
+
+ T x = a;
+ T y = b;
+ int opType = estimateOperandsType(a, b);
+
+ if (opType == OPERANDS_TYPE_MIXED) {
+ if (a instanceof DspBufferDouble) {
+ x = b; //Complex first
+ y = a;
+ }
+ }
+
+ if (opType == OPERANDS_TYPE_UNKNOWN) {
+ return MATH_RESULT_UNDEFINED;
+ }
+
+ if (r instanceof DspBufferComplex) {
+ switch (opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] =
+ ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
+ ((DspBufferComplex) r).mImag[i] = 0;
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] =
+ ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
+ ((DspBufferComplex) r).mImag[i] =
+ ((DspBufferComplex) x).mImag[i] + ((DspBufferComplex) y).mImag[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] =
+ ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
+ ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ } else if (r instanceof DspBufferDouble) {
+ switch (opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] =
+ ((DspBufferDouble) x).mData[i] + ((DspBufferDouble) y).mData[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] =
+ ((DspBufferComplex) x).mReal[i] + ((DspBufferComplex) y).mReal[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] =
+ ((DspBufferComplex) x).mReal[i] + ((DspBufferDouble) y).mData[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ }
+ return MATH_RESULT_ERROR;
+ }
+
+ /**
+ * mult r = a * b; element by element
+ */
+ static public <T extends DspBufferBase> int mult(T r, T a, T b) {
+ int size = Math.min(a.getSize(), b.getSize());
+ r.setSize(size);
+
+ T x = a;
+ T y = b;
+ int opType = estimateOperandsType(a, b);
+
+ if (opType == OPERANDS_TYPE_MIXED) {
+ if (a instanceof DspBufferDouble) {
+ x = b; //Complex first
+ y = a;
+ }
+ }
+
+ if (opType == OPERANDS_TYPE_UNKNOWN) {
+ return MATH_RESULT_UNDEFINED;
+ }
+
+ if (r instanceof DspBufferComplex) {
+ switch (opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] =
+ ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
+ ((DspBufferComplex) r).mImag[i] = 0;
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ double A = ((DspBufferComplex) x).mReal[i];
+ double B = ((DspBufferComplex) x).mImag[i];
+ double C = ((DspBufferComplex) y).mReal[i];
+ double D = ((DspBufferComplex) y).mImag[i];
+ ((DspBufferComplex) r).mReal[i] = (C * A) - (B * D);
+ ((DspBufferComplex) r).mImag[i] = (C * B) + (A * D);
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ double A = ((DspBufferComplex) x).mReal[i];
+ double B = ((DspBufferComplex) x).mImag[i];
+ double C = ((DspBufferDouble) y).mData[i];
+ //double D = 0;
+ ((DspBufferComplex) r).mReal[i] = C * A;
+ ((DspBufferComplex) r).mImag[i] = C * B;
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ } else if (r instanceof DspBufferDouble) {
+ switch (opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] =
+ ((DspBufferDouble) x).mData[i] * ((DspBufferDouble) y).mData[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ double A = ((DspBufferComplex) x).mReal[i];
+ double B = ((DspBufferComplex) x).mImag[i];
+ double C = ((DspBufferComplex) y).mReal[i];
+ double D = ((DspBufferComplex) y).mImag[i];
+ ((DspBufferDouble) r).mData[i] = (C * A) - (B * D);
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ double A = ((DspBufferComplex) x).mReal[i];
+ double B = ((DspBufferComplex) x).mImag[i];
+ double C = ((DspBufferDouble) y).mData[i];
+ //double D = 0;
+ ((DspBufferDouble) r).mData[i] = C * A;
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ }
+ return MATH_RESULT_ERROR;
+ }
+
+ /**
+ * mult r = a * v; element by element
+ */
+ static public <T extends DspBufferBase> int mult(T r, T a, double v) {
+ int size = a.getSize();
+ r.setSize(size);
+
+ T x = a;
+ int opType = estimateOperandsType(r, a);
+
+ if (opType == OPERANDS_TYPE_UNKNOWN) {
+ return MATH_RESULT_UNDEFINED;
+ }
+
+ if (r instanceof DspBufferComplex) {
+ switch (opType) {
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i] * v;
+ ((DspBufferComplex) r).mImag[i] = 0;
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i] * v;
+ ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i] * v;
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ } else if (r instanceof DspBufferDouble) {
+ switch (opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i] * v;
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i] * v;
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ }
+ return MATH_RESULT_ERROR;
+ }
+
+ /**
+ * set r = a ; element by element
+ */
+ static public <T extends DspBufferBase> int set(T r, T a) {
+ int size = a.getSize();
+ r.setSize(size);
+
+ T x = a;
+ int opType = estimateOperandsType(r, a);
+
+ if (opType == OPERANDS_TYPE_UNKNOWN) {
+ return MATH_RESULT_UNDEFINED;
+ }
+
+ if (r instanceof DspBufferComplex) {
+ switch (opType) {
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] = ((DspBufferDouble) x).mData[i];
+ ((DspBufferComplex) r).mImag[i] = 0;
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_COMPLEX:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] = ((DspBufferComplex) x).mReal[i];
+ ((DspBufferComplex) r).mImag[i] = ((DspBufferComplex) x).mImag[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ } else if (r instanceof DspBufferDouble) {
+ switch(opType) {
+ case OPERANDS_TYPE_REAL:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] = ((DspBufferDouble) x).mData[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ case OPERANDS_TYPE_MIXED:
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] = ((DspBufferComplex) x).mReal[i];
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ }
+ return MATH_RESULT_ERROR;
+ }
+
+
+ /**
+ * set r = v ; all elements the same
+ * It keeps the size of the return vector
+ */
+ static public <T extends DspBufferBase> int set(T r, double ...values) {
+ int size = r.getSize();
+
+ double a = 0;
+ double b = 0;
+ if (values.length > 0) {
+ a = values[0];
+ }
+ if (values.length > 1) {
+ b = values[1];
+ }
+
+ if (r instanceof DspBufferComplex) {
+ for (int i = 0; i < size; i++) {
+ ((DspBufferComplex) r).mReal[i] = a;
+ ((DspBufferComplex) r).mImag[i] = b;
+ }
+ return MATH_RESULT_SUCCESS;
+ } else if (r instanceof DspBufferDouble) {
+ for (int i = 0; i < size; i++) {
+ ((DspBufferDouble) r).mData[i] = a;
+ }
+ return MATH_RESULT_SUCCESS;
+ }
+ return MATH_RESULT_ERROR;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java
new file mode 100644
index 0000000..09337f1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspFftServer.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public class DspFftServer {
+ private int mN = 0;
+ private int mOrder = 0;
+
+ DspBufferDouble mCos;
+ DspBufferDouble mSin;
+ public boolean isInitialized = false;
+
+ public DspFftServer(int size) {
+ init(size);
+ }
+
+ public boolean init(int size) {
+ boolean status = false;
+ mN=size;
+
+ mOrder = (int) (Math.log(mN) / Math.log(2));
+ if (mN == (1 << mOrder)) {
+ mCos = new DspBufferDouble(mN / 2);
+ mSin = new DspBufferDouble(mN / 2);
+ for (int i = 0; i < mN / 2; i++) {
+ mCos.mData[i] = Math.cos(-2 * Math.PI * i / mN);
+ mSin.mData[i] = Math.sin(-2 * Math.PI * i / mN);
+ }
+ status = true;
+ } else {
+ mN = 0;
+ throw new RuntimeException("FFT must be power of 2");
+ }
+ isInitialized = status;
+ return status;
+ }
+
+ public void fft(DspBufferComplex r, int sign) {
+ int ii, jj, kk, n1, n2, aa;
+ double cc, ss, t1, t2;
+
+ // Bit-reverse
+ jj = 0;
+ n2 = mN / 2;
+ for (ii = 1; ii < mN - 1; ii++) {
+ n1 = n2;
+ while (jj >= n1) {
+ jj = jj - n1;
+ n1 = n1 / 2;
+ }
+ jj = jj + n1;
+
+ if (ii < jj) {
+ t1 = r.mReal[ii];
+ r.mReal[ii] = r.mReal[jj];
+ r.mReal[jj] = t1;
+ t1 = r.mImag[ii];
+ r.mImag[ii] = r.mImag[jj];
+ r.mImag[jj] = t1;
+ }
+ }
+
+ // FFT
+ n1 = 0;
+ n2 = 1;
+ for (ii = 0; ii < mOrder; ii++) {
+ n1 = n2;
+ n2 = n2 + n2;
+ aa = 0;
+
+ for (jj = 0; jj < n1; jj++) {
+ cc = mCos.mData[aa];
+ ss = sign * mSin.mData[aa];
+ aa += 1 << (mOrder - ii - 1);
+ for (kk = jj; kk < mN; kk = kk + n2) {
+ t1 = cc * r.mReal[kk + n1] - ss * r.mImag[kk + n1];
+ t2 = ss * r.mReal[kk + n1] + cc * r.mImag[kk + n1];
+ r.mReal[kk + n1] = r.mReal[kk] - t1;
+ r.mImag[kk + n1] = r.mImag[kk] - t2;
+ r.mReal[kk] = r.mReal[kk] + t1;
+ r.mImag[kk] = r.mImag[kk] + t2;
+ }
+ }
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java
new file mode 100644
index 0000000..3ccca43
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/DspWindow.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+public class DspWindow {
+ public DspBufferDouble mBuffer;
+ private int mWindowType = WINDOW_RECTANGULAR;
+ private int mSize;
+ private int mOverlap;
+
+ private static final double TWOPI = Math.PI * 2;
+
+ public static final int WINDOW_RECTANGULAR = 0;
+ public static final int WINDOW_TRIANGULAR = 1;
+ public static final int WINDOW_TRIANGULAR_FLAT_TOP = 2;
+ public static final int WINDOW_HAMMING = 3;
+ public static final int WINDOW_HAMMING_FLAT_TOP = 4;
+ public static final int WINDOW_HANNING = 5;
+ public static final int WINDOW_HANNING_FLAT_TOP = 6;
+
+ public DspWindow(int windowType, int size, int overlap) {
+ init(windowType, size, overlap);
+ }
+
+ public DspWindow(int windowType, int size) {
+ init(windowType, size, size / 2);
+ }
+
+ public void init(int windowType, int size, int overlap) {
+ if (size > 0 && overlap > 0) {
+ mSize = size;
+ mOverlap = overlap;
+ if (mOverlap > mSize / 2) {
+ mOverlap = mSize / 2;
+ }
+
+ mBuffer = new DspBufferDouble(mSize);
+ if (fillWindow(mBuffer, windowType, mOverlap)) {
+ mWindowType = windowType;
+ }
+ }
+ }
+
+ public void scale(double scale) {
+ DspBufferMath.mult(mBuffer, mBuffer, scale);
+ }
+
+ public static boolean fillWindow(DspBufferDouble r, int type, int overlap) {
+ boolean status = false;
+ int size = r.getSize();
+ if (overlap > size / 2) {
+ overlap = size / 2;
+ }
+
+ switch(type) {
+ case WINDOW_RECTANGULAR:
+ status = fillRectangular(r);
+ break;
+ case WINDOW_TRIANGULAR:
+ status = fillTriangular(r, size / 2);
+ break;
+ case WINDOW_TRIANGULAR_FLAT_TOP:
+ status = fillTriangular(r, overlap);
+ break;
+ case WINDOW_HAMMING:
+ status = fillHamming(r, size / 2);
+ break;
+ case WINDOW_HAMMING_FLAT_TOP:
+ status = fillHamming(r, overlap);
+ break;
+ case WINDOW_HANNING:
+ status = fillHanning(r, size / 2);
+ break;
+ case WINDOW_HANNING_FLAT_TOP:
+ status = fillHanning(r, overlap);
+ break;
+ }
+ return status;
+ }
+
+ private static boolean fillRectangular(DspBufferDouble r) {
+ if (DspBufferMath.set(r, 1.0) == DspBufferMath.MATH_RESULT_SUCCESS) {
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean fillTriangular(DspBufferDouble b, int overlap) {
+ int size = b.getSize();
+ if (overlap > size / 2) {
+ overlap = size / 2;
+ }
+
+ double value;
+ //ramp up
+ int i = 0;
+ if (overlap > 0) {
+ for (i = 0; i < overlap; i++) {
+ value = (2.0 * i + 1) / (2 * overlap);
+ b.mData[i] = value;
+ }
+ }
+
+ //flat top
+ for (; i < size - overlap; i++) {
+ b.mData[i] = 1.0;
+ }
+
+ //ramp down
+ if (overlap > 0) {
+ for (; i < size; i++) {
+ value = (2.0 * (size - i) - 1) / (2 * overlap);
+ b.mData[i] = value;
+ }
+ }
+ return true;
+ }
+
+ private static boolean fillHamming(DspBufferDouble b, int overlap) {
+ int size = b.getSize();
+ if (overlap > size / 2)
+ overlap = size / 2;
+
+ //create window, then copy
+ double value;
+
+ int twoOverlap = 2 * overlap;
+ //ramp up
+ int i = 0;
+ if (overlap > 0) {
+ for (i = 0; i < overlap; i++) {
+ value = 0.54 - 0.46 * Math.cos(TWOPI * i / (twoOverlap - 1));
+ b.mData[i] = value;
+ }
+ }
+
+ //flat top
+ for (; i < size - overlap; i++) {
+ b.mData[i] = 1.0;
+ }
+
+ //ramp down
+ int k;
+ if (overlap > 0) {
+ for (; i < size; i++) {
+ k = i - (size - 2 * overlap);
+ value = 0.54 - 0.46 * Math.cos(TWOPI * k / (twoOverlap - 1));
+ b.mData[i] = value;
+ }
+ }
+ return true;
+ }
+
+ private static boolean fillHanning(DspBufferDouble b, int overlap) {
+ int size = b.getSize();
+ if (overlap > size / 2)
+ overlap = size / 2;
+
+ //create window, then copy
+ double value;
+
+ int twoOverlap = 2*overlap;
+ //ramp up
+ int i = 0;
+ if (overlap > 0) {
+ for (i = 0; i < overlap; i++) {
+ value = 0.5 * (1.0 - Math.cos(TWOPI * i / (twoOverlap - 1)));
+ b.mData[i] = value;
+ }
+ }
+
+ //flat top
+ for (; i < size - overlap; i++) {
+ b.mData[i] = 1.0;
+ }
+
+ //ramp down
+ if (overlap > 0) {
+ for (; i < size; i++) {
+ int k = i - (size - 2 * overlap);
+ value = 0.5 * (1.0 - Math.cos(TWOPI * k / (twoOverlap - 1)));
+ b.mData[i] = value;
+ }
+ }
+ return true;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java
new file mode 100644
index 0000000..83b171f
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/PipeShort.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+// Non-blocking pipe supports a single writer and single reader.
+// The write side of a pipe permits overruns; flow control is the caller's responsibility.
+
+public class PipeShort {
+ private int mFront;
+ private int mRear;
+ private short mBuffer[];
+ private volatile int mVolatileRear; // written by write(), read by read()
+ private int mMaxValues;
+ private int mBytesOverrun;
+ private int mOverruns;
+ public static final int OVERRUN = -2;
+
+ // maxBytes will be rounded up to a power of 2, and all slots are available. Must be >= 2.
+ public PipeShort(int maxValues)
+ {
+ mMaxValues = roundup(maxValues);
+ mBuffer = new short[mMaxValues];
+ }
+
+ // buffer must != null.
+ // offset must be >= 0.
+ // count is maximum number of bytes to copy, and must be >= 0.
+ // offset + count must be <= buffer.length.
+ // Returns actual number of bytes copied >= 0.
+ public int write(short[] buffer, int offset, int count)
+ {
+ int rear = mRear & (mMaxValues - 1);
+ int written = mMaxValues - rear;
+ if (written > count) {
+ written = count;
+ }
+ System.arraycopy(buffer, offset, mBuffer, rear, written);
+ if (rear + written == mMaxValues) {
+ if ((count -= written) > rear) {
+ count = rear;
+ }
+ if (count > 0) {
+ System.arraycopy(buffer, offset + written, mBuffer, 0, count);
+ written += count;
+ }
+ }
+ mRear += written;
+ mVolatileRear = mRear;
+ return written;
+ }
+
+ public int availableToRead()
+ {
+ int rear = mVolatileRear;
+ int avail = rear - mFront;
+ if (avail > mMaxValues) {
+ // Discard 1/16 of the most recent data in pipe to avoid another overrun immediately
+ int oldFront = mFront;
+ mFront = rear - mMaxValues + (mMaxValues >> 4);
+ mBytesOverrun += mFront - oldFront;
+ ++mOverruns;
+ return OVERRUN;
+ }
+ return avail;
+ }
+
+ // buffer must != null.
+ // offset must be >= 0.
+ // count is maximum number of bytes to copy, and must be >= 0.
+ // offset + count must be <= buffer.length.
+ // Returns actual number of bytes copied >= 0.
+ public int read(short[] buffer, int offset, int count)
+ {
+ int avail = availableToRead();
+ if (avail <= 0) {
+ return avail;
+ }
+ // An overrun can occur from here on and be silently ignored,
+ // but it will be caught at next read()
+ if (count > avail) {
+ count = avail;
+ }
+ int front = mFront & (mMaxValues - 1);
+ int red = mMaxValues - front;
+ if (red > count) {
+ red = count;
+ }
+ // In particular, an overrun during the System.arraycopy will result in reading corrupt data
+ System.arraycopy(mBuffer, front, buffer, offset, red);
+ // We could re-read the rear pointer here to detect the corruption, but why bother?
+ if (front + red == mMaxValues) {
+ if ((count -= red) > front) {
+ count = front;
+ }
+ if (count > 0) {
+ System.arraycopy(mBuffer, 0, buffer, offset + red, count);
+ red += count;
+ }
+ }
+ mFront += red;
+ return red;
+ }
+
+ public void flush()
+ {
+ mRear = mFront;
+ mVolatileRear = mFront;
+ }
+
+ // Round up to the next highest power of 2
+ private static int roundup(int v)
+ {
+ // Integer.numberOfLeadingZeros() returns 32 for zero input
+ if (v == 0) {
+ v = 1;
+ }
+ int lz = Integer.numberOfLeadingZeros(v);
+ int rounded = 0x80000000 >>> lz;
+ // 0x800000001 and higher are actually rounded _down_ to prevent overflow
+ if (v > rounded && lz > 0) {
+ rounded <<= 1;
+ }
+ return rounded;
+ }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.java
new file mode 100644
index 0000000..41f0411
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/wavelib/VectorAverage.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio.wavelib;
+
+import android.util.Log;
+
+public class VectorAverage {
+ private static final String LOGTAG = "VectorAverage";
+ private static final int mVersion = 0;
+ private double[] mData;
+ private int mValueCount = 0;
+
+ public void setData(double[] data, boolean replace) {
+ int size = data.length;
+ if (mData == null || mData.length != size) {
+ mData = new double[size];
+ mValueCount = 0;
+ }
+ if (replace || mValueCount == 0) {
+ System.arraycopy(data, 0, mData, 0, size);
+ mValueCount = 1;
+ } else {
+ for (int i = 0; i < size; i++) {
+ mData[i] += data[i];
+ }
+ mValueCount++;
+ }
+ }
+
+ public int getData(double[] data, boolean raw) {
+ int nCount = 0;
+ if (mData != null && mData.length <= data.length) {
+ nCount = mData.length;
+ if (mValueCount == 0) {
+ for (int i = 0; i < nCount; i++) {
+ data[i] = 0;
+ }
+ } else if (!raw && mValueCount > 1) {
+ for (int i = 0; i < nCount; i++) {
+ data[i] = mData[i] / mValueCount;
+ }
+ } else {
+ for (int i = 0; i < nCount; i++) {
+ data[i] = mData[i];
+ }
+ }
+ }
+ return nCount;
+ }
+
+ public int getCount() {
+ return mValueCount;
+ }
+
+ public int getSize() {
+ if (mData != null) {
+ return mData.length;
+ }
+ return 0;
+ }
+
+ public void reset() {
+ mValueCount = 0;
+ }
+
+ private final String SERIALIZED_VERSION = "VECTOR_AVERAGE_VERSION";
+ private final String SERIALIZED_COUNT = "COUNT";
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+
+ //version
+ sb.append(SERIALIZED_VERSION +"="+ mVersion +"\n");
+
+ double[] data = new double[getSize()];
+ getData(data,false);
+
+ //element count
+ int nCount = data.length;
+ sb.append(SERIALIZED_COUNT + "=" + nCount +"\n");
+
+ for (int i = 0; i < nCount; i++) {
+ sb.append(String.format("%f\n",data[i]));
+ }
+
+ return sb.toString();
+ }
+
+ public boolean initFromString(String string) {
+ boolean success = false;
+
+ String[] lines = string.split(System.getProperty("line.separator"));
+
+ int lineCount = lines.length;
+ if (lineCount > 3) {
+ int nVersion = -1;
+ int nCount = -1;
+ int nIndex = 0;
+
+ //search for version:
+ while (nIndex < lineCount) {
+ String[] separated = lines[nIndex].split("=");
+ nIndex++;
+ if (separated.length > 1 && separated[0].equalsIgnoreCase(SERIALIZED_VERSION)) {
+ nVersion = Integer.parseInt(separated[1]);
+ break;
+ }
+ }
+
+ if (nVersion >= 0) {
+ //get count
+
+ while (nIndex < lineCount) {
+ String[] separated = lines[nIndex].split("=");
+ nIndex++;
+ if (separated.length > 1 && separated[0].equalsIgnoreCase(SERIALIZED_COUNT)) {
+ nCount = Integer.parseInt(separated[1]);
+ break;
+ }
+ }
+
+ if (nCount > 0 && nCount <= lineCount-2 && nCount < 20000) { //foolproof
+ //now add nCount to the vector.
+ double[] data = new double[nCount];
+ int dataIndex=0;
+
+ while (nIndex < lineCount) {
+ double value = Double.parseDouble(lines[nIndex]);
+ data[dataIndex++] = value;
+ nIndex++;
+ }
+ setData(data, true);
+ success = true;
+ }
+ }
+ }
+
+ return success;
+ }
+
+ private static void log(String msg) {
+ Log.v(LOGTAG, msg);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 15e80b7..3037376 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -1156,25 +1156,34 @@
}
// Initiate the captures.
+ long maxExpTimeNs = -1;
for (int i = 0; i < requests.size(); i++) {
+ CaptureRequest.Builder req = requests.get(i);
// For DNG captures, need the LSC map to be available.
if (mCaptureRawIsDng) {
- requests.get(i).set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 1);
+ req.set(CaptureRequest.STATISTICS_LENS_SHADING_MAP_MODE, 1);
+ }
+ Long expTimeNs = req.get(CaptureRequest.SENSOR_EXPOSURE_TIME);
+ if (expTimeNs != null && expTimeNs > maxExpTimeNs) {
+ maxExpTimeNs = expTimeNs;
}
- CaptureRequest.Builder req = requests.get(i);
for (int j = 0; j < numSurfaces; j++) {
req.addTarget(mOutputImageReaders[j].getSurface());
}
mSession.capture(req.build(), mCaptureResultListener, mResultHandler);
}
+ long timeout = TIMEOUT_CALLBACK * 1000;
+ if (maxExpTimeNs > 0) {
+ timeout += maxExpTimeNs / 1000000; // ns to ms
+ }
// Make sure all callbacks have been hit (wait until captures are done).
// If no timeouts are received after a timeout, then fail.
int currentCount = mCountCallbacksRemaining.get();
while (currentCount > 0) {
try {
- Thread.sleep(TIMEOUT_CALLBACK*1000);
+ Thread.sleep(timeout);
} catch (InterruptedException e) {
throw new ItsException("Timeout failure", e);
}
@@ -1286,8 +1295,8 @@
CaptureRequest.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR));
inputReqest.set(CaptureRequest.NOISE_REDUCTION_MODE,
- CaptureRequest.NOISE_REDUCTION_MODE_OFF);
- inputReqest.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_OFF);
+ CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
+ inputReqest.set(CaptureRequest.EDGE_MODE, CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
inputReqest.set(CaptureRequest.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR, null);
inputReqest.addTarget(mInputImageReader.getSurface());
mSession.capture(inputReqest.build(), captureCallbackWaiter, mResultHandler);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index a463937..bee1241 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -32,6 +32,7 @@
import com.android.cts.verifier.DialogTestListActivity;
import com.android.cts.verifier.R;
import com.android.cts.verifier.TestListActivity;
+import com.android.cts.verifier.TestListAdapter.TestListItem;
import com.android.cts.verifier.TestResult;
/**
@@ -73,6 +74,7 @@
private DialogTestListItem mCrossProfileImageCaptureSupportTest;
private DialogTestListItem mCrossProfileVideoCaptureSupportTest;
private DialogTestListItem mCrossProfileAudioCaptureSupportTest;
+ private TestListItem mKeyguardDisabledFeaturesTest;
public ByodFlowTestActivity() {
super(R.layout.provisioning_byod,
@@ -256,6 +258,11 @@
R.string.provisioning_byod_cross_profile_instruction,
chooser);
+ mKeyguardDisabledFeaturesTest = TestListItem.newTest(this,
+ R.string.provisioning_byod_keyguard_disabled_features,
+ KeyguardDisabledFeaturesActivity.class.getName(),
+ new Intent(this, KeyguardDisabledFeaturesActivity.class), null);
+
// Test for checking if the required intent filters are set during managed provisioning.
mIntentFiltersTest = new DialogTestListItem(this,
R.string.provisioning_byod_cross_profile_intent_filters,
@@ -295,6 +302,7 @@
adapter.add(mEnableNonMarketTest);
adapter.add(mIntentFiltersTest);
adapter.add(mPermissionLockdownTest);
+ adapter.add(mKeyguardDisabledFeaturesTest);
if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
// Capture image intent can be resolved in primary profile, so test.
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 4d1a92a..09e6393 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -67,8 +67,13 @@
public static final String ACTION_CAPTURE_AND_CHECK_VIDEO = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO";
// Primage -> managed intent: request to capture and check an audio recording
public static final String ACTION_CAPTURE_AND_CHECK_AUDIO = "com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_AUDIO";
+ public static final String ACTION_KEYGUARD_DISABLED_FEATURES =
+ "com.android.cts.verifier.managedprovisioning.BYOD_KEYGUARD_DISABLED_FEATURES";
+ public static final String ACTION_LOCKNOW =
+ "com.android.cts.verifier.managedprovisioning.BYOD_LOCKNOW";
public static final String EXTRA_PROVISIONED = "extra_provisioned";
+ public static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
// Primary -> managed intent: set unknown sources restriction and install package
public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK";
@@ -187,6 +192,14 @@
finish();
}
return;
+ } else if (ACTION_KEYGUARD_DISABLED_FEATURES.equals(action)) {
+ final int value = intent.getIntExtra(EXTRA_PARAMETER_1,
+ DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE);
+ ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
+ mDevicePolicyManager.setKeyguardDisabledFeatures(admin, value);
+ } else if (ACTION_LOCKNOW.equals(action)) {
+ mDevicePolicyManager.lockNow();
+ setResult(RESULT_OK);
}
// This activity has no UI and is only used to respond to CtsVerifier in the primary side.
finish();
@@ -267,6 +280,10 @@
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
+ public static Intent createLockIntent() {
+ return new Intent(ACTION_LOCKNOW);
+ }
+
private Uri getTempUri(String fileName) {
final File file = new File(getFilesDir() + File.separator + "images"
+ File.separator + fileName);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index 4987f86..b18e816 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -61,8 +61,11 @@
filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE);
filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_VIDEO);
filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_AUDIO);
+ filter.addAction(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES);
+ filter.addAction(ByodHelperActivity.ACTION_LOCKNOW);
filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE);
filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
+ filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_TOAST);
filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
new file mode 100644
index 0000000..0fdc498
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.R;
+
+public class KeyguardDisabledFeaturesActivity extends DialogTestListActivity {
+
+ public KeyguardDisabledFeaturesActivity() {
+ super(R.layout.provisioning_byod,
+ R.string.provisioning_byod_keyguard_disabled_features,
+ R.string.provisioning_byod_keyguard_disabled_features_info,
+ R.string.provisioning_byod_keyguard_disabled_features_instruction);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mPrepareTestButton.setText(
+ R.string.provisioning_byod_keyguard_disabled_features_prepare_button);
+ mPrepareTestButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ resetPassword("testpassword");
+ setKeyguardDisabledFeatures(DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS |
+ DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
+ DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+ }
+ });
+ }
+
+ @Override
+ public void finish() {
+ // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
+ // clear the password.
+ resetPassword(null);
+ super.finish();
+ }
+
+ private void setKeyguardDisabledFeatures(final int flags) {
+ Intent setKeyguardDisabledFeaturesIntent =
+ new Intent(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES)
+ .putExtra(ByodHelperActivity.EXTRA_PARAMETER_1, flags);
+ startActivity(setKeyguardDisabledFeaturesIntent);
+ }
+
+ /**
+ * Reset device password
+ * @param password password to reset to (may be null)
+ */
+ private void resetPassword(String password) {
+ DevicePolicyManager dpm = (DevicePolicyManager)
+ getSystemService(Context.DEVICE_POLICY_SERVICE);
+ dpm.resetPassword(password, 0);
+ }
+
+ @Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_trust_agents,
+ "BYOD_DisableTrustAgentsTest",
+ R.string.provisioning_byod_disable_trust_agents_instruction,
+ new Intent(Settings.ACTION_SECURITY_SETTINGS)));
+ adapter.add(new DialogTestListItemWithIcon(this,
+ R.string.provisioning_byod_disable_notifications,
+ "BYOD_DisableUnredactedNotifications",
+ R.string.provisioning_byod_disable_notifications_instruction,
+ new Intent(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN),
+ R.drawable.ic_corp_icon));
+ FingerprintManager fpm = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
+ if (fpm.isHardwareDetected()) {
+ adapter.add(new DialogTestListItem(this,
+ R.string.provisioning_byod_fingerprint_disabled_in_settings,
+ "BYOD_FingerprintDisabledInSettings",
+ R.string.provisioning_byod_fingerprint_disabled_in_settings_instruction,
+ new Intent(Settings.ACTION_SECURITY_SETTINGS)));
+ adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_fingerprint,
+ "BYOD_DisableFingerprint",
+ R.string.provisioning_byod_disable_fingerprint_instruction,
+ ByodHelperActivity.createLockIntent()));
+ }
+ }
+
+ @Override
+ protected void clearRemainingState(final DialogTestListItem test) {
+ super.clearRemainingState(test);
+ if (WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(
+ test.getManualTestIntent().getAction())) {
+ try {
+ startActivity(new Intent(
+ WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION));
+ } catch (ActivityNotFoundException e) {
+ // User shouldn't run this test before work profile is set up.
+ }
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
index c85ccf5..a912d2c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
@@ -19,7 +19,9 @@
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManager;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import com.android.cts.verifier.R;
@@ -30,26 +32,37 @@
public class WorkNotificationTestActivity extends Activity {
public static final String ACTION_WORK_NOTIFICATION =
"com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION";
+ public static final String ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN =
+ "com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION";
public static final String ACTION_CLEAR_WORK_NOTIFICATION =
"com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION";
private static final int NOTIFICATION_ID = 7;
+ private NotificationManager mNotificationManager;
+
+ private void showWorkNotification(int visibility) {
+ final Notification notification = new Notification.Builder(this)
+ .setSmallIcon(R.drawable.icon)
+ .setContentTitle(getString(R.string.provisioning_byod_work_notification_title))
+ .setVisibility(visibility)
+ .setAutoCancel(true)
+ .build();
+ mNotificationManager.notify(NOTIFICATION_ID, notification);
+ }
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final String action = getIntent().getAction();
- final NotificationManager notificationManager = (NotificationManager)
- getSystemService(Context.NOTIFICATION_SERVICE);
+ mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (ACTION_WORK_NOTIFICATION.equals(action)) {
- final Notification notification = new Notification.Builder(this)
- .setSmallIcon(R.drawable.icon)
- .setContentTitle(getString(R.string.provisioning_byod_work_notification_title))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setAutoCancel(true)
- .build();
- notificationManager.notify(NOTIFICATION_ID, notification);
+ showWorkNotification(Notification.VISIBILITY_PUBLIC);
+ } else if (ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(action)) {
+ DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ dpm.lockNow();
+ showWorkNotification(Notification.VISIBILITY_PRIVATE);
} else if (ACTION_CLEAR_WORK_NOTIFICATION.equals(action)) {
- notificationManager.cancel(NOTIFICATION_ID);
+ mNotificationManager.cancel(NOTIFICATION_ID);
}
finish();
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index f01db4f..7fe0b80 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -26,12 +26,14 @@
import android.test.AndroidTestCase;
import android.util.Log;
+import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -166,6 +168,21 @@
return paths;
}
+ public static List<File> getMountPaths() throws IOException {
+ final List<File> paths = new ArrayList<>();
+ final BufferedReader br = new BufferedReader(new FileReader("/proc/self/mounts"));
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ final String[] fields = line.split(" ");
+ paths.add(new File(fields[1]));
+ }
+ } finally {
+ br.close();
+ }
+ return paths;
+ }
+
private static File[] dropFirst(File[] before) {
final File[] after = new File[before.length - 1];
System.arraycopy(before, 1, after, 0, after.length);
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
index 7dc462a..6030f1c 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
@@ -17,8 +17,10 @@
package com.android.cts.externalstorageapp;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
import android.app.DownloadManager;
import android.app.DownloadManager.Query;
@@ -34,7 +36,9 @@
import android.test.AndroidTestCase;
import android.text.format.DateUtils;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -76,6 +80,25 @@
}
/**
+ * Verify that we don't have read access to any storage mountpoints.
+ */
+ public void testMountPointsNotReadable() throws Exception {
+ final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+ final List<File> mountPaths = getMountPaths();
+ for (File path : mountPaths) {
+ if (path.getAbsolutePath().startsWith("/mnt/")
+ || path.getAbsolutePath().startsWith("/storage/")) {
+ // Mount points could be multi-user aware, so try probing both
+ // top level and user-specific directory.
+ final File userPath = new File(path, userId);
+
+ assertDirNoAccess(path);
+ assertDirNoAccess(userPath);
+ }
+ }
+ }
+
+ /**
* Verify that we can't download things outside package directory.
*/
public void testDownloadManager() throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
index 71faab2..995da90 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadExternalStorageTest.java
@@ -16,9 +16,11 @@
package com.android.cts.readexternalstorageapp;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadOnlyAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirReadWriteAccess;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
import android.os.Environment;
import android.test.AndroidTestCase;
@@ -64,4 +66,23 @@
}
}
}
+
+ /**
+ * Verify that we don't have write access to any mountpoints.
+ */
+ public void testMountPointsNotWritable() throws Exception {
+ final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+ final List<File> mountPaths = getMountPaths();
+ for (File path : mountPaths) {
+ if (path.getAbsolutePath().startsWith("/mnt/")
+ || path.getAbsolutePath().startsWith("/storage/")) {
+ // Mount points could be multi-user aware, so try probing both
+ // top level and user-specific directory.
+ final File userPath = new File(path, userId);
+
+ assertDirNoWriteAccess(path);
+ assertDirNoWriteAccess(userPath);
+ }
+ }
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index badc852..5e6aa3e 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -24,6 +24,7 @@
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildProbeFile;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.deleteContents;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getMountPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getPrimaryPackageSpecificPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getSecondaryPackageSpecificPaths;
import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
@@ -35,9 +36,7 @@
import com.android.cts.externalstorageapp.CommonExternalStorageTest;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileReader;
import java.util.List;
import java.util.Random;
@@ -273,28 +272,29 @@
* {@link CommonExternalStorageTest#testAllPackageDirsWritable()}.
*/
public void testSecondaryMountPointsNotWritable() throws Exception {
+ // Probe path could be /storage/emulated/0 or /storage/1234-5678
final File probe = buildProbeFile(Environment.getExternalStorageDirectory());
assertTrue(probe.createNewFile());
- final BufferedReader br = new BufferedReader(new FileReader("/proc/self/mounts"));
- try {
- String line;
- while ((line = br.readLine()) != null) {
- final String[] fields = line.split(" ");
- final File testMount = new File(fields[1]);
- final File testProbe = new File(testMount, probe.getName());
- if (testProbe.exists()) {
- Log.d(TAG, "Primary external mountpoint " + testMount);
- } else {
- // This mountpoint is not primary external storage; we must
- // not be able to write.
- Log.d(TAG, "Other mountpoint " + testMount);
- assertDirNoWriteAccess(testProbe.getParentFile());
- }
+ final String userId = Integer.toString(android.os.Process.myUid() / 100000);
+ final List<File> mountPaths = getMountPaths();
+ for (File path : mountPaths) {
+ // Mount points could be multi-user aware, so try probing both top
+ // level and user-specific directory.
+ final File userPath = new File(path, userId);
+
+ final File testProbe = new File(path, probe.getName());
+ final File testUserProbe = new File(userPath, probe.getName());
+
+ if (testProbe.exists() || testUserProbe.exists()) {
+ Log.d(TAG, "Primary external mountpoint " + path);
+ } else {
+ // This mountpoint is not primary external storage; we must
+ // not be able to write.
+ Log.d(TAG, "Other mountpoint " + path);
+ assertDirNoWriteAccess(path);
+ assertDirNoWriteAccess(userPath);
}
- } finally {
- br.close();
- probe.delete();
- }
+ }
}
}
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
new file mode 100644
index 0000000..c74211d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/NfcTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.managedprofile;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class NfcTest extends AndroidTestCase {
+ private static final String SAMPLE_TEXT = "This is my text to send.";
+ private static final String TEXT_MIME_TYPE = "text/plain";
+ private static final String NFC_BEAM_ACTIVITY = "com.android.nfc.BeamShareActivity";
+
+ public void testNfcShareDisabled() throws Exception {
+ Intent intent = getTextShareIntent();
+ assertFalse("Nfc beam activity should not be resolved", isNfcBeamActivityResolved(intent));
+ }
+
+ public void testNfcShareEnabled() throws Exception {
+ Intent intent = getTextShareIntent();
+ assertTrue("Nfc beam activity should be resolved", isNfcBeamActivityResolved(intent));
+ }
+
+ private Intent getTextShareIntent() {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_TEXT, SAMPLE_TEXT);
+ intent.setType(TEXT_MIME_TYPE);
+ return intent;
+ }
+
+ private boolean isNfcBeamActivityResolved(Intent intent) {
+ PackageManager pm = mContext.getPackageManager();
+ for (ResolveInfo resolveInfo : pm.queryIntentActivities(intent, 0)) {
+ if (NFC_BEAM_ACTIVITY.equals(resolveInfo.activityInfo.name)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
+
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index a1ae9b9..54b535a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -62,6 +62,8 @@
private int mUserId;
private String mPackageVerifier;
+ private boolean mHasNfcFeature;
+
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -69,6 +71,7 @@
// We need multi user to be supported in order to create a profile of the user owner.
mHasFeature = mHasFeature && hasDeviceFeature(
"android.software.managed_users");
+ mHasNfcFeature = hasDeviceFeature("android.hardware.nfc");
if (mHasFeature) {
removeTestUsers();
@@ -563,6 +566,30 @@
}
}
+ public void testNfcRestriction() throws Exception {
+ if (!mHasFeature || !mHasNfcFeature) {
+ return;
+ }
+
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+ "testNfcShareEnabled", mUserId));
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+ "testNfcShareEnabled", 0));
+
+ String restriction = "no_outgoing_beam"; // UserManager.DISALLOW_OUTGOING_BEAM
+ String command = "add-restriction";
+
+ String addRestrictionCommandOutput =
+ changeUserRestrictionForUser(restriction, command, mUserId);
+ assertTrue("Command was expected to succeed " + addRestrictionCommandOutput,
+ addRestrictionCommandOutput.contains("Status: ok"));
+
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+ "testNfcShareDisabled", mUserId));
+ assertTrue(runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".NfcTest",
+ "testNfcShareEnabled", 0));
+ }
+
private void disableActivityForUser(String activityName, int userId)
throws DeviceNotAvailableException {
String command = "am start -W --user " + userId
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index 4ce06afb..0589792 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -576,10 +576,10 @@
}
private void checkKernelWakelock(String[] parts) {
- assertEquals(7, parts.length);
- assertNotNull(parts[4]); // kernel wakelock
- assertInteger(parts[5]); // totalTime
- assertInteger(parts[6]); // count
+ assertTrue(parts.length >= 7);
+ assertNotNull(parts[4]); // Kernel wakelock
+ assertInteger(parts[parts.length-2]); // totalTime
+ assertInteger(parts[parts.length-1]); // count
}
private void checkWakeupReason(String[] parts) {
diff --git a/tests/deviceadmin/res/xml/device_admin.xml b/tests/deviceadmin/res/xml/device_admin.xml
index 263fda6..f7d394e 100644
--- a/tests/deviceadmin/res/xml/device_admin.xml
+++ b/tests/deviceadmin/res/xml/device_admin.xml
@@ -22,6 +22,7 @@
<force-lock />
<wipe-data />
<expire-password />
+ <disable-keyguard-features />
</uses-policies>
</device-admin>
diff --git a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 04e2ba3..66e12c0 100644
--- a/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -526,6 +526,23 @@
}
}
+ public void testKeyguardDisabledFeatures() {
+ if (!mDeviceAdmin) {
+ Log.w(TAG, "Skipping testKeyguardDisabledFeatures");
+ return;
+ }
+ int originalValue = mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent);
+ try {
+ for (int which = DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
+ which < 2 * DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; ++which) {
+ mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, which);
+ assertEquals(which, mDevicePolicyManager.getKeyguardDisabledFeatures(mComponent));
+ }
+ } finally {
+ mDevicePolicyManager.setKeyguardDisabledFeatures(mComponent, originalValue);
+ }
+ }
+
public void testCreateUser_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testCreateUser_failIfNotDeviceOwner");
diff --git a/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java b/tests/tests/assist/common/src/android/assist/common/Utils.java
similarity index 72%
rename from tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
rename to tests/tests/assist/common/src/android/assist/common/Utils.java
index b9fb7cf..1831182 100644
--- a/tests/tests/assist/common/src/android/voiceinteraction/common/Utils.java
+++ b/tests/tests/assist/common/src/android/assist/common/Utils.java
@@ -18,6 +18,7 @@
import android.app.VoiceInteractor;
import android.app.VoiceInteractor.PickOptionRequest.Option;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -28,10 +29,6 @@
import java.util.concurrent.CountDownLatch;
public class Utils {
- public enum TestCaseType {
- ASSIST_STRUCTURE,
- DISABLE_CONTEXT,
- }
public static final String TESTCASE_TYPE = "testcase_type";
public static final String TESTINFO = "testinfo";
public static final String BROADCAST_INTENT = "android.intent.action.ASSIST_TESTAPP";
@@ -40,17 +37,39 @@
public static final String ASSIST_STRUCTURE_KEY = "assist_structure";
public static final String ASSIST_CONTENT_KEY = "assist_content";
- public static final String ASSIST_BUNDLE = "assist_bundle";
+ public static final String ASSIST_BUNDLE_KEY = "assist_bundle";
+ public static final String ASSIST_SCREENSHOT_KEY = "assist_screenshot";
public static final int TIMEOUT_MS = 2 * 1000; // TODO(awlee): what is the timeout
+ public static final String ASSIST_STRUCTURE = "ASSIST_STRUCTURE";
+ public static final String DISABLE_CONTEXT = "DISABLE_CONTEXT";
+
+ /**
+ * The shim activity that starts the service associated with each test.
+ */
public static final String getTestActivity(String testCaseType) {
- if (testCaseType.equals("ASSIST_STRUCTURE")) {
- return "service.AssistStructureActivity";
- } else if (testCaseType.equals("DISABLE_CONTEXT")) {
- return "service.DisableContextActivity";
+ switch (testCaseType) {
+ case ASSIST_STRUCTURE:
+ return "service.AssistStructureActivity";
+ case DISABLE_CONTEXT:
+ return "service.DisableContextActivity";
+ default:
+ return "";
}
- return "";
+ }
+
+ /**
+ * The test app associated with each test.
+ */
+ public static final ComponentName getTestAppComponent(String testCaseType) {
+ switch (testCaseType) {
+ case ASSIST_STRUCTURE:
+ return new ComponentName(
+ "android.assist.testapp", "android.assist.testapp.TestApp");
+ default:
+ return new ComponentName("","");
+ }
}
public static final String toBundleString(Bundle bundle) {
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
index 8b63b25..784d63b 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/AssistStructureActivity.java
@@ -35,8 +35,8 @@
super.onStart();
Intent intent = new Intent();
intent.setComponent(new ComponentName(this, MainInteractionService.class));
- ComponentName serviceName = startService(intent);
- Log.i(TAG, "Started service: " + serviceName);
- getLayoutInflater().inflate(R.layout.voice_interaction_main, null);
+ Log.i(TAG, "Starting service.");
+ finish();
+ startService(intent);
}
}
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
index 56017ce..684c817 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionService.java
@@ -48,14 +48,9 @@
Log.wtf(TAG, "Can't start session because either intent is null or onReady() "
+ "has not been called yet. mIntent = " + mIntent + ", mReady = " + mReady);
} else {
- Log.i(TAG, "Yay! about to start session with TestApp");
+ Log.i(TAG, "Yay! about to start session");
if (isActiveService(this, new ComponentName(this, getClass()))) {
- Bundle args = new Bundle();
- Intent intent = new Intent();
- intent.setComponent(new ComponentName("android.assist.testapp",
- "android.assist.testapp.TestApp"));
- args.putParcelable("intent", intent);
- showSession(args, VoiceInteractionSession.SHOW_WITH_ASSIST |
+ showSession(new Bundle(), VoiceInteractionSession.SHOW_WITH_ASSIST |
VoiceInteractionSession.SHOW_WITH_SCREENSHOT);
} else {
Log.wtf(TAG, "**** Not starting MainInteractionService because" +
diff --git a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
index d19c6f8..7b77ea0 100644
--- a/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
+++ b/tests/tests/assist/service/src/android/voiceinteraction/service/MainInteractionSession.java
@@ -31,6 +31,7 @@
import android.service.voice.VoiceInteractionSession.PickOptionRequest;
import android.util.Log;
+import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
@@ -44,6 +45,9 @@
Context mContext;
Bundle mAssistData = new Bundle();
+ private boolean hasReceivedAssistData = false;
+ private boolean hasReceivedScreenshot = false;
+
MainInteractionSession(Context context) {
super(context);
mContext = context;
@@ -64,8 +68,6 @@
public void onShow(Bundle args, int showFlags) {
// set some content view.
// TODO: check that the view takes up the whole screen.
- mStartIntent = args.getParcelable("intent");
- startVoiceActivity(mStartIntent); // remove
// check that interactor mode is for assist
if ((showFlags & SHOW_WITH_ASSIST) == 0) {
return;
@@ -73,32 +75,52 @@
super.onShow(args, showFlags);
}
-
@Override
public void onHandleAssist(/*@Nullable */Bundle data, /*@Nullable*/ AssistStructure structure,
/*@Nullable*/ AssistContent content) {
Log.i(TAG, "onHandleAssist");
- Log.i(TAG, String.format("Bundle: %s, Structure: %s, Content: %s", data, structure, content));
+ Log.i(TAG,
+ String.format("Bundle: %s, Structure: %s, Content: %s", data, structure, content));
super.onHandleAssist(data, structure, content);
// send to test to verify that this is accurate.
mAssistData.putParcelable(Utils.ASSIST_STRUCTURE_KEY, structure);
mAssistData.putParcelable(Utils.ASSIST_CONTENT_KEY, content);
- mAssistData.putBundle(Utils.ASSIST_BUNDLE, data);
- broadcastResults();
+ mAssistData.putBundle(Utils.ASSIST_BUNDLE_KEY, data);
+ hasReceivedAssistData = true;
+ maybeBroadcastResults();
}
@Override
public void onHandleScreenshot(/*@Nullable*/ Bitmap screenshot) {
+ Log.i(TAG, "onHandleScreenshot");
super.onHandleScreenshot(screenshot);
- // add this to mAssistData?
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ if (screenshot != null) {
+ screenshot.compress(Bitmap.CompressFormat.PNG, 50, bs);
+ mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, bs.toByteArray());
+ } else {
+ mAssistData.putByteArray(Utils.ASSIST_SCREENSHOT_KEY, null);
+ }
+ hasReceivedScreenshot = true;
+ maybeBroadcastResults();
}
- private void broadcastResults() {
- Intent intent = new Intent(Utils.BROADCAST_ASSIST_DATA_INTENT);
- intent.putExtras(mAssistData);
- Log.i(TAG, "broadcasting: " + intent.toString() + ", Bundle = " + mAssistData.toString());
- mContext.sendBroadcast(intent);
+ private void maybeBroadcastResults() {
+ if (!hasReceivedAssistData) {
+ Log.i(TAG, "waiting for assist data before broadcasting results");
+ } else if (!hasReceivedScreenshot) {
+ Log.i(TAG, "waiting for screenshot before broadcasting results");
+ } else {
+ Intent intent = new Intent(Utils.BROADCAST_ASSIST_DATA_INTENT);
+ intent.putExtras(mAssistData);
+ Log.i(TAG,
+ "broadcasting: " + intent.toString() + ", Bundle = " + mAssistData.toString());
+ mContext.sendBroadcast(intent);
+
+ hasReceivedAssistData = false;
+ hasReceivedScreenshot = false;
+ }
}
class DoneReceiver extends BroadcastReceiver {
diff --git a/tests/tests/assist/src/android/assist/TestStartActivity.java b/tests/tests/assist/src/android/assist/TestStartActivity.java
index 06bf5aa..c0549c6 100644
--- a/tests/tests/assist/src/android/assist/TestStartActivity.java
+++ b/tests/tests/assist/src/android/assist/TestStartActivity.java
@@ -52,6 +52,14 @@
startActivity(intent);
}
+ public void start3pApp() {
+ Intent intent = new Intent();
+ intent.setComponent(new ComponentName("android.assist.testapp",
+ "android.assist.testapp.TestApp"));
+ startActivity(intent);
+
+ }
+
@Override protected void onPause() {
Log.i(TAG, " in onPause");
super.onPause();
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index 3c93c8a..d113774 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
@@ -42,7 +43,7 @@
public class AssistStructureTest extends AssistTestBase {
static final String TAG = "AssistStructureTest";
- private static final String TEST_CASE_TYPE = "ASSIST_STRUCTURE";
+ private static final String TEST_CASE_TYPE = Utils.ASSIST_STRUCTURE;
public AssistStructureTest() {
super();
@@ -52,38 +53,26 @@
protected void setUp() throws Exception {
super.setUp();
startTestActivity(TEST_CASE_TYPE);
- waitForBroadcast(Utils.TestCaseType.ASSIST_STRUCTURE);
+ waitForBroadcast();
}
public void testAssistStructure() throws Exception {
- // verify assist data contains what we want.
- // go through all things in the bundle, verify not null, verify contains what we want.
-
- // TODO(awlee): verify that the context is not off by default.
- if (mAssistContent == null || mAssistBundle == null) {
+ // TODO(awlee): verify that the context/screenshot setting is on if appropriate
+ if (mAssistContent == null) {
fail("Received null assistBundle or assistContent.");
return;
}
+ if (mAssistBundle == null) {
+ fail("Received null assistBundle.");
+ return;
+ }
if (mAssistStructure == null) {
fail("Received null assistStructure");
return;
} else {
- verifyAssistStructure(new ComponentName("android.assist.service",
- "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
- }
- }
-
- private void verifyAssistStructure(ComponentName backgroundApp,
- boolean isSecureWindow) {
- // Check component name matches
- assertEquals(backgroundApp.flattenToString(),
- mAssistStructure.getActivityComponent().flattenToString());
-
- int numWindows = mAssistStructure.getWindowNodeCount();
- assertEquals(1, numWindows);
- for (int i = 0; i < numWindows; i++) {
- AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+ verifyAssistStructure(Utils.getTestAppComponent(TEST_CASE_TYPE),
+ false /*FLAG_SECURE set*/);
}
}
}
\ No newline at end of file
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index a4f4cbc..b2ec739 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -27,11 +27,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
-import java.lang.Override;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -41,11 +42,11 @@
protected TestStartActivity mTestActivity;
protected AssistContent mAssistContent;
protected AssistStructure mAssistStructure;
+ protected Bitmap mScreenshot;
protected BroadcastReceiver mReceiver;
protected Bundle mAssistBundle;
protected Context mContext;
protected CountDownLatch mLatch;
- protected Utils.TestCaseType mTestCaseType;
private String mTestName;
public AssistTestBase() {
@@ -78,8 +79,7 @@
/**
* Called after startTestActivity
*/
- protected boolean waitForBroadcast(Utils.TestCaseType testCaseType) throws Exception {
- mTestCaseType = testCaseType;
+ protected boolean waitForBroadcast() throws Exception {
mLatch = new CountDownLatch(1);
if (mReceiver != null) {
mContext.unregisterReceiver(mReceiver);
@@ -88,6 +88,7 @@
mContext.registerReceiver(mReceiver,
new IntentFilter(Utils.BROADCAST_ASSIST_DATA_INTENT));
+ mTestActivity.start3pApp();
mTestActivity.startTest(mTestName);
if (!mLatch.await(Utils.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
fail("Failed to receive broadcast in " + Utils.TIMEOUT_MS + "msec");
@@ -96,18 +97,39 @@
return true;
}
+ protected void verifyAssistStructure(ComponentName backgroundApp, boolean isSecureWindow) {
+ // Check component name matches
+ assertEquals(backgroundApp.flattenToString(),
+ mAssistStructure.getActivityComponent().flattenToString());
+
+ int numWindows = mAssistStructure.getWindowNodeCount();
+ assertEquals(1, numWindows);
+ for (int i = 0; i < numWindows; i++) {
+ AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+ // TODO: traverse view heirarchy and verify it matches what we expect
+ }
+ }
+
class TestResultsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equalsIgnoreCase(Utils.BROADCAST_ASSIST_DATA_INTENT)) { // not necessary?
- Log.i(TAG, "received broadcast with results ");
+ Log.i(TAG, "Received broadcast with assist data.");
Bundle assistData = intent.getExtras();
+ AssistTestBase.this.mAssistBundle = assistData.getBundle(Utils.ASSIST_BUNDLE_KEY);
AssistTestBase.this.mAssistStructure = assistData.getParcelable(
Utils.ASSIST_STRUCTURE_KEY);
- AssistTestBase.this.mAssistBundle = assistData.getBundle(Utils.ASSIST_BUNDLE);
AssistTestBase.this.mAssistContent = assistData.getParcelable(
Utils.ASSIST_CONTENT_KEY);
+ byte[] bitmapArray = assistData.getByteArray(Utils.ASSIST_SCREENSHOT_KEY);
+ if (bitmapArray != null) {
+ AssistTestBase.this.mScreenshot = BitmapFactory.decodeByteArray(
+ bitmapArray, 0, bitmapArray.length);
+ } else {
+ AssistTestBase.this.mScreenshot = null;
+ }
+
if (mLatch != null) {
mLatch.countDown();
}
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index f3da32b..6801737 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -27,7 +27,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.cts.util.SystemUtil;
import android.os.Bundle;
+import android.provider.Settings;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
@@ -39,7 +41,7 @@
public class DisableContextTest extends AssistTestBase {
static final String TAG = "DisableContextTest";
- private static final String TEST_CASE_TYPE = "DISABLE_CONTEXT";
+ private static final String TEST_CASE_TYPE = Utils.DISABLE_CONTEXT;
public DisableContextTest() {
super();
@@ -48,43 +50,65 @@
@Override
public void setUp() throws Exception {
super.setUp();
- // need to set action/component/activityintent for the test activity?
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_structure_enabled 0");
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_screenshot_enabled 0");
+
startTestActivity(TEST_CASE_TYPE);
- waitForBroadcast(Utils.TestCaseType.DISABLE_CONTEXT);
+ waitForBroadcast();
}
- public void testContextOnAndOff() throws Exception {
- // filler
+ @Override
+ public void tearDown() throws Exception {
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_structure_enabled 1");
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_screenshot_enabled 1");
+ super.tearDown();
+ }
+ public void testContextAndScreenshotOff() throws Exception {
+ // Both settings off
+ if (mAssistContent != null || mAssistBundle != null || mAssistStructure != null) {
+ fail(String.format("Should have all been null - Bundle: %s, Structure: %s, Content: %s",
+ mAssistBundle, mAssistStructure, mAssistContent));
+ }
- // verify assist data contains what we want.
- // go through all things in the bundle, verify not null, verify contains what we want.
+ if (mScreenshot != null) {
+ fail(String.format("Should have been null - Screenshot: %s", mScreenshot));
+ }
- // TODO(awlee): verify that the context is not off by default.
+ // Screenshot off, context on
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_structure_enabled 1");
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_screenshot_enabled 0");
+ waitForBroadcast();
+
+ if (mScreenshot != null) {
+ fail(String.format("Should have been null - Screenshot: %s", mScreenshot));
+ }
+
if (mAssistContent == null || mAssistBundle == null) {
- fail("Received null assistBundle or assistContent.");
- return;
+ fail(String.format("Should not have been null - Bundle: %s, Content: %s",
+ mAssistBundle, mAssistContent));
}
- if (mAssistStructure == null) {
- fail("Received null assistStructure");
- return;
- } else {
- verifyAssistStructure(new ComponentName("android.assist.service",
- "android.assist." + Utils.getTestActivity(TEST_CASE_TYPE)), false /*FLAG_SECURE set*/);
+ // Context off, screenshot on
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_screenshot_enabled 1");
+ SystemUtil.runShellCommand(getInstrumentation(),
+ "settings put secure assist_structure_enabled 0");
+ waitForBroadcast();
+
+ if (mScreenshot == null) {
+ fail(String.format("Should not have been null - Screenshot: %s", mScreenshot));
}
- }
- private void verifyAssistStructure(ComponentName backgroundApp,
- boolean isSecureWindow) {
- // Check component name matches
- assertEquals(backgroundApp.flattenToString(),
- mAssistStructure.getActivityComponent().flattenToString());
-
- int numWindows = mAssistStructure.getWindowNodeCount();
- assertEquals(1, numWindows);
- for (int i = 0; i < numWindows; i++) {
- AssistStructure.ViewNode node = mAssistStructure.getWindowNodeAt(i).getRootViewNode();
+ if (mAssistContent != null || mAssistBundle != null || mAssistStructure != null) {
+ fail(String.format("Should have all been null - Bundle: %s, Structure: %s, Content: %s",
+ mAssistBundle, mAssistStructure, mAssistContent));
}
}
}
\ No newline at end of file
diff --git a/tests/tests/assist/service/res/layout/voice_interaction_main.xml b/tests/tests/assist/testapp/res/layout/voice_interaction_main.xml
similarity index 100%
rename from tests/tests/assist/service/res/layout/voice_interaction_main.xml
rename to tests/tests/assist/testapp/res/layout/voice_interaction_main.xml
diff --git a/tests/tests/assist/service/res/values/strings.xml b/tests/tests/assist/testapp/res/values/strings.xml
similarity index 100%
rename from tests/tests/assist/service/res/values/strings.xml
rename to tests/tests/assist/testapp/res/values/strings.xml
diff --git a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
index 9083cda..7fa9653 100644
--- a/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
+++ b/tests/tests/assist/testapp/src/android/voiceinteraction/testapp/TestApp.java
@@ -17,20 +17,11 @@
package android.assist.testapp;
import android.app.Activity;
-import android.app.VoiceInteractor;
-import android.app.VoiceInteractor.AbortVoiceRequest;
-import android.app.VoiceInteractor.CommandRequest;
-import android.app.VoiceInteractor.CompleteVoiceRequest;
-import android.app.VoiceInteractor.ConfirmationRequest;
-import android.app.VoiceInteractor.PickOptionRequest;
-import android.app.VoiceInteractor.PickOptionRequest.Option;
-import android.app.VoiceInteractor.Prompt;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.service.voice.VoiceInteractionService;
import android.util.Log;
import java.util.ArrayList;
@@ -38,5 +29,20 @@
import android.assist.common.Utils;
public class TestApp extends Activity {
+ static final String TAG = "TestApp";
-}
+ Bundle mTestinfo = new Bundle();
+ Bundle mTotalInfo = new Bundle();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.i(TAG, "TestApp created");
+ getLayoutInflater().inflate(R.layout.voice_interaction_main, null);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
index 4b966367..235c1f8 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -1205,7 +1205,9 @@
changeExposure(requestBuilder, expTimes[i], sensitivities[j]);
mSession.capture(requestBuilder.build(), listener, mHandler);
- CaptureResult result = listener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+ // make sure timeout is long enough for long exposure time
+ long timeout = WAIT_FOR_RESULT_TIMEOUT_MS + expTimes[i];
+ CaptureResult result = listener.getCaptureResult(timeout);
long resultExpTime = getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME);
int resultSensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
validateExposureTime(expTimes[i], resultExpTime);
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java
index d8f8a1d..380e47d 100755
--- a/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java
@@ -497,7 +497,7 @@
* TODO: This should be made stricter once SurfaceTexture timestamps are generated by the drivers.
*/
@UiThreadTest
- @TimeoutReq(minutes = 20)
+ @TimeoutReq(minutes = 30)
public void testCameraToSurfaceTextureMetadata() throws Exception {
runForAllCameras(testCameraToSurfaceTextureMetadataByCamera);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
index 33706dd..6869ed1 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/CameraTest.java
@@ -45,6 +45,7 @@
import android.util.Log;
import android.view.SurfaceHolder;
+import com.android.cts.util.TimeoutReq;
import java.io.File;
import java.io.FileOutputStream;
@@ -1770,6 +1771,7 @@
}
@UiThreadTest
+ @TimeoutReq(minutes = 30)
public void testPreviewPictureSizesCombination() throws Exception {
int nCameras = Camera.getNumberOfCameras();
for (int id = 0; id < nCameras; id++) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
index 18796d4..68efef0 100755
--- a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
@@ -97,15 +97,15 @@
} else {
assertMinMemoryMb(424);
}
- } else if (greaterThanDpi(density, DENSITY_XHIGH, screenSize,
+ } else if (greaterThanDpi(density, DENSITY_560, screenSize,
SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
- greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
- greaterThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+ greaterThanDpi(density, DENSITY_400, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+ greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
if (supports64Bit) {
- assertMinMemoryMb(832);
+ assertMinMemoryMb(1824);
} else {
- assertMinMemoryMb(512);
+ assertMinMemoryMb(1344);
}
} else if (greaterThanDpi(density, DENSITY_400, screenSize,
SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
@@ -117,15 +117,15 @@
} else {
assertMinMemoryMb(896);
}
- } else if (greaterThanDpi(density, DENSITY_560, screenSize,
+ } else if (greaterThanDpi(density, DENSITY_XHIGH, screenSize,
SCREENLAYOUT_SIZE_NORMAL, SCREENLAYOUT_SIZE_SMALL) ||
- greaterThanDpi(density, DENSITY_400, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
- greaterThanDpi(density, DENSITY_XHIGH, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
+ greaterThanDpi(density, DENSITY_TV, screenSize, SCREENLAYOUT_SIZE_LARGE) ||
+ greaterThanDpi(density, DENSITY_MEDIUM, screenSize, SCREENLAYOUT_SIZE_XLARGE)) {
if (supports64Bit) {
- assertMinMemoryMb(1824);
+ assertMinMemoryMb(832);
} else {
- assertMinMemoryMb(1344);
+ assertMinMemoryMb(512);
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
index 6f17e7b..687e63b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
@@ -62,7 +62,7 @@
public void testVerify_missing_events() {
// Timestamps in ns, expected in us
long[] timestamps = {1000000, 2000000, 3000000, 5000000, 6000000};
- runVerification(1000, timestamps, false, new int[]{3});
+ runVerification(1000, timestamps, true, new int[]{3});
}
private void runVerification(int expected, long[] timestamps, boolean pass,
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
index 9e278bc..5a176d5 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerification.java
@@ -49,10 +49,8 @@
@SuppressWarnings("deprecation")
public static EventOrderingVerification getDefault(TestSensorEnvironment environment) {
int reportingMode = environment.getSensor().getReportingMode();
- if (reportingMode != Sensor.REPORTING_MODE_CONTINUOUS
- && reportingMode != Sensor.REPORTING_MODE_ON_CHANGE) {
+ if (reportingMode == Sensor.REPORTING_MODE_ONE_SHOT)
return null;
- }
return new EventOrderingVerification();
}
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index 2320990..a999135 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -657,7 +657,6 @@
} catch (InterruptedException e) {
// don't care
}
- cleanupGl();
mCompositionThread = null;
mSurface = null;
mStartCompletionSemaphore = null;
@@ -970,7 +969,6 @@
public void cleanup() {
mNumTextureUpdated.set(0);
- mVerticesData.clear();
if (mTextureId != 0) {
int[] textures = new int[] {
mTextureId
diff --git a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
index f513709..94af087 100644
--- a/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
+++ b/tests/tests/media/src/android/media/cts/EnumDevicesTest.java
@@ -115,29 +115,31 @@
// Sample Rates
int[] sampleRates = deviceInfo.getSampleRates();
assertNotNull(sampleRates);
- // "analog" devices won't list any sample rates
+ // Note: an empty array indicates that the device supports arbitrary sample rates.
// Channel Masks
int[] channelMasks = deviceInfo.getChannelMasks();
assertNotNull(channelMasks);
- // "analog" devices won't list any channel masks
+ // Note: an empty array indicates that the device supports arbitrary channel masks.
// Channel Index Masks
int[] indexMasks = deviceInfo.getChannelIndexMasks();
- assertNotNull(channelMasks);
+ assertNotNull(indexMasks);
+ // Note: an empty array indicates that the device supports arbitrary channel index
+ // masks.
// Channel Counts
int[] channelCounts = deviceInfo.getChannelCounts();
assertNotNull(channelCounts);
- // "analog" devices won't list any channel Counts
+ // Note: an empty array indicates that the device supports arbitrary channel counts.
// Encodings
int[] encodings = deviceInfo.getEncodings();
assertNotNull(encodings);
- // "analog" devices won't list any encodings
+ // Note: an empty array indicates that the device supports arbitrary encodings.
int type = deviceInfo.getType();
- assert(type > AudioDeviceInfo.TYPE_UNKNOWN);
+ assertTrue(type != AudioDeviceInfo.TYPE_UNKNOWN);
}
}
@@ -167,7 +169,7 @@
}
return myLooper;
}
-
+
public void test_deviceCallback() {
// null callback?
mAudioManager.registerAudioDeviceCallback(null,null);
@@ -187,7 +189,7 @@
mAudioManager.unregisterAudioDeviceCallback(callback);
Looper myLooper = prepareIfNeededLooper();
-
+
mAudioManager.registerAudioDeviceCallback(callback, new Handler());
// unregister null callback
mAudioManager.unregisterAudioDeviceCallback(null);
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index b3fcce1..813af0f2 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -19,6 +19,7 @@
import android.cts.util.MediaUtils;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.AudioCapabilities;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.CodecProfileLevel;
import android.media.MediaCodecInfo.VideoCapabilities;
@@ -530,24 +531,35 @@
}
}
- private static MediaFormat createMinFormat(String mime, VideoCapabilities vcaps, int color) {
- int minWidth = vcaps.getSupportedWidths().getLower();
- int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
- int minBitrate = vcaps.getBitrateRange().getLower();
+ private static MediaFormat createMinFormat(String mime, CodecCapabilities caps) {
+ MediaFormat format;
+ if (caps.getVideoCapabilities() != null) {
+ VideoCapabilities vcaps = caps.getVideoCapabilities();
+ int minWidth = vcaps.getSupportedWidths().getLower();
+ int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
+ int minBitrate = vcaps.getBitrateRange().getLower();
+ format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
+ } else {
+ AudioCapabilities acaps = caps.getAudioCapabilities();
+ int minSampleRate = acaps.getSupportedSampleRateRanges()[0].getLower();
+ int minChannelCount = 1;
+ int minBitrate = acaps.getBitrateRange().getLower();
+ format = MediaFormat.createAudioFormat(mime, minSampleRate, minChannelCount);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
+ }
- MediaFormat format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT, color);
- format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
- format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
- format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
return format;
}
private static int getActualMax(
boolean isEncoder, String name, String mime, CodecCapabilities caps, int max) {
int flag = isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0;
- MediaFormat format =
- createMinFormat(mime, caps.getVideoCapabilities(), caps.colorFormats[0]);
+ MediaFormat format = createMinFormat(mime, caps);
+ Log.d(TAG, "Test format " + format);
Vector<MediaCodec> codecs = new Vector<MediaCodec>();
MediaCodec codec = null;
for (int i = 0; i < max; ++i) {
@@ -588,14 +600,6 @@
return actualMax;
}
- private static boolean shouldTestActual(CodecCapabilities caps) {
- if (caps.getVideoCapabilities() == null) {
- // TODO: test audio codecs.
- return false;
- }
- return true;
- }
-
public void testGetMaxSupportedInstances() {
final int MAX_INSTANCES = 32;
StringBuilder xmlOverrides = new StringBuilder();
@@ -612,21 +616,19 @@
Log.d(TAG, "getMaxSupportedInstances returns " + max);
assertTrue(max > 0);
- if (shouldTestActual(caps)) {
- int actualMax = getActualMax(
- info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES);
- Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
- if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
- String codec = "<MediaCodec name=\"" + info.getName() +
- "\" type=\"" + types[j] + "\" >";
- String limit = " <Limit name=\"concurrent-instances\" max=\"" +
- actualMax + "\" />";
- xmlOverrides.append(codec);
- xmlOverrides.append("\n");
- xmlOverrides.append(limit);
- xmlOverrides.append("\n");
- xmlOverrides.append("</MediaCodec>\n");
- }
+ int actualMax = getActualMax(
+ info.isEncoder(), info.getName(), types[j], caps, MAX_INSTANCES);
+ Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
+ if (actualMax < (int)(max * 0.9) || actualMax > (int) Math.ceil(max * 1.1)) {
+ String codec = "<MediaCodec name=\"" + info.getName() +
+ "\" type=\"" + types[j] + "\" >";
+ String limit = " <Limit name=\"concurrent-instances\" max=\"" +
+ actualMax + "\" />";
+ xmlOverrides.append(codec);
+ xmlOverrides.append("\n");
+ xmlOverrides.append(limit);
+ xmlOverrides.append("\n");
+ xmlOverrides.append("</MediaCodec>\n");
}
}
}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 1895dcc..88dbd7c 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -33,6 +33,7 @@
import android.net.wifi.WifiManager;
import android.test.AndroidTestCase;
import android.util.Log;
+import android.os.SystemProperties;
import com.android.internal.telephony.PhoneConstants;
@@ -66,7 +67,6 @@
private PackageManager mPackageManager;
private final HashMap<Integer, NetworkConfig> mNetworks =
new HashMap<Integer, NetworkConfig>();
- private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
@Override
protected void setUp() throws Exception {
@@ -78,20 +78,17 @@
// Get com.android.internal.R.array.networkAttributes
int resId = getContext().getResources().getIdentifier("networkAttributes", "array", "android");
String[] naStrings = getContext().getResources().getStringArray(resId);
-
+ //TODO: What is the "correct" way to determine if this is a wifi only device?
+ boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false);
for (String naString : naStrings) {
try {
NetworkConfig n = new NetworkConfig(naString);
+ if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) {
+ continue;
+ }
mNetworks.put(n.type, n);
} catch (Exception e) {}
}
-
- // Get com.android.internal.R.array.config_protectedNetworks
- resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
- int[] protectedNetworks = getContext().getResources().getIntArray(resId);
- for (int p : protectedNetworks) {
- mProtectedNetworks.add(p);
- }
}
public void testIsNetworkTypeValid() {
@@ -185,6 +182,27 @@
}
}
+ private void assertStartUsingNetworkFeatureUnsupported(int networkType, String feature) {
+ try {
+ mCm.startUsingNetworkFeature(networkType, feature);
+ fail("startUsingNetworkFeature is no longer supported in the current API version");
+ } catch (UnsupportedOperationException expected) {}
+ }
+
+ private void assertStopUsingNetworkFeatureUnsupported(int networkType, String feature) {
+ try {
+ mCm.startUsingNetworkFeature(networkType, feature);
+ fail("stopUsingNetworkFeature is no longer supported in the current API version");
+ } catch (UnsupportedOperationException expected) {}
+ }
+
+ private void assertRequestRouteToHostUnsupported(int networkType, int hostAddress) {
+ try {
+ mCm.requestRouteToHost(networkType, hostAddress);
+ fail("requestRouteToHost is no longer supported in the current API version");
+ } catch (UnsupportedOperationException expected) {}
+ }
+
public void testStartUsingNetworkFeature() {
final String invalidateFeature = "invalidateFeature";
@@ -193,27 +211,9 @@
final int wifiOnlyStartFailureCode = PhoneConstants.APN_REQUEST_FAILED;
final int wifiOnlyStopFailureCode = -1;
- NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
- if (ni != null) {
- assertEquals(PhoneConstants.APN_REQUEST_FAILED,
- mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidateFeature));
- assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
- invalidateFeature));
- } else {
- assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
- invalidateFeature));
- assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
- invalidateFeature));
- }
-
- ni = mCm.getNetworkInfo(TYPE_WIFI);
- if (ni != null) {
- // Should return failure because MMS is not supported on WIFI.
- assertEquals(PhoneConstants.APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
- mmsFeature));
- assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
- mmsFeature));
- }
+ assertStartUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+ assertStopUsingNetworkFeatureUnsupported(TYPE_MOBILE, invalidateFeature);
+ assertStartUsingNetworkFeatureUnsupported(TYPE_WIFI, mmsFeature);
}
private boolean isSupported(int networkType) {
@@ -224,11 +224,6 @@
(networkType == ConnectivityManager.TYPE_VPN);
}
- // true if only the system can turn it on
- private boolean isNetworkProtected(int networkType) {
- return mProtectedNetworks.contains(networkType);
- }
-
public void testIsNetworkSupported() {
for (int type = -1; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
boolean supported = mCm.isNetworkSupported(type);
@@ -242,82 +237,14 @@
public void testRequestRouteToHost() {
for (int type = -1 ; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- NetworkInfo ni = mCm.getNetworkInfo(type);
- boolean expectToWork = isSupported(type) && !isNetworkProtected(type) &&
- ni != null && ni.isConnected();
-
- try {
- assertTrue("Network type " + type,
- mCm.requestRouteToHost(type, HOST_ADDRESS) == expectToWork);
- } catch (Exception e) {
- Log.d(TAG, "got exception in requestRouteToHost for type " + type);
- assertFalse("Exception received for type " + type, expectToWork);
- }
-
- //TODO verify route table
+ assertRequestRouteToHostUnsupported(type, HOST_ADDRESS);
}
-
- assertFalse(mCm.requestRouteToHost(-1, HOST_ADDRESS));
}
public void testTest() {
mCm.getBackgroundDataSetting();
}
- /** Test that hipri can be brought up when Wifi is enabled. */
- public void testStartUsingNetworkFeature_enableHipri() throws Exception {
- if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
- || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
- // This test requires a mobile data connection and WiFi.
- return;
- }
-
- boolean isWifiEnabled = mWifiManager.isWifiEnabled();
- boolean isWifiConnected = false;
-
- NetworkInfo nwInfo = mCm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
- if (nwInfo != null) {
- isWifiConnected = nwInfo.isConnected();
- }
- try {
- // Make sure WiFi is connected to an access point.
- if (!isWifiConnected) {
- connectToWifi();
- }
-
- // Register a receiver that will capture the connectivity change for hipri.
- ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
- ConnectivityManager.TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED);
- IntentFilter filter = new IntentFilter();
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
- mContext.registerReceiver(receiver, filter);
-
- // Try to start using the hipri feature...
- int result = mCm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- FEATURE_ENABLE_HIPRI);
- assertTrue("Couldn't start using the HIPRI feature.", result != -1);
-
- // Check that the ConnectivityManager reported that it connected using hipri...
- assertTrue("Couldn't connect using hipri...", receiver.waitForState());
-
- assertTrue("Couldn't requestRouteToHost using HIPRI.",
- mCm.requestRouteToHost(ConnectivityManager.TYPE_MOBILE_HIPRI, HOST_ADDRESS));
- // TODO check dns selection
- // TODO check routes
- } catch (InterruptedException e) {
- fail("Broadcast receiver waiting for ConnectivityManager interrupted.");
- } finally {
- mCm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- FEATURE_ENABLE_HIPRI);
- // TODO wait for HIPRI to go
- // TODO check dns selection
- // TODO check routes
- if (!isWifiEnabled) {
- disconnectFromWifi();
- }
- }
- }
-
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
diff --git a/tests/tests/netlegacy22/Android.mk b/tests/tests/netlegacy22/Android.mk
new file mode 100644
index 0000000..68fd6f8
--- /dev/null
+++ b/tests/tests/netlegacy22/Android.mk
@@ -0,0 +1,32 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := CtsNetTestCasesLegacyApi22
+
+LOCAL_SDK_VERSION := 22
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/netlegacy22/AndroidManifest.xml b/tests/tests/netlegacy22/AndroidManifest.xml
new file mode 100644
index 0000000..d243e45
--- /dev/null
+++ b/tests/tests/netlegacy22/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.net.legacy22">
+
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.net.legacy22"
+ android:label="CTS tests of legacy android.net APIs as of API 22">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
new file mode 100644
index 0000000..8a9002b
--- /dev/null
+++ b/tests/tests/netlegacy22/src/android/net/cts/legacy/api22/ConnectivityManagerLegacyTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts.legacy.api22;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
+import android.os.ConditionVariable;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.net.DatagramSocket;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_VPN;
+import static android.net.ConnectivityManager.TYPE_WIFI;
+
+public class ConnectivityManagerLegacyTest extends AndroidTestCase {
+ private static final String TAG = ConnectivityManagerLegacyTest.class.getSimpleName();
+ private static final String FEATURE_ENABLE_HIPRI = "enableHIPRI";
+ private static final String HOST_ADDRESS1 = "192.0.2.1";
+ private static final String HOST_ADDRESS2 = "192.0.2.2";
+ private static final String HOST_ADDRESS3 = "192.0.2.3";
+
+ // These are correct as of API level 22, which is what we target here.
+ private static final int APN_REQUEST_FAILED = 3;
+ private static final int MAX_NETWORK_TYPE = TYPE_VPN;
+
+ private ConnectivityManager mCm;
+ private WifiManager mWifiManager;
+ private PackageManager mPackageManager;
+
+ private final List<Integer>mProtectedNetworks = new ArrayList<Integer>();
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
+ mPackageManager = getContext().getPackageManager();
+
+ // Get com.android.internal.R.array.config_protectedNetworks
+ int resId = getContext().getResources().getIdentifier("config_protectedNetworks", "array", "android");
+ int[] protectedNetworks = getContext().getResources().getIntArray(resId);
+ for (int p : protectedNetworks) {
+ mProtectedNetworks.add(p);
+ }
+ }
+
+ // true if only the system can turn it on
+ private boolean isNetworkProtected(int networkType) {
+ return mProtectedNetworks.contains(networkType);
+ }
+
+ private int ipv4AddrToInt(String addrString) throws Exception {
+ byte[] addr = ((Inet4Address) InetAddress.getByName(addrString)).getAddress();
+ return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
+ ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
+ }
+
+ private void checkSourceAddress(String addrString, int type) throws Exception {
+ DatagramSocket d = new DatagramSocket();
+ d.connect(InetAddress.getByName(addrString), 7);
+ InetAddress localAddress = d.getLocalAddress();
+
+ Network[] networks = mCm.getAllNetworks();
+ for (int i = 0; i < networks.length; i++) {
+ NetworkInfo ni = mCm.getNetworkInfo(networks[i]);
+ if (ni != null && ni.getType() == type) {
+ LinkProperties lp = mCm.getLinkProperties(networks[i]);
+ for (LinkAddress address : lp.getLinkAddresses()) {
+ if (address.getAddress().equals(localAddress)) {
+ return;
+ }
+ }
+ }
+ }
+ fail("Local address " + localAddress + " not assigned to any network of type " + type);
+ }
+
+ /** Test that hipri can be brought up when Wifi is enabled. */
+ public void testStartUsingNetworkFeature_enableHipri() throws Exception {
+ if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)
+ || !mPackageManager.hasSystemFeature(PackageManager.FEATURE_WIFI)) {
+ // This test requires a mobile data connection and WiFi.
+ return;
+ }
+
+ // Make sure WiFi is connected to an access point.
+ connectToWifi();
+
+ expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.CONNECTED,
+ new Runnable() {
+ public void run() {
+ int ret = mCm.startUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+ assertTrue("Couldn't start using the HIPRI feature.", ret != -1);
+ }
+ });
+
+ assertTrue("Couldn't requestRouteToHost using HIPRI.",
+ mCm.requestRouteToHost(TYPE_MOBILE_HIPRI, ipv4AddrToInt(HOST_ADDRESS1)));
+
+ try { Thread.sleep(1000); } catch(Exception e) {}
+ checkSourceAddress(HOST_ADDRESS1, TYPE_MOBILE);
+ checkSourceAddress(HOST_ADDRESS2, TYPE_WIFI);
+
+ // TODO check dns selection
+
+ expectNetworkBroadcast(TYPE_MOBILE_HIPRI, NetworkInfo.State.DISCONNECTED,
+ new Runnable() {
+ public void run() {
+ int ret = mCm.stopUsingNetworkFeature(TYPE_MOBILE, FEATURE_ENABLE_HIPRI);
+ assertTrue("Couldn't stop using the HIPRI feature.", ret != -1);
+ }
+ });
+
+
+ // TODO check dns selection
+ disconnectFromWifi();
+ }
+
+ public void testStartUsingNetworkFeature() {
+
+ final String invalidFeature = "invalidFeature";
+ final String mmsFeature = "enableMMS";
+ final int failureCode = -1;
+ final int wifiOnlyStartFailureCode = APN_REQUEST_FAILED;
+ final int wifiOnlyStopFailureCode = -1;
+
+ NetworkInfo ni = mCm.getNetworkInfo(TYPE_MOBILE);
+ if (ni != null) {
+ assertEquals(APN_REQUEST_FAILED,
+ mCm.startUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+ assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE, invalidFeature));
+ } else {
+ assertEquals(wifiOnlyStartFailureCode, mCm.startUsingNetworkFeature(TYPE_MOBILE,
+ invalidFeature));
+ assertEquals(wifiOnlyStopFailureCode, mCm.stopUsingNetworkFeature(TYPE_MOBILE,
+ invalidFeature));
+ }
+
+ ni = mCm.getNetworkInfo(TYPE_WIFI);
+ if (ni != null) {
+ // Should return failure because MMS is not supported on WIFI.
+ assertEquals(APN_REQUEST_FAILED, mCm.startUsingNetworkFeature(TYPE_WIFI,
+ mmsFeature));
+ assertEquals(failureCode, mCm.stopUsingNetworkFeature(TYPE_WIFI,
+ mmsFeature));
+ }
+ }
+
+ private void expectNetworkBroadcast(final int type, final NetworkInfo.State state,
+ Runnable afterWhat) {
+ final int TIMEOUT_MS = 30 * 1000;
+ final ConditionVariable var = new ConditionVariable();
+
+ Log.d(TAG, "Waiting for " + state + " broadcast for type " + type);
+ BroadcastReceiver receiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ NetworkInfo ni = intent.getExtras()
+ .getParcelable(ConnectivityManager.EXTRA_NETWORK_INFO);
+ assertNotNull("CONNECTIVITY_ACTION with null EXTRA_NETWORK_INFO", ni);
+ if (ni.getType() == type && ni.getState().equals(state)) {
+ Log.d(TAG, "Received expected " + state + " broadcast for type " + type);
+ var.open();
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(CONNECTIVITY_ACTION);
+ mContext.registerReceiver(receiver, filter);
+
+ try {
+ afterWhat.run();
+ final String msg = "Did not receive expected " + state + " broadcast for type " + type +
+ " after " + TIMEOUT_MS + " ms";
+ assertTrue(msg, var.block(TIMEOUT_MS));
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ }
+
+ private boolean isWifiConnected() {
+ NetworkInfo ni = mCm.getNetworkInfo(TYPE_WIFI);
+ return ni != null && ni.isConnected();
+ }
+
+ private void setWifiState(final boolean enabled) {
+ if (enabled != isWifiConnected()) {
+ final NetworkInfo.State desiredState = enabled ?
+ NetworkInfo.State.CONNECTED :
+ NetworkInfo.State.DISCONNECTED;
+ expectNetworkBroadcast(TYPE_WIFI, desiredState, new Runnable() {
+ public void run() {
+ mWifiManager.setWifiEnabled(enabled);
+ }
+ });
+ }
+ }
+
+ private void connectToWifi() {
+ setWifiState(true);
+ }
+
+ private void disconnectFromWifi() {
+ setWifiState(false);
+ }
+
+ private boolean isNetworkSupported(int networkType) {
+ return mCm.getNetworkInfo(networkType) != null;
+ }
+
+ public void testRequestRouteToHost() throws Exception {
+ for (int type = -1 ; type <= MAX_NETWORK_TYPE; type++) {
+ NetworkInfo ni = mCm.getNetworkInfo(type);
+ boolean expectToWork = isNetworkSupported(type) && !isNetworkProtected(type) &&
+ ni != null && ni.isConnected();
+
+ try {
+ assertTrue("Network type " + type,
+ mCm.requestRouteToHost(type, ipv4AddrToInt(HOST_ADDRESS3)) == expectToWork);
+ } catch (Exception e) {
+ Log.d(TAG, "got exception in requestRouteToHost for type " + type);
+ assertFalse("Exception received for type " + type, expectToWork);
+ }
+
+ //TODO verify route table
+ }
+
+ assertFalse(mCm.requestRouteToHost(-1, ipv4AddrToInt(HOST_ADDRESS1)));
+ }
+}
diff --git a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
index d9c7ce7..6807523 100644
--- a/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
+++ b/tests/tests/security/jni/android_security_cts_AudioPolicyBinderTest.cpp
@@ -151,11 +151,12 @@
return false;
}
- if (aps->isStreamActive((audio_stream_type_t)(AUDIO_STREAM_MIN -1), 0)) {
+ status_t status = aps->isStreamActive((audio_stream_type_t)(-1), 0);
+ if (status == NO_ERROR) {
return false;
}
-
- if (aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0)) {
+ status = aps->isStreamActive((audio_stream_type_t)AUDIO_STREAM_CNT, 0);
+ if (status == NO_ERROR) {
return false;
}
return true;
diff --git a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
index 4850140..216ba97 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ExtendedInCallServiceTest.java
@@ -366,7 +366,7 @@
assertCallState(call, Call.STATE_ACTIVE);
final String postDialString = "12345";
- connection.setPostDialWait(postDialString);
+ ((Connection) connection).setPostDialWait(postDialString);
mOnPostDialWaitCounter.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
assertEquals(postDialString, mOnPostDialWaitCounter.getArgs(0)[1]);
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index 5c4420c..79fb592 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -289,7 +289,7 @@
};
mRemoteConnectionObject.registerCallback(callback, handler);
char postDialChar = '3';
- mRemoteConnection.setNextPostDialChar(postDialChar);
+ ((Connection) mRemoteConnection).setNextPostDialChar(postDialChar);
callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
assertEquals(mRemoteConnectionObject, callbackInvoker.getArgs(0)[0]);
assertEquals(postDialChar, callbackInvoker.getArgs(0)[1]);
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index ce3fe78..41fe996 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -177,7 +177,7 @@
assertTrue("Phone count should be > 0", phoneCount > 0);
break;
case TelephonyManager.PHONE_TYPE_NONE:
- assertTrue("Phone count should be 0", phoneCount == 0);
+ assertTrue("Phone count should be 0", phoneCount == 0 || phoneCount == 1);
break;
default:
throw new IllegalArgumentException("Did you add a new phone type? " + phoneType);
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index a52eabe..e6b656f 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -95,7 +95,7 @@
* brackets are optional):
* <p/>
* Mozilla/5.0 (Linux;[ U;] Android <version>;[ <language>-<country>;]
- * [<devicemodel>;] Build/<buildID>) AppleWebKit/<major>.<minor> (KHTML, like Gecko)
+ * [<devicemodel>;] Build/<buildID>[; wv]) AppleWebKit/<major>.<minor> (KHTML, like Gecko)
* Version/<major>.<minor> Chrome/<major>.<minor>.<branch>.<build>[ Mobile]
* Safari/<major>.<minor>
*/
@@ -107,7 +107,7 @@
Log.i(LOG_TAG, String.format("Checking user agent string %s", actualUserAgentString));
final String patternString =
"Mozilla/5\\.0 \\(Linux;( U;)? Android ([^;]+);( (\\w+)-(\\w+);)?" +
- "\\s?(.*)\\sBuild/(.+); wv\\) AppleWebKit/(\\d+)\\.(\\d+) " +
+ "\\s?(.*)\\sBuild/(.+?)(; wv)?\\) AppleWebKit/(\\d+)\\.(\\d+) " +
"\\(KHTML, like Gecko\\) " +
"Version/\\d+\\.\\d+ Chrome/\\d+\\.\\d+\\.\\d+\\.\\d+( Mobile)? " +
"Safari/(\\d+)\\.(\\d+)";
@@ -119,11 +119,12 @@
// 5 - language
// 6 - device model (optional)
// 7 - build ID
- // 8 - AppleWebKit major version number
- // 9 - AppleWebKit minor version number
- // 10 - " Mobile" string (optional)
- // 11 - Safari major version number
- // 12 - Safari minor version number
+ // 8 - WebView identifier "; wv" (optional)
+ // 9 - AppleWebKit major version number
+ // 10 - AppleWebKit minor version number
+ // 11 - " Mobile" string (optional)
+ // 12 - Safari major version number
+ // 13 - Safari minor version number
Log.i(LOG_TAG, String.format("Trying to match pattern %s", patternString));
final Pattern userAgentExpr = Pattern.compile(patternString);
Matcher patternMatcher = userAgentExpr.matcher(actualUserAgentString);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
index 12adb9f..43aaf98 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/DeqpTestRunner.java
@@ -64,7 +64,6 @@
new BatchRunConfiguration("rgba8888d24s8", "unspecified", "window");
private static final int UNRESPOSIVE_CMD_TIMEOUT_MS = 60000; // one minute
- private static final int FILE_REMOVE_RETRY_INTERVAL = 2000; // 2 seconds
private final String mPackageName;
private final String mName;
@@ -79,7 +78,6 @@
private Set<String> mDeviceFeatures;
private Map<String, Boolean> mConfigQuerySupportCache = new HashMap<>();
private IRunUtil mRunUtil = RunUtil.getDefault();
- private ISleepProvider mSleepProvider = new SleepProvider();
private IRecovery mDeviceRecovery = new Recovery();
{
@@ -154,15 +152,6 @@
}
/**
- * Sets the sleep provider DeqpTestRunner works on.
- *
- * Exposed for unit testing.
- */
- public void setSleepProvider(ISleepProvider sleepProvider) {
- mSleepProvider = sleepProvider;
- }
-
- /**
* Set IRunUtil.
*
* Exposed for unit testing.
@@ -777,12 +766,12 @@
public void recoverConnectionRefused() throws DeviceNotAvailableException;
/**
- * Tries to recover device after abnormal termination of a command or a test run execution
- * or link failure.
+ * Tries to recover device after abnormal execution termination or link failure.
*
+ * @param progressedSinceLastCall true if test execution has progressed since last call
* @throws DeviceNotAvailableException if recovery did not succeed
*/
- public void recoverCommandNotCompleted() throws DeviceNotAvailableException;
+ public void recoverComLinkKilled() throws DeviceNotAvailableException;
};
/**
@@ -875,7 +864,7 @@
* {@inheritDoc}
*/
@Override
- public void recoverCommandNotCompleted() throws DeviceNotAvailableException {
+ public void recoverComLinkKilled() throws DeviceNotAvailableException {
switch (mState) {
case WAIT:
// First failure, just try to wait and try again
@@ -890,10 +879,10 @@
killDeqpProcess();
} catch (DeviceNotAvailableException ex) {
// chain forward
- recoverCommandNotCompleted();
+ recoverComLinkKilled();
} catch (ProcessKillFailureException ex) {
// chain forward
- recoverCommandNotCompleted();
+ recoverComLinkKilled();
}
break;
@@ -907,10 +896,10 @@
killDeqpProcess();
} catch (DeviceNotAvailableException ex) {
// chain forward
- recoverCommandNotCompleted();
+ recoverComLinkKilled();
} catch (ProcessKillFailureException ex) {
// chain forward
- recoverCommandNotCompleted();
+ recoverComLinkKilled();
}
break;
@@ -923,7 +912,7 @@
rebootDevice();
} catch (DeviceNotAvailableException ex) {
// chain forward
- recoverCommandNotCompleted();
+ recoverComLinkKilled();
}
break;
@@ -1408,51 +1397,6 @@
}
}
- private static final class FileRecreateFailedException extends Exception {
- };
-
- /**
- * Creates a log file suitable for writing.
- *
- * Creates an empty file that is suitable for writing. If target file already exists, it will
- * first be removed and then recreated. This delete-recreate cycle should guarantee that the
- * target file is always writable and is not affected by file-access flags of the pre-existing
- * file.
- *
- * Precreating a file in the runner makes detecting file-access issues faster and more
- * reliable. It also avoids issues caused by sdcard FUSE spuriously preventing file creation.
- */
- private void precreateLogFile() throws DeviceNotAvailableException,
- FileRecreateFailedException {
- final int NUM_ATTEMPTS = 4;
- int attemptNum = 0;
- for (;;) {
- mDevice.executeShellCommand("rm " + LOG_FILE_NAME);
- ++attemptNum;
-
- if (!mDevice.doesFileExist(LOG_FILE_NAME)) {
- // yay, remove works like it should
- break;
- } else if (attemptNum < NUM_ATTEMPTS) {
- // wait if we failed
- CLog.w("Remote file removal failed, retrying...");
- mSleepProvider.sleep(FILE_REMOVE_RETRY_INTERVAL);
- } else {
- // Bail
- CLog.e("Could not delete a remote file.");
- throw new FileRecreateFailedException();
- }
- }
-
- // create & truncate and make world read-writable
- mDevice.pushString("", LOG_FILE_NAME);
-
- if (!mDevice.doesFileExist(LOG_FILE_NAME)) {
- CLog.e("Could not precreate log file.");
- throw new FileRecreateFailedException();
- }
- }
-
/**
* Runs one execution pass over the given batch.
*
@@ -1468,8 +1412,8 @@
final String testCases = generateTestCaseTrie(batch.tests);
- // Caselist file cannot linger.
mDevice.executeShellCommand("rm " + CASE_LIST_FILE_NAME);
+ mDevice.executeShellCommand("rm " + LOG_FILE_NAME);
mDevice.pushString(testCases + "\n", CASE_LIST_FILE_NAME);
final String instrumentationName =
@@ -1499,9 +1443,6 @@
Throwable interruptingError = null;
try {
- // we might have lingering log file from a previous dirty run and it might be somehow
- // locked (details unknown). Make sure it's writable when test is run.
- precreateLogFile();
executeShellCommandAndReadOutput(command, parser);
} catch (Throwable ex) {
interruptingError = ex;
@@ -1521,9 +1462,7 @@
if (interruptingError instanceof AdbComLinkOpenError) {
mDeviceRecovery.recoverConnectionRefused();
} else if (interruptingError instanceof AdbComLinkKilledError) {
- mDeviceRecovery.recoverCommandNotCompleted();
- } else if (interruptingError instanceof FileRecreateFailedException) {
- mDeviceRecovery.recoverCommandNotCompleted();
+ mDeviceRecovery.recoverComLinkKilled();
} else if (interruptingError instanceof RunInterruptedException) {
// external run interruption request. Terminate immediately.
throw (RunInterruptedException)interruptingError;
@@ -1534,7 +1473,7 @@
// recoverXXX did not throw => recovery succeeded
} else if (!parser.wasSuccessful()) {
- mDeviceRecovery.recoverCommandNotCompleted();
+ mDeviceRecovery.recoverComLinkKilled();
// recoverXXX did not throw => recovery succeeded
}
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
index 4c879b4..7ec09c9 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/testtype/DeqpTestRunnerTest.java
@@ -106,7 +106,7 @@
* {@inheritDoc}
*/
@Override
- public void recoverCommandNotCompleted() throws DeviceNotAvailableException {
+ public void recoverComLinkKilled() throws DeviceNotAvailableException {
}
};
@@ -1717,14 +1717,11 @@
EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
.andReturn("").once();
- EasyMock.expect(mockDevice.pushString("{dEQP-GLES3{loss{instance}}}\n", CASE_LIST_FILE_NAME))
- .andReturn(true).once();
-
EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
.andReturn("").once();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(false).once();
- EasyMock.expect(mockDevice.pushString("", LOG_FILE_NAME)).andReturn(true).once();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
+
+ EasyMock.expect(mockDevice.pushString("{dEQP-GLES3{loss{instance}}}\n", CASE_LIST_FILE_NAME))
+ .andReturn(true).once();
String command = String.format(
"am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \""
@@ -1756,10 +1753,10 @@
});
if (!recoverySuccessful) {
- mockRecovery.recoverCommandNotCompleted();
+ mockRecovery.recoverComLinkKilled();
EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()).once();
} else {
- mockRecovery.recoverCommandNotCompleted();
+ mockRecovery.recoverComLinkKilled();
EasyMock.expectLastCall().once();
// retry running config B
@@ -1863,7 +1860,7 @@
recovery.recoverConnectionRefused();
break;
case FAIL_LINK_KILLED:
- recovery.recoverCommandNotCompleted();
+ recovery.recoverComLinkKilled();
break;
}
}
@@ -2144,7 +2141,7 @@
orderedControl.replay();
recovery.setDevice(mockDevice);
recovery.setSleepProvider(mockSleepProvider);
- recovery.recoverCommandNotCompleted();
+ recovery.recoverComLinkKilled();
orderedControl.verify();
}
@@ -2315,216 +2312,16 @@
EasyMock.verify(mockDevice, mockIDevice);
}
- /**
- * Test log file precreate persistent failure
- */
- public void testPrecreate_persistentFailure() throws Exception {
- final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.precreate", "test");
- final String testTrie = "{dEQP-GLES3{precreate{test}}}";
-
- Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
- tests.add(testId);
-
- Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
- instance.put(testId, DEFAULT_INSTANCE_ARGS);
-
- ITestInvocationListener mockListener
- = EasyMock.createStrictMock(ITestInvocationListener.class);
- ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
- IDevice mockIDevice = EasyMock.createMock(IDevice.class);
- DeqpTestRunner.ISleepProvider mockSleepProvider =
- EasyMock.createMock(DeqpTestRunner.ISleepProvider.class);
- DeqpTestRunner.IRecovery mockRecovery =
- EasyMock.createMock(DeqpTestRunner.IRecovery.class);
-
- DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
- deqpTest.setAbi(UnitTests.ABI);
- deqpTest.setDevice(mockDevice);
- deqpTest.setBuildHelper(new StubCtsBuildHelper());
- deqpTest.setSleepProvider(mockSleepProvider);
- deqpTest.setRecovery(mockRecovery);
-
- mockRecovery.setDevice(mockDevice);
- EasyMock.expectLastCall().atLeastOnce();
-
- int version = 3 << 16;
- EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
- .andReturn(Integer.toString(version)).atLeastOnce();
-
- EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
- andReturn("").once();
-
- EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
- EasyMock.eq(true),
- EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
- .once();
-
- expectRenderConfigQuery(mockDevice,
- "--deqp-gl-config-name=rgba8888d24s8 --deqp-screen-rotation=unspecified "
- + "--deqp-surface-type=window --deqp-gl-major-version=3 "
- + "--deqp-gl-minor-version=0");
-
- EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
- .andReturn("").once();
-
- EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
- .andReturn(true).once();
-
- // fail persistently...
- EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
- .andReturn("").anyTimes();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).anyTimes();
- mockSleepProvider.sleep(EasyMock.gt(0));
- EasyMock.expectLastCall().anyTimes();
-
- // ..and when retries won't help, trigger recovery tactics
- mockRecovery.recoverCommandNotCompleted();
- EasyMock.expectLastCall().andThrow(new DeviceNotAvailableException()).once();
-
- mockListener.testRunStarted(ID, 1);
- EasyMock.expectLastCall().once();
-
- EasyMock.replay(mockDevice, mockIDevice);
- EasyMock.replay(mockListener);
- EasyMock.replay(mockSleepProvider);
- EasyMock.replay(mockRecovery);
- try {
- deqpTest.run(mockListener);
- fail("expected DeviceNotAvailableException");
- } catch (DeviceNotAvailableException ex) {
- // expected
- }
- EasyMock.verify(mockRecovery);
- EasyMock.verify(mockSleepProvider);
- EasyMock.verify(mockListener);
- EasyMock.verify(mockDevice, mockIDevice);
- }
-
- /**
- * Test log file precreate transient failure
- */
- public void testPrecreate_transientFailure() throws Exception {
- final TestIdentifier testId = new TestIdentifier("dEQP-GLES3.precreate", "test");
- final String testPath = "dEQP-GLES3.precreate.test";
- final String testTrie = "{dEQP-GLES3{precreate{test}}}";
- final String output = "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseName\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=2014.x\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=releaseId\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=0xcafebabe\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Name=targetName\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=SessionInfo\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-SessionInfo-Value=android\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginSession\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=BeginTestCase\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-BeginTestCase-TestCasePath=" + testPath + "\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Code=Pass\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-TestCaseResult-Details=DetailPass\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=TestCaseResult\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=EndTestCase\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_STATUS: dEQP-EventType=EndSession\r\n"
- + "INSTRUMENTATION_STATUS_CODE: 0\r\n"
- + "INSTRUMENTATION_CODE: 0\r\n";
-
- Collection<TestIdentifier> tests = new ArrayList<TestIdentifier>();
- tests.add(testId);
-
- Map<TestIdentifier, List<Map<String, String>>> instance = new HashMap<>();
- instance.put(testId, DEFAULT_INSTANCE_ARGS);
-
- ITestInvocationListener mockListener
- = EasyMock.createStrictMock(ITestInvocationListener.class);
- ITestDevice mockDevice = EasyMock.createMock(ITestDevice.class);
- IDevice mockIDevice = EasyMock.createMock(IDevice.class);
- DeqpTestRunner.ISleepProvider mockSleepProvider =
- EasyMock.createMock(DeqpTestRunner.ISleepProvider.class);
-
- DeqpTestRunner deqpTest = new DeqpTestRunner(NAME, NAME, tests, instance);
- deqpTest.setAbi(UnitTests.ABI);
- deqpTest.setDevice(mockDevice);
- deqpTest.setBuildHelper(new StubCtsBuildHelper());
- deqpTest.setSleepProvider(mockSleepProvider);
-
- int version = 3 << 16;
- EasyMock.expect(mockDevice.getProperty("ro.opengles.version"))
- .andReturn(Integer.toString(version)).atLeastOnce();
-
- EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
- andReturn("").once();
-
- EasyMock.expect(mockDevice.installPackage(EasyMock.<File>anyObject(),
- EasyMock.eq(true),
- EasyMock.eq(AbiUtils.createAbiFlag(UnitTests.ABI.getName())))).andReturn(null)
- .once();
-
- expectRenderConfigQuery(mockDevice,
- "--deqp-gl-config-name=rgba8888d24s8 --deqp-screen-rotation=unspecified "
- + "--deqp-surface-type=window --deqp-gl-major-version=3 "
- + "--deqp-gl-minor-version=0");
-
- // fail once
- EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
- .andReturn("").once();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
- mockSleepProvider.sleep(EasyMock.gt(0));
- EasyMock.expectLastCall().once();
-
- String commandLine = String.format(
- "--deqp-caselist-file=%s --deqp-gl-config-name=rgba8888d24s8 "
- + "--deqp-screen-rotation=unspecified "
- + "--deqp-surface-type=window "
- + "--deqp-log-images=disable "
- + "--deqp-watchdog=enable",
- CASE_LIST_FILE_NAME);
-
- runInstrumentationLineAndAnswer(mockDevice, mockIDevice, testTrie, commandLine,
- output);
-
- EasyMock.expect(mockDevice.uninstallPackage(EasyMock.eq(DEQP_ONDEVICE_PKG))).
- andReturn("").once();
-
- mockListener.testRunStarted(ID, 1);
- EasyMock.expectLastCall().once();
-
- mockListener.testStarted(EasyMock.eq(testId));
- EasyMock.expectLastCall().once();
-
- mockListener.testEnded(EasyMock.eq(testId), EasyMock.<Map<String, String>>notNull());
- EasyMock.expectLastCall().once();
-
- mockListener.testRunEnded(EasyMock.anyLong(), EasyMock.<Map<String, String>>notNull());
- EasyMock.expectLastCall().once();
-
- EasyMock.replay(mockDevice, mockIDevice);
- EasyMock.replay(mockListener);
- EasyMock.replay(mockSleepProvider);
- deqpTest.run(mockListener);
- EasyMock.verify(mockSleepProvider);
- EasyMock.verify(mockListener);
- EasyMock.verify(mockDevice, mockIDevice);
- }
-
private void runInstrumentationLineAndAnswer(ITestDevice mockDevice, IDevice mockIDevice,
final String testTrie, final String cmd, final String output) throws Exception {
EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + CASE_LIST_FILE_NAME)))
.andReturn("").once();
- EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
- .andReturn(true).once();
-
EasyMock.expect(mockDevice.executeShellCommand(EasyMock.eq("rm " + LOG_FILE_NAME)))
.andReturn("").once();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(false).once();
- EasyMock.expect(mockDevice.pushString("", LOG_FILE_NAME)).andReturn(true).once();
- EasyMock.expect(mockDevice.doesFileExist(LOG_FILE_NAME)).andReturn(true).once();
+
+ EasyMock.expect(mockDevice.pushString(testTrie + "\n", CASE_LIST_FILE_NAME))
+ .andReturn(true).once();
String command = String.format(
"am instrument %s -w -e deqpLogFileName \"%s\" -e deqpCmdLine \"%s\" "