Merge "Update ThemeHostTests"
diff --git a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
index d9d40c6..25cb53d 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/alert/AnomalyDetectionTests.java
@@ -55,7 +55,6 @@
     private static final int SUBSCRIPTION_ID_INCIDENTD = 41;
     private static final int ANOMALY_DETECT_MATCH_ID = 10;
     private static final int ANOMALY_EVENT_ID = 101;
-    private static final int APP_BREADCRUMB_REPORTED_UID = 0;
     private static final int INCIDENTD_SECTION = -1;
 
     @Override
@@ -94,37 +93,29 @@
         // count(label=6) -> 1 (not an anomaly, since not "greater than 2")
         doAppBreadcrumbReportedStart(6);
         Thread.sleep(500);
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertFalse("Incident", didIncidentdFireSince(markTime));
-        }
         assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 
         // count(label=6) -> 2 (not an anomaly, since not "greater than 2")
         doAppBreadcrumbReportedStart(6);
         Thread.sleep(500);
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertFalse("Incident", didIncidentdFireSince(markTime));
-        }
         assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 
         // count(label=12) -> 1 (not an anomaly, since not "greater than 2")
         doAppBreadcrumbReportedStart(12);
         Thread.sleep(1000);
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertFalse("Incident", didIncidentdFireSince(markTime));
-        }
         assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 
         doAppBreadcrumbReportedStart(6); // count(label=6) -> 3 (anomaly, since "greater than 2"!)
         Thread.sleep(1000);
 
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertTrue("No incident", didIncidentdFireSince(markTime));
-        }
         List<EventMetricData> data = getEventMetricDataList();
         assertEquals("Expected 1 anomaly", 1, data.size());
         AnomalyDetected a = data.get(0).getAtom().getAnomalyDetected();
         assertEquals("Wrong alert_id", ALERT_ID, a.getAlertId());
+        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
     }
 
     // Tests that anomaly detection for duration works.
@@ -188,12 +179,10 @@
         doAppBreadcrumbReportedStart(1);
         Thread.sleep(10_000);
         // We can do an incidentd test now that all the timing issues are done.
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertTrue("No incident", didIncidentdFireSince(markTime));
-        }
         data = getEventMetricDataList();
         assertEquals("Expected another anomaly,", 1, data.size());
         assertEquals(ALERT_ID, data.get(0).getAtom().getAnomalyDetected().getAlertId());
+        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
 
         doAppBreadcrumbReportedStop(1);
         turnScreenOff();
@@ -272,21 +261,17 @@
         String markTime = getCurrentLogcatDate();
         doAppBreadcrumbReportedStart(6); // value = 6, which is NOT > trigger
         Thread.sleep(2000);
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertFalse("Incident", didIncidentdFireSince(markTime));
-        }
         assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 
         doAppBreadcrumbReportedStart(14); // value = 14 > trigger
         Thread.sleep(2000);
 
-        if (INCIDENTD_TESTS_ENABLED) {
-            assertTrue("No incident", didIncidentdFireSince(markTime));
-        }
         List<EventMetricData> data = getEventMetricDataList();
         assertEquals("Expected 1 anomaly", 1, data.size());
         AnomalyDetected a = data.get(0).getAtom().getAnomalyDetected();
         assertEquals("Wrong alert_id", ALERT_ID, a.getAlertId());
+        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
     }
 
     // TODO: Removed until b/73091354 is solved, since it keeps crashing statsd. Update CTS later.
@@ -313,22 +298,22 @@
 //        String markTime = getCurrentLogcatDate();
 //        doAppBreadcrumbReportedStart(6); // gauge = 6, which is NOT > trigger
 //        Thread.sleep(2000);
-//        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 //        assertEquals("Premature anomaly", 0, getEventMetricDataList().size());
+//        if (INCIDENTD_TESTS_ENABLED) assertFalse("Incident", didIncidentdFireSince(markTime));
 //
 //        doAppBreadcrumbReportedStart(14); // gauge = 6+1 > trigger
 //        Thread.sleep(2000);
 //
-//        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
 //        List<EventMetricData> data = getEventMetricDataList();
 //        assertEquals("Expected 1 anomaly", 1, data.size());
 //        AnomalyDetected a = data.get(0).getAtom().getAnomalyDetected();
 //        assertEquals("Wrong alert_id", ALERT_ID, a.getAlertId());
+//        if (INCIDENTD_TESTS_ENABLED) assertTrue("No incident", didIncidentdFireSince(markTime));
 //    }
 
-    private static final StatsdConfig.Builder getBaseConfig(int numBuckets,
-            int refractorySecs,
-            long triggerIfSumGt) {
+    private final StatsdConfig.Builder getBaseConfig(int numBuckets,
+                                                     int refractorySecs,
+                                                     long triggerIfSumGt) throws Exception {
         return StatsdConfig.newBuilder().setId(CONFIG_ID)
                 // Items of relevance for detecting the anomaly:
                 .addAtomMatcher(StatsdConfigProto.AtomMatcher.newBuilder()
@@ -338,7 +323,7 @@
                                 // Event only when the uid is this app's uid.
                                 .addFieldValueMatcher(
                                         createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
-                                                .setEqInt(APP_BREADCRUMB_REPORTED_UID)
+                                                .setEqInt(getHostUid())
                                 )
                                 .addFieldValueMatcher(
                                         createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
@@ -354,7 +339,7 @@
                                 // Event only when the uid is this app's uid.
                                 .addFieldValueMatcher(
                                         createFvm(AppBreadcrumbReported.UID_FIELD_NUMBER)
-                                                .setEqInt(APP_BREADCRUMB_REPORTED_UID)
+                                                .setEqInt(getHostUid())
                                 )
                                 .addFieldValueMatcher(
                                         createFvm(AppBreadcrumbReported.STATE_FIELD_NUMBER)
@@ -379,7 +364,8 @@
                 )
                 // We want to trigger anomalies on METRIC_ID, but don't want the actual data.
                 .addNoReportMetric(METRIC_ID)
-                .addAllowedLogSource("AID_ROOT") // needed for adb cmd AppBreadcrumbReported
+                .addAllowedLogSource("AID_ROOT") // needed for AppBreadcrumb (if rooted)
+                .addAllowedLogSource("AID_SHELL") // needed for AppBreadcrumb (if unrooted)
                 .addAllowedLogSource("AID_STATSD") // needed for AnomalyDetected
                 // No need in this test for .addAllowedLogSource("AID_SYSTEM")
 
@@ -390,7 +376,7 @@
                                 .setAtomId(Atom.ANOMALY_DETECTED_FIELD_NUMBER)
                                 .addFieldValueMatcher(
                                         createFvm(AnomalyDetected.CONFIG_UID_FIELD_NUMBER)
-                                                .setEqInt(Integer.parseInt(CONFIG_UID))
+                                                .setEqInt(getHostUid())
                                 )
                                 .addFieldValueMatcher(
                                         createFvm(AnomalyDetected.CONFIG_ID_FIELD_NUMBER)
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
index 3b017bf..7f68c63 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/AtomTestCase.java
@@ -37,6 +37,7 @@
 import com.android.os.StatsLog.EventMetricData;
 import com.android.os.StatsLog.GaugeMetricData;
 import com.android.os.StatsLog.StatsLogReport;
+import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil;
 
 import com.google.common.io.Files;
@@ -121,17 +122,17 @@
         File configFile = File.createTempFile("statsdconfig", ".config");
         configFile.deleteOnExit();
         Files.write(config.toByteArray(), configFile);
-        String remotePath = "/data/" + configFile.getName();
+        String remotePath = "/data/local/tmp/" + configFile.getName();
         getDevice().pushFile(configFile, remotePath);
         getDevice().executeShellCommand(
-                String.join(" ", "cat", remotePath, "|", UPDATE_CONFIG_CMD, CONFIG_UID,
+                String.join(" ", "cat", remotePath, "|", UPDATE_CONFIG_CMD,
                         String.valueOf(CONFIG_ID)));
         getDevice().executeShellCommand("rm " + remotePath);
     }
 
     protected void removeConfig(long configId) throws Exception {
         getDevice().executeShellCommand(
-                String.join(" ", REMOVE_CONFIG_CMD, CONFIG_UID, String.valueOf(configId)));
+                String.join(" ", REMOVE_CONFIG_CMD, String.valueOf(configId)));
     }
 
     /** Gets the statsd report and sorts it. Note that this also deletes that report from statsd. */
@@ -187,7 +188,7 @@
     protected ConfigMetricsReportList getReportList() throws Exception {
         try {
             ConfigMetricsReportList reportList = getDump(ConfigMetricsReportList.parser(),
-                    String.join(" ", DUMP_REPORT_CMD, CONFIG_UID, String.valueOf(CONFIG_ID),
+                    String.join(" ", DUMP_REPORT_CMD, String.valueOf(CONFIG_ID),
                             "--proto"));
             return reportList;
         } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -380,6 +381,23 @@
         data.subList(0, firstStateIdx).clear();
     }
 
+    /** Returns the UID of the host, which should always either be SHELL (2000) or ROOT (0). */
+    protected int getHostUid() throws DeviceNotAvailableException {
+        String strUid = "";
+        try {
+            strUid = getDevice().executeShellCommand("id -u");
+            return Integer.parseInt(strUid.trim());
+        } catch (NumberFormatException e) {
+            LogUtil.CLog.e("Failed to get host's uid via shell command. Found " + strUid);
+            // Fall back to alternative method...
+            if (getDevice().isAdbRoot()) {
+                return 0; // ROOT
+            } else {
+                return 2000; // SHELL
+            }
+        }
+    }
+
     protected void turnScreenOn() throws Exception {
         getDevice().executeShellCommand("input keyevent KEYCODE_WAKEUP");
         getDevice().executeShellCommand("wm dismiss-keyguard");
@@ -419,7 +437,7 @@
 
     public void doAppBreadcrumbReported(int label, int state) throws Exception {
         getDevice().executeShellCommand(String.format(
-                "cmd stats log-app-breadcrumb-reported %d %d", label, state));
+                "cmd stats log-app-breadcrumb %d %d", label, state));
     }
 
     protected void setBatteryLevel(int level) throws Exception {
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
index 5605eb5..6ceec71 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/HostAtomTests.java
@@ -59,8 +59,6 @@
     private static final String TAG = "Statsd.HostAtomTests";
 
     private static final boolean TESTS_ENABLED = false;
-    // For tests that require incidentd. Keep as true until TESTS_ENABLED is permanently enabled.
-    private static final boolean INCIDENTD_TESTS_ENABLED = true;
 
     private static final String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
     private static final String FEATURE_WIFI = "android.hardware.wifi";
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index f84d520..1f6737f 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -29,6 +29,7 @@
 import android.os.SystemClock;
 import android.util.Pair;
 import android.util.Size;
+import android.hardware.camera2.cts.helpers.CameraErrorCollector;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
 
@@ -43,6 +44,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -54,14 +56,11 @@
     private static final int NUM_FRAMES_VERIFIED = 30;
     private static final long WAIT_FOR_RESULT_TIMEOUT_MS = 3000;
 
-    // List that includes all public keys from CaptureResult
-    List<CaptureResult.Key<?>> mAllKeys;
 
     // List tracking the failed test keys.
 
     @Override
     public void setContext(Context context) {
-        mAllKeys = getAllCaptureResultKeys();
         super.setContext(context);
 
         /**
@@ -123,12 +122,9 @@
                 SimpleCaptureCallback captureListener = new SimpleCaptureCallback();
                 startCapture(requestBuilder.build(), /*repeating*/true, captureListener, mHandler);
 
-                // Get the waived keys for current camera device
-                List<CaptureResult.Key<?>> waiverkeys = getWaiverKeysForCamera();
-
                 // Verify results
-                validateCaptureResult(captureListener, waiverkeys, requestBuilder,
-                        NUM_FRAMES_VERIFIED);
+                validateCaptureResult(mCollector, captureListener, mStaticInfo, mAllStaticInfo,
+                        null/*requestedPhysicalIds*/, requestBuilder, NUM_FRAMES_VERIFIED);
 
                 stopCapture(/*fast*/false);
             } finally {
@@ -379,76 +375,111 @@
                 resultImage.getTimestamp(), captureTime);
     }
 
-    private void validateCaptureResult(SimpleCaptureCallback captureListener,
-            List<CaptureResult.Key<?>> skippedKeys, CaptureRequest.Builder requestBuilder,
-            int numFramesVerified) throws Exception {
-        CaptureResult result = null;
+    public static void validateCaptureResult(CameraErrorCollector errorCollector,
+            SimpleCaptureCallback captureListener, StaticMetadata staticInfo,
+            Map<String, StaticMetadata> allStaticInfo, List<String> requestedPhysicalIds,
+            CaptureRequest.Builder requestBuilder, int numFramesVerified) throws Exception {
+        // List that includes all public keys from CaptureResult
+        List<CaptureResult.Key<?>> allKeys = getAllCaptureResultKeys();
+        // Get the waived keys for current camera device
+        List<CaptureResult.Key<?>> waiverKeys = getWaiverKeysForCamera(staticInfo);
+        if (requestedPhysicalIds == null) {
+            requestedPhysicalIds = new ArrayList<String>();
+        }
+
+        HashMap<String, List<CaptureResult.Key<?>>> physicalWaiverKeys = new HashMap<>();
+        for (String physicalId : requestedPhysicalIds) {
+            StaticMetadata physicalStaticInfo = allStaticInfo.get(physicalId);
+            physicalWaiverKeys.put(physicalId, getWaiverKeysForCamera(physicalStaticInfo));
+        }
+
+        TotalCaptureResult result = null;
         for (int i = 0; i < numFramesVerified; i++) {
-            String failMsg = "Failed capture result " + i + " test ";
-            result = captureListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+            result = captureListener.getTotalCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
+            Map<String, CaptureResult> physicalCaptureResults = result.getPhysicalCameraResults();
+            errorCollector.expectEquals("Number of physical result metadata doesn't match " +
+                    physicalCaptureResults.size() + " vs " + requestedPhysicalIds.size(),
+                    physicalCaptureResults.size(), requestedPhysicalIds.size());
 
-            for (CaptureResult.Key<?> key : mAllKeys) {
-                if (!skippedKeys.contains(key)) {
-                    /**
-                     * Check the critical tags here.
-                     * TODO: Can use the same key for request and result when request/result
-                     * becomes symmetric (b/14059883). Then below check can be wrapped into
-                     * a generic function.
-                     */
-                    String msg = failMsg + "for key " + key.getName();
-                    if (key.equals(CaptureResult.CONTROL_AE_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.CONTROL_AE_MODE),
-                                result.get(CaptureResult.CONTROL_AE_MODE));
-                    } else if (key.equals(CaptureResult.CONTROL_AF_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.CONTROL_AF_MODE),
-                                result.get(CaptureResult.CONTROL_AF_MODE));
-                    } else if (key.equals(CaptureResult.CONTROL_AWB_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.CONTROL_AWB_MODE),
-                                result.get(CaptureResult.CONTROL_AWB_MODE));
-                    } else if (key.equals(CaptureResult.CONTROL_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.CONTROL_MODE),
-                                result.get(CaptureResult.CONTROL_MODE));
-                    } else if (key.equals(CaptureResult.STATISTICS_FACE_DETECT_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.STATISTICS_FACE_DETECT_MODE),
-                                result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE));
-                    } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
-                                result.get(CaptureResult.NOISE_REDUCTION_MODE));
-                    } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
-                                result.get(CaptureResult.NOISE_REDUCTION_MODE));
-                    } else if (key.equals(CaptureResult.REQUEST_PIPELINE_DEPTH)) {
+            validateOneCaptureResult(errorCollector, waiverKeys, allKeys, requestBuilder, result,
+                    null/*cameraId*/, i);
+            for (String physicalId : requestedPhysicalIds) {
+                validateOneCaptureResult(errorCollector, physicalWaiverKeys.get(physicalId),
+                        allKeys, requestBuilder, physicalCaptureResults.get(physicalId),
+                        physicalId, i);
+            }
+        }
+    }
 
-                    } else if (key.equals(CaptureResult.STATISTICS_OIS_DATA_MODE)) {
-                        mCollector.expectEquals(msg,
-                                requestBuilder.get(CaptureRequest.STATISTICS_OIS_DATA_MODE),
-                                result.get(CaptureResult.STATISTICS_OIS_DATA_MODE));
-                    } else {
-                        // Only do non-null check for the rest of keys.
-                        mCollector.expectKeyValueNotNull(failMsg, result, key);
-                    }
+    private static void validateOneCaptureResult(CameraErrorCollector errorCollector,
+            List<CaptureResult.Key<?>> skippedKeys, List<CaptureResult.Key<?>> allKeys,
+            CaptureRequest.Builder requestBuilder, CaptureResult result, String cameraId,
+            int resultCount) throws Exception {
+        String failMsg = "Failed capture result " + resultCount + " test ";
+        if (cameraId != null) {
+            failMsg += "for camera " + cameraId + " ";
+        }
+        for (CaptureResult.Key<?> key : allKeys) {
+            if (!skippedKeys.contains(key)) {
+                /**
+                 * Check the critical tags here.
+                 * TODO: Can use the same key for request and result when request/result
+                 * becomes symmetric (b/14059883). Then below check can be wrapped into
+                 * a generic function.
+                 */
+                String msg = failMsg + "for key " + key.getName();
+                if (key.equals(CaptureResult.CONTROL_AE_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.CONTROL_AE_MODE),
+                            result.get(CaptureResult.CONTROL_AE_MODE));
+                } else if (key.equals(CaptureResult.CONTROL_AF_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.CONTROL_AF_MODE),
+                            result.get(CaptureResult.CONTROL_AF_MODE));
+                } else if (key.equals(CaptureResult.CONTROL_AWB_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.CONTROL_AWB_MODE),
+                            result.get(CaptureResult.CONTROL_AWB_MODE));
+                } else if (key.equals(CaptureResult.CONTROL_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.CONTROL_MODE),
+                            result.get(CaptureResult.CONTROL_MODE));
+                } else if (key.equals(CaptureResult.STATISTICS_FACE_DETECT_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.STATISTICS_FACE_DETECT_MODE),
+                            result.get(CaptureResult.STATISTICS_FACE_DETECT_MODE));
+                } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
+                            result.get(CaptureResult.NOISE_REDUCTION_MODE));
+                } else if (key.equals(CaptureResult.NOISE_REDUCTION_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.NOISE_REDUCTION_MODE),
+                            result.get(CaptureResult.NOISE_REDUCTION_MODE));
+                } else if (key.equals(CaptureResult.REQUEST_PIPELINE_DEPTH)) {
+
+                } else if (key.equals(CaptureResult.STATISTICS_OIS_DATA_MODE)) {
+                    errorCollector.expectEquals(msg,
+                            requestBuilder.get(CaptureRequest.STATISTICS_OIS_DATA_MODE),
+                            result.get(CaptureResult.STATISTICS_OIS_DATA_MODE));
                 } else {
-                    // These keys should always be null
-                    if (key.equals(CaptureResult.CONTROL_AE_REGIONS)) {
-                        mCollector.expectNull(
-                                "Capture result contains AE regions but aeMaxRegions is 0",
-                                result.get(CaptureResult.CONTROL_AE_REGIONS));
-                    } else if (key.equals(CaptureResult.CONTROL_AWB_REGIONS)) {
-                        mCollector.expectNull(
-                                "Capture result contains AWB regions but awbMaxRegions is 0",
-                                result.get(CaptureResult.CONTROL_AWB_REGIONS));
-                    } else if (key.equals(CaptureResult.CONTROL_AF_REGIONS)) {
-                        mCollector.expectNull(
-                                "Capture result contains AF regions but afMaxRegions is 0",
-                                result.get(CaptureResult.CONTROL_AF_REGIONS));
-                    }
+                    // Only do non-null check for the rest of keys.
+                    errorCollector.expectKeyValueNotNull(failMsg, result, key);
+                }
+            } else {
+                // These keys should always be null
+                if (key.equals(CaptureResult.CONTROL_AE_REGIONS)) {
+                    errorCollector.expectNull(
+                            "Capture result contains AE regions but aeMaxRegions is 0",
+                            result.get(CaptureResult.CONTROL_AE_REGIONS));
+                } else if (key.equals(CaptureResult.CONTROL_AWB_REGIONS)) {
+                    errorCollector.expectNull(
+                            "Capture result contains AWB regions but awbMaxRegions is 0",
+                            result.get(CaptureResult.CONTROL_AWB_REGIONS));
+                } else if (key.equals(CaptureResult.CONTROL_AF_REGIONS)) {
+                    errorCollector.expectNull(
+                            "Capture result contains AF regions but afMaxRegions is 0",
+                            result.get(CaptureResult.CONTROL_AF_REGIONS));
                 }
             }
         }
@@ -459,7 +490,7 @@
      *
      * Must be called after camera device is opened.
      */
-    private List<CaptureResult.Key<?>> getWaiverKeysForCamera() {
+    private static List<CaptureResult.Key<?>> getWaiverKeysForCamera(StaticMetadata staticInfo) {
         List<CaptureResult.Key<?>> waiverKeys = new ArrayList<>();
 
         // Global waiver keys
@@ -488,7 +519,7 @@
         waiverKeys.add(CaptureResult.REPROCESS_EFFECTIVE_EXPOSURE_FACTOR);
 
         //Keys not required if RAW is not supported
-        if (!mStaticInfo.isCapabilitySupported(
+        if (!staticInfo.isCapabilitySupported(
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW)) {
             waiverKeys.add(CaptureResult.SENSOR_NEUTRAL_COLOR_POINT);
             waiverKeys.add(CaptureResult.SENSOR_GREEN_SPLIT);
@@ -496,7 +527,7 @@
         }
 
         //Keys for depth output capability
-        if (!mStaticInfo.isCapabilitySupported(
+        if (!staticInfo.isCapabilitySupported(
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT)) {
             waiverKeys.add(CaptureResult.LENS_POSE_ROTATION);
             waiverKeys.add(CaptureResult.LENS_POSE_TRANSLATION);
@@ -505,7 +536,7 @@
         }
 
         // Waived if RAW output is not supported
-        int[] outputFormats = mStaticInfo.getAvailableFormats(
+        int[] outputFormats = staticInfo.getAvailableFormats(
                 StaticMetadata.StreamDirection.Output);
         boolean supportRaw = false;
         for (int format : outputFormats) {
@@ -519,38 +550,38 @@
             waiverKeys.add(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
         }
 
-        if (mStaticInfo.getAeMaxRegionsChecked() == 0) {
+        if (staticInfo.getAeMaxRegionsChecked() == 0) {
             waiverKeys.add(CaptureResult.CONTROL_AE_REGIONS);
         }
-        if (mStaticInfo.getAwbMaxRegionsChecked() == 0) {
+        if (staticInfo.getAwbMaxRegionsChecked() == 0) {
             waiverKeys.add(CaptureResult.CONTROL_AWB_REGIONS);
         }
-        if (mStaticInfo.getAfMaxRegionsChecked() == 0) {
+        if (staticInfo.getAfMaxRegionsChecked() == 0) {
             waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS);
         }
 
         // Keys for dynamic black/white levels
-        if (!mStaticInfo.isOpticalBlackRegionSupported()) {
+        if (!staticInfo.isOpticalBlackRegionSupported()) {
             waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
             waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
         }
 
-        if (!mStaticInfo.isEnableZslSupported()) {
+        if (!staticInfo.isEnableZslSupported()) {
             waiverKeys.add(CaptureResult.CONTROL_ENABLE_ZSL);
         }
 
-        if (!mStaticInfo.isAfSceneChangeSupported()) {
+        if (!staticInfo.isAfSceneChangeSupported()) {
             waiverKeys.add(CaptureResult.CONTROL_AF_SCENE_CHANGE);
         }
 
-        if (!mStaticInfo.isOisDataModeSupported()) {
+        if (!staticInfo.isOisDataModeSupported()) {
             waiverKeys.add(CaptureResult.STATISTICS_OIS_DATA_MODE);
             waiverKeys.add(CaptureResult.STATISTICS_OIS_TIMESTAMPS);
             waiverKeys.add(CaptureResult.STATISTICS_OIS_X_SHIFTS);
             waiverKeys.add(CaptureResult.STATISTICS_OIS_Y_SHIFTS);
         }
 
-        if (mStaticInfo.isHardwareLevelAtLeastFull()) {
+        if (staticInfo.isHardwareLevelAtLeastFull()) {
             return waiverKeys;
         }
 
@@ -558,40 +589,40 @@
          * Hardware Level = LIMITED or LEGACY
          */
         // Key not present if certain control is not supported
-        if (!mStaticInfo.isColorCorrectionSupported()) {
+        if (!staticInfo.isColorCorrectionSupported()) {
             waiverKeys.add(CaptureResult.COLOR_CORRECTION_GAINS);
             waiverKeys.add(CaptureResult.COLOR_CORRECTION_MODE);
             waiverKeys.add(CaptureResult.COLOR_CORRECTION_TRANSFORM);
         }
 
-        if (!mStaticInfo.isManualColorAberrationControlSupported()) {
+        if (!staticInfo.isManualColorAberrationControlSupported()) {
             waiverKeys.add(CaptureResult.COLOR_CORRECTION_ABERRATION_MODE);
         }
 
-        if (!mStaticInfo.isManualToneMapSupported()) {
+        if (!staticInfo.isManualToneMapSupported()) {
             waiverKeys.add(CaptureResult.TONEMAP_MODE);
         }
 
-        if (!mStaticInfo.isEdgeModeControlSupported()) {
+        if (!staticInfo.isEdgeModeControlSupported()) {
             waiverKeys.add(CaptureResult.EDGE_MODE);
         }
 
-        if (!mStaticInfo.isHotPixelMapModeControlSupported()) {
+        if (!staticInfo.isHotPixelMapModeControlSupported()) {
             waiverKeys.add(CaptureResult.HOT_PIXEL_MODE);
         }
 
-        if (!mStaticInfo.isNoiseReductionModeControlSupported()) {
+        if (!staticInfo.isNoiseReductionModeControlSupported()) {
             waiverKeys.add(CaptureResult.NOISE_REDUCTION_MODE);
         }
 
-        if (!mStaticInfo.isManualLensShadingMapSupported()) {
+        if (!staticInfo.isManualLensShadingMapSupported()) {
             waiverKeys.add(CaptureResult.SHADING_MODE);
         }
 
         //Keys not required if neither MANUAL_SENSOR nor READ_SENSOR_SETTINGS is supported
-        if (!mStaticInfo.isCapabilitySupported(
+        if (!staticInfo.isCapabilitySupported(
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR) &&
-            !mStaticInfo.isCapabilitySupported(
+            !staticInfo.isCapabilitySupported(
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
             waiverKeys.add(CaptureResult.SENSOR_EXPOSURE_TIME);
             waiverKeys.add(CaptureResult.SENSOR_SENSITIVITY);
@@ -599,7 +630,7 @@
             waiverKeys.add(CaptureResult.LENS_APERTURE);
         }
 
-        if (!mStaticInfo.isCapabilitySupported(
+        if (!staticInfo.isCapabilitySupported(
                 CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
             waiverKeys.add(CaptureResult.SENSOR_FRAME_DURATION);
             waiverKeys.add(CaptureResult.BLACK_LEVEL_LOCK);
@@ -608,7 +639,7 @@
             waiverKeys.add(CaptureResult.LENS_FILTER_DENSITY);
         }
 
-        if (mStaticInfo.isHardwareLevelLimited() && mStaticInfo.isColorOutputSupported()) {
+        if (staticInfo.isHardwareLevelLimited() && staticInfo.isColorOutputSupported()) {
             return waiverKeys;
         }
 
@@ -627,7 +658,7 @@
         waiverKeys.add(CaptureResult.CONTROL_AE_TARGET_FPS_RANGE);
         waiverKeys.add(CaptureResult.CONTROL_AF_TRIGGER);
 
-        if (mStaticInfo.isHardwareLevelLegacy()) {
+        if (staticInfo.isHardwareLevelLegacy()) {
             return waiverKeys;
         }
 
diff --git a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index e66660b..0514987 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -1388,6 +1388,7 @@
                         CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE,
                         CameraCharacteristics.LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_CALIBRATED);
 
+                Integer timestampSource = c.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
                 for (String physicalCameraId : physicalCameraIds) {
                     assertNotNull("Physical camera id shouldn't be null", physicalCameraId);
                     assertTrue(
@@ -1414,6 +1415,11 @@
 
                     verifyLensCalibration(poseRotation, poseTranslation, poseReference,
                             cameraIntrinsics, radialDistortion, precorrectionArray);
+
+                    Integer timestampSourcePhysical =
+                            pc.get(CameraCharacteristics.SENSOR_INFO_TIMESTAMP_SOURCE);
+                    mCollector.expectEquals("Logical camera and physical cameras must have same " +
+                            "timestamp source", timestampSource, timestampSourcePhysical);
                 }
             }
             counter++;
diff --git a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
index 6650743..0a9f052 100644
--- a/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/LogicalCameraDeviceTest.java
@@ -30,7 +30,9 @@
 import android.hardware.camera2.CaptureResult;
 import android.hardware.camera2.TotalCaptureResult;
 import android.hardware.camera2.CaptureFailure;
+import android.hardware.camera2.cts.CaptureResultTest;
 import android.hardware.camera2.cts.helpers.StaticMetadata;
+import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
@@ -71,6 +73,21 @@
 
     private static final double FRAME_DURATION_THRESHOLD = 0.03;
 
+    private HashMap<String, StaticMetadata> mAllStaticInfo;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mAllStaticInfo = new HashMap<String, StaticMetadata>();
+        for (String cameraId : mCameraIds) {
+            StaticMetadata staticMetadata = new StaticMetadata(
+                    mCameraManager.getCameraCharacteristics(cameraId),
+                    CheckLevel.ASSERT, /*collector*/null);
+            mAllStaticInfo.put(cameraId, staticMetadata);
+        }
+    }
+
     /**
      * Test that passing in invalid physical camera ids in OutputConfiguragtion behaves as expected
      * for logical multi-camera and non-logical multi-camera.
@@ -507,6 +524,11 @@
                     CaptureResult.CONTROL_AE_STATE_LOCKED, NUM_RESULTS_WAIT_TIMEOUT);
         }
 
+        // Verify results
+        CaptureResultTest.validateCaptureResult(mCollector, simpleResultListener,
+                mStaticInfo, mAllStaticInfo, null/*requestedPhysicalIds*/,
+                requestBuilder, NUM_FRAMES_CHECKED);
+
         // Collect timestamps for one logical stream only.
         long prevTimestamp = -1;
         long[] logicalTimestamps = new long[NUM_FRAMES_CHECKED];
@@ -516,14 +538,6 @@
                     CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
             logicalTimestamps[i] = totalCaptureResult.get(CaptureResult.SENSOR_TIMESTAMP);
         }
-        // Make sure that a logical stream request wont' generate physical result metadata.
-        TotalCaptureResult totalCaptureResult =
-                simpleResultListener.getTotalCaptureResult(
-                CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
-        Map<String, CaptureResult> physicalResults =
-                totalCaptureResult.getPhysicalCameraResults();
-        assertTrue("Logical stream request must not generate physical result metadata",
-                physicalResults.isEmpty());
 
         double logicalAvgDurationMs = (logicalTimestamps[NUM_FRAMES_CHECKED-1] -
                 logicalTimestamps[0])/(NS_PER_MS*(NUM_FRAMES_CHECKED-1));
@@ -537,6 +551,12 @@
         mSession.setRepeatingRequest(requestBuilder.build(), simpleResultListenerDual,
                 mHandler);
 
+        // Verify results for physical streams request.
+        CaptureResultTest.validateCaptureResult(mCollector, simpleResultListenerDual,
+                mStaticInfo, mAllStaticInfo, physicalCameraIds, requestBuilder,
+                NUM_FRAMES_CHECKED);
+
+        // Acquire the timestamps of the physical camera.
         long[] logicalTimestamps2 = new long[NUM_FRAMES_CHECKED];
         long [][] physicalTimestamps = new long[physicalTargets.size()][];
         for (int i = 0; i < physicalTargets.size(); i++) {
@@ -557,14 +577,6 @@
                  index++;
             }
         }
-        // Verify the size of the physical result metadata map
-        TotalCaptureResult totalCaptureResultDual =
-                simpleResultListenerDual.getTotalCaptureResult(
-                CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
-        Map<String, CaptureResult> physicalResultsDual =
-                totalCaptureResultDual.getPhysicalCameraResults();
-        assertTrue("Stream request must generate 2 physical result metadata",
-                physicalResultsDual.size() == 2);
 
         // Check timestamp monolithity for individual camera and across cameras
         for (int i = 0; i < NUM_FRAMES_CHECKED-1; i++) {
diff --git a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
index 6c39692..ee1dc1e 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/DisplaySizeTest.java
@@ -115,7 +115,7 @@
 
     private int getStableDensity() {
         final String densityProp;
-        if (Build.getSerial().startsWith("emulator-")) {
+        if (Build.IS_EMULATOR) {
             densityProp = DENSITY_PROP_EMULATOR;
         } else {
             densityProp = DENSITY_PROP_DEVICE;
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
index b482b24..1eadf59 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardLockedTests.java
@@ -22,6 +22,8 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeTrue;
 
+import android.app.KeyguardManager;
+
 import org.junit.Before;
 import org.junit.Test;
 
@@ -41,7 +43,6 @@
     @Override
     public void setUp() throws Exception {
         super.setUp();
-
         assumeTrue(isHandheld());
     }
 
@@ -50,12 +51,18 @@
         try (final LockScreenSession lockScreenSession = new LockScreenSession()) {
             lockScreenSession.setLockCredential()
                     .gotoKeyguard();
+            assertTrue(mKeyguardManager.isKeyguardLocked());
+            assertTrue(mKeyguardManager.isDeviceLocked());
+            assertTrue(mKeyguardManager.isDeviceSecure());
+            assertTrue(mKeyguardManager.isKeyguardSecure());
             mAmWmState.waitForKeyguardShowingAndNotOccluded();
             mAmWmState.assertKeyguardShowingAndNotOccluded();
             lockScreenSession.unlockDevice()
                     .enterAndConfirmLockCredential();
             mAmWmState.waitForKeyguardGone();
             mAmWmState.assertKeyguardGone();
+            assertFalse(mKeyguardManager.isDeviceLocked());
+            assertFalse(mKeyguardManager.isKeyguardLocked());
         }
     }
 
@@ -194,6 +201,7 @@
             mAmWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
 
             lockScreenSession.gotoKeyguard();
+            mAmWmState.computeState(true);
             mAmWmState.waitForKeyguardShowingAndOccluded();
             mAmWmState.assertKeyguardShowingAndOccluded();
             mAmWmState.assertVisibility(SHOW_WHEN_LOCKED_ACTIVITY, true);
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTestBase.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTestBase.java
index d95e973..07d125e 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTestBase.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTestBase.java
@@ -20,11 +20,21 @@
 
 import static org.junit.Assert.fail;
 
+import android.app.KeyguardManager;
+
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 public class KeyguardTestBase extends ActivityManagerTestBase {
 
+    protected KeyguardManager mKeyguardManager;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
+    }
+
     protected void assertOnDismissSucceededInLogcat(LogSeparator logSeparator) throws Exception {
         assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded", logSeparator);
     }
diff --git a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
index 7d13d51..1024bc3 100644
--- a/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
+++ b/tests/framework/base/activitymanager/src/android/server/am/KeyguardTests.java
@@ -56,8 +56,10 @@
             lockScreenSession.gotoKeyguard();
             mAmWmState.computeState(true);
             mAmWmState.assertKeyguardShowingAndNotOccluded();
+            assertTrue(mKeyguardManager.isKeyguardLocked());
             mAmWmState.assertVisibility("TestActivity", false);
         }
+        assertFalse(mKeyguardManager.isKeyguardLocked());
     }
 
     @Test
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
index ddf8a70..4813ac6 100644
--- a/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
+++ b/tests/framework/base/activitymanager/util/src/android/server/am/ActivityManagerTestBase.java
@@ -904,13 +904,14 @@
             setLockDisabled(mIsLockDisabled);
             if (mLockCredentialSet) {
                 removeLockCredential();
-                // Dismiss active keyguard after credential is cleared, so keyguard doesn't ask for
-                // the stale credential.
-                pressBackButton();
-                sleepDevice();
-                wakeUpDevice();
-                unlockDevice();
             }
+
+            // Dismiss active keyguard after credential is cleared, so keyguard doesn't ask for
+            // the stale credential.
+            pressBackButton();
+            sleepDevice();
+            wakeUpDevice();
+            unlockDevice();
         }
 
         /**
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
index 676465e..841ecad 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -728,7 +728,6 @@
 
     private List<File> getTargetFiles() {
         final List<File> targets = new ArrayList<File>();
-        targets.add(mContext.getFilesDir());
         for (File dir : mContext.getObbDirs()) {
             assertNotNull("Valid media must be inserted during CTS", dir);
             assertEquals("Valid media must be inserted during CTS", Environment.MEDIA_MOUNTED,
diff --git a/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java b/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
index ffc024a..317cd8e 100644
--- a/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
+++ b/tests/tests/text/src/android/text/style/cts/TypefaceSpanTest.java
@@ -36,6 +36,14 @@
     private static final String FAMILY = "monospace";
 
     @Test
+    public void testConstructorFromTypeface() {
+        Typeface typeface = Typeface.create(FAMILY, Typeface.BOLD);
+        TypefaceSpan t = new TypefaceSpan(typeface);
+
+        assertEquals(typeface, t.getTypeface());
+    }
+
+    @Test
     public void testConstructor() {
         TypefaceSpan t = new TypefaceSpan(FAMILY);
 
@@ -69,7 +77,7 @@
         assertEquals(Typeface.NORMAL, tp.getTypeface().getStyle());
     }
 
-    @Test(expected=NullPointerException.class)
+    @Test(expected = NullPointerException.class)
     public void testUpdateMeasureStateNull() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
 
@@ -90,7 +98,7 @@
         assertEquals(Typeface.NORMAL, tp.getTypeface().getStyle());
     }
 
-    @Test(expected=NullPointerException.class)
+    @Test(expected = NullPointerException.class)
     public void testUpdateDrawStateNull() {
         TypefaceSpan typefaceSpan = new TypefaceSpan(FAMILY);
 
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index 3ea818e..8bf2e83 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -19,6 +19,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.argThat;
+import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -42,6 +44,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatcher;
 
 import java.util.HashMap;
 import java.util.Locale;
@@ -965,7 +968,9 @@
                 .addLink(start, end, entityScores)
                 .build();
 
-        when(classifier.generateLinks(text, options)).thenReturn(links);
+        when(classifier.generateLinks(argThat(new EqStringMatcher(text)), eq(options)))
+            .thenReturn(links);
+        when(classifier.getMaxGenerateLinksTextLength()).thenReturn(Integer.MAX_VALUE);
 
         final Future future = Linkify.addLinksAsync(textView, options, executor, callback);
         future.get();
@@ -1032,4 +1037,18 @@
         assertTrue(msg, linksAdded);
         assertEquals(msg, expected, spans[0].getURL().toString());
     }
+
+    /** Helper to match a CharSequence based on String equivalence. */
+    class EqStringMatcher implements ArgumentMatcher<CharSequence> {
+        private final String mReference;
+
+        EqStringMatcher(CharSequence reference) {
+            mReference = reference.toString();
+        }
+
+        @Override
+        public boolean matches(CharSequence arg) {
+            return mReference.equals(arg.toString());
+        }
+    }
 }
diff --git a/tests/tests/uirendering/res/layout/simple_shadow_layout.xml b/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
index 2f21df0..042c2a9 100644
--- a/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_shadow_layout.xml
@@ -17,7 +17,8 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/test_width"
     android:layout_height="@dimen/test_height">
-    <View android:layout_width="40px"
+    <View android:id="@+id/shadow_view"
+        android:layout_width="40px"
         android:layout_height="40px"
         android:translationX="25px"
         android:translationY="25px"
diff --git a/tests/tests/uirendering/res/values-television/dimens.xml b/tests/tests/uirendering/res/values-television/dimens.xml
new file mode 100644
index 0000000..6d5b6d1
--- /dev/null
+++ b/tests/tests/uirendering/res/values-television/dimens.xml
@@ -0,0 +1,18 @@
+<!-- Copyright (C) 2018 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.
+  -->
+<resources>
+    <item type="dimen" format="float" name="expected_ambient_shadow_alpha">0.15</item>
+    <item type="dimen" format="float" name="expected_spot_shadow_alpha">0.3</item>
+</resources>
diff --git a/tests/tests/uirendering/res/values/dimens.xml b/tests/tests/uirendering/res/values/dimens.xml
index 1c304d3..4228611 100644
--- a/tests/tests/uirendering/res/values/dimens.xml
+++ b/tests/tests/uirendering/res/values/dimens.xml
@@ -15,4 +15,7 @@
 <resources>
     <dimen name="test_width">90px</dimen>
     <dimen name="test_height">90px</dimen>
+
+    <item type="dimen" format="float" name="expected_ambient_shadow_alpha">0.039</item>
+    <item type="dimen" format="float" name="expected_spot_shadow_alpha">0.19</item>
 </resources>
diff --git a/tests/tests/uirendering/res/values/themes.xml b/tests/tests/uirendering/res/values/themes.xml
index f08f029..c12ca95 100644
--- a/tests/tests/uirendering/res/values/themes.xml
+++ b/tests/tests/uirendering/res/values/themes.xml
@@ -14,7 +14,7 @@
 limitations under the License.
 -->
 <resources>
-    <style name="WhiteBackgroundTheme" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+    <style name="WhiteBackgroundTheme" parent="@android:style/Theme.Material.NoActionBar.Fullscreen">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowOverscan">true</item>
@@ -22,5 +22,7 @@
         <item name="android:windowBackground">@android:color/white</item>
         <item name="android:windowContentTransitions">false</item>
         <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:ambientShadowAlpha">0.039</item>
+        <item name="android:spotShadowAlpha">0.19</item>
     </style>
 </resources>
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
index c97e020..31cd282 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/SamplePointVerifier.java
@@ -28,10 +28,10 @@
  */
 public class SamplePointVerifier extends BitmapVerifier {
     private static final String TAG = "SamplePoint";
-    private static final int DEFAULT_TOLERANCE = 20;
+    public static final int DEFAULT_TOLERANCE = 20;
     private final Point[] mTestPoints;
     private final int[] mExpectedColors;
-    private final int mTolerance;
+    protected final int mTolerance;
 
     public SamplePointVerifier(Point[] testPoints, int[] expectedColors) {
         this(testPoints, expectedColors, DEFAULT_TOLERANCE);
@@ -74,4 +74,18 @@
     protected boolean verifyPixel(int color, int expectedColor) {
         return CompareUtils.verifyPixelWithThreshold(color, expectedColor, mTolerance);
     }
+
+    public interface VerifyPixelColor {
+        boolean verifyPixel(int color);
+    }
+
+    public static SamplePointVerifier create(Point[] testPoints, int[] expectedColors,
+            int tolerance, VerifyPixelColor verifier) {
+        return new SamplePointVerifier(testPoints, expectedColors, tolerance) {
+            @Override
+            protected boolean verifyPixel(int color, int expectedColor) {
+                return super.verifyPixel(color, expectedColor) && verifier.verifyPixel(color);
+            }
+        };
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
index 2f0ed64..57462b6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/EdgeEffectTests.java
@@ -33,6 +33,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
+import android.uirendering.cts.testinfrastructure.Tracer;
 import android.uirendering.cts.util.BitmapAsserter;
 import android.uirendering.cts.util.MockVsyncHelper;
 import android.view.ContextThemeWrapper;
@@ -41,7 +42,6 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
-import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 
@@ -53,7 +53,7 @@
     private static final int HEIGHT = 90;
 
     @Rule
-    public TestName name = new TestName();
+    public Tracer name = new Tracer();
 
     private BitmapAsserter mBitmapAsserter = new BitmapAsserter(this.getClass().getSimpleName(),
             name.getMethodName());
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
index e4f9809..3de3d59 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -15,6 +15,12 @@
  */
 package android.uirendering.cts.testclasses;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.Point;
 import android.support.test.filters.MediumTest;
@@ -23,6 +29,9 @@
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.util.CompareUtils;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.View;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -31,28 +40,9 @@
 @RunWith(AndroidJUnit4.class)
 public class ShadowTests extends ActivityTestBase {
 
-    private class GrayScaleVerifier extends SamplePointVerifier {
-        public GrayScaleVerifier(Point[] testPoints, int[] expectedColors, int tolerance) {
-            super(testPoints, expectedColors, tolerance) ;
-        }
-
-        @Override
-        protected boolean verifyPixel(int color, int expectedColor) {
-            return super.verifyPixel(color, expectedColor)
-                    && CompareUtils.verifyPixelGrayScale(color, 1);
-        }
-    }
-
-    @Test
-    public void testShadowLayout() {
-        int shadowColorValue = 0xDB;
-        // Android TV theme overrides shadow opacity to be darker.
-        if (getActivity().getOnTv()) {
-            shadowColorValue = 0xBB;
-        }
-
-        // Use a higher threshold than default value (20), since we also double check gray scale;
-        GrayScaleVerifier verifier = new GrayScaleVerifier(
+    private static SamplePointVerifier createVerifier(int expectedColor,
+            SamplePointVerifier.VerifyPixelColor verifier) {
+        return SamplePointVerifier.create(
                 new Point[] {
                         // view area
                         new Point(25, 64),
@@ -64,13 +54,96 @@
                 new int[] {
                         Color.WHITE,
                         Color.WHITE,
-                        Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
-                        Color.rgb(shadowColorValue, shadowColorValue, shadowColorValue),
-                },
-                64);
+                        expectedColor,
+                        expectedColor,
+                }, SamplePointVerifier.DEFAULT_TOLERANCE, verifier);
+    }
+
+    @Test
+    public void testShadowResources() {
+        final Context context = new ContextThemeWrapper(getInstrumentation().getTargetContext(),
+                android.R.style.Theme_Material_Light);
+        final Resources resources = context.getResources();
+        final TypedValue value = new TypedValue();
+
+        resources.getValue(R.dimen.expected_spot_shadow_alpha, value, false);
+        assertEquals(TypedValue.TYPE_FLOAT, value.type);
+        float expectedSpot = value.getFloat();
+
+        resources.getValue(R.dimen.expected_ambient_shadow_alpha, value, false);
+        assertEquals(TypedValue.TYPE_FLOAT, value.type);
+        float expectedAmbient = value.getFloat();
+
+        assertTrue(expectedSpot > 0);
+        assertTrue(expectedAmbient > 0);
+
+        TypedArray typedArray = context.obtainStyledAttributes(new int[] {
+                android.R.attr.spotShadowAlpha,
+                android.R.attr.ambientShadowAlpha,
+        });
+
+        assertEquals(expectedSpot, typedArray.getFloat(0, 0.0f), 0);
+        assertEquals(expectedAmbient, typedArray.getFloat(1, 0.0f), 0);
+    }
+
+    @Test
+    public void testShadowLayout() {
+        // Use a higher threshold than default value (20), since we also double check gray scale;
+        SamplePointVerifier verifier = createVerifier(0xffe6e6e6,
+                color -> CompareUtils.verifyPixelGrayScale(color, 1));
 
         createTest()
                 .addLayout(R.layout.simple_shadow_layout, null, true/* HW only */)
                 .runWithVerifier(verifier);
     }
+
+    @Test
+    public void testRedSpotShadow() {
+        SamplePointVerifier verifier = createVerifier(0xfff8e6e6,
+                color -> {
+                    if (color == Color.WHITE) return true;
+                    return Color.red(color) > Color.green(color)
+                            && Color.red(color) > Color.blue(color);
+                });
+
+        createTest()
+                .addLayout(R.layout.simple_shadow_layout, view -> {
+                    view.findViewById(R.id.shadow_view).setOutlineSpotShadowColor(Color.RED);
+                }, true/* HW only */)
+                .runWithVerifier(verifier);
+    }
+
+    @Test
+    public void testRedAmbientShadow() {
+        SamplePointVerifier verifier = createVerifier(0xffede6e6,
+                color -> {
+                    if (color == Color.WHITE) return true;
+                    return Color.red(color) > Color.green(color)
+                            && Color.red(color) > Color.blue(color);
+                });
+
+        createTest()
+                .addLayout(R.layout.simple_shadow_layout, view -> {
+                    view.findViewById(R.id.shadow_view).setOutlineAmbientShadowColor(Color.RED);
+                }, true/* HW only */)
+                .runWithVerifier(verifier);
+    }
+
+    @Test
+    public void testRedAmbientBlueSpotShadow() {
+        SamplePointVerifier verifier = createVerifier(0xffede6f8,
+                color -> {
+                    if (color == Color.WHITE) return true;
+                    return Color.red(color) > Color.green(color)
+                            && Color.blue(color) > Color.red(color);
+                });
+
+        createTest()
+                .addLayout(R.layout.simple_shadow_layout, view -> {
+                    View shadow = view.findViewById(R.id.shadow_view);
+                    shadow.setOutlineAmbientShadowColor(Color.RED);
+                    shadow.setOutlineSpotShadowColor(Color.BLUE);
+                }, true/* HW only */)
+                .runWithVerifier(verifier);
+    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index e8a154a..99f2780 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -15,8 +15,6 @@
  */
 package android.uirendering.cts.testinfrastructure;
 
-import com.android.compatibility.common.util.SynchronousPixelCopy;
-
 import android.app.Instrumentation;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -31,12 +29,12 @@
 import android.util.Log;
 import android.view.PixelCopy;
 
+import com.android.compatibility.common.util.SynchronousPixelCopy;
+
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
-import org.junit.Before;
 import org.junit.Rule;
-import org.junit.rules.TestName;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -62,7 +60,7 @@
     private static DrawActivity sActivity;
 
     @Rule
-    public TestName name = new TestName();
+    public Tracer name = new Tracer();
 
     private BitmapAsserter mBitmapAsserter = new BitmapAsserter(this.getClass().getSimpleName(),
             name.getMethodName());
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/Tracer.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/Tracer.java
new file mode 100644
index 0000000..8ea72fc
--- /dev/null
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/Tracer.java
@@ -0,0 +1,47 @@
+/*
+  * Copyright (C) 2018 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.uirendering.cts.testinfrastructure;
+
+import android.os.Trace;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+public class Tracer implements TestRule {
+    private String mName;
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                mName = description.getMethodName();
+                Trace.beginSection(mName);
+                try {
+                    base.evaluate();
+                } finally {
+                    Trace.endSection();
+                }
+            }
+        };
+    }
+
+    public String getMethodName() {
+        return mName;
+    }
+}
diff --git a/tests/tests/widget/res/layout/linearlayout_zero_weight_horizontal.xml b/tests/tests/widget/res/layout/linearlayout_zero_weight_horizontal.xml
new file mode 100644
index 0000000..9178cb7
--- /dev/null
+++ b/tests/tests/widget/res/layout/linearlayout_zero_weight_horizontal.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.
+ -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:id="@+id/container1"
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/view1"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:background="@android:color/holo_green_light">
+            <View
+                android:layout_width="30dp"
+                android:layout_height="10dp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/view2"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:background="@android:color/holo_orange_light">
+            <View
+                android:layout_width="30dp"
+                android:layout_height="10dp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/view3"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content">
+            <View
+                android:layout_width="100dp"
+                android:layout_height="10dp" />
+        </LinearLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/tests/widget/res/layout/linearlayout_zero_weight_vertical.xml b/tests/tests/widget/res/layout/linearlayout_zero_weight_vertical.xml
new file mode 100644
index 0000000..9e50d72
--- /dev/null
+++ b/tests/tests/widget/res/layout/linearlayout_zero_weight_vertical.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 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.
+ -->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <LinearLayout
+        android:id="@+id/container1"
+        android:layout_height="100dp"
+        android:layout_width="wrap_content"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/view1"
+            android:layout_height="0dp"
+            android:layout_width="wrap_content"
+            android:layout_weight="1"
+            android:background="@android:color/holo_green_light">
+            <View
+                android:layout_height="30dp"
+                android:layout_width="10dp"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/view2"
+            android:layout_height="0dp"
+            android:layout_width="wrap_content"
+            android:layout_weight="1"
+            android:background="@android:color/holo_orange_light">
+            <View
+                android:layout_height="30dp"
+                android:layout_width="10dp"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/view3"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content">
+            <View
+                android:layout_height="100dp"
+                android:layout_width="10dp"/>
+        </LinearLayout>
+
+    </LinearLayout>
+
+</FrameLayout>
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 4704e37..b7dbd8e 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -1217,6 +1217,30 @@
                 dividerSize, Color.RED, dividerPadding);
     }
 
+    @Test
+    public void testZeroWeightDistributionHorizontal() throws Throwable {
+        // Ensure that weight is correctly distributed when there is no excess space.
+        final View parent = mActivity.findViewById(android.R.id.content);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
+                () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_horizontal));
+
+        assertEquals(0, mActivity.findViewById(R.id.view1).getWidth());
+        assertEquals(0, mActivity.findViewById(R.id.view2).getWidth());
+        assertEquals(parent.getWidth(), mActivity.findViewById(R.id.view3).getWidth());
+    }
+
+    @Test
+    public void testZeroWeightDistributionVertical() throws Throwable {
+        // Ensure that weight is correctly distributed when there is no excess space.
+        final View parent = mActivity.findViewById(android.R.id.content);
+        WidgetTestUtils.runOnMainAndDrawSync(mActivityRule, parent,
+                () -> mActivity.setContentView(R.layout.linearlayout_zero_weight_vertical));
+
+        assertEquals(0, mActivity.findViewById(R.id.view1).getWidth());
+        assertEquals(0, mActivity.findViewById(R.id.view2).getWidth());
+        assertEquals(parent.getWidth(), mActivity.findViewById(R.id.view3).getWidth());
+    }
+
     private class MockListView extends ListView {
         private final static int DEFAULT_CHILD_BASE_LINE = 1;