Merge "Increase timeout for ordered broadcast response." into nougat-cts-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 68aefa9..0c1e1db 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1938,6 +1938,17 @@
android:value="android.software.live_tv" />
</activity>
+ <activity android:name=".tv.MicrophoneDeviceTestActivity"
+ android:label="@string/tv_microphone_device_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_tv" />
+ <meta-data android:name="test_required_features"
+ android:value="android.software.leanback" />
+ </activity>
+
<activity android:name=".screenpinning.ScreenPinningTestActivity"
android:label="@string/screen_pinning_test">
<intent-filter>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 91ca7c7..5c5f56d 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2527,6 +2527,8 @@
<string name="tv_parental_control_turn_off_disabled">No</string>
<string name="tv_parental_control_turn_off_enabled">Yes</string>
+ <string name="tv_yes">Yes</string>
+ <string name="tv_no">No</string>
<string name="tv_launch_tv_app">Launch TV app</string>
<string name="tv_launch_epg">Launch EPG</string>
<string name="tv_launch_setup">Launch setup</string>
@@ -2609,6 +2611,35 @@
2) You should see the text \"Cts App-Link Text\".\n
</string>
+ <string name="tv_microphone_device_test">Microphone device test</string>
+ <string name="tv_microphone_device_test_info">
+ This test checks if InputDevice.hasMicrophone of the Media API reports a
+ correct value on every input device (including remote controls).
+ </string>
+ <string name="tv_microphone_device_test_prep_question">
+ Before continuing, please make sure that you pair all primary input
+ devices intended to be used by the device, including bluetooth
+ remotes and companion remote-control apps such as the Android TV Remote Control.
+ Have you paired every primary input device with the device under test (DUT)?
+ </string>
+ <string name="tv_microphone_device_test_mic_question">
+ Does input device \"%1$s\" have a microphone?
+ </string>
+ <string name="tv_microphone_device_test_negative_mismatch">
+ InputDevice.hasMicrophone reports that this input device DOES have a
+ microphone whereas you selected that it does not. Please correct it by
+ declaring \"audio.mic = 0\" in the device\'s input device configuration
+ (.idc) file.
+ </string>
+ <string name="tv_microphone_device_test_positive_mismatch">
+ InputDevice.hasMicrophone reports that this input device does NOT have a
+ microphone whereas you selected that it does. Please correct it by
+ declaring \"audio.mic = 1\" in the device\'s input device configuration
+ (.idc) file and make sure that relevant files such as key layout (.kl)
+ and key character map (.kcm) files are found by the system accordingly.
+ </string>
+ <string name="tv_microphone_device_test_no_input_devices">No input devices found.</string>
+
<string name="overlay_view_text">Overlay View Dummy Text</string>
<string name="custom_rating">Example of input app specific custom rating.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/MicrophoneDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MicrophoneDeviceTestActivity.java
new file mode 100644
index 0000000..eca02c1
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/MicrophoneDeviceTestActivity.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2017 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.tv;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.hardware.input.InputManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.cts.verifier.R;
+
+/**
+ * Tests for verifying that all input devices report correct hasMicrophone() states.
+ */
+@SuppressLint("NewApi")
+public class MicrophoneDeviceTestActivity extends TvAppVerifierActivity
+ implements View.OnClickListener {
+ private static final String TAG = "MicrophoneDeviceTestActivity";
+ private static final boolean PASS = true;
+
+ private InputManager mInputManager;
+ private HashMap<View, List<Object>> mInputDeviceItems;
+ private View mPreparationYesItem;
+ private View mPreparationNoItem;
+
+ @Override
+ public void onClick(View v) {
+ final View postTarget = getPostTarget();
+
+ if (containsButton(mPreparationYesItem, v)) {
+ setPassState(mPreparationYesItem, true);
+ setButtonEnabled(mPreparationNoItem, false);
+ createInputDeviceItems();
+ return;
+ } else if (containsButton(mPreparationNoItem, v)) {
+ setPassState(mPreparationYesItem, false);
+ setButtonEnabled(mPreparationNoItem, false);
+ getPassButton().setEnabled(false);
+ return;
+ } else if (mInputDeviceItems == null) {
+ return;
+ }
+
+ for (View item : mInputDeviceItems.keySet()) {
+ if (containsButton(item, v)) {
+ final List<Object> triple = mInputDeviceItems.get(item);
+ final boolean userAnswer = (boolean) triple.get(0);
+ final boolean actualAnswer = (boolean) triple.get(1);
+ final View pairedItem = (View) triple.get(2);
+
+ if (userAnswer == actualAnswer) {
+ setPassState(userAnswer ? item : pairedItem, true);
+ setButtonEnabled(userAnswer ? pairedItem : item, false);
+ item.setTag(PASS); pairedItem.setTag(PASS);
+ if (checkAllPassed()) {
+ getPassButton().setEnabled(true);
+ }
+ return;
+ }
+
+ final int messageId =
+ actualAnswer ? R.string.tv_microphone_device_test_negative_mismatch :
+ R.string.tv_microphone_device_test_positive_mismatch;
+ Toast.makeText(this, messageId, Toast.LENGTH_LONG).show();
+ setPassState(userAnswer ? item : pairedItem, false);
+ getPassButton().setEnabled(false);
+ return;
+ }
+ }
+ }
+
+ @Override
+ protected void createTestItems() {
+ mPreparationYesItem = createUserItem(
+ R.string.tv_microphone_device_test_prep_question,
+ R.string.tv_yes, this);
+ setButtonEnabled(mPreparationYesItem, true);
+ mPreparationNoItem = createButtonItem(R.string.tv_no, this);
+ setButtonEnabled(mPreparationNoItem, true);
+ }
+
+ private void createInputDeviceItems() {
+ final Context context = MicrophoneDeviceTestActivity.this;
+ mInputManager = (InputManager) context.getSystemService(Context.INPUT_SERVICE);
+
+ final int[] inputDeviceIds = mInputManager.getInputDeviceIds();
+ mInputDeviceItems = new HashMap<View, List<Object>>();
+
+ for (int inputDeviceId : inputDeviceIds) {
+ final InputDevice inputDevice = mInputManager.getInputDevice(inputDeviceId);
+ final boolean hasMicrophone = inputDevice.hasMicrophone();
+ Log.w(TAG, "name: " + inputDevice.getName() + ", mic: " + hasMicrophone + ", virtual: "
+ + inputDevice.isVirtual() + ", descriptor: " + inputDevice.getDescriptor());
+
+ // Skip virtual input devices such as virtual keyboards. This does
+ // not, e.g., include com.google.android.tv.remote bluetooth connections.
+ if (inputDevice.isVirtual()) {
+ continue;
+ }
+
+ final CharSequence micQuestion =
+ getString(R.string.tv_microphone_device_test_mic_question, inputDevice.getName());
+
+ final View inputDeviceYesItem = createUserItem(micQuestion, R.string.tv_yes, this);
+ setButtonEnabled(inputDeviceYesItem, true);
+ final View inputDeviceNoItem = createButtonItem(R.string.tv_no, this);
+ setButtonEnabled(inputDeviceNoItem, true);
+ mInputDeviceItems.put(
+ inputDeviceYesItem, Arrays.asList(true, hasMicrophone, inputDeviceNoItem));
+ mInputDeviceItems.put(
+ inputDeviceNoItem, Arrays.asList(false, hasMicrophone, inputDeviceYesItem));
+ }
+
+ if (mInputDeviceItems.size() == 0) {
+ Toast.makeText(this, R.string.tv_microphone_device_test_no_input_devices,
+ Toast.LENGTH_LONG).show();
+ getPassButton().setEnabled(true);
+ }
+ }
+
+ @Override
+ protected void setInfoResources() {
+ setInfoResources(R.string.tv_microphone_device_test,
+ R.string.tv_microphone_device_test_info, -1);
+ }
+
+ private boolean hasPassed(View item) {
+ return (item.getTag() != null) && ((Boolean) item.getTag()) == PASS;
+ }
+
+ private boolean checkAllPassed() {
+ if (mInputDeviceItems != null && mInputDeviceItems.size() > 0) {
+ for (View item : mInputDeviceItems.keySet()) {
+ if (!hasPassed(item)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
index cb50fac..b95ba98 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvAppVerifierActivity.java
@@ -93,6 +93,22 @@
}
/**
+ * Call this to create a test step where the user must perform some action.
+ */
+ protected View createUserItem(CharSequence instructionCharSequence,
+ int buttonTextId, View.OnClickListener l) {
+ View item = mInflater.inflate(R.layout.tv_item, mItemList, false);
+ TextView instructions = (TextView) item.findViewById(R.id.instructions);
+ instructions.setText(instructionCharSequence);
+ Button button = (Button) item.findViewById(R.id.user_action_button);
+ button.setVisibility(View.VISIBLE);
+ button.setText(buttonTextId);
+ button.setOnClickListener(l);
+ mItemList.addView(item);
+ return item;
+ }
+
+ /**
* Call this to create a test step where the test automatically evaluates whether
* an expected condition is satisfied.
*/
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index acdaa0a..4cc0351 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -157,6 +157,9 @@
public void addDynamicConfigFile(String moduleName, File configFile) {
mBuildInfo.addBuildAttribute(DynamicConfigHostSide.CONFIG_PATH_PREFIX + moduleName,
configFile.getAbsolutePath());
+ // If invocation fails and ResultReporter never moves this file into the result,
+ // using setFile() ensures BuildInfo will delete upon cleanUp().
+ mBuildInfo.setFile(configFile.getName(), configFile, "1" /* version */);
}
public void setModuleIds(String[] moduleIds) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 32d3cda..fecc216 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -483,7 +483,7 @@
long startTime = mResult.getStartTime();
try {
// Zip the full test results directory.
- copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
+ copyDynamicConfigFiles();
copyFormattingFiles(mResultDir, mBuildHelper.getSuiteName());
File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
@@ -702,18 +702,32 @@
* @param configFiles
* @param resultsDir
*/
- static void copyDynamicConfigFiles(Map<String, File> configFiles, File resultsDir) {
- if (configFiles.size() == 0) return;
+ private void copyDynamicConfigFiles() {
+ File configDir = new File(mResultDir, "config");
+ if (!configDir.mkdir()) {
+ warn("Failed to make dynamic config directory \"%s\" in the result",
+ configDir.getAbsolutePath());
+ }
- File folder = new File(resultsDir, "config");
- folder.mkdir();
- for (String moduleName : configFiles.keySet()) {
- File resultFile = new File(folder, moduleName+".dynamic");
- try {
- FileUtil.copyFile(configFiles.get(moduleName), resultFile);
- FileUtil.deleteFile(configFiles.get(moduleName));
- } catch (IOException e) {
- warn("Failed to copy config file for %s to file", moduleName);
+ Set<String> uniqueModules = new HashSet<>();
+ for (IBuildInfo buildInfo : mMasterBuildInfos) {
+ CompatibilityBuildHelper helper = new CompatibilityBuildHelper(buildInfo);
+ Map<String, File> dcFiles = helper.getDynamicConfigFiles();
+ for (String moduleName : dcFiles.keySet()) {
+ File srcFile = dcFiles.get(moduleName);
+ if (!uniqueModules.contains(moduleName)) {
+ // have not seen config for this module yet, copy into result
+ File destFile = new File(configDir, moduleName + ".dynamic");
+ try {
+ FileUtil.copyFile(srcFile, destFile);
+ uniqueModules.add(moduleName); // Add to uniqueModules if copy succeeds
+ } catch (IOException e) {
+ warn("Failure when copying config file \"%s\" to \"%s\" for module %s",
+ srcFile.getAbsolutePath(), destFile.getAbsolutePath(), moduleName);
+ CLog.e(e);
+ }
+ }
+ FileUtil.deleteFile(srcFile);
}
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
index 7600eb7..2570432 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
@@ -28,7 +28,6 @@
import com.android.tradefed.targetprep.BuildError;
import com.android.tradefed.targetprep.ITargetCleaner;
import com.android.tradefed.targetprep.TargetSetupError;
-import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.StreamUtil;
import org.json.JSONException;
@@ -50,7 +49,6 @@
}
private static final String LOG_TAG = DynamicConfigPusher.class.getSimpleName();
- private static final String TMP_FOLDER_DYNAMIC_FILES = "dynamic-config-files";
@Option(name = "cleanup", description = "Whether to remove config files from the test " +
"target after test completion.")
@@ -68,8 +66,7 @@
"from the server, e.g. \"1.0\". Defaults to suite version string.")
private static String mVersion;
-
- private String mFilePushed;
+ private String mDeviceFilePushed;
void setModuleName(String moduleName) {
mModuleName = moduleName;
@@ -115,46 +112,27 @@
"Dynamic config override URL is not set, using local configuration values");
}
- File src = null;
+ // Use DynamicConfigHandler to merge local and service configuration into one file
+ File hostFile = null;
try {
- src = DynamicConfigHandler.getMergedDynamicConfigFile(
+ hostFile = DynamicConfigHandler.getMergedDynamicConfigFile(
localConfigFile, apfeConfigInJson, mModuleName);
} catch (IOException | XmlPullParserException | JSONException e) {
throw new TargetSetupError("Cannot get merged dynamic config file", e);
}
- switch (mTarget) {
- case DEVICE:
- String deviceDest = DynamicConfig.CONFIG_FOLDER_ON_DEVICE + src.getName();
- if (!device.pushFile(src, deviceDest)) {
- throw new TargetSetupError(String.format(
- "Failed to push local '%s' to remote '%s'",
- src.getAbsolutePath(), deviceDest));
- } else {
- mFilePushed = deviceDest;
- buildHelper.addDynamicConfigFile(mModuleName, src);
- }
- break;
-
- case HOST:
- File storageDir = null;
- try {
- storageDir = FileUtil.createTempDir(TMP_FOLDER_DYNAMIC_FILES);
- } catch (IOException e) {
- throw new TargetSetupError("Fail to create a tmp folder for dynamic config "
- + "files", e);
- }
- File hostDest = new File(storageDir, src.getName());
- try {
- FileUtil.copyFile(src, hostDest);
- } catch (IOException e) {
- throw new TargetSetupError(String.format("Failed to copy file from %s to %s",
- src.getAbsolutePath(), hostDest.getAbsolutePath()), e);
- }
- mFilePushed = storageDir.getAbsolutePath();
- buildHelper.addDynamicConfigFile(mModuleName, src);
- break;
+ if (TestTarget.DEVICE.equals(mTarget)) {
+ String deviceDest = String.format("%s%s.dynamic",
+ DynamicConfig.CONFIG_FOLDER_ON_DEVICE, mModuleName);
+ if (!device.pushFile(hostFile, deviceDest)) {
+ throw new TargetSetupError(String.format(
+ "Failed to push local '%s' to remote '%s'", hostFile.getAbsolutePath(),
+ deviceDest));
+ }
+ mDeviceFilePushed = deviceDest;
}
+ // add host file to build
+ buildHelper.addDynamicConfigFile(mModuleName, hostFile);
}
/**
@@ -163,16 +141,10 @@
@Override
public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
throws DeviceNotAvailableException {
- switch (mTarget) {
- case DEVICE:
- if (!(e instanceof DeviceNotAvailableException)
- && mCleanup && mFilePushed != null) {
- device.executeShellCommand("rm -r " + mFilePushed);
- }
- break;
- case HOST:
- FileUtil.recursiveDelete(new File(mFilePushed));
- break;
+ // Remove any file we have pushed to the device, host file will be moved to the result
+ // directory by ResultReporter upon invocation completion.
+ if (mDeviceFilePushed != null && !(e instanceof DeviceNotAvailableException) && mCleanup) {
+ device.executeShellCommand("rm -r " + mDeviceFilePushed);
}
}
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java
index 8df1ebc..0528a1b 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/DynamicConfigHandler.java
@@ -37,7 +37,8 @@
public class DynamicConfigHandler {
- private final static String MERGED_CONFIG_FILE_FOLDER = "dynamic-config-files-merged";
+ private final static String MERGED_CONFIG_FILE = "dynamic-config-files-merged";
+ private final static String FILE_EXT = ".dynamic";
private static final String NS = null; //xml constant representing null namespace
private static final String ENCODING = "UTF-8";
@@ -76,8 +77,7 @@
private static File storeMergedConfigFile(Map<String, List<String>> configMap,
String moduleName) throws XmlPullParserException, IOException {
- File folder = FileUtil.createTempDir(MERGED_CONFIG_FILE_FOLDER);
- File mergedConfigFile = new File(folder, moduleName + ".dynamic");
+ File mergedConfigFile = FileUtil.createTempFile(MERGED_CONFIG_FILE, FILE_EXT);
OutputStream stream = new FileOutputStream(mergedConfigFile);
XmlSerializer serializer = XmlPullParserFactory.newInstance().newSerializer();
serializer.setOutput(stream, ENCODING);
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
index 38b742b..fecccf4 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ReportLogHostInfoStore.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.util;
import com.android.json.stream.JsonWriter;
+import com.android.tradefed.util.FileUtil;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@@ -92,6 +93,8 @@
// Copy from temp file directly to avoid large metrics string in memory.
metricsWriter.write(line, 0, line.length());
}
+ } finally {
+ FileUtil.deleteFile(tempJsonFile);
}
}
}
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
index 36c4970..204a8f1 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
@@ -16,6 +16,9 @@
package com.android.compatibility.common.util;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+
import junit.framework.TestCase;
import java.io.File;
@@ -92,26 +95,31 @@
public void testDynamicConfigHandler() throws Exception {
String module = "test1";
File localConfigFile = createFileFromStr(localConfig, module);
+ File mergedFile = null;
+ try {
+ mergedFile = DynamicConfigHandler
+ .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
- File mergedFile = DynamicConfigHandler
- .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
+ Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
- Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
+ assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
+ assertTrue(configMap.get("override-config-list-1")
+ .contains("override-config-list-val-1-1"));
+ assertTrue(configMap.get("override-config-list-1")
+ .contains("override-config-list-val-1-2"));
+ assertTrue(configMap.get("override-config-list-3").size() == 0);
- assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
- assertTrue(configMap.get("override-config-list-1")
- .contains("override-config-list-val-1-1"));
- assertTrue(configMap.get("override-config-list-1")
- .contains("override-config-list-val-1-2"));
- assertTrue(configMap.get("override-config-list-3").size() == 0);
+ assertEquals("test config 1", configMap.get("test-config-1").get(0));
+ assertTrue(configMap.get("config-list").contains("config2"));
- assertEquals("test config 1", configMap.get("test-config-1").get(0));
- assertTrue(configMap.get("config-list").contains("config2"));
-
- assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
- assertEquals(1, configMap.get("override-config-list-2").size());
- assertTrue(configMap.get("override-config-list-2")
- .contains("override-config-list-val-2-1"));
+ assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
+ assertEquals(1, configMap.get("override-config-list-2").size());
+ assertTrue(configMap.get("override-config-list-2")
+ .contains("override-config-list-val-2-1"));
+ } finally {
+ FileUtil.deleteFile(localConfigFile);
+ FileUtil.recursiveDelete(mergedFile);
+ }
}
@@ -123,9 +131,7 @@
stream.write(configStr.getBytes());
stream.flush();
} finally {
- if (stream != null) {
- stream.close();
- }
+ StreamUtil.close(stream);
}
return file;
}
diff --git a/common/util/src/com/android/compatibility/common/util/ModuleResult.java b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
index 60500a2..e786a1e 100644
--- a/common/util/src/com/android/compatibility/common/util/ModuleResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ModuleResult.java
@@ -267,11 +267,14 @@
this.mRuntime += otherModuleResult.getRuntime();
this.mNotExecuted += otherModuleResult.getNotExecuted();
- this.setDone(otherModuleResult.isDoneSoFar());
- this.mActualTestRuns += otherModuleResult.getTestRuns();
- // expected test runs are the same across shards, except for shards that do not run this
- // module at least once (for which the value is not yet set).
- this.mExpectedTestRuns = otherModuleResult.getExpectedTestRuns();
+ // only touch variables related to 'done' status if this module is not already done
+ if (!isDone()) {
+ this.setDone(otherModuleResult.isDoneSoFar());
+ this.mActualTestRuns += otherModuleResult.getTestRuns();
+ // expected test runs are the same across shards, except for shards that do not run
+ // this module at least once (for which the value is not yet set).
+ this.mExpectedTestRuns = otherModuleResult.getExpectedTestRuns();
+ }
for (ICaseResult otherCaseResult : otherModuleResult.getResults()) {
ICaseResult caseResult = getOrCreateResult(otherCaseResult.getName());
caseResult.mergeFrom(otherCaseResult);
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index b1455bd..eb83341 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -681,8 +681,10 @@
//
// Verify recording starts within 400 ms of AudioTrack completion (typical 180ms)
// Verify recording completes within 50 ms of expected test time (typical 20ms)
- assertEquals(TEST_NAME, PLAYBACK_TIME_IN_MS, firstSampleTime - startTime, 400);
- assertEquals(TEST_NAME, RECORD_TIME_IN_MS, endTime - firstSampleTime, 50);
+ assertEquals(TEST_NAME, PLAYBACK_TIME_IN_MS, firstSampleTime - startTime,
+ isLowLatencyDevice() ? 400 : 800);
+ assertEquals(TEST_NAME, RECORD_TIME_IN_MS, endTime - firstSampleTime,
+ isLowLatencyDevice()? 50 : 400);
record.stop();
assertEquals(TEST_NAME, AudioRecord.RECORDSTATE_STOPPED, record.getRecordingState());
@@ -984,7 +986,8 @@
assertTrue(coldInputStartTime < 5000); // must start within 5 seconds.
// Verify recording completes within 50 ms of expected test time (typical 20ms)
- assertEquals(TEST_TIME_MS, endTime - firstSampleTime, auditRecording ? 1000 : 50);
+ assertEquals(TEST_TIME_MS, endTime - firstSampleTime, auditRecording ?
+ (isLowLatencyDevice() ? 1000 : 2000) : (isLowLatencyDevice() ? 50 : 400));
// Even though we've read all the frames we want, the events may not be sent to
// the listeners (events are handled through a separate internal callback thread).
@@ -1065,16 +1068,18 @@
// " markerPeriodsReceived " + markerList.size());
//Log.d(TAG, "updatePeriods " + updatePeriods +
// " updatePeriodsReceived " + periodicList.size());
- assertTrue(TAG + ": markerPeriods " + markerPeriods +
- " <= markerPeriodsReceived " + markerList.size() +
- " <= markerPeriodsMax " + markerPeriodsMax,
- markerPeriods <= markerList.size()
- && markerList.size() <= markerPeriodsMax);
- assertTrue(TAG + ": updatePeriods " + updatePeriods +
- " <= updatePeriodsReceived " + periodicList.size() +
- " <= updatePeriodsMax " + updatePeriodsMax,
- updatePeriods <= periodicList.size()
- && periodicList.size() <= updatePeriodsMax);
+ if (isLowLatencyDevice()) {
+ assertTrue(TAG + ": markerPeriods " + markerPeriods +
+ " <= markerPeriodsReceived " + markerList.size() +
+ " <= markerPeriodsMax " + markerPeriodsMax,
+ markerPeriods <= markerList.size()
+ && markerList.size() <= markerPeriodsMax);
+ assertTrue(TAG + ": updatePeriods " + updatePeriods +
+ " <= updatePeriodsReceived " + periodicList.size() +
+ " <= updatePeriodsMax " + updatePeriodsMax,
+ updatePeriods <= periodicList.size()
+ && periodicList.size() <= updatePeriodsMax);
+ }
// Since we don't have accurate positioning of the start time of the recorder,
// and there is no record.getPosition(), we consider only differential timing
@@ -1092,7 +1097,9 @@
//Log.d(TAG, "Marker: " + i + " expected(" + expected + ") actual(" + actual
// + ") diff(" + (actual - expected) + ")"
// + " tolerance " + toleranceInFrames);
- assertEquals(expected, actual, toleranceInFrames);
+ if (isLowLatencyDevice()) {
+ assertEquals(expected, actual, toleranceInFrames);
+ }
markerStat.add((double)(actual - expected) * 1000 / TEST_SR);
}
@@ -1106,7 +1113,9 @@
//Log.d(TAG, "Update: " + i + " expected(" + expected + ") actual(" + actual
// + ") diff(" + (actual - expected) + ")"
// + " tolerance " + toleranceInFrames);
- assertEquals(expected, actual, toleranceInFrames);
+ if (isLowLatencyDevice()) {
+ assertEquals(expected, actual, toleranceInFrames);
+ }
periodicStat.add((double)(actual - expected) * 1000 / TEST_SR);
}
@@ -1234,6 +1243,11 @@
.isLowRamDevice();
}
+ private boolean isLowLatencyDevice() {
+ return getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUDIO_LOW_LATENCY);
+ }
+
private void verifyContinuousTimestamps(
AudioTimestamp startTs, AudioTimestamp stopTs, int sampleRate)
throws Exception {
@@ -1246,7 +1260,7 @@
// Usually the ratio is accurate to one part per thousand or better.
// Log.d(TAG, "ratio=" + ratio + ", timeDiff=" + timeDiff + ", frameDiff=" + frameDiff +
// ", timeByFrames=" + timeByFrames + ", sampleRate=" + sampleRate);
- assertEquals(1.0 /* expected */, ratio, 0.01 /* delta */);
+ assertEquals(1.0 /* expected */, ratio, isLowLatencyDevice() ? 0.01 : 0.5 /* delta */);
}
// remove if AudioTimestamp has a better toString().
diff --git a/tests/tests/security/src/android/security/cts/EncryptionTest.java b/tests/tests/security/src/android/security/cts/EncryptionTest.java
index 85d82e2..2f18866 100644
--- a/tests/tests/security/src/android/security/cts/EncryptionTest.java
+++ b/tests/tests/security/src/android/security/cts/EncryptionTest.java
@@ -22,6 +22,7 @@
import junit.framework.TestCase;
import android.app.ActivityManager;
+import android.content.pm.PackageManager;
import android.content.Context;
import android.util.Log;
import java.io.BufferedReader;
@@ -79,7 +80,7 @@
private boolean isRequired() {
// Optional before MIN_API_LEVEL or if the device has low RAM
- return PropertyUtil.getFirstApiLevel() >= MIN_API_LEVEL && !hasLowRAM();
+ return PropertyUtil.getFirstApiLevel() >= MIN_API_LEVEL && !hasLowRAM() && !isTelevision();
}
public void testConfig() throws Exception {
@@ -105,6 +106,12 @@
}
}
+ private boolean isTelevision() {
+ PackageManager pm = getContext().getPackageManager();
+ return pm.hasSystemFeature(PackageManager.FEATURE_TELEVISION)
+ || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+ }
+
public void testEncryption() throws Exception {
if (!isRequired() || deviceIsEncrypted()) {
return;