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