Merge "JniTest: Fix linker_namespace test for /vendor libraries" into oc-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index fd17de2..341575b 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -992,6 +992,7 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:screenOrientation="nosensor" />
+ <!-- FeatureSummaryActivity is replaced by CTS SystemFeaturesTest
<activity android:name=".features.FeatureSummaryActivity" android:label="@string/feature_summary">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -999,6 +1000,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_features" />
</activity>
+ -->
<activity android:name=".location.GpsTestActivity"
android:label="@string/location_gps_test"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index ffe29d2..8c779c5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -118,11 +118,16 @@
ICaseResult caseResult = moduleResult.getOrCreateResult(TEST_CASE_NAME);
int count = mAdapter.getCount();
+ int notExecutedCount = 0;
for (int i = 0; i < count; i++) {
TestListItem item = mAdapter.getItem(i);
if (item.isTest()) {
ITestResult currentTestResult = caseResult.getOrCreateResult(item.testName);
- currentTestResult.setResultStatus(getTestResultStatus(mAdapter.getTestResult(i)));
+ TestStatus resultStatus = getTestResultStatus(mAdapter.getTestResult(i));
+ if (resultStatus == null) {
+ ++notExecutedCount;
+ }
+ currentTestResult.setResultStatus(resultStatus);
// TODO: report test details with Extended Device Info (EDI) or CTS metrics
// String details = mAdapter.getTestDetails(i);
@@ -133,6 +138,7 @@
}
}
moduleResult.setDone(true);
+ moduleResult.setNotExecuted(notExecutedCount);
return result;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index d1977d8..395eac0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -246,6 +246,22 @@
new Feature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, false),
new Feature(PackageManager.FEATURE_PICTURE_IN_PICTURE, false),
new Feature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT, false),
+ // FEATURE_FILE_BASED_ENCRYPTION is hide
+ new Feature("android.software.file_based_encryption", false),
+ };
+
+ public static final Feature[] ALL_O_FEATURES = {
+ new Feature(PackageManager.FEATURE_VULKAN_HARDWARE_COMPUTE, false),
+ // FEATURE_TELEPHONY_CARRIERLOCK is SystemApi
+ new Feature("android.hardware.telephony.carrierlock", false),
+ new Feature(PackageManager.FEATURE_WIFI_AWARE, false),
+ new Feature(PackageManager.FEATURE_EMBEDDED, false),
+ new Feature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP, false),
+ new Feature(PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS, false),
+ new Feature(PackageManager.FEATURE_VR_HEADTRACKING, false),
+ // FEATURE_CTS is hide
+ new Feature("android.software.cts", false),
+ new Feature(PackageManager.FEATURE_WIFI_AWARE, false),
};
@Override
@@ -279,6 +295,9 @@
// add features from latest to last so that the latest requirements are put in the set first
int apiVersion = Build.VERSION.SDK_INT;
+ if (apiVersion >= Build.VERSION_CODES.O) {
+ Collections.addAll(features, ALL_O_FEATURES);
+ }
if (apiVersion >= Build.VERSION_CODES.N) {
Collections.addAll(features, ALL_NYC_FEATURES);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
index eecf9a7..f231b01 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/UserRestrictions.java
@@ -110,7 +110,7 @@
Settings.ACTION_DEVICE_INFO_SETTINGS,
Settings.ACTION_PRIVACY_SETTINGS,
Settings.ACTION_DEVICE_INFO_SETTINGS,
- Settings.ACTION_MANAGE_EXTERNAL_SOURCES,
+ Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Settings.ACTION_SYNC_SETTINGS,
Settings.ACTION_WIRELESS_SETTINGS,
Settings.ACTION_WIRELESS_SETTINGS,
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index 09fed81..970e35f 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -18,7 +18,7 @@
import com.android.compatibility.SuiteInfo;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
-import com.android.compatibility.common.tradefed.result.SubPlanCreator;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
@@ -404,7 +404,7 @@
}
private void addSubPlan(String[] flatArgs) {
- SubPlanCreator creator = new SubPlanCreator();
+ SubPlanHelper creator = new SubPlanHelper();
try {
ArgsOptionParser optionParser = new ArgsOptionParser(creator);
optionParser.parse(Arrays.asList(flatArgs));
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 6887d48..4df29c6 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
@@ -17,7 +17,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
-import com.android.compatibility.common.tradefed.testtype.CompatibilityTest.RetryType;
+import com.android.compatibility.common.tradefed.util.RetryType;
import com.android.compatibility.common.util.ICaseResult;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.IModuleResult;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
similarity index 89%
rename from common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
rename to common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
index 9dbbcbb..950a129 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanHelper.java
@@ -33,11 +33,15 @@
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
+import com.android.tradefed.util.StreamUtil;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
@@ -50,7 +54,9 @@
/**
* Class for creating subplans from compatibility result XML.
*/
-public class SubPlanCreator {
+public class SubPlanHelper {
+
+ private static final String XML_EXT = ".xml";
// result types
public static final String PASSED = "passed";
@@ -108,22 +114,45 @@
IInvocationResult mResult = null;
/**
- * Create an empty {@link SubPlanCreator}.
+ * Create an empty {@link SubPlanHelper}.
* <p/>
* All {@link Option} fields must be populated via
* {@link com.android.tradefed.config.ArgsOptionParser}
*/
- public SubPlanCreator() {}
+ public SubPlanHelper() {}
/**
- * Create a {@link SubPlanCreator} using the specified option values.
+ * Create a {@link SubPlanHelper} using the specified option values.
*/
- public SubPlanCreator(String name, int session, Collection<String> resultTypes) {
+ public SubPlanHelper(String name, int session, Collection<String> resultTypes) {
mSubPlanName = name;
mSessionId = session;
mResultTypes.addAll(resultTypes);
}
+ public static ISubPlan getSubPlanByName(CompatibilityBuildHelper buildHelper, String name) {
+ if (!name.endsWith(XML_EXT)) {
+ name = name + XML_EXT; // only append XML extension to name if not already there
+ }
+ InputStream subPlanInputStream = null;
+ try {
+ File subPlanFile = new File(buildHelper.getSubPlansDir(), name);
+ if (!subPlanFile.exists()) {
+ throw new IllegalArgumentException(
+ String.format("Could not retrieve subplan \"%s\"", name));
+ }
+ subPlanInputStream = new FileInputStream(subPlanFile);
+ ISubPlan subPlan = new SubPlan();
+ subPlan.parse(subPlanInputStream);
+ return subPlan;
+ } catch (FileNotFoundException | ParseException e) {
+ throw new RuntimeException(
+ String.format("Unable to find or parse subplan %s", name), e);
+ } finally {
+ StreamUtil.closeStream(subPlanInputStream);
+ }
+ }
+
/**
* Set the result from which to derive the subplan.
* @param result
@@ -333,7 +362,7 @@
mSubPlanName = createPlanName();
}
try {
- mSubPlanFile = new File(buildHelper.getSubPlansDir(), mSubPlanName + ".xml");
+ mSubPlanFile = new File(buildHelper.getSubPlansDir(), mSubPlanName + XML_EXT);
if (mSubPlanFile.exists()) {
throw new ConfigurationException(String.format("Subplan %s already exists",
mSubPlanName));
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 30d5f95..9f07307 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -19,15 +19,16 @@
import com.android.compatibility.SuiteInfo;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
-import com.android.compatibility.common.tradefed.result.SubPlanCreator;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
import com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker;
import com.android.compatibility.common.tradefed.util.OptionHelper;
+import com.android.compatibility.common.tradefed.util.RetryFilterHelper;
+import com.android.compatibility.common.tradefed.util.RetryType;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.TestFilter;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.config.ArgsOptionParser;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
@@ -153,10 +154,6 @@
importance = Importance.ALWAYS)
private List<String> mTestArgs = new ArrayList<>();
- public enum RetryType {
- FAILED, NOT_EXECUTED;
- }
-
@Option(name = RETRY_OPTION,
shortName = 'r',
description = "retry a previous session's failed and not executed tests.",
@@ -671,113 +668,45 @@
*/
void setupFilters() throws DeviceNotAvailableException {
if (mRetrySessionId != null) {
- // Track --module/-m and --test/-t options to ensure we don't overwrite non-null
- // values on retry
- String newModuleName = mModuleName;
- String newTestName = mTestName;
-
- // Load the invocation result
- IInvocationResult result = null;
- try {
- result = ResultHandler.findResult(mBuildHelper.getResultsDir(), mRetrySessionId);
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
- }
- if (result == null) {
- throw new IllegalArgumentException(String.format(
- "Could not find session with id %d", mRetrySessionId));
- }
-
- String oldBuildFingerprint = result.getBuildFingerprint();
- String currentBuildFingerprint = mDevice.getProperty("ro.build.fingerprint");
- if (oldBuildFingerprint.equals(currentBuildFingerprint)) {
- CLog.logAndDisplay(LogLevel.INFO, "Retrying session from: %s",
- CompatibilityBuildHelper.getDirSuffix(result.getStartTime()));
- } else {
- throw new IllegalArgumentException(String.format(
- "Device build fingerprint must match %s to retry session %d",
- oldBuildFingerprint, mRetrySessionId));
- }
-
- String retryCommandLineArgs = result.getCommandLineArgs();
- if (retryCommandLineArgs != null) {
- try {
- // parse the command-line string from the result file and set options
- ArgsOptionParser parser = new ArgsOptionParser(this);
- parser.parse(OptionHelper.getValidCliArgs(retryCommandLineArgs, this));
- } catch (ConfigurationException e) {
- throw new RuntimeException(e);
- }
- }
-
- if ((mModuleName != null && mModuleName != newModuleName)
- || (mTestName != null && mTestName != newTestName)) {
- // These options cannot be changed on retry if non-null for the previous session
- CLog.w("Cannot override non-null value(s) from session %d for option(s) \"%s\""
- + " or \"%s\" on retry", mRetrySessionId, MODULE_OPTION, TEST_OPTION);
- }
-
- SubPlanCreator retryPlanCreator = new SubPlanCreator();
- retryPlanCreator.setResult(result);
- if (RetryType.FAILED.equals(mRetryType)) {
- // retry only failed tests
- retryPlanCreator.addResultType(SubPlanCreator.FAILED);
- } else if (RetryType.NOT_EXECUTED.equals(mRetryType)){
- // retry only not executed tests
- retryPlanCreator.addResultType(SubPlanCreator.NOT_EXECUTED);
- } else {
- // retry both failed and not executed tests
- retryPlanCreator.addResultType(SubPlanCreator.FAILED);
- retryPlanCreator.addResultType(SubPlanCreator.NOT_EXECUTED);
- }
- try {
- ISubPlan retryPlan = retryPlanCreator.createSubPlan(mBuildHelper);
- mIncludeFilters.addAll(retryPlan.getIncludeFilters());
- mExcludeFilters.addAll(retryPlan.getExcludeFilters());
- } catch (ConfigurationException e) {
- throw new RuntimeException ("Failed to create subplan for retry", e);
- }
- }
- if (mSubPlan != null) {
- try {
- File subPlanFile = new File(mBuildHelper.getSubPlansDir(), mSubPlan + ".xml");
- if (!subPlanFile.exists()) {
- throw new IllegalArgumentException(
- String.format("Could not retrieve subplan \"%s\"", mSubPlan));
- }
- InputStream subPlanInputStream = new FileInputStream(subPlanFile);
- ISubPlan subPlan = new SubPlan();
- subPlan.parse(subPlanInputStream);
+ RetryFilterHelper helper = new RetryFilterHelper(mBuildHelper, mRetrySessionId);
+ helper.validateBuildFingerprint(mDevice);
+ helper.setAllOptionsFrom(this);
+ helper.setCommandLineOptionsFor(this);
+ helper.populateRetryFilters();
+ mIncludeFilters = helper.getIncludeFilters();
+ mExcludeFilters = helper.getExcludeFilters();
+ helper.tearDown();
+ } else {
+ if (mSubPlan != null) {
+ ISubPlan subPlan = SubPlanHelper.getSubPlanByName(mBuildHelper, mSubPlan);
mIncludeFilters.addAll(subPlan.getIncludeFilters());
mExcludeFilters.addAll(subPlan.getExcludeFilters());
- } catch (FileNotFoundException | ParseException e) {
- throw new RuntimeException(
- String.format("Unable to find or parse subplan %s", mSubPlan), e);
}
- }
- if (mModuleName != null) {
- try {
- List<String> modules = ModuleRepo.getModuleNamesMatching(
- mBuildHelper.getTestsDir(), mModuleName);
- if (modules.size() == 0) {
- throw new IllegalArgumentException(
- String.format("No modules found matching %s", mModuleName));
- } else if (modules.size() > 1) {
- throw new IllegalArgumentException(String.format(
- "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
- mModuleName, ArrayUtil.join("\n", modules)));
- } else {
- String module = modules.get(0);
- cleanFilters(mIncludeFilters, module);
- cleanFilters(mExcludeFilters, module);
- mIncludeFilters.add(new TestFilter(mAbiName, module, mTestName).toString());
+ if (mModuleName != null) {
+ try {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuildHelper.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format("Multiple modules found"
+ + " matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String module = modules.get(0);
+ cleanFilters(mIncludeFilters, module);
+ cleanFilters(mExcludeFilters, module);
+ mIncludeFilters.add(
+ new TestFilter(mAbiName, module, mTestName).toString());
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
}
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
+ } else if (mTestName != null) {
+ throw new IllegalArgumentException(
+ "Test name given without module name. Add --module <module-name>");
}
- } else if (mTestName != null) {
- throw new IllegalArgumentException(
- "Test name given without module name. Add --module <module-name>");
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
new file mode 100644
index 0000000..9a68089
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
@@ -0,0 +1,322 @@
+/*
+ * 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.compatibility.common.tradefed.util;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.SubPlanHelper;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
+import com.android.compatibility.common.tradefed.testtype.ISubPlan;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.LightInvocationResult;
+import com.android.compatibility.common.util.ResultHandler;
+import com.android.compatibility.common.util.TestFilter;
+import com.android.tradefed.config.ArgsOptionParser;
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.Option.Importance;
+import com.android.tradefed.config.OptionCopier;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.ArrayUtil;
+
+import java.io.FileNotFoundException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper for generating --include-filter and --exclude-filter values on compatibility retry.
+ */
+public class RetryFilterHelper {
+
+ @Option(name = CompatibilityTest.SUBPLAN_OPTION,
+ description = "the subplan to run",
+ importance = Importance.IF_UNSET)
+ protected String mSubPlan;
+
+ @Option(name = CompatibilityTest.INCLUDE_FILTER_OPTION,
+ description = "the include module filters to apply.",
+ importance = Importance.ALWAYS)
+ protected Set<String> mIncludeFilters = new HashSet<>();
+
+ @Option(name = CompatibilityTest.EXCLUDE_FILTER_OPTION,
+ description = "the exclude module filters to apply.",
+ importance = Importance.ALWAYS)
+ protected Set<String> mExcludeFilters = new HashSet<>();
+
+ @Option(name = CompatibilityTest.ABI_OPTION,
+ shortName = 'a',
+ description = "the abi to test.",
+ importance = Importance.IF_UNSET)
+ protected String mAbiName = null;
+
+ @Option(name = CompatibilityTest.MODULE_OPTION,
+ shortName = 'm',
+ description = "the test module to run.",
+ importance = Importance.IF_UNSET)
+ protected String mModuleName = null;
+
+ @Option(name = CompatibilityTest.TEST_OPTION,
+ shortName = CompatibilityTest.TEST_OPTION_SHORT_NAME,
+ description = "the test run.",
+ importance = Importance.IF_UNSET)
+ protected String mTestName = null;
+
+ @Option(name = CompatibilityTest.RETRY_TYPE_OPTION,
+ description = "used with " + CompatibilityTest.RETRY_OPTION + ", retry tests"
+ + " of a certain status. Possible values include \"failed\" and \"not_executed\".",
+ importance = Importance.IF_UNSET)
+ protected RetryType mRetryType = null;
+
+ /* Instance variables handy for retreiving the result to be retried */
+ private CompatibilityBuildHelper mBuild = null;
+ private int mSessionId;
+
+ /* Sets to be populated by retry logic and returned by getter methods */
+ private Set<String> mRetryIncludes;
+ private Set<String> mRetryExcludes;
+
+ /**
+ * Constructor for a {@link RetryFilterHelper}. Requires a CompatibilityBuildHelper for
+ * retrieving previous sessions and the ID of the session to retry.
+ */
+ public RetryFilterHelper(CompatibilityBuildHelper build, int sessionId) {
+ mBuild = build;
+ mSessionId = sessionId;
+ }
+
+ /**
+ * Throws an {@link IllegalArgumentException} if the device build fingerprint doesn't match
+ * the fingerprint recorded in the previous session's result.
+ */
+ public void validateBuildFingerprint(ITestDevice device) throws DeviceNotAvailableException {
+ String oldBuildFingerprint = new LightInvocationResult(getResult()).getBuildFingerprint();
+ String currentBuildFingerprint = device.getProperty("ro.build.fingerprint");
+ if (!oldBuildFingerprint.equals(currentBuildFingerprint)) {
+ throw new IllegalArgumentException(String.format(
+ "Device build fingerprint must match %s to retry session %d",
+ oldBuildFingerprint, mSessionId));
+ }
+ }
+
+ /**
+ * Copy all applicable options from an input object to this instance of RetryFilterHelper.
+ */
+ public void setAllOptionsFrom(Object obj) {
+ clearOptions(); // Remove existing options first
+ OptionCopier.copyOptionsNoThrow(obj, this);
+ }
+
+ /**
+ * Set a single option on this instance of RetryFilterHelper
+ * @throws {@link ConfigurationException} if the option cannot be set.
+ */
+ public void setOption(String option, String value) throws ConfigurationException {
+ OptionSetter setter = new OptionSetter(this);
+ setter.setOptionValue(option, value);
+ }
+
+ /**
+ * Clear all option values of this RetryFilterHelper.
+ */
+ public void clearOptions() {
+ mSubPlan = null;
+ mIncludeFilters = new HashSet<>();
+ mExcludeFilters = new HashSet<>();
+ mModuleName = null;
+ mTestName = null;
+ mRetryType = null;
+ mAbiName = null;
+ }
+
+ /**
+ * Using command-line arguments from the previous session's result, set the input object's
+ * option values to the values applied in the previous session.
+ */
+ public void setCommandLineOptionsFor(Object obj) {
+ // only need light version to retrieve command-line args
+ IInvocationResult result = new LightInvocationResult(getResult());
+ String retryCommandLineArgs = result.getCommandLineArgs();
+ if (retryCommandLineArgs != null) {
+ try {
+ // parse the command-line string from the result file and set options
+ ArgsOptionParser parser = new ArgsOptionParser(obj);
+ parser.parse(OptionHelper.getValidCliArgs(retryCommandLineArgs, obj));
+ } catch (ConfigurationException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ /**
+ * Retrieve an instance of the result to retry using the instance variables referencing
+ * the build and the desired session ID. While it is faster to load this result once and
+ * store it as an instance variable, {@link IInvocationResult} objects are large, and
+ * memory is of greater concern.
+ */
+ public IInvocationResult getResult() {
+ IInvocationResult result = null;
+ try {
+ result = ResultHandler.findResult(mBuild.getResultsDir(), mSessionId);
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ if (result == null) {
+ throw new IllegalArgumentException(String.format(
+ "Could not find session with id %d", mSessionId));
+ }
+ return result;
+ }
+
+ /**
+ * Populate mRetryIncludes and mRetryExcludes based on the options and the result set for
+ * this instance of RetryFilterHelper.
+ */
+ public void populateRetryFilters() {
+ mRetryIncludes = new HashSet<>(mIncludeFilters); // reset for each population
+ mRetryExcludes = new HashSet<>(mExcludeFilters); // reset for each population
+ if (RetryType.CUSTOM.equals(mRetryType)) {
+ Set<String> customIncludes = new HashSet<>(mIncludeFilters);
+ Set<String> customExcludes = new HashSet<>(mExcludeFilters);
+ if (mSubPlan != null) {
+ ISubPlan retrySubPlan = SubPlanHelper.getSubPlanByName(mBuild, mSubPlan);
+ customIncludes.addAll(retrySubPlan.getIncludeFilters());
+ customExcludes.addAll(retrySubPlan.getExcludeFilters());
+ }
+ // If includes were added, only use those includes. Also use excludes added directly
+ // or by subplan. Otherwise, default to normal retry.
+ if (!customIncludes.isEmpty()) {
+ mRetryIncludes.clear();
+ mRetryIncludes.addAll(customIncludes);
+ mRetryExcludes.addAll(customExcludes);
+ return;
+ }
+ }
+ // remove any extra filtering options
+ // TODO(aaronholden) remove non-plan includes (e.g. those in cts-vendor-interface)
+ // TODO(aaronholden) remove non-known-failure excludes
+ mModuleName = null;
+ mTestName = null;
+ mSubPlan = null;
+ populateFiltersBySubPlan();
+ populatePreviousSessionFilters();
+ }
+
+ /* Generation of filters based on previous sessions is implemented thoroughly in SubPlanHelper,
+ * and retry filter generation is just a subset of the use cases for the subplan retry logic.
+ * Use retry type to determine which result types SubPlanHelper targets. */
+ private void populateFiltersBySubPlan() {
+ SubPlanHelper retryPlanCreator = new SubPlanHelper();
+ retryPlanCreator.setResult(getResult());
+ if (RetryType.FAILED.equals(mRetryType)) {
+ // retry only failed tests
+ retryPlanCreator.addResultType(SubPlanHelper.FAILED);
+ } else if (RetryType.NOT_EXECUTED.equals(mRetryType)){
+ // retry only not executed tests
+ retryPlanCreator.addResultType(SubPlanHelper.NOT_EXECUTED);
+ } else {
+ // retry both failed and not executed tests
+ retryPlanCreator.addResultType(SubPlanHelper.FAILED);
+ retryPlanCreator.addResultType(SubPlanHelper.NOT_EXECUTED);
+ }
+ try {
+ ISubPlan retryPlan = retryPlanCreator.createSubPlan(mBuild);
+ mRetryIncludes.addAll(retryPlan.getIncludeFilters());
+ mRetryExcludes.addAll(retryPlan.getExcludeFilters());
+ } catch (ConfigurationException e) {
+ throw new RuntimeException ("Failed to create subplan for retry", e);
+ }
+ }
+
+ /* Retrieves the options set via command-line on the previous session, and generates/adds
+ * filters accordingly */
+ private void populatePreviousSessionFilters() {
+ // Temporarily store options from this instance in another instance
+ RetryFilterHelper tmpHelper = new RetryFilterHelper(mBuild, mSessionId);
+ tmpHelper.setAllOptionsFrom(this);
+ // Copy command-line args from previous session to this RetryFilterHelper's options
+ setCommandLineOptionsFor(this);
+
+ mRetryIncludes.addAll(mIncludeFilters);
+ mRetryExcludes.addAll(mExcludeFilters);
+ if (mSubPlan != null) {
+ ISubPlan retrySubPlan = SubPlanHelper.getSubPlanByName(mBuild, mSubPlan);
+ mRetryIncludes.addAll(retrySubPlan.getIncludeFilters());
+ mRetryExcludes.addAll(retrySubPlan.getExcludeFilters());
+ }
+ if (mModuleName != null) {
+ try {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuild.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format(
+ "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String module = modules.get(0);
+ cleanFilters(mRetryIncludes, module);
+ cleanFilters(mRetryExcludes, module);
+ mRetryIncludes.add(new TestFilter(mAbiName, module, mTestName).toString());
+ }
+ } catch (FileNotFoundException e) {
+ throw new RuntimeException(e);
+ }
+ } else if (mTestName != null) {
+ throw new IllegalArgumentException(
+ "Test name given without module name. Add --module <module-name>");
+ }
+
+ // Copy options for current session back to this instance
+ setAllOptionsFrom(tmpHelper);
+ }
+
+ /* Helper method designed to remove filters in a list not applicable to the given module */
+ private static void cleanFilters(Set<String> filters, String module) {
+ Set<String> cleanedFilters = new HashSet<String>();
+ for (String filter : filters) {
+ if (module.equals(TestFilter.createFrom(filter).getName())) {
+ cleanedFilters.add(filter); // Module name matches, filter passes
+ }
+ }
+ filters.clear();
+ filters.addAll(cleanedFilters);
+ }
+
+ /** Retrieve include filters to be applied on retry */
+ public Set<String> getIncludeFilters() {
+ return new HashSet<>(mRetryIncludes);
+ }
+
+ /** Retrieve exclude filters to be applied on retry */
+ public Set<String> getExcludeFilters() {
+ return new HashSet<>(mRetryExcludes);
+ }
+
+ /** Clears retry filters and internal storage of options, except buildInfo and session ID */
+ public void tearDown() {
+ clearOptions();
+ mRetryIncludes = null;
+ mRetryExcludes = null;
+ // keep references to buildInfo and session ID
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java
new file mode 100644
index 0000000..b5d3cd5
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryType.java
@@ -0,0 +1,26 @@
+/*
+ * 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.compatibility.common.tradefed.util;
+
+/**
+ * Enum for --retry-type option value in compatibility testing.
+ */
+public enum RetryType {
+ FAILED,
+ NOT_EXECUTED,
+ CUSTOM;
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index bb96ed2..b6861db 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -25,7 +25,7 @@
import com.android.compatibility.common.tradefed.result.ConsoleReporterTest;
import com.android.compatibility.common.tradefed.result.MetadataReporterTest;
import com.android.compatibility.common.tradefed.result.ResultReporterTest;
-import com.android.compatibility.common.tradefed.result.SubPlanCreatorTest;
+import com.android.compatibility.common.tradefed.result.SubPlanHelperTest;
import com.android.compatibility.common.tradefed.targetprep.PropertyCheckTest;
import com.android.compatibility.common.tradefed.targetprep.SettingsPreparerTest;
import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBaseTest;
@@ -36,6 +36,7 @@
import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
import com.android.compatibility.common.tradefed.util.OptionHelperTest;
+import com.android.compatibility.common.tradefed.util.RetryFilterHelperTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -67,7 +68,7 @@
ConsoleReporterTest.class,
MetadataReporterTest.class,
ResultReporterTest.class,
- SubPlanCreatorTest.class,
+ SubPlanHelperTest.class,
// targetprep
PropertyCheckTest.class,
@@ -84,6 +85,7 @@
// util
CollectorUtilTest.class,
OptionHelperTest.class,
+ RetryFilterHelperTest.class,
})
public class UnitTests {
// empty on purpose
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
similarity index 96%
rename from common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
rename to common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
index e3240c1..a19eb30 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanHelperTest.java
@@ -39,7 +39,7 @@
import java.util.Arrays;
import java.util.Set;
-public class SubPlanCreatorTest extends TestCase {
+public class SubPlanHelperTest extends TestCase {
// Values used to populate mock results
private static final String SUITE_NAME = "CTS";
@@ -75,7 +75,7 @@
private static final String SP_RESULT_TYPE_NOT_EXECUTED = "not_executed";
private CompatibilityBuildHelper mBuildHelper;
- private SubPlanCreator mSubPlanCreator;
+ private SubPlanHelper mSubPlanHelper;
private File mResultsDir = null;
private File mResultDir = null;
@@ -89,8 +89,8 @@
mBuildHelper = new SpctMockCompatibilityBuildHelper(new BuildInfo("0", "", ""));
populateResults();
- mSubPlanCreator = new SubPlanCreator();
- ArgsOptionParser optionParser = new ArgsOptionParser(mSubPlanCreator);
+ mSubPlanHelper = new SubPlanHelper();
+ ArgsOptionParser optionParser = new ArgsOptionParser(mSubPlanHelper);
optionParser.parse(Arrays.asList(
"-n", SP_NAME,
"--session", SP_SESSION,
@@ -109,7 +109,7 @@
}
public void testCreateSubPlan() throws Exception {
- ISubPlan plan = mSubPlanCreator.createSubPlan(mBuildHelper);
+ ISubPlan plan = mSubPlanHelper.createSubPlan(mBuildHelper);
Set<String> planIncludes = plan.getIncludeFilters();
Set<String> planExcludes = plan.getExcludeFilters();
TestFilter mf1 = new TestFilter(ABI, NAME_A, null);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java
new file mode 100644
index 0000000..05d35ec
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/RetryFilterHelperTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.compatibility.common.tradefed.util;
+
+import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
+import com.android.tradefed.config.OptionSetter;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link RetryFilterHelper}
+ */
+public class RetryFilterHelperTest extends TestCase {
+
+ private static final String TEST_STRING = "abcd";
+ private static final RetryType TEST_RETRY_TYPE = RetryType.FAILED;
+
+ public void testSetAllOptionsFrom() throws Exception {
+ RetryFilterHelper helper = new RetryFilterHelper(null, 0);
+ RetryFilterHelper otherObj = new RetryFilterHelper(null, 0);
+ OptionSetter otherObjSetter = new OptionSetter(otherObj);
+ otherObjSetter.setOptionValue(CompatibilityTest.SUBPLAN_OPTION, TEST_STRING);
+ helper.setAllOptionsFrom(otherObj);
+ assertEquals(TEST_STRING, helper.mSubPlan);
+ }
+
+ public void testClearOptions() throws Exception {
+ RetryFilterHelper helper = new RetryFilterHelper(null, 0);
+ OptionSetter setter = new OptionSetter(helper);
+ setter.setOptionValue(CompatibilityTest.SUBPLAN_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.INCLUDE_FILTER_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.EXCLUDE_FILTER_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.ABI_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.MODULE_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.TEST_OPTION, TEST_STRING);
+ setter.setOptionValue(CompatibilityTest.TEST_OPTION, TEST_RETRY_TYPE.name());
+ helper.clearOptions();
+ assertTrue(helper.mSubPlan == null);
+ assertTrue(helper.mIncludeFilters.isEmpty());
+ assertTrue(helper.mExcludeFilters.isEmpty());
+ assertTrue(helper.mAbiName == null);
+ assertTrue(helper.mModuleName == null);
+ assertTrue(helper.mTestName == null);
+ assertTrue(helper.mRetryType == null);
+ }
+
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
index d033785..a773737 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAdminServiceProfileOwnerTest.java
@@ -27,7 +27,9 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- mUserId = createUser();
+ if (isTestEnabled()) {
+ mUserId = createUser();
+ }
}
@Override
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
index 29f1ef2..cd39ff2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -876,7 +876,7 @@
* Test that virtual display content is hidden when device is locked.
*/
public void testVirtualDisplayHidesContentWhenLocked() throws Exception {
- if (!supportsMultiDisplay()) { return; }
+ if (!supportsMultiDisplay() || !isHandheld()) { return; }
// Create new usual virtual display.
final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
@@ -1257,7 +1257,7 @@
mAmWmState.waitForValidState(mDevice, new String[] {TEST_ACTIVITY_NAME},
null /* stackIds */, false /* compareTaskAndStackBounds */, componentName);
- // Check that the second activity is launched onto the fullscren stack
+ // Check that the second activity is launched onto the fullscreen stack
final ActivityManagerState.ActivityStack fullscreenStack =
mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID);
assertEquals("Activity launched on default display must be resumed",
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
index a137784..5454e2f 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_clamp_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
index d5288d1..ea6441a 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_1_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
index 237c86e..06eccb8 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_golden.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
index 0a4b40f..64a6476 100644
--- a/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
+++ b/tests/tests/graphics/res/drawable-nodpi/vector_icon_gradient_3_mirror_golden.png
Binary files differ
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 8bfd79b..f01b833 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -56,6 +56,7 @@
import android.os.SystemProperties;
import android.security.KeyStoreException;
import android.security.keystore.AttestationUtils;
+import android.security.keystore.DeviceIdAttestationException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.test.AndroidTestCase;
@@ -357,9 +358,9 @@
}
public void testDeviceIdAttestation() throws Exception {
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL);
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI);
- testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID);
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_SERIAL, null);
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_IMEI, "Unable to retrieve IMEI");
+ testDeviceIdAttestationFailure(AttestationUtils.ID_TYPE_MEID, "Unable to retrieve MEID");
}
@SuppressWarnings("deprecation")
@@ -855,13 +856,23 @@
}
}
- private void testDeviceIdAttestationFailure(int idType) throws Exception {
+ private void testDeviceIdAttestationFailure(int idType,
+ String acceptableDeviceIdAttestationFailureMessage) throws Exception {
try {
AttestationUtils.attestDeviceIds(getContext(), new int[] {idType}, "123".getBytes());
fail("Attestation should have failed.");
} catch (SecurityException e) {
- // Attestation is expected to fail with a SecurityException as we do not hold
+ // Attestation is expected to fail. If the device has the device ID type we are trying
+ // to attest, it should fail with a SecurityException as we do not hold
// READ_PRIVILEGED_PHONE_STATE permission.
+ } catch (DeviceIdAttestationException e) {
+ // Attestation is expected to fail. If the device does not have the device ID type we
+ // are trying to attest (e.g. no IMEI on devices without a radio), it should fail with
+ // a corresponding DeviceIdAttestationException.
+ if (acceptableDeviceIdAttestationFailureMessage == null ||
+ !acceptableDeviceIdAttestationFailureMessage.equals(e.getMessage())) {
+ throw e;
+ }
}
}
}
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
index efe8bb4..61edbba 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordingConfigurationTest.java
@@ -36,12 +36,13 @@
import java.util.List;
public class AudioRecordingConfigurationTest extends CtsAndroidTestCase {
- private final static String TAG = "AudioRecordingConfigurationTest";
+ private static final String TAG = "AudioRecordingConfigurationTest";
- private final static int TEST_SAMPLE_RATE = 16000;
- private final static int TEST_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
+ private static final int TEST_SAMPLE_RATE = 16000;
+ private static final int TEST_AUDIO_SOURCE = MediaRecorder.AudioSource.VOICE_RECOGNITION;
- private final static int TEST_TIMING_TOLERANCE_MS = 70;
+ private static final int TEST_TIMING_TOLERANCE_MS = 70;
+ private static final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
private AudioRecord mAudioRecord;
private Looper mLooper;
@@ -93,6 +94,7 @@
mAudioRecord.stop();
mAudioRecord.release();
mLooper.quit();
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
}
super.tearDown();
}
@@ -127,10 +129,10 @@
// stopping recording: verify there are less active record configurations
mAudioRecord.stop();
- Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
configs = am.getActiveRecordingConfigurations();
- assertTrue("end of recording not reported in record configs",
- configs.size() < nbConfigsDuringRecording);
+ assertEquals("Unexpected number of recording configs after stop",
+ configs.size(), 0);
}
public void testCallback() throws Exception {
@@ -169,15 +171,23 @@
assertEquals(AudioRecord.RECORDSTATE_RECORDING, mAudioRecord.getRecordingState());
Thread.sleep(TEST_TIMING_TOLERANCE_MS);
- assertTrue("AudioRecordingCallback not called", callback.mCalled);
- assertTrue("Expected record configuration was not found", callback.mParamMatch);
+ assertTrue("AudioRecordingCallback not called after start", callback.mCalled);
+ Thread.sleep(TEST_TIMING_TOLERANCE_MS);
+
+ final AudioDeviceInfo testDevice = mAudioRecord.getRoutedDevice();
+ assertTrue("AudioRecord null routed device after start", testDevice != null);
+ final boolean match = verifyAudioConfig(mAudioRecord.getAudioSource(),
+ mAudioRecord.getAudioSessionId(), mAudioRecord.getFormat(),
+ testDevice, callback.mConfigs);
+ assertTrue("Expected record configuration was not found", match);
// stopping recording: callback is called with no match
callback.reset();
mAudioRecord.stop();
- Thread.sleep(TEST_TIMING_TOLERANCE_MS);
- assertTrue("AudioRecordingCallback not called", callback.mCalled);
- assertFalse("Should not have found test record configuration", callback.mParamMatch);
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
+ assertTrue("AudioRecordingCallback not called after stop", callback.mCalled);
+ assertEquals("Should not have found record configurations", callback.mConfigs.size(),
+ 0);
// unregister callback and start recording again
am.unregisterAudioRecordingCallback(callback);
@@ -231,14 +241,14 @@
class MyAudioRecordingCallback extends AudioManager.AudioRecordingCallback {
boolean mCalled = false;
- boolean mParamMatch = false;
+ List<AudioRecordingConfiguration> mConfigs;
final AudioManager mAM;
final int mTestSource;
final int mTestSession;
void reset() {
mCalled = false;
- mParamMatch = false;
+ mConfigs = null;
}
MyAudioRecordingCallback(int session, int source) {
@@ -250,8 +260,7 @@
@Override
public void onRecordingConfigChanged(List<AudioRecordingConfiguration> configs) {
mCalled = true;
- mParamMatch = verifyAudioConfig(mTestSource, mTestSession, mAudioRecord.getFormat(),
- mAudioRecord.getRoutedDevice(), configs);
+ mConfigs = configs;
}
}
@@ -266,6 +275,8 @@
final Iterator<AudioRecordingConfiguration> confIt = configs.iterator();
while (confIt.hasNext()) {
final AudioRecordingConfiguration config = confIt.next();
+ final AudioDeviceInfo configDevice = config.getAudioDevice();
+ assertTrue("Current recording config has null device", configDevice != null);
if ((config.getClientAudioSource() == source)
&& (config.getClientAudioSessionId() == session)
// test the client format matches that requested (same as the AudioRecord's)
@@ -281,7 +292,7 @@
&& ((config.getFormat().getChannelMask() != AudioFormat.CHANNEL_INVALID)
|| (config.getFormat().getChannelIndexMask() !=
AudioFormat.CHANNEL_INVALID))
- && deviceMatch(device, config.getAudioDevice())) {
+ && deviceMatch(device, configDevice)) {
return true;
}
}
diff --git a/tests/tests/media/src/android/media/cts/VolumeShaperTest.java b/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
index 8206ecb..fce8c80 100644
--- a/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
+++ b/tests/tests/media/src/android/media/cts/VolumeShaperTest.java
@@ -45,7 +45,7 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { 0.f, 0.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// Duck configurations go from 1.f down to 0.2f (not full ramp down).
@@ -54,28 +54,28 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { 1.f, 0.2f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// Ramp configurations go from 0.f up to 1.f
private static final VolumeShaper.Configuration LINEAR_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.LINEAR_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration CUBIC_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.CUBIC_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration SINE_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.SINE_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration SCURVE_RAMP =
new VolumeShaper.Configuration.Builder(VolumeShaper.Configuration.SCURVE_RAMP)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
// internal use only
@@ -85,7 +85,7 @@
.setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_VOLUME_IN_DBFS)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { -80.f, 0.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration[] ALL_STANDARD_RAMPS = {
@@ -101,7 +101,7 @@
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC_MONOTONIC)
.setCurve(new float[] { 0.f, 0.3f, 0.7f, 1.f } /* times */,
new float[] { 0.f, 0.5f, 0.5f, 1.f } /* volumes */)
- .setDurationMs((double)RAMP_TIME_MS)
+ .setDurationMillis((double)RAMP_TIME_MS)
.build();
private static final VolumeShaper.Configuration MONOTONIC_TEST_FAIL =
@@ -266,7 +266,7 @@
final VolumeShaper.Configuration config =
new VolumeShaper.Configuration.Builder()
.setCurve(ohOne, ohOne)
- .setDurationMs(-1.)
+ .setDurationMillis(-1.)
.build();
fail(TEST_NAME + " configuration builder should fail on invalid duration");
} catch (IllegalArgumentException e) {
@@ -291,7 +291,7 @@
assertEquals(TEST_NAME + " default interpolation should be cubic",
VolumeShaper.Configuration.INTERPOLATOR_TYPE_CUBIC, config.getInterpolatorType());
assertEquals(TEST_NAME + " default duration should be 1000 ms",
- 1000., config.getDurationMs());
+ 1000., config.getDurationMillis());
assertTrue(TEST_NAME + " times should be { 0.f, 1.f }",
Arrays.equals(ohOne, config.getTimes()));
assertTrue(TEST_NAME + " volumes should be { 0.f, 1.f }",
@@ -319,7 +319,7 @@
checkEqual(TEST_NAME, testRamp, ramp);
ramp = new VolumeShaper.Configuration.Builder(testRamp)
- .setDurationMs(10)
+ .setDurationMillis(10)
.build();
checkNotEqual(TEST_NAME, testRamp, ramp);
@@ -563,7 +563,7 @@
// we join several LINEAR_RAMPS together - this should effectively
// be one long LINEAR_RAMP.
volumeShaper.replace(new VolumeShaper.Configuration.Builder(LINEAR_RAMP)
- .setDurationMs((double)(duration - i))
+ .setDurationMillis((double)(duration - i))
.build(),
VolumeShaper.Operation.PLAY, true /* join */);
assertEquals(TEST_NAME + " linear ramp should continue on join",
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index 2cbc446..eb394b3 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -290,16 +290,16 @@
clearPrintSpoolerData();
Log.d(LOG_TAG, "enable animations");
- if (sWindowAnimationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sWindowAnimationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global window_animation_scale " + sWindowAnimationScaleBefore);
}
- if (sTransitionAnimationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sTransitionAnimationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global transition_animation_scale " +
sTransitionAnimationScaleBefore);
}
- if (sAnimatiorDurationScaleBefore != Float.NaN) {
+ if (!Float.isNaN(sAnimatiorDurationScaleBefore)) {
SystemUtil.runShellCommand(sInstrumentation,
"settings put global animator_duration_scale " + sAnimatiorDurationScaleBefore);
}
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index 3ed0ad4..bb4ffb6 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -17,13 +17,11 @@
package android.text.method.cts;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.reset;
@@ -221,23 +219,6 @@
assertSame(method0, method1);
}
- @Test
- public void testOnFocusChanged() {
- // lose focus
- reset(mMethod);
- assertTrue(mEditText.isFocused());
- CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_DOWN");
- assertFalse(mEditText.isFocused());
- verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
-
- // gain focus
- reset(mMethod);
- assertFalse(mEditText.isFocused());
- CtsKeyEventUtil.sendKeys(mInstrumentation, mEditText, "DPAD_UP");
- assertTrue(mEditText.isFocused());
- verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
- }
-
private void savePasswordPref() {
try {
mPasswordPrefBackUp = System.getInt(mActivity.getContentResolver(),
diff --git a/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java
new file mode 100644
index 0000000..d67fc59
--- /dev/null
+++ b/tests/tests/text/src/android/text/method/cts/TransformationMethodTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text.method.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.returnsFirstArg;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.method.TransformationMethod;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.LinearLayout.LayoutParams;
+
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test that {@link TransformationMethod} interface gets called.
+ */
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class TransformationMethodTest {
+ private static final int EDIT_TXT_ID = 1;
+
+ private Instrumentation mInstrumentation;
+ private CtsActivity mActivity;
+ private TransformationMethod mMethod;
+ private EditText mEditText;
+ private Button mButton;
+
+ @Rule
+ public ActivityTestRule<CtsActivity> mActivityRule = new ActivityTestRule<>(CtsActivity.class);
+
+ @Before
+ public void setup() throws Throwable {
+ mActivity = mActivityRule.getActivity();
+ PollingCheck.waitFor(1000, mActivity::hasWindowFocus);
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mMethod = mock(TransformationMethod.class);
+ when(mMethod.getTransformation(any(), any())).then(returnsFirstArg());
+
+ mActivityRule.runOnUiThread(() -> {
+ mEditText = new EditTextNoIme(mActivity);
+ mEditText.setId(EDIT_TXT_ID);
+ mEditText.setTransformationMethod(mMethod);
+ mButton = new Button(mActivity);
+ mButton.setFocusableInTouchMode(true);
+ LinearLayout layout = new LinearLayout(mActivity);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(mEditText, new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ layout.addView(mButton, new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ mActivity.setContentView(layout);
+ mEditText.requestFocus();
+ });
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mEditText.isFocused());
+ }
+
+ @Test
+ public void testGetTransformation() throws Throwable {
+ reset(mMethod);
+ when(mMethod.getTransformation(any(), any())).then(returnsFirstArg());
+ mActivityRule.runOnUiThread(() -> mEditText.setText("some text"));
+ mInstrumentation.waitForIdleSync();
+ verify(mMethod, atLeastOnce()).getTransformation(any(), any());
+ }
+
+ @Test
+ public void testOnFocusChanged() throws Throwable {
+ // lose focus
+ reset(mMethod);
+ assertTrue(mEditText.isFocused());
+ mActivityRule.runOnUiThread(() -> mButton.requestFocus());
+ mInstrumentation.waitForIdleSync();
+ verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
+
+ // gain focus
+ reset(mMethod);
+ assertFalse(mEditText.isFocused());
+ mActivityRule.runOnUiThread(() -> mEditText.requestFocus());
+ mInstrumentation.waitForIdleSync();
+ assertTrue(mEditText.isFocused());
+ verify(mMethod, atLeastOnce()).onFocusChanged(any(), any(), anyBoolean(), anyInt(), any());
+ }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index 0a14361..4b55057 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -17,19 +17,24 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import android.animation.Animator;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.transition.ChangeBounds;
import android.transition.Transition;
+import android.transition.TransitionValues;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.LinearInterpolator;
import org.junit.Before;
import org.junit.Test;
@@ -43,19 +48,22 @@
private static final int SMALL_OFFSET_DP = 2;
ChangeBounds mChangeBounds;
+ ValidateBoundsListener mBoundsChangeListener;
@Override
@Before
public void setup() {
super.setup();
resetChangeBoundsTransition();
+ mBoundsChangeListener = null;
}
private void resetChangeBoundsTransition() {
mListener = mock(Transition.TransitionListener.class);
- mChangeBounds = new ChangeBounds();
+ mChangeBounds = new MyChangeBounds();
mChangeBounds.setDuration(400);
mChangeBounds.addListener(mListener);
+ mChangeBounds.setInterpolator(new LinearInterpolator());
mTransition = mChangeBounds;
}
@@ -65,11 +73,10 @@
validateInScene1();
- startTransition(R.layout.scene6);
+ mBoundsChangeListener = new ValidateBoundsListener(true);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateNormalIntermediate();
+ startTransition(R.layout.scene6);
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene6();
@@ -84,11 +91,11 @@
validateInScene1();
+ mBoundsChangeListener = new ValidateBoundsListener(true);
+
startTransition(R.layout.scene6);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateClippedIntermediate();
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene6();
@@ -101,11 +108,10 @@
validateInScene6();
+ mBoundsChangeListener = new ValidateBoundsListener(false);
startTransition(R.layout.scene1);
- // now delay for at least a few frames before checking intermediate values:
- Thread.sleep(150);
- validateClippedIntermediate();
+ // The update listener will validate that it is changing throughout the animation
waitForEnd(400);
validateInScene1();
@@ -252,63 +258,6 @@
assertNull(belowSquare.getClipBounds());
}
- private void validateIntermediatePosition() {
- Resources resources = mActivity.getResources();
- float smallDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
-
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
- assertTrue(redSquare.getTop() != 0);
- assertTrue(greenSquare.getTop() != 0);
- assertNotWithinAPixel(smallDim, redSquare.getTop());
- assertNotWithinAPixel(largeDim, redSquare.getTop());
- assertNotWithinAPixel(smallDim, greenSquare.getTop());
- assertNotWithinAPixel(largeDim, greenSquare.getTop());
- }
-
- private void validateClippedIntermediate() {
- validateIntermediatePosition();
- Resources resources = mActivity.getResources();
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
-
- assertWithinAPixel(largeDim, redSquare.getWidth());
- assertWithinAPixel(largeDim, redSquare.getHeight());
- assertWithinAPixel(largeDim, greenSquare.getWidth());
- assertWithinAPixel(largeDim, greenSquare.getHeight());
-
- assertNotNull(redSquare.getClipBounds());
- assertNotNull(greenSquare.getClipBounds());
- }
-
- private void validateNormalIntermediate() {
- validateIntermediatePosition();
- Resources resources = mActivity.getResources();
- float smallDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- float largeDim = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics());
- View redSquare = mActivity.findViewById(R.id.redSquare);
- View greenSquare = mActivity.findViewById(R.id.greenSquare);
- assertNotWithinAPixel(smallDim, redSquare.getWidth());
- assertNotWithinAPixel(smallDim, redSquare.getHeight());
- assertNotWithinAPixel(largeDim, redSquare.getWidth());
- assertNotWithinAPixel(largeDim, redSquare.getHeight());
-
- assertNotWithinAPixel(smallDim, greenSquare.getWidth());
- assertNotWithinAPixel(smallDim, greenSquare.getHeight());
- assertNotWithinAPixel(largeDim, greenSquare.getWidth());
- assertNotWithinAPixel(largeDim, greenSquare.getHeight());
-
- assertNull(redSquare.getClipBounds());
- assertNull(greenSquare.getClipBounds());
- }
-
private static boolean isWithinAPixel(float expectedDim, int dim) {
return (Math.abs(dim - expectedDim) <= 1);
}
@@ -322,5 +271,114 @@
assertTrue("Expected dimension to not be within one pixel of "
+ expectedDim + ", but was " + dim, !isWithinAPixel(expectedDim, dim));
}
+
+ private class MyChangeBounds extends ChangeBounds {
+ private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds";
+ @Override
+ public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+ TransitionValues endValues) {
+ Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+ if (animator != null && mBoundsChangeListener != null) {
+ animator.addListener(mBoundsChangeListener);
+ Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS);
+ Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS);
+ }
+ return animator;
+ }
+ }
+
+ private class ValidateBoundsListener implements ViewTreeObserver.OnDrawListener,
+ Animator.AnimatorListener {
+ final boolean mGrow;
+ final int mMin;
+ final int mMax;
+
+ final Point mRedDimensions = new Point(-1, -1);
+ final Point mGreenDimensions = new Point(-1, -1);
+
+ View mRedSquare;
+ View mGreenSquare;
+
+ boolean mDidChangeSize;
+
+ private ValidateBoundsListener(boolean grow) {
+ mGrow = grow;
+
+ Resources resources = mActivity.getResources();
+ mMin = (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ SMALL_SQUARE_SIZE_DP, resources.getDisplayMetrics()));
+ mMax = (int) Math.ceil(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ LARGE_SQUARE_SIZE_DP, resources.getDisplayMetrics()));
+ }
+
+ public void validateView(View view, Point dimensions) {
+ final String name = view.getTransitionName();
+ final boolean clipped = mChangeBounds.getResizeClip();
+ assertEquals(clipped, view.getClipBounds() != null);
+
+ final int width;
+ final int height;
+ if (clipped) {
+ width = view.getClipBounds().width();
+ height = view.getClipBounds().height();
+ } else {
+ width = view.getWidth();
+ height = view.getHeight();
+ }
+ validateDim(name, "width", dimensions.x, width);
+ validateDim(name, "height", dimensions.y, height);
+ dimensions.set(width, height);
+ }
+
+ private void validateDim(String name, String dimen, int lastDim, int newDim) {
+ if (lastDim != -1) {
+ if (mGrow) {
+ assertTrue(name + " new " + dimen + " " + newDim
+ + " is less than previous " + lastDim,
+ newDim >= lastDim);
+ } else {
+ assertTrue(name + " new " + dimen + " " + newDim
+ + " is more than previous " + lastDim,
+ newDim <= lastDim);
+ }
+ if (newDim != lastDim) {
+ mDidChangeSize = true;
+ }
+ }
+ assertTrue(name + " " + dimen + " " + newDim + " must be <= " + mMax,
+ newDim <= mMax);
+ assertTrue(name + " " + dimen + " " + newDim + " must be >= " + mMin,
+ newDim >= mMin);
+ }
+
+ @Override
+ public void onDraw() {
+ if (mRedSquare == null) {
+ mRedSquare = mActivity.findViewById(R.id.redSquare);
+ mGreenSquare = mActivity.findViewById(R.id.greenSquare);
+ }
+ validateView(mRedSquare, mRedDimensions);
+ validateView(mGreenSquare, mGreenDimensions);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mActivity.getWindow().getDecorView().getViewTreeObserver().addOnDrawListener(this);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mActivity.getWindow().getDecorView().getViewTreeObserver().removeOnDrawListener(this);
+ assertTrue(mDidChangeSize);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
}
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
index e42b33f..0b28d05 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvContractTest.java
@@ -159,6 +159,9 @@
TvContentRating rating = TvContentRating.createRating("android.media.tv", "US_TVPG",
"US_TVPG_TV_MA", "US_TVPG_S", "US_TVPG_V");
values.put(Programs.COLUMN_CONTENT_RATING, rating.flattenToString());
+ values.put(Programs.COLUMN_REVIEW_RATING_STYLE,
+ RecordedPrograms.REVIEW_RATING_STYLE_STARS);
+ values.put(Programs.COLUMN_REVIEW_RATING, "4.5");
return values;
}
@@ -256,6 +259,9 @@
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2, 3);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3, 2);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4, 1);
+ values.put(RecordedPrograms.COLUMN_REVIEW_RATING_STYLE,
+ RecordedPrograms.REVIEW_RATING_STYLE_STARS);
+ values.put(RecordedPrograms.COLUMN_REVIEW_RATING, "4.5");
return values;
}
@@ -547,6 +553,8 @@
verifyStringColumn(cursor, expectedValues, Programs.COLUMN_THUMBNAIL_URI);
verifyBlobColumn(cursor, expectedValues, Programs.COLUMN_INTERNAL_PROVIDER_DATA);
verifyIntegerColumn(cursor, expectedValues, Programs.COLUMN_VERSION_NUMBER);
+ verifyStringColumn(cursor, expectedValues, Programs.COLUMN_REVIEW_RATING_STYLE);
+ verifyStringColumn(cursor, expectedValues, Programs.COLUMN_REVIEW_RATING);
}
}
@@ -991,6 +999,8 @@
verifyIntegerColumn(cursor, expectedValues,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4);
verifyIntegerColumn(cursor, expectedValues, RecordedPrograms.COLUMN_VERSION_NUMBER);
+ verifyStringColumn(cursor, expectedValues, RecordedPrograms.COLUMN_REVIEW_RATING_STYLE);
+ verifyStringColumn(cursor, expectedValues, RecordedPrograms.COLUMN_REVIEW_RATING);
}
}
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index 70fbd73..93f4846 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -282,6 +282,13 @@
android:autoSizeStepGranularity="1px" />
<TextView
+ android:id="@+id/textview_autosize_basic"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/text_view_hello"
+ android:autoSizeTextType="uniform" />
+
+ <TextView
android:id="@+id/textview_fontresource_fontfamily"
android:text="@string/text_view_hello"
android:layout_width="wrap_content"
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 0b500f3..3da2cb4 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -63,6 +63,7 @@
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.fonts.FontVariationAxis;
+import android.icu.lang.UCharacter;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -3369,9 +3370,22 @@
// The default variation settings should be null.
assertNull(mTextView.getFontVariationSettings());
- final String[] nonEffectiveSettings = {
+ final String[] invalidFormatSettings = {
"invalid syntax",
"'aaa' 1.0", // tag is not 4 ascii chars
+ };
+ for (String settings : invalidFormatSettings) {
+ try {
+ mTextView.setFontVariationSettings(settings);
+ fail();
+ } catch (FontVariationAxis.InvalidFormatException e) {
+ // pass.
+ }
+ assertNull("Must not change settings for " + settings,
+ mTextView.getFontVariationSettings());
+ }
+
+ final String[] nonEffectiveSettings = {
"'bbbb' 1.0", // unsupported tag
"' ' 1.0", // unsupported tag
"'AAAA' 0.7", // unsupported tag (case sensitive)
@@ -5392,28 +5406,75 @@
@UiThreadTest
@Test
- public void testAllCapsLocalization() {
- String testString = "abcdefghijklmnopqrstuvwxyz";
+ public void testAllCaps_Localization() {
+ final String testString = "abcdefghijklmnopqrstuvwxyz i\u0307\u0301 άέήίΐόύΰώάυ ή";
- // The capitalized characters of "i" on Turkish and Azerbaijani are different from English.
- Locale[] testLocales = {
- new Locale("az", "AZ"),
- new Locale("tr", "TR"),
- new Locale("en", "US"),
+ // Capital "i" in Turkish and Azerbaijani is different from English, Lithuanian has special
+ // rules for uppercasing dotted i with accents, and Greek has complex capitalization rules.
+ final Locale[] testLocales = {
+ new Locale("az", "AZ"), // Azerbaijani
+ new Locale("tr", "TR"), // Turkish
+ new Locale("lt", "LT"), // Lithuanian
+ new Locale("el", "GR"), // Greek
+ Locale.US,
};
- TextView tv = new TextView(mActivity);
+ final TextView tv = new TextView(mActivity);
tv.setAllCaps(true);
for (Locale locale: testLocales) {
tv.setTextLocale(locale);
assertEquals("Locale: " + locale.getDisplayName(),
- testString.toUpperCase(locale),
+ UCharacter.toUpperCase(locale, testString),
tv.getTransformationMethod().getTransformation(testString, tv).toString());
}
}
@UiThreadTest
@Test
+ public void testAllCaps_SpansArePreserved() {
+ final Locale greek = new Locale("el", "GR");
+ final String lowerString = "ι\u0301ριδα"; // ίριδα with first letter decomposed
+ final String upperString = "ΙΡΙΔΑ"; // uppercased
+ // expected lowercase to uppercase index map
+ final int[] indexMap = {0, 1, 1, 2, 3, 4, 5};
+ final int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
+
+ final TextView tv = new TextView(mActivity);
+ tv.setTextLocale(greek);
+ tv.setAllCaps(true);
+
+ final Spannable source = new SpannableString(lowerString);
+ source.setSpan(new Object(), 0, 1, flags);
+ source.setSpan(new Object(), 1, 2, flags);
+ source.setSpan(new Object(), 2, 3, flags);
+ source.setSpan(new Object(), 3, 4, flags);
+ source.setSpan(new Object(), 4, 5, flags);
+ source.setSpan(new Object(), 5, 6, flags);
+ source.setSpan(new Object(), 0, 2, flags);
+ source.setSpan(new Object(), 1, 3, flags);
+ source.setSpan(new Object(), 2, 4, flags);
+ source.setSpan(new Object(), 0, 6, flags);
+ final Object[] sourceSpans = source.getSpans(0, source.length(), Object.class);
+
+ final CharSequence transformed =
+ tv.getTransformationMethod().getTransformation(source, tv);
+ assertTrue(transformed instanceof Spanned);
+ final Spanned result = (Spanned) transformed;
+
+ assertEquals(upperString, transformed.toString());
+ final Object[] resultSpans = result.getSpans(0, result.length(), Object.class);
+ assertEquals(sourceSpans.length, resultSpans.length);
+ for (int i = 0; i < sourceSpans.length; i++) {
+ assertSame(sourceSpans[i], resultSpans[i]);
+ final Object span = sourceSpans[i];
+ assertEquals(indexMap[source.getSpanStart(span)], result.getSpanStart(span));
+ assertEquals(indexMap[source.getSpanEnd(span)], result.getSpanEnd(span));
+ assertEquals(source.getSpanFlags(span), result.getSpanFlags(span));
+ }
+ }
+
+ @UiThreadTest
+ @Test
public void testTextAlignmentDefault() {
TextView tv = new TextView(mActivity);
assertEquals(View.TEXT_ALIGNMENT_GRAVITY, tv.getRawTextAlignment());
@@ -6387,6 +6448,7 @@
final TextUtils.TruncateAt newEllipsizeValue = TextUtils.TruncateAt.END;
mActivityRule.runOnUiThread(() ->
textView.setEllipsize(newEllipsizeValue));
+ mInstrumentation.waitForIdleSync();
assertEquals(newEllipsizeValue, textView.getEllipsize());
assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_NONE, textView.getAutoSizeTextType());
assertEquals(-1, textView.getAutoSizeMinTextSize());
@@ -6396,6 +6458,7 @@
mActivityRule.runOnUiThread(() ->
textView.setAutoSizeTextTypeWithDefaults(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM));
+ mInstrumentation.waitForIdleSync();
assertEquals(newEllipsizeValue, textView.getEllipsize());
assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM, textView.getAutoSizeTextType());
// The auto-size defaults have been used.
@@ -6713,6 +6776,19 @@
}
@Test
+ public void testAutoSizeCallers_setHeightForOneLineText() throws Throwable {
+ final TextView autoSizeTextView = (TextView) mActivity.findViewById(
+ R.id.textview_autosize_basic);
+ assertEquals(TextView.AUTO_SIZE_TEXT_TYPE_UNIFORM, autoSizeTextView.getAutoSizeTextType());
+ final float initialTextSize = autoSizeTextView.getTextSize();
+ mActivityRule.runOnUiThread(() -> autoSizeTextView.setHeight(
+ autoSizeTextView.getHeight() * 3));
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(autoSizeTextView.getTextSize() > initialTextSize);
+ }
+
+ @Test
public void testAutoSizeUniform_obtainStyledAttributes() {
DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
TextView autoSizeTextViewUniform = (TextView) mActivity.findViewById(
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 4c0d1af..769336d 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -186,4 +186,9 @@
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferVeryFast" />
<option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferVeryFast" />
+ <!-- b/37216168 -->
+ <option name="compatibility:exclude-filter" value="CtsNativeHardwareTestCases AHardwareBufferTest#AHardwareBuffer_SendAndRecv_Succeeds" />
+
+ <!-- b/37108688 -->
+ <option name="compatibility:exclude-filter" value="CtsHardwareTestCases android.hardware.cts.HardwareBufferTest#testCreate" />
</configuration>