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>