Merge "Test newly added batterystats background stats" into oc-dev
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index 9e98b79..070bada 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -63,7 +63,8 @@
     # Not yet mandated tests
     NOT_YET_MANDATED = {
         "scene0": [
-            "test_jitter"
+            "test_jitter",
+            "test_burst_capture"
             ],
         "scene1": [
             "test_ae_af",
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 99a4ee3..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"
@@ -2394,6 +2396,10 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_STATUS" />
                 <category android:name="android.intent.category.DEFAULT"></category>
             </intent-filter>
+            <intent-filter>
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.BYOD_DISK_ENCRYPTION_STATUS" />
+                <category android:name="android.intent.category.DEFAULT"></category>
+            </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_managed_provisioning" />
             <meta-data android:name="test_required_features" android:value="android.software.managed_users:android.software.device_admin" />
         </activity>
@@ -2420,6 +2426,7 @@
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_QUERY" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_REMOVE" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK" />
+                <action android:name="com.android.cts.verifier.managedprovisioning.action.BYOD_CHECK_DISK_ENCRYPTION" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.action.CHECK_INTENT_FILTERS" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_IMAGE" />
                 <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_CAPTURE_AND_CHECK_VIDEO_WITH_EXTRA_OUTPUT" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 02cb70f..1d3ea85 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -2045,7 +2045,33 @@
         The only way to disable the encryption is to factory reset the device.
     </string>
     <string name="provisioning_byod_profileowner">Profile owner installed</string>
-    <string name="provisioning_byod_diskencryption">Full disk encryption enabled</string>
+    <string name="provisioning_byod_disk_encryption">Full disk encryption enabled</string>
+    <string name="provisioning_byod_disk_encryption_default_key_toast">
+        Cannot secure device with screen lock. Please re-run the test if you forgot to select
+        the \"require PIN to boot\" option.
+    </string>
+    <string name="provisioning_byod_disk_encryption_no_pin_toast">
+        No PIN is detected. Please re-run the test if you forgot to set a PIN.
+    </string>
+    <string name="provisioning_byod_set_screen_lock_dialog_message">
+        Next, you will be asked to set a screen lock for the device.\n
+        \n
+        Please set \"1111\" as the new PIN (or any other PIN that you can memorize).
+        You have to enter this PIN again later in order to finish the test.\n
+        \n
+        You may be asked whether the PIN should be required to boot the device. Please answer yes.\n
+        \n
+        Tap Go button to set a new screen lock.
+    </string>
+    <string name="provisioning_byod_remove_screen_lock_dialog_message">
+        The test is almost finished. \n
+        \n
+        Next, you will be asked to remove the screen lock that you just set. Please enter \"1111\"
+        (or your own PIN) when prompted for the old PIN, and do not set any new screen lock. This
+        is to make sure that the device returns to the initial state after this test.\n
+        \n
+        Tap Go button to remove existing screen lock.
+    </string>
     <string name="provisioning_byod_profile_visible">Profile-aware accounts settings</string>
     <string name="provisioning_byod_admin_visible">Profile-aware device administrator settings</string>
     <string name="provisioning_byod_workapps_visible">Badged work apps visible in Launcher</string>
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/audio/peripheralprofile/ProfileManager.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
index 1d585ac..035dc3f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/peripheralprofile/ProfileManager.java
@@ -56,6 +56,10 @@
               "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
               "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000,88200,96000\" />" +
             "</PeripheralProfile>" +
+            "<PeripheralProfile ProfileName=\"AudioBox USB\" ProfileDescription=\"Presonus AudioBox USB\" ProductName=\"USB-Audio - AudioBox USB\">" +
+              "<OutputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+              "<InputDevInfo ChanCounts=\"2\" ChanPosMasks=\"12\" ChanIndexMasks=\"3\" Encodings=\"4\" SampleRates=\"44100,48000\" />" +
+            "</PeripheralProfile>" +
           "</ProfileList>";
 
     // XML Tags and Attributes
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/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index f52d7eb..3b5632b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.verifier.managedprovisioning;
 
+import android.app.KeyguardManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
@@ -23,6 +24,7 @@
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.provider.Settings;
 import android.util.Log;
@@ -30,6 +32,7 @@
 import android.view.View.OnClickListener;
 import android.widget.Toast;
 
+import com.android.compatibility.common.util.PropertyUtil;
 import com.android.cts.verifier.ArrayTestListAdapter;
 import com.android.cts.verifier.DialogTestListActivity;
 import com.android.cts.verifier.R;
@@ -39,9 +42,10 @@
 import com.android.cts.verifier.location.LocationListenerActivity;
 
 /**
- * CTS verifier test for BYOD managed provisioning flow.
- * This activity is responsible for starting the managed provisioning flow and verify the outcome of provisioning.
- * It performs the following verifications:
+ * CTS verifier test for BYOD managed provisioning flow
+ *
+ * This activity is responsible for starting the managed provisioning flow and verify the outcome of
+ * provisioning. It performs the following verifications:
  *   Full disk encryption is enabled.
  *   Profile owner is correctly installed.
  *   Profile owner shows up in the Settings app.
@@ -51,15 +55,20 @@
  */
 public class ByodFlowTestActivity extends DialogTestListActivity {
 
-    private final String TAG = "ByodFlowTestActivity";
+    private static final String TAG = "ByodFlowTestActivity";
     private static ConnectivityManager mCm;
     private static final int REQUEST_MANAGED_PROVISIONING = 0;
     private static final int REQUEST_PROFILE_OWNER_STATUS = 1;
     private static final int REQUEST_INTENT_FILTERS_STATUS = 2;
+    private static final int REQUEST_CHECK_DISK_ENCRYPTION = 3;
+    private static final int REQUEST_SET_LOCK_FOR_ENCRYPTION = 4;
 
     private ComponentName mAdminReceiverComponent;
+    private KeyguardManager mKeyguardManager;
+    private ByodFlowTestHelper mByodFlowTestHelper;
 
     private DialogTestListItem mProfileOwnerInstalled;
+    private DialogTestListItem mDiskEncryptionTest;
     private DialogTestListItem mProfileAccountVisibleTest;
     private DialogTestListItem mDeviceAdminVisibleTest;
     private DialogTestListItem mWorkAppVisibleTest;
@@ -109,9 +118,12 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mByodFlowTestHelper = new ByodFlowTestHelper(this);
         mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+        mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
 
-        enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+        mByodFlowTestHelper.setup();
+
         mPrepareTestButton.setText(R.string.provisioning_byod_start);
         mPrepareTestButton.setOnClickListener(new OnClickListener() {
             @Override
@@ -149,17 +161,24 @@
         switch (requestCode) {
             case REQUEST_MANAGED_PROVISIONING:
                 return;
-            case REQUEST_PROFILE_OWNER_STATUS: {
+            case REQUEST_PROFILE_OWNER_STATUS:
                 // Called after queryProfileOwner()
                 handleStatusUpdate(resultCode, data);
-            } break;
-            case REQUEST_INTENT_FILTERS_STATUS: {
+                break;
+            case REQUEST_CHECK_DISK_ENCRYPTION:
+                // Called after checkDiskEncryption()
+                handleDiskEncryptionStatus(resultCode, data);
+                break;
+            case REQUEST_SET_LOCK_FOR_ENCRYPTION:
+                // Called after handleDiskEncryptionStatus() to set screen lock if necessary
+                handleSetLockForEncryption();
+                break;
+            case REQUEST_INTENT_FILTERS_STATUS:
                 // Called after checkIntentFilters()
                 handleIntentFiltersStatus(resultCode);
-            } break;
-            default: {
+                break;
+            default:
                 super.handleActivityResult(requestCode, resultCode, data);
-            }
         }
     }
 
@@ -174,8 +193,7 @@
     public void finish() {
         // Pass and fail buttons are known to call finish() when clicked, and this is when we want to
         // clean up the provisioned profile.
-        Utils.requestDeleteManagedProfile(this);
-        enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+        mByodFlowTestHelper.tearDown();
         super.finish();
     }
 
@@ -190,6 +208,15 @@
             }
         };
 
+        mDiskEncryptionTest = new DialogTestListItem(this,
+                R.string.provisioning_byod_disk_encryption,
+                "BYOD_DiskEncryptionTest") {
+            @Override
+            public void performTest(DialogTestListActivity activity) {
+                checkDiskEncryption();
+            }
+        };
+
         /*
          * To keep the image in this test up to date, use the instructions in
          * {@link ByodIconSamplerActivity}.
@@ -399,6 +426,11 @@
                 policyTransparencyTestIntent, null);
 
         adapter.add(mProfileOwnerInstalled);
+        if (PropertyUtil.getFirstApiLevel() >= VERSION_CODES.N_MR1) {
+            // Previous devices were not required to entangle the disk encryption key with lock
+            // screen credentials.
+            adapter.add(mDiskEncryptionTest);
+        }
 
         // Badge related tests
         adapter.add(mWorkAppVisibleTest);
@@ -605,6 +637,59 @@
         }
     }
 
+    private void checkDiskEncryption() {
+        try {
+            Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
+            startActivityForResult(intent, REQUEST_CHECK_DISK_ENCRYPTION);
+        } catch (ActivityNotFoundException e) {
+            Log.d(TAG, "checkDiskEncryption: ActivityNotFoundException", e);
+            setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+            Utils.showToast(this, R.string.provisioning_byod_no_activity);
+        }
+    }
+
+    private void handleDiskEncryptionStatus(int resultCode, Intent data) {
+        if (resultCode != RESULT_OK || data == null) {
+            Log.e(TAG, "Failed to get result for disk encryption, result code: " + resultCode);
+            setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+            return;
+        }
+
+        final int status = data.getIntExtra(ByodHelperActivity.EXTRA_ENCRYPTION_STATUS,
+                DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED);
+        switch (status) {
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE:
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER:
+                setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_PASSED);
+                break;
+            case DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY:
+                if (!mKeyguardManager.isDeviceSecure()) {
+                    Utils.setScreenLock(this, REQUEST_SET_LOCK_FOR_ENCRYPTION);
+                    return;
+                }
+                Log.e(TAG, "Disk encryption key is not entangled with lock screen credentials");
+                Toast.makeText(this, R.string.provisioning_byod_disk_encryption_default_key_toast,
+                        Toast.LENGTH_LONG).show();
+                // fall through
+            default:
+                setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+        }
+
+        if (mKeyguardManager.isDeviceSecure()) {
+            Utils.removeScreenLock(this);
+        }
+    }
+
+    private void handleSetLockForEncryption() {
+        if (mKeyguardManager.isDeviceSecure()) {
+            checkDiskEncryption();
+        } else {
+            setTestResult(mDiskEncryptionTest, TestResult.TEST_RESULT_FAILED);
+            Toast.makeText(this, R.string.provisioning_byod_disk_encryption_no_pin_toast,
+                    Toast.LENGTH_LONG).show();
+        }
+    }
+
     private void checkIntentFilters() {
         try {
             // Enable component HandleIntentActivity before intent filters are checked.
@@ -640,29 +725,6 @@
                 intentFiltersSet ? TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
     }
 
-    /**
-     *  Disable or enable app components in the current profile. When they are disabled only the
-     * counterpart in the other profile can respond (via cross-profile intent filter).
-     * @param enabledState {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} or
-     *                      {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
-     */
-    private void enableComponent(final int enabledState) {
-        final String[] components = {
-            ByodHelperActivity.class.getName(),
-            WorkStatusTestActivity.class.getName(),
-            PermissionLockdownTestActivity.ACTIVITY_ALIAS,
-            AuthenticationBoundKeyTestActivity.class.getName(),
-            VpnTestActivity.class.getName(),
-            RecentsRedactionActivity.class.getName(),
-            CommandReceiverActivity.class.getName(),
-            SetSupportMessageActivity.class.getName()
-        };
-        for (String component : components) {
-            getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
-                    enabledState, PackageManager.DONT_KILL_APP);
-        }
-    }
-
     private void setHandleIntentActivityEnabledSetting(final int enableState) {
         getPackageManager().setComponentEnabledSetting(
             new ComponentName(ByodFlowTestActivity.this, HandleIntentActivity.class.getName()),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
new file mode 100644
index 0000000..d1308ad
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestHelper.java
@@ -0,0 +1,51 @@
+package com.android.cts.verifier.managedprovisioning;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+public class ByodFlowTestHelper {
+    private Context mContext;
+    private PackageManager mPackageManager;
+
+    public ByodFlowTestHelper(Context context) {
+        this.mContext = context;
+        this.mPackageManager = mContext.getPackageManager();
+    }
+
+    public void setup() {
+        setComponentsEnabledState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+    }
+
+    /**
+     * Clean up things. This has to be working even it is called multiple times.
+     */
+    public void tearDown() {
+        Utils.requestDeleteManagedProfile(mContext);
+        setComponentsEnabledState(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+    }
+
+    /**
+     * Disable or enable app components in the current profile. When they are disabled only the
+     * counterpart in the other profile can respond (via cross-profile intent filter).
+     *
+     * @param enabledState {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} or
+     *                     {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
+     */
+    private void setComponentsEnabledState(final int enabledState) {
+        final String[] components = {
+                ByodHelperActivity.class.getName(),
+                WorkStatusTestActivity.class.getName(),
+                PermissionLockdownTestActivity.ACTIVITY_ALIAS,
+                AuthenticationBoundKeyTestActivity.class.getName(),
+                VpnTestActivity.class.getName(),
+                RecentsRedactionActivity.class.getName(),
+                CommandReceiverActivity.class.getName(),
+                SetSupportMessageActivity.class.getName()
+        };
+        for (String component : components) {
+            mPackageManager.setComponentEnabledSetting(new ComponentName(mContext, component),
+                    enabledState, PackageManager.DONT_KILL_APP);
+        }
+    }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 6ad1634..e9b6523 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -81,6 +81,15 @@
     public static final String EXTRA_PROVISIONED = "extra_provisioned";
     public static final String EXTRA_PARAMETER_1 = "extra_parameter_1";
 
+    // Primary -> managed intent: check if the disk of the device is encrypted
+    public static final String ACTION_CHECK_DISK_ENCRYPTION =
+            "com.android.cts.verifier.managedprovisioning.action.BYOD_CHECK_DISK_ENCRYPTION";
+    // Managed -> primary intent: update disk encryption status in primary's CtsVerifier
+    public static final String ACTION_DISK_ENCRYPTION_STATUS =
+            "com.android.cts.verifier.managedprovisioning.action.BYOD_DISK_ENCRYPTION_STATUS";
+    // Int extra field indicating the encryption status of the device storage
+    public static final String EXTRA_ENCRYPTION_STATUS = "extra_encryption_status";
+
     // Primary -> managed intent: set unknown sources restriction and install package
     public static final String ACTION_INSTALL_APK = "com.android.cts.verifier.managedprovisioning.BYOD_INSTALL_APK";
     public static final String EXTRA_ALLOW_NON_MARKET_APPS = "allow_non_market_apps";
@@ -212,6 +221,11 @@
                 mDevicePolicyManager.wipeData(0);
                 showToast(R.string.provisioning_byod_profile_deleted);
             }
+        } else if (action.equals(ACTION_CHECK_DISK_ENCRYPTION)) {
+            final int status = mDevicePolicyManager.getStorageEncryptionStatus();
+            final Intent response = new Intent(ACTION_DISK_ENCRYPTION_STATUS)
+                    .putExtra(EXTRA_ENCRYPTION_STATUS, status);
+            setResult(RESULT_OK, response);
         } else if (action.equals(ACTION_INSTALL_APK)) {
             boolean allowNonMarket = intent.getBooleanExtra(EXTRA_ALLOW_NON_MARKET_APPS, false);
             boolean wasAllowed = !isUnknownSourcesRestrictionSet();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index a59abbc..1c40ac1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -85,6 +85,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(ByodHelperActivity.ACTION_QUERY_PROFILE_OWNER);
         filter.addAction(ByodHelperActivity.ACTION_REMOVE_MANAGED_PROFILE);
+        filter.addAction(ByodHelperActivity.ACTION_CHECK_DISK_ENCRYPTION);
         filter.addAction(ByodHelperActivity.ACTION_INSTALL_APK);
         filter.addAction(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
         filter.addAction(ByodHelperActivity.ACTION_CAPTURE_AND_CHECK_IMAGE);
@@ -122,6 +123,7 @@
         // Work -> primary direction
         filter = new IntentFilter();
         filter.addAction(ByodHelperActivity.ACTION_PROFILE_OWNER_STATUS);
+        filter.addAction(ByodHelperActivity.ACTION_DISK_ENCRYPTION_STATUS);
         filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_PERSONAL);
         filter.addAction(LocationListenerActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES);
         dpm.addCrossProfileIntentFilter(getWho(context), filter,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index 67e7fd4..0cae6be 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -78,6 +78,10 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        // Tidy up in case previous run crashed.
+        new ByodFlowTestHelper(this).tearDown();
+
         if (ACTION_CHECK_DEVICE_OWNER.equals(getIntent().getAction())) {
             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
                     Context.DEVICE_POLICY_SERVICE);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 1d23175..7ab8e7e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -80,6 +80,9 @@
             return;
         }
 
+        // Tidy up in case previous run crashed.
+        new ByodFlowTestHelper(this).tearDown();
+
         setContentView(R.layout.requesting_bugreport_device_owner);
         setInfoResources(R.string.device_owner_requesting_bugreport_tests,
                 R.string.device_owner_requesting_bugreport_tests_info, 0);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index acd346a..476eb80 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -29,6 +29,7 @@
 import android.media.audiofx.AudioEffect;
 import android.net.Uri;
 import android.nfc.cardemulation.CardEmulation;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -67,7 +68,6 @@
                 new Intent(AlarmClock.ACTION_SET_TIMER),
                 new Intent(AlarmClock.ACTION_SHOW_ALARMS),
                 new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS),
-                new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS),
                 new Intent(Settings.ACTION_CAPTIONING_SETTINGS),
                 new Intent(Settings.ACTION_DATE_SETTINGS),
                 new Intent(Settings.ACTION_DEVICE_INFO_SETTINGS),
@@ -266,6 +266,11 @@
             notForwardedIntentsFromManaged.add(
                     new Intent(Settings.ACTION_PRINT_SETTINGS));
         }
+
+        if (Build.TYPE.equals("user")) {
+            forwardedIntentsFromManaged.add(
+                    new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS));
+        }
     }
 
     public boolean checkCrossProfileIntentFilters(int flag) {
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/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
index 92bb555..f12d698 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/Utils.java
@@ -17,19 +17,20 @@
 package com.android.cts.verifier.managedprovisioning;
 
 import android.app.Activity;
+import android.app.AlertDialog;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
-import android.widget.Toast;
 import android.content.ActivityNotFoundException;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.util.Log;
+import android.widget.Toast;
 
 import com.android.cts.verifier.IntentDrivenTestActivity;
 import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
-import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.TestListAdapter.TestListItem;
 
@@ -58,9 +59,8 @@
     static void requestDeleteManagedProfile(Context context) {
         try {
             Intent intent = new Intent(ByodHelperActivity.ACTION_REMOVE_MANAGED_PROFILE);
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             context.startActivity(intent);
-            String message = context.getString(R.string.provisioning_byod_delete_profile);
-            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
         }
         catch (ActivityNotFoundException e) {
             Log.d(TAG, "requestDeleteProfileOwner: ActivityNotFoundException", e);
@@ -93,4 +93,41 @@
     static void showToast(Context context, int messageId) {
         Toast.makeText(context, messageId, Toast.LENGTH_SHORT).show();
     }
+
+    /**
+     * Prompts the tester to set a screen lock credential, or change it if one exists.
+     *
+     * An instruction dialog is shown before the tester is sent to the ChooseLockGeneric activity
+     * in Settings.
+     *
+     * @param activity The calling activity where the result is handled
+     * @param requestCode The callback request code when the lock is set
+     */
+    static void setScreenLock(Activity activity, int requestCode) {
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+        new AlertDialog.Builder(activity)
+                .setTitle(R.string.provisioning_byod)
+                .setMessage(R.string.provisioning_byod_set_screen_lock_dialog_message)
+                .setPositiveButton(R.string.go_button_text, (DialogInterface dialog, int which) ->
+                        activity.startActivityForResult(intent, requestCode))
+                .show();
+    }
+
+    /**
+     * Prompts the tester to remove the current screen lock credential.
+     *
+     * An instruction dialog is shown before the tester is sent to the ChooseLockGeneric activity
+     * in Settings.
+     *
+     * @param activity The calling activity
+     */
+    static void removeScreenLock(Activity activity) {
+        final Intent intent = new Intent(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
+        new AlertDialog.Builder(activity)
+                .setTitle(R.string.provisioning_byod)
+                .setMessage(R.string.provisioning_byod_remove_screen_lock_dialog_message)
+                .setPositiveButton(R.string.go_button_text, (DialogInterface dialog, int which) ->
+                        activity.startActivity(intent))
+                .show();
+    }
 }
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
index bc30eefe..792c88a 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
@@ -64,7 +64,11 @@
     private void collectFileDetails(DeviceInfoStore store, String path, String suffix)
             throws Exception {
         File dir = new File(path);
-        for (File file : dir.listFiles()) {
+        File[] files = dir.listFiles();
+        if (files == null) {
+            return;
+        }
+        for (File file : files) {
             String name = file.getName();
             if (file.isFile() && name.endsWith(suffix)) {
                 String sha1 = "unknown";
diff --git a/common/host-side/tradefed/res/report/compatibility_failures.xsl b/common/host-side/tradefed/res/report/compatibility_failures.xsl
index be65b91..ef067f2 100644
--- a/common/host-side/tradefed/res/report/compatibility_failures.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_failures.xsl
@@ -82,12 +82,6 @@
                             </td>
                         </tr>
                         <tr>
-                            <td class="rowtitle">Tests Not Executed</td>
-                            <td>
-                                <xsl:value-of select="Result/Summary/@not_executed"/>
-                            </td>
-                        </tr>
-                        <tr>
                             <td class="rowtitle">Modules Done</td>
                             <td>
                                 <xsl:value-of select="Result/Summary/@modules_done"/>
@@ -134,8 +128,8 @@
                             <th>Module</th>
                             <th>Passed</th>
                             <th>Failed</th>
-                            <th>Not Executed</th>
                             <th>Total Tests</th>
+                            <th>Done</th>
                         </tr>
                         <xsl:for-each select="Result/Module">
                             <tr>
@@ -155,10 +149,10 @@
                                     <xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(TestCase/Test[@result = 'not_executed'])"/>
+                                    <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(TestCase/Test[@result = 'fail']) + @pass + count(TestCase/Test[@result = 'not_executed']) "/>
+                                    <xsl:value-of select="@done"/>
                                 </td>
                             </tr>
                         </xsl:for-each> <!-- end Module -->
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsd b/common/host-side/tradefed/res/report/compatibility_result.xsd
index 9b2758c..95bae85 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsd
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsd
@@ -36,7 +36,6 @@
 
   <xs:complexType name="summaryType">
     <xs:attribute name="failed" type="xs:integer"/>
-    <xs:attribute name="not_executed" type="xs:integer"/>
     <xs:attribute name="pass" type="xs:integer"/>
   </xs:complexType>
 
@@ -121,7 +120,6 @@
     <xs:restriction base="xs:string">
       <xs:enumeration value="pass"/>
       <xs:enumeration value="fail"/>
-      <xs:enumeration value="not_executed"/>
     </xs:restriction>
   </xs:simpleType>
-</xs:schema>
\ No newline at end of file
+</xs:schema>
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index b8c1245..a0c337a7 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -82,12 +82,6 @@
                             </td>
                         </tr>
                         <tr>
-                            <td class="rowtitle">Tests Not Executed</td>
-                            <td>
-                                <xsl:value-of select="Result/Summary/@not_executed"/>
-                            </td>
-                        </tr>
-                        <tr>
                             <td class="rowtitle">Modules Done</td>
                             <td>
                                 <xsl:value-of select="Result/Summary/@modules_done"/>
@@ -134,8 +128,8 @@
                             <th>Module</th>
                             <th>Passed</th>
                             <th>Failed</th>
-                            <th>Not Executed</th>
                             <th>Total Tests</th>
+                            <th>Done</th>
                         </tr>
                         <xsl:for-each select="Result/Module">
                             <tr>
@@ -150,10 +144,10 @@
                                     <xsl:value-of select="count(TestCase/Test[@result = 'fail'])"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="@not_executed"/>
+                                    <xsl:value-of select="count(TestCase/Test)"/>
                                 </td>
                                 <td>
-                                    <xsl:value-of select="count(TestCase/Test) + @not_executed"/>
+                                    <xsl:value-of select="@done"/>
                                 </td>
                             </tr>
                         </xsl:for-each> <!-- end Module -->
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..6fe1155 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;
@@ -361,7 +361,6 @@
                         Integer.toString(i),
                         Integer.toString(result.countResults(TestStatus.PASS)),
                         Integer.toString(result.countResults(TestStatus.FAIL)),
-                        Integer.toString(result.getNotExecuted()),
                         moduleProgress,
                         CompatibilityBuildHelper.getDirSuffix(result.getStartTime()),
                         result.getTestPlan(),
@@ -372,9 +371,8 @@
             }
 
             // add the table header to the beginning of the list
-            table.add(0, Arrays.asList("Session", "Pass", "Fail", "Not Executed",
-                    "Modules Complete", "Result Directory", "Test Plan", "Device serial(s)",
-                    "Build ID", "Product"));
+            table.add(0, Arrays.asList("Session", "Pass", "Fail", "Modules Complete",
+                "Result Directory", "Test Plan", "Device serial(s)", "Build ID", "Product"));
             tableFormatter.displayTable(table, new PrintWriter(System.out, true));
         } else {
             printLine(String.format("No results found"));
@@ -404,7 +402,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 fc57e22..ad7cf47 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;
@@ -89,8 +89,8 @@
 
     @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\".",
+            + ", retry tests of a certain status. Possible values include \"failed\", "
+            + "\"not_executed\", and \"custom\".",
             importance = Importance.IF_UNSET)
     private RetryType mRetryType = null;
 
@@ -106,6 +106,9 @@
     @Option(name = "use-log-saver", description = "Also saves generated result with log saver")
     private boolean mUseLogSaver = false;
 
+    @Option(name = "compress-logs", description = "Whether logs will be saved with compression")
+    private boolean mCompressLogs = true;
+
     private CompatibilityBuildHelper mBuildHelper;
     private File mResultDir = null;
     private File mLogDir = null;
@@ -368,23 +371,10 @@
     public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
         mCurrentModuleResult.inProgress(false);
         mCurrentModuleResult.addRuntime(elapsedTime);
-        if (!mModuleWasDone) {
-            // Not executed count now represents an upper-bound for a fix to b/33211104.
-            // Only setNotExecuted this number if the module has already been completely executed.
-            int testCountDiff = Math.max(mTotalTestsInModule - mCurrentTestNum, 0);
-            if (isShardResultReporter()) {
-                // reset value, which is added to total count for master shard upon merge
-                mCurrentModuleResult.setNotExecuted(testCountDiff);
-            } else {
-                // increment value for master shard
-                mCurrentModuleResult.setNotExecuted(mCurrentModuleResult.getNotExecuted()
-                        + testCountDiff);
-            }
-            if (mCanMarkDone) {
-                // Only mark module done if status of the invocation allows it (mCanMarkDone) and
-                // if module has not already been marked done.
-                mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
-            }
+        if (!mModuleWasDone && mCanMarkDone) {
+            // Only mark module done if status of the invocation allows it (mCanMarkDone) and
+            // if module has not already been marked done.
+            mCurrentModuleResult.setDone(mCurrentTestNum >= mTotalTestsInModule);
         }
         if (isShardResultReporter()) {
             // Forward module results to the master.
@@ -514,6 +504,7 @@
             } else {
                 info("Test Result: %s", resultFile.getCanonicalPath());
             }
+            info("Test Logs: %s", mLogDir.getCanonicalPath());
             debug("Full Result: %s", zippedResults.getCanonicalPath());
 
             saveLog(resultFile, zippedResults);
@@ -525,11 +516,10 @@
             CLog.e(e);
         }
         // print the run results last.
-        info("Invocation finished in %s. PASSED: %d, FAILED: %d, NOT EXECUTED: %d, MODULES: %s",
+        info("Invocation finished in %s. PASSED: %d, FAILED: %d, MODULES: %s",
                 TimeUtil.formatElapsedTime(elapsedTime),
                 mResult.countResults(TestStatus.PASS),
                 mResult.countResults(TestStatus.FAIL),
-                mResult.getNotExecuted(),
                 moduleProgress);
     }
 
@@ -554,7 +544,12 @@
             return;
         }
         try {
-            File logFile = mTestLogSaver.saveAndZipLogData(name, type, stream.createInputStream());
+            File logFile = null;
+            if (mCompressLogs) {
+                logFile = mTestLogSaver.saveAndGZipLogData(name, type, stream.createInputStream());
+            } else {
+                logFile = mTestLogSaver.saveLogData(name, type, stream.createInputStream());
+            }
             debug("Saved logs for %s in %s", name, logFile.getAbsolutePath());
         } catch (IOException e) {
             warn("Failed to write log for %s", name);
@@ -677,6 +672,7 @@
             return true; // always allow modules to be marked done if not retry
         }
         return !(RetryType.FAILED.equals(mRetryType)
+                || RetryType.CUSTOM.equals(mRetryType)
                 || args.contains(CompatibilityTest.INCLUDE_FILTER_OPTION)
                 || args.contains(CompatibilityTest.EXCLUDE_FILTER_OPTION)
                 || args.contains(CompatibilityTest.SUBPLAN_OPTION)
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/targetprep/NetworkConnectivityChecker.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
index 5479474..d77d931 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/NetworkConnectivityChecker.java
@@ -19,6 +19,7 @@
 import com.android.compatibility.common.util.MonitoringUtils;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.suite.checker.ISystemStatusChecker;
 
 /**
@@ -26,14 +27,23 @@
  */
 public class NetworkConnectivityChecker implements ISystemStatusChecker {
 
+    // Only report is as failed (capture bugreport) when status goes from pass-> fail
+    private boolean mIsFailed = false;
+
     /**
      * {@inheritDoc}
      */
     @Override
     public boolean postExecutionCheck(ITestDevice device) throws DeviceNotAvailableException {
         if (!MonitoringUtils.checkDeviceConnectivity(device)) {
+            if (mIsFailed) {
+                CLog.w("NetworkConnectivityChecker is still failing.");
+                return true;
+            }
+            mIsFailed = true;
             return false;
         }
+        mIsFailed = false;
         return true;
     }
 }
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..cd80500 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.tradefed.util.UniqueModuleCountUtil;
 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;
@@ -56,15 +57,11 @@
 import com.android.tradefed.util.ArrayUtil;
 import com.android.tradefed.util.StreamUtil;
 import com.android.tradefed.util.TimeUtil;
-import com.android.tradefed.util.xml.AbstractXmlParser.ParseException;
 
 import com.google.common.annotations.VisibleForTesting;
 
 import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -153,10 +150,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.",
@@ -165,7 +158,7 @@
 
     @Option(name = RETRY_TYPE_OPTION,
             description = "used with " + RETRY_OPTION + ", retry tests of a certain status. "
-            + "Possible values include \"failed\" and \"not_executed\".",
+            + "Possible values include \"failed\", \"not_executed\", and \"custom\".",
             importance = Importance.IF_UNSET)
     private RetryType mRetryType = null;
 
@@ -360,6 +353,15 @@
 
                     // Add the entire list of modules to the CompatibilityBuildHelper for reporting
                     mBuildHelper.setModuleIds(mModuleRepo.getModuleIds());
+
+                    int count = UniqueModuleCountUtil.countUniqueModules(
+                            mModuleRepo.getTokenModules()) +
+                            UniqueModuleCountUtil.countUniqueModules(
+                                    mModuleRepo.getNonTokenModules());
+                    CLog.logAndDisplay(LogLevel.INFO, "========================================");
+                    CLog.logAndDisplay(LogLevel.INFO, "Starting a run with %s unique modules.",
+                            count);
+                    CLog.logAndDisplay(LogLevel.INFO, "========================================");
                 } else {
                     CLog.d("ModuleRepo already initialized.");
                 }
@@ -386,8 +388,10 @@
                 }
                 return;
             } else {
-                CLog.logAndDisplay(LogLevel.INFO, "Starting %d module%s on %s", moduleCount,
-                        (moduleCount > 1) ? "s" : "", mDevice.getSerialNumber());
+                int uniqueModuleCount = UniqueModuleCountUtil.countUniqueModules(modules);
+                CLog.logAndDisplay(LogLevel.INFO, "Starting %d test sub-module%s on %s",
+                        uniqueModuleCount, (uniqueModuleCount > 1) ? "s" : "",
+                                mDevice.getSerialNumber());
             }
 
             if (mRebootBeforeTest) {
@@ -671,113 +675,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/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 794e45e..ea76919 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -18,6 +18,7 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.compatibility.common.tradefed.result.TestRunHandler;
 import com.android.compatibility.common.tradefed.util.LinearPartition;
+import com.android.compatibility.common.tradefed.util.UniqueModuleCountUtil;
 import com.android.compatibility.common.util.TestFilter;
 import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.build.IBuildInfo;
@@ -491,14 +492,19 @@
             if (mInitCount == (mTotalShards - 1) &&
                     mTokenModuleScheduled.size() != mTokenModules.size()) {
                 mTokenModules.removeAll(mTokenModuleScheduled);
-                CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+                if (mTotalShards != 1) {
+                    // Only print the warnings if we are sharding.
+                    CLog.e("Could not find any token for %s. Adding to last shard.", mTokenModules);
+                }
                 modules.addAll(mTokenModules);
             }
             mInitCount++;
         }
         Collections.sort(modules, new ExecutionOrderComparator());
-        CLog.logAndDisplay(LogLevel.INFO, "%s running %s modules, expected to complete in %s: %s",
-                serial, modules.size(), TimeUtil.formatElapsedTime(estimatedTime), modules);
+        int uniqueCount = UniqueModuleCountUtil.countUniqueModules(modules);
+        CLog.logAndDisplay(LogLevel.INFO, "%s running %s test sub-modules, expected to complete "
+                + "in %s.", serial, uniqueCount, TimeUtil.formatElapsedTime(estimatedTime));
+        CLog.d("module list for this shard: %s", modules);
         LinkedList<IModuleDef> tests = new LinkedList<>();
         tests.addAll(modules);
         return tests;
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..4ff3953
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/RetryFilterHelper.java
@@ -0,0 +1,323 @@
+/*
+ * 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\", "
+            + "\"not_executed\", and \"custom\".",
+            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/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
new file mode 100644
index 0000000..e801ab3
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtil.java
@@ -0,0 +1,42 @@
+/*
+ * 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.IModuleDef;
+
+import java.util.HashSet;
+import java.util.List;
+
+/**
+ * Utility to count the number of unique module from list of {@link IModuleDef}.
+ */
+public class UniqueModuleCountUtil {
+
+    /**
+     * Count the number of unique modules within the list using module id. If two IModuleDef have
+     * the same id, they are part of the same module.
+     *
+     * @param listModules list of {@link IModuleDef} to count from
+     * @return the count of unique module.
+     */
+    public static int countUniqueModules(List<IModuleDef> listModules) {
+        HashSet<String> uniqueNames = new HashSet<>();
+        for (IModuleDef subModule : listModules) {
+            uniqueNames.add(subModule.getId());
+        }
+        return uniqueNames.size();
+    }
+}
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..4e7c8c2 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,8 @@
 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 com.android.compatibility.common.tradefed.util.UniqueModuleCountUtilTest;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -67,7 +69,7 @@
     ConsoleReporterTest.class,
     MetadataReporterTest.class,
     ResultReporterTest.class,
-    SubPlanCreatorTest.class,
+    SubPlanHelperTest.class,
 
     // targetprep
     PropertyCheckTest.class,
@@ -84,6 +86,8 @@
     // util
     CollectorUtilTest.class,
     OptionHelperTest.class,
+    RetryFilterHelperTest.class,
+    UniqueModuleCountUtilTest.class,
 })
 public class UnitTests {
     // empty on purpose
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
index c8896a96..8ef909e 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/IntegrationTest.java
@@ -185,7 +185,6 @@
         mReporter.invocationEnded(500);
         EasyMock.verify(mMockDevice, mMockBuildInfo);
         IInvocationResult result = mReporter.getResult();
-        assertEquals(0, result.getNotExecuted());
         assertEquals(2, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         assertEquals(1, result.getModules().size());
@@ -212,7 +211,6 @@
         mReporter.invocationEnded(500);
         EasyMock.verify(mMockDevice, mMockBuildInfo);
         IInvocationResult result = mReporter.getResult();
-        assertEquals(1, result.getNotExecuted());
         assertEquals(1, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         // Module should not be seen as complete.
@@ -243,7 +241,6 @@
         EasyMock.verify(mMockDevice, mMockBuildInfo);
         IInvocationResult result = mReporter.getResult();
         // FIXME: All tests should be marked as executed and not aggregating the count.
-        assertEquals(3, result.getNotExecuted());
         assertEquals(2, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         // FIXME: Module should be complete since all its test have run.
@@ -283,7 +280,6 @@
         mReporter.invocationEnded(500);
 
         IInvocationResult result = mReporter.getResult();
-        assertEquals(1, result.getNotExecuted());
         assertEquals(1, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         // Module should not be seen as complete.
@@ -313,7 +309,6 @@
         result = mReporter.getResult();
         // FIXME: We should only have 1 not_executed in the retry too. They should not aggregate
         // from one run to another.
-        assertEquals(2, result.getNotExecuted());
         assertEquals(1, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         // Module should not be seen as complete.
@@ -352,7 +347,6 @@
         mReporter.invocationEnded(500);
 
         IInvocationResult result = mReporter.getResult();
-        assertEquals(1, result.getNotExecuted());
         assertEquals(1, result.countResults(TestStatus.PASS));
         assertEquals(1, result.countResults(TestStatus.FAIL));
         // Module should not be seen as complete.
@@ -386,7 +380,6 @@
 
         // Check retry results
         result = mReporter.getResult();
-        assertEquals(0, result.getNotExecuted());
         assertEquals(3, result.countResults(TestStatus.PASS));
         assertEquals(0, result.countResults(TestStatus.FAIL));
         // Module should be marked as complete after retry.
@@ -489,7 +482,6 @@
         EasyMock.verify(mMockDevice, mMockBuildInfo);
         // Check aggregated results to make sure it's consistent.
         IInvocationResult result = mReporter.getResult();
-        assertEquals(0, result.getNotExecuted());
         assertEquals(4, result.countResults(TestStatus.PASS));
         assertEquals(4, result.countResults(TestStatus.FAIL));
         assertEquals(2, result.getModules().size());
@@ -540,7 +532,6 @@
         EasyMock.verify(mMockDevice, mMockBuildInfo);
         // Check aggregated results to make sure it's consistent.
         IInvocationResult result = mReporter.getResult();
-        assertEquals(4, result.getNotExecuted());
         assertEquals(4, result.countResults(TestStatus.PASS));
         assertEquals(4, result.countResults(TestStatus.FAIL));
         assertEquals(2, result.getModules().size());
@@ -592,7 +583,6 @@
         EasyMock.verify(mMockDevice, mMockBuildInfo);
 
         IInvocationResult result = mReporter.getResult();
-        assertEquals(0, result.getNotExecuted());
         assertEquals(2, result.countResults(TestStatus.PASS));
         assertEquals(2, result.countResults(TestStatus.FAIL));
         // FIXME: Only one module should be expected since within the one shard requested to run
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
index 763acb7..23fcb9a 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -93,7 +93,6 @@
         mInvocationResult = resultReporter.getResult();
         mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
         mModuleResult.setDone(true);
-        mModuleResult.setNotExecuted(0);
         ICaseResult caseResult = mModuleResult.getOrCreateResult("Case-1");
         ITestResult test1 = caseResult.getOrCreateResult("Test1");
         test1.passed(mReportLog);
@@ -103,7 +102,6 @@
         IModuleResult moduleResult2 = mInvocationResult.getOrCreateModule("Module-2");
         ICaseResult caseResult2 = moduleResult2.getOrCreateResult("Case-2");
         mModuleResult.setDone(false);
-        mModuleResult.setNotExecuted(1);
         ITestResult test3 = caseResult2.getOrCreateResult("Test3");
         test3.passed(mReportLog);
 
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..db6ca6e 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);
@@ -137,7 +137,6 @@
         moduleATest1.setResultStatus(TestStatus.PASS);
         ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
         moduleATest2.setResultStatus(null); // not executed test
-        moduleA.setNotExecuted(1);
 
         IModuleResult moduleB = result.getOrCreateModule(ID_B);
         moduleB.setDone(true);
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/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
new file mode 100644
index 0000000..799cff3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/util/UniqueModuleCountUtilTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.compatibility.common.tradefed.testtype.ModuleDef;
+import com.android.compatibility.common.tradefed.testtype.TestStub;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.testtype.Abi;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Unit tests for {@link UniqueModuleCountUtil}.
+ */
+public class UniqueModuleCountUtilTest {
+
+    @Test
+    public void testCountEmptyList() {
+        List<IModuleDef> emptyList = new ArrayList<>();
+        assertEquals(0, UniqueModuleCountUtil.countUniqueModules(emptyList));
+    }
+
+    @Test
+    public void testCount_2uniquesModules() {
+        List<IModuleDef> list = new ArrayList<>();
+        list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        assertEquals(2, UniqueModuleCountUtil.countUniqueModules(list));
+    }
+
+    @Test
+    public void testCount_2subModules() {
+        List<IModuleDef> list = new ArrayList<>();
+        list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        assertEquals(1, UniqueModuleCountUtil.countUniqueModules(list));
+    }
+
+    @Test
+    public void testCount_mix() {
+        List<IModuleDef> list = new ArrayList<>();
+        list.add(new ModuleDef("moduleA", new Abi("arm64", "64"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleB", new Abi("arm64", "64"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleB", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleC", new Abi("arm64", "64"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleA", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        list.add(new ModuleDef("moduleC", new Abi("arm32", "32"), new TestStub(),
+                new ArrayList<ITargetPreparer>()));
+        assertEquals(6, UniqueModuleCountUtil.countUniqueModules(list));
+    }
+}
diff --git a/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
index 32fa532..ce39f38 100644
--- a/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
+++ b/common/util/src/com/android/compatibility/common/util/ChecksumReporter.java
@@ -331,7 +331,6 @@
         sb.append(buildFingerprint).append(SEPARATOR)
                 .append(module.getId()).append(SEPARATOR)
                 .append(module.isDone()).append(SEPARATOR)
-                .append(module.getNotExecuted()).append(SEPARATOR)
                 .append(module.countResults(TestStatus.FAIL));
         return sb.toString();
     }
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index 6306287..5f88bcd 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -93,7 +93,6 @@
     private static final String MODULES_DONE_ATTR = "modules_done";
     private static final String MODULES_TOTAL_ATTR = "modules_total";
     private static final String NAME_ATTR = "name";
-    private static final String NOT_EXECUTED_ATTR = "not_executed";
     private static final String OS_ARCH_ATTR = "os_arch";
     private static final String OS_NAME_ATTR = "os_name";
     private static final String OS_VERSION_ATTR = "os_version";
@@ -210,9 +209,6 @@
                 boolean done = Boolean.parseBoolean(parser.getAttributeValue(NS, DONE_ATTR));
                 IModuleResult module = invocation.getOrCreateModule(moduleId);
                 module.initializeDone(done);
-                int notExecuted = Integer.parseInt(
-                        parser.getAttributeValue(NS, NOT_EXECUTED_ATTR));
-                module.setNotExecuted(notExecuted);
                 long runtime = Long.parseLong(parser.getAttributeValue(NS, RUNTIME_ATTR));
                 module.addRuntime(runtime);
                 while (parser.nextTag() == XmlPullParser.START_TAG) {
@@ -300,7 +296,6 @@
                     throws IOException, XmlPullParserException {
         int passed = result.countResults(TestStatus.PASS);
         int failed = result.countResults(TestStatus.FAIL);
-        int notExecuted = result.getNotExecuted();
         File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
         OutputStream stream = new FileOutputStream(resultFile);
         XmlSerializer serializer = XmlPullParserFactory.newInstance(TYPE, null).newSerializer();
@@ -371,7 +366,6 @@
         serializer.startTag(NS, SUMMARY_TAG);
         serializer.attribute(NS, PASS_ATTR, Integer.toString(passed));
         serializer.attribute(NS, FAILED_ATTR, Integer.toString(failed));
-        serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(notExecuted));
         serializer.attribute(NS, MODULES_DONE_ATTR,
                 Integer.toString(result.getModuleCompleteCount()));
         serializer.attribute(NS, MODULES_TOTAL_ATTR,
@@ -385,7 +379,6 @@
             serializer.attribute(NS, ABI_ATTR, module.getAbi());
             serializer.attribute(NS, RUNTIME_ATTR, String.valueOf(module.getRuntime()));
             serializer.attribute(NS, DONE_ATTR, Boolean.toString(module.isDone()));
-            serializer.attribute(NS, NOT_EXECUTED_ATTR, Integer.toString(module.getNotExecuted()));
             serializer.attribute(NS, PASS_ATTR,
                     Integer.toString(module.countResults(TestStatus.PASS)));
             for (ICaseResult cr : module.getResults()) {
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 4035dd3..49c4045 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -49,8 +49,6 @@
     private static final String NAME_B = "ModuleB";
     private static final String DONE_A = "false";
     private static final String DONE_B = "true";
-    private static final String NOT_EXECUTED_A = "1";
-    private static final String NOT_EXECUTED_B = "0";
     private static final String RUNTIME_A = "100";
     private static final String RUNTIME_B = "200";
     private static final String ABI = "mips64";
@@ -105,10 +103,10 @@
             "  <Build build_fingerprint=\"%s\" " + BUILD_ID + "=\"%s\" " +
                BUILD_PRODUCT + "=\"%s\" />\n";
     private static final String XML_SUMMARY =
-            "  <Summary pass=\"%d\" failed=\"%d\" not_executed=\"%d\" " +
+            "  <Summary pass=\"%d\" failed=\"%d\" " +
             "modules_done=\"1\" modules_total=\"1\" />\n";
     private static final String XML_MODULE =
-            "  <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\" not_executed=\"%s\">\n" +
+            "  <Module name=\"%s\" abi=\"%s\" device=\"%s\" runtime=\"%s\" done=\"%s\">\n" +
             "%s" +
             "  </Module>\n";
     private static final String XML_CASE =
@@ -167,7 +165,6 @@
         moduleATest1.setResultStatus(TestStatus.PASS);
         ITestResult moduleATest2 = moduleACase.getOrCreateResult(METHOD_2);
         moduleATest2.setResultStatus(null); // not executed test
-        moduleA.setNotExecuted(1);
         // Module B: test3 fails, test4 passes with report log, test5 passes with skip
         IModuleResult moduleB = result.getOrCreateModule(ID_B);
         moduleB.setDone(true);
@@ -231,7 +228,7 @@
             String moduleATest = String.format(XML_TEST_PASS, METHOD_1);
             String moduleACases = String.format(XML_CASE, CLASS_A, moduleATest);
             String moduleA = String.format(XML_MODULE, NAME_A, ABI, DEVICE_A, RUNTIME_A, DONE_A,
-                    NOT_EXECUTED_A, moduleACases);
+                    moduleACases);
             String moduleBTest3 = String.format(XML_TEST_FAIL, METHOD_3, MESSAGE, STACK_TRACE,
                     BUG_REPORT, LOGCAT, SCREENSHOT);
             String moduleBTest4 = String.format(XML_TEST_RESULT, METHOD_4, SUMMARY_SOURCE,
@@ -241,7 +238,7 @@
             String moduleBTests = String.join("", moduleBTest3, moduleBTest4, moduleBTest5);
             String moduleBCases = String.format(XML_CASE, CLASS_B, moduleBTests);
             String moduleB = String.format(XML_MODULE, NAME_B, ABI, DEVICE_B, RUNTIME_B, DONE_B,
-                    NOT_EXECUTED_B, moduleBCases);
+                    moduleBCases);
             String modules = String.join("", moduleA, moduleB);
             String hostName = "";
             try {
@@ -265,7 +262,6 @@
     static void checkLightResult(IInvocationResult lightResult) throws Exception {
         assertEquals("Expected 3 passes", 3, lightResult.countResults(TestStatus.PASS));
         assertEquals("Expected 1 failure", 1, lightResult.countResults(TestStatus.FAIL));
-        assertEquals("Expected 1 not executed", 1, lightResult.getNotExecuted());
 
         Map<String, String> buildInfo = lightResult.getInvocationInfo();
         assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
@@ -287,7 +283,6 @@
     static void checkResult(IInvocationResult result) throws Exception {
         assertEquals("Expected 3 passes", 3, result.countResults(TestStatus.PASS));
         assertEquals("Expected 1 failure", 1, result.countResults(TestStatus.FAIL));
-        assertEquals("Expected 1 not executed", 1, result.getNotExecuted());
 
         Map<String, String> buildInfo = result.getInvocationInfo();
         assertEquals("Incorrect Build ID", EXAMPLE_BUILD_ID, buildInfo.get(BUILD_ID));
diff --git a/development/ide/eclipse/cts-tradefed-harness.classpath b/development/ide/eclipse/cts-tradefed-harness.classpath
new file mode 100644
index 0000000..3355a7d
--- /dev/null
+++ b/development/ide/eclipse/cts-tradefed-harness.classpath
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="cts/common/host-side/tradefed/src"/>
+	<classpathentry kind="src" path="cts/common/host-side/util/src"/>
+	<classpathentry kind="src" path="cts/common/util/src"/>
+	<classpathentry kind="src" path="cts/libs/json/src"/>
+	<classpathentry kind="src" path="tools/loganalysis/src"/>
+	<classpathentry kind="src" path="tools/tradefederation/src"/>
+	<classpathentry kind="src" path="tools/tradefederation/remote/src"/>
+	<classpathentry kind="src" path="external/easymock/src"/>
+	<classpathentry kind="src" path="external/guava/guava/src"/>
+	<classpathentry kind="src" path="external/hamcrest/hamcrest-core/src/main/java"/>
+	<classpathentry kind="src" path="external/jline/src/src/main/java"/>
+	<classpathentry kind="src" path="external/jsr305/ri/src/main/java"/>
+	<classpathentry kind="src" path="external/junit/src/main/java"/>
+	<classpathentry kind="src" path="external/mockito/src/main/java"/>
+	<classpathentry kind="src" path="external/objenesis/main/src/main/java"/>
+	<classpathentry kind="src" path="external/protobuf/java/core/src/main/java"/>
+	<classpathentry including="com/" kind="src" path="out/host/common/obj/JAVA_LIBRARIES/cts-tradefed_intermediates"/>
+	<classpathentry kind="src" path="out/host/common/obj/JAVA_LIBRARIES/host-libprotobuf-java-full_intermediates/proto/src"/>
+	<classpathentry kind="src" path="out/host/common/obj/JAVA_LIBRARIES/tradefed-protos_intermediates/proto/src"/>
+	<classpathentry kind="src" path="tools/tradefederation/tests/src"/>
+	<classpathentry kind="src" path="cts/common/host-side/tradefed/tests/src"/>
+	<classpathentry kind="src" path="cts/common/host-side/util/tests/src"/>
+	<classpathentry kind="lib" path="external/mockito/lib/byte-buddy-1.6.9.jar"/>
+	<classpathentry kind="lib" path="external/mockito/lib/byte-buddy-agent-1.6.9.jar"/>
+	<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates/classes-jarjar.jar"/>
+	<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/conscrypt_intermediates/classes-jarjar.jar"/>
+	<classpathentry kind="lib" path="out/target/common/obj/JAVA_LIBRARIES/okhttp_intermediates/classes-jarjar.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/commons-compress/commons-compress-prebuilt.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/ddmlib/ddmlib-prebuilt.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/devtools-annotations/devtools-annotations-prebuilt.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/json/json-prebuilt.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/kxml2/kxml2-2.3.0.jar"/>
+	<classpathentry kind="lib" path="prebuilts/misc/common/sdklib/sdklib-prebuilt.jar"/>
+	<classpathentry kind="lib" path="prebuilts/sdk/tools/jack-jacoco-reporter.jar"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 78f4a78..e0ac96f 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -47,6 +47,7 @@
     private static final String UNEXPOSED_PKG = "com.android.cts.unexposedapp";
 
     private static final String TEST_CLASS = ".ClientTest";
+    private static final String WEBVIEW_TEST_CLASS = ".WebViewTest";
 
     private String mOldVerifierValue;
     private IAbi mAbi;
@@ -120,6 +121,10 @@
         runDeviceTests(EPHEMERAL_1_PKG, TEST_CLASS, "testPackageInfo");
     }
 
+    public void testWebViewLoads() throws Exception {
+        runDeviceTests(EPHEMERAL_1_PKG, WEBVIEW_TEST_CLASS, "testWebViewLoads");
+    }
+
     private void runDeviceTests(String packageName, String testClassName, String testMethodName)
             throws DeviceNotAvailableException {
         Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
index a047732..15197a0 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
@@ -92,8 +92,6 @@
         mDevice.waitForIdle();
 
         // Set a PIN for this user
-        mDevice.executeShellCommand("settings put global require_password_to_decrypt 0");
-        mDevice.executeShellCommand("locksettings set-disabled false");
         mDevice.executeShellCommand("locksettings set-pin 12345");
     }
 
@@ -107,8 +105,6 @@
 
         // Clear PIN for this user
         mDevice.executeShellCommand("locksettings clear --old 12345");
-        mDevice.executeShellCommand("locksettings set-disabled true");
-        mDevice.executeShellCommand("settings delete global require_password_to_decrypt");
     }
 
     public void doBootCountBefore() throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
index 672bcd4..b13432b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/Android.mk
@@ -17,11 +17,14 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_MODULE_TAGS := tests
 LOCAL_STATIC_JAVA_LIBRARIES := \
     cts-aia-util \
     android-support-test \
-    legacy-android-test
+    legacy-android-test \
+	ctsdeviceutillegacy \
+	ctstestrunner
 
 # tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
index e591c25..b0f53e0 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/AndroidManifest.xml
@@ -63,6 +63,7 @@
             android:theme="@android:style/Theme.NoDisplay">
             <!-- TEST: ephemeral apps can start this activity using directed intent -->
         </activity>
+        <activity android:name=".WebViewTestActivity" />
         <service
             android:name=".EphemeralService">
             <!-- TEST: ephemeral apps can see this service using query methods -->
@@ -76,6 +77,15 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </service>
+
+        <provider
+            android:name=".EphemeralProvider"
+            android:authorities="com.android.cts.ephemeralapp1.provider"
+            android:exported="true">
+            <intent-filter android:priority="0">
+                <action android:name="com.android.cts.ephemeraltest.QUERY" />
+            </intent-filter>
+        </provider>
     </application>
 
     <instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
index ada9c36..12797a1 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/ClientTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
+import android.annotation.Nullable;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -32,6 +33,7 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.database.Cursor;
 import android.net.Uri;
 import android.os.Build;
 import android.os.IBinder;
@@ -125,7 +127,7 @@
         filter.addCategory(Intent.CATEGORY_DEFAULT);
         mReceiver = new ActivityBroadcastReceiver(mResultQueue);
         InstrumentationRegistry.getContext()
-                .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+                .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
     }
 
     @After
@@ -135,6 +137,53 @@
 
     @Test
     public void testQuery() throws Exception {
+        // query normal activities
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(2));
+            assertThat(resolveInfo.get(0).activityInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).activityInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralActivity"));
+            assertThat(resolveInfo.get(0).instantAppAvailable,
+                    is(true));
+            assertThat(resolveInfo.get(1).activityInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(1).activityInfo.name,
+                    is("com.android.cts.normalapp.ExposedActivity"));
+            assertThat(resolveInfo.get(1).instantAppAvailable,
+                    is(false));
+        }
+
+        // query normal activities; directed package
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(2));
+            assertThat(resolveInfo.get(0).activityInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).activityInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralActivity"));
+            assertThat(resolveInfo.get(0).instantAppAvailable,
+                    is(true));
+            assertThat(resolveInfo.get(1).activityInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(1).activityInfo.name,
+                    is("com.android.cts.normalapp.ExposedActivity"));
+            assertThat(resolveInfo.get(1).instantAppAvailable,
+                    is(false));
+        }
+
+        // query normal activities; directed component
         {
             final Intent queryIntent = new Intent(ACTION_QUERY);
             final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -176,6 +225,93 @@
             assertThat(resolveInfo.get(1).instantAppAvailable,
                     is(false));
         }
+
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setPackage("com.android.cts.ephemeralapp1");
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(1));
+            assertThat(resolveInfo.get(0).serviceInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).serviceInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralService"));
+        }
+
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setComponent(
+                    new ComponentName("com.android.cts.ephemeralapp1",
+                            "com.android.cts.ephemeralapp1.EphemeralService"));
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(1));
+            assertThat(resolveInfo.get(0).serviceInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).serviceInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralService"));
+        }
+
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentContentProviders(
+                            queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(2));
+            assertThat(resolveInfo.get(0).providerInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).providerInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+            assertThat(resolveInfo.get(1).providerInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(1).providerInfo.name,
+                    is("com.android.cts.normalapp.ExposedProvider"));
+            assertThat(resolveInfo.get(1).instantAppAvailable,
+                    is(false));
+        }
+
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setPackage("com.android.cts.ephemeralapp1");
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentContentProviders(
+                            queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(1));
+            assertThat(resolveInfo.get(0).providerInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).providerInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+        }
+
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setComponent(
+                    new ComponentName("com.android.cts.ephemeralapp1",
+                            "com.android.cts.ephemeralapp1.EphemeralProvider"));
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentContentProviders(
+                            queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(1));
+            assertThat(resolveInfo.get(0).providerInfo.packageName,
+                    is("com.android.cts.ephemeralapp1"));
+            assertThat(resolveInfo.get(0).providerInfo.name,
+                    is("com.android.cts.ephemeralapp1.EphemeralProvider"));
+        }
     }
 
     @Test
@@ -230,6 +366,48 @@
         // provide any feedback. The alternative is to wait for the broadcast timeout
         // but it's silly to artificially slow down CTS. We'll rely on queryIntentService
         // to check whether or not the service is actually exposed
+
+        // bind to the normal service; directed package
+        {
+            final Intent startNormalIntent = new Intent(ACTION_START_NORMAL);
+            startNormalIntent.setPackage("com.android.cts.normalapp");
+            final TestServiceConnection connection = new TestServiceConnection();
+            try {
+                assertThat(InstrumentationRegistry.getContext().bindService(
+                        startNormalIntent, connection, Context.BIND_AUTO_CREATE /*flags*/),
+                        is(false));
+            } finally {
+                InstrumentationRegistry.getContext().unbindService(connection);
+            }
+        }
+
+        // bind to the normal service; directed component
+        {
+            final Intent startNormalIntent = new Intent(ACTION_START_NORMAL);
+            startNormalIntent.setComponent(new ComponentName(
+                    "com.android.cts.normalapp", "com.android.cts.normalapp.NormalService"));
+            final TestServiceConnection connection = new TestServiceConnection();
+            try {
+                assertThat(InstrumentationRegistry.getContext().bindService(
+                        startNormalIntent, connection, Context.BIND_AUTO_CREATE /*flags*/),
+                        is(false));
+            } finally {
+                InstrumentationRegistry.getContext().unbindService(connection);
+            }
+        }
+
+        // connect to the normal provider
+        {
+            final String provider = "content://com.android.cts.normalapp.provider/table";
+            final Cursor testCursor = InstrumentationRegistry
+                    .getContext().getContentResolver().query(
+                            Uri.parse(provider),
+                            null /*projection*/,
+                            null /*selection*/,
+                            null /*selectionArgs*/,
+                            null /*sortOrder*/);
+            assertThat(testCursor, is(nullValue()));
+        }
     }
 
     @Test
@@ -376,12 +554,43 @@
                         is("onBind"));
                 assertThat(testResult.getStatus(),
                         is("PASS"));
+                assertThat(testResult.getEphemeralPackageInfoExposed(),
+                        is(true));
                 assertThat(testResult.getException(),
                         is(nullValue()));
             } finally {
                 InstrumentationRegistry.getContext().unbindService(connection);
             }
         }
+
+        // connect to exposed provider
+        {
+            final String provider = "content://com.android.cts.normalapp.exposed.provider/table";
+            final Cursor testCursor = InstrumentationRegistry
+                    .getContext().getContentResolver().query(
+                            Uri.parse(provider),
+                            null /*projection*/,
+                            null /*selection*/,
+                            null /*selectionArgs*/,
+                            null /*sortOrder*/);
+            assertThat(testCursor, is(notNullValue()));
+            assertThat(testCursor.getCount(), is(1));
+            assertThat(testCursor.getColumnCount(), is(2));
+            assertThat(testCursor.moveToFirst(), is(true));
+            assertThat(testCursor.getInt(0), is(1));
+            assertThat(testCursor.getString(1), is("ExposedProvider"));
+            final TestResult testResult = getResult();
+            assertThat(testResult.getPackageName(),
+                    is("com.android.cts.normalapp"));
+            assertThat(testResult.getComponentName(),
+                    is("ExposedProvider"));
+            assertThat(testResult.getStatus(),
+                    is("PASS"));
+            assertThat(testResult.getEphemeralPackageInfoExposed(),
+                    is(true));
+            assertThat(testResult.getException(),
+                    is(nullValue()));
+        }
     }
 
     @Test
@@ -607,6 +816,24 @@
                 InstrumentationRegistry.getContext().unbindService(connection);
             }
         }
+
+        // connect to the instant app provider
+        {
+            final String provider = "content://com.android.cts.ephemeralapp1.provider/table";
+            final Cursor testCursor = InstrumentationRegistry
+                    .getContext().getContentResolver().query(
+                            Uri.parse(provider),
+                            null /*projection*/,
+                            null /*selection*/,
+                            null /*selectionArgs*/,
+                            null /*sortOrder*/);
+            assertThat(testCursor, is(notNullValue()));
+            assertThat(testCursor.getCount(), is(1));
+            assertThat(testCursor.getColumnCount(), is(2));
+            assertThat(testCursor.moveToFirst(), is(true));
+            assertThat(testCursor.getInt(0), is(1));
+            assertThat(testCursor.getString(1), is("InstantAppProvider"));
+        }
     }
 
     @Test
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java
new file mode 100644
index 0000000..d34d494
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/EphemeralProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.ephemeralapp1;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class EphemeralProvider extends ContentProvider {
+    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+    static {
+        sUriMatcher.addURI("com.android.cts.ephemeralapp1.provider", "table", 1);
+    }
+    private static final String[] sColumnNames = { "_ID", "name" };
+    private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+    static {
+        sCursor.newRow().add(1).add("InstantAppProvider");
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
new file mode 100644
index 0000000..11d1c60
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.ephemeralapp1;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+
+import android.webkit.WebView;
+import android.webkit.cts.WebViewOnUiThread;
+
+public class WebViewTest extends ActivityInstrumentationTestCase2<WebViewTestActivity> {
+
+    private WebView mWebView;
+    private WebViewOnUiThread mOnUiThread;
+
+    public WebViewTest() {
+        super("com.android.cts.ephemeralapp1", WebViewTestActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        final WebViewTestActivity activity = getActivity();
+        mWebView = activity.getWebView();
+        mOnUiThread = new WebViewOnUiThread(this, mWebView);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mOnUiThread.cleanUp();
+        super.tearDown();
+    }
+
+    @UiThreadTest
+    public void testWebViewLoads() throws Exception {
+        mOnUiThread.loadUrlAndWaitForCompletion("about:blank");
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
new file mode 100644
index 0000000..aae2b65
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp1/src/com/android/cts/ephemeralapp1/WebViewTestActivity.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.ephemeralapp1;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.webkit.WebView;
+
+import com.android.compatibility.common.util.NullWebViewUtils;
+
+public class WebViewTestActivity extends Activity {
+    private WebView mWebView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        try {
+            super.onCreate(savedInstanceState);
+            mWebView = new WebView(this);
+            setContentView(mWebView);
+        } catch (Exception e) {
+            NullWebViewUtils.determineIfWebViewAvailable(this, e);
+        }
+    }
+
+    public WebView getWebView() {
+        return mWebView;
+    }
+
+    @Override
+    public void onDestroy() {
+        if (mWebView != null) {
+            ViewParent parent =  mWebView.getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).removeView(mWebView);
+            }
+            mWebView.destroy();
+        }
+        super.onDestroy();
+    }
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
index 06d569e..78c282b 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/EphemeralApp2/AndroidManifest.xml
@@ -43,12 +43,23 @@
                 <action android:name="com.android.cts.ephemeraltest.START_EPHEMERAL" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
-          </activity>
-          <!-- This should still not be visible to other Instant Apps -->
-          <activity
-            android:name=".FakeExposedActivity"
+        </activity>
+
+        <!-- This should still not be visible to other Instant Apps -->
+        <activity
+            android:name=".ExposedActivity"
             android:visibleToInstantApps="true"
             android:theme="@android:style/Theme.NoDisplay" />
+
+        <!-- This should still not be visible to other Instant Apps -->
+        <provider
+            android:name=".EphemeralProvider"
+            android:authorities="com.android.cts.ephemeralapp2.provider"
+            android:exported="true">
+            <intent-filter android:priority="0">
+                <action android:name="com.android.cts.ephemeraltest.QUERY" />
+            </intent-filter>
+        </provider>
     </application>
 
     <instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
index ff542a4..4c27dba 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/AndroidManifest.xml
@@ -64,6 +64,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
+
         <service
             android:name=".NormalService">
             <!-- TEST: ephemeral apps can't see this service using query methods -->
@@ -91,6 +92,24 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </service>
+
+        <provider
+            android:name=".NormalProvider"
+            android:authorities="com.android.cts.normalapp.provider"
+            android:exported="true">
+            <intent-filter android:priority="-20">
+                <action android:name="com.android.cts.ephemeraltest.QUERY" />
+            </intent-filter>
+        </provider>
+        <provider
+            android:name=".ExposedProvider"
+            android:authorities="com.android.cts.normalapp.exposed.provider"
+            android:visibleToInstantApps="true"
+            android:exported="true">
+            <intent-filter android:priority="-10">
+                <action android:name="com.android.cts.ephemeraltest.QUERY" />
+            </intent-filter>
+        </provider>
     </application>
 
     <instrumentation
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
index d428158..22b8c25 100644
--- a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ClientTest.java
@@ -17,6 +17,8 @@
 package com.android.cts.normalapp;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
@@ -27,6 +29,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ResolveInfo;
+import android.database.Cursor;
 import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
@@ -73,7 +76,7 @@
         filter.addCategory(Intent.CATEGORY_DEFAULT);
         mReceiver = new ActivityBroadcastReceiver(mResultQueue);
         InstrumentationRegistry.getContext()
-                .registerReceiver(mReceiver, filter, true /*visibleToEmphemeral*/);
+                .registerReceiver(mReceiver, filter, Context.RECEIVER_VISIBLE_TO_INSTANT_APPS);
     }
 
     @After
@@ -83,9 +86,9 @@
 
     @Test
     public void testQuery() throws Exception {
-        final Intent queryIntent = new Intent(ACTION_QUERY);
         // query activities without flags
         {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
             final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
                     .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
             if (resolveInfo == null || resolveInfo.size() == 0) {
@@ -108,6 +111,7 @@
 
         // query activities asking for ephemeral apps [we should only get normal apps]
         {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
             final int MATCH_EPHEMERAL = 0x00800000;
 
             final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -130,8 +134,29 @@
                     is(false));
         }
 
+        // query activities; directed package
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setPackage("com.android.cts.ephemeralapp1");
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
+
+        // query activities; directed component
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setComponent(
+                    new ComponentName("com.android.cts.ephemeralapp1",
+                            "com.android.cts.ephemeralapp1.EphemeralActivity"));
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentActivities(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
+
         // query services without flags
         {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
             final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
                     .getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
             if (resolveInfo == null || resolveInfo.size() == 0) {
@@ -154,6 +179,7 @@
 
         // query services asking for ephemeral apps [we should only get normal apps]
         {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
             final int MATCH_EPHEMERAL = 0x00800000;
 
             final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
@@ -175,6 +201,92 @@
             assertThat(resolveInfo.get(1).instantAppAvailable,
                     is(false));
         }
+
+        // query services; directed package
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setPackage("com.android.cts.ephemeralapp1");
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
+
+        // query services; directed component
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setComponent(
+                    new ComponentName("com.android.cts.ephemeralapp1",
+                            "com.android.cts.ephemeralapp1.EphemeralService"));
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentServices(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
+
+        // query content providers without flags
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry
+                    .getContext().getPackageManager().queryIntentContentProviders(
+                            queryIntent, 0 /*flags*/);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(2));
+            assertThat(resolveInfo.get(0).providerInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(0).providerInfo.name,
+                    is("com.android.cts.normalapp.ExposedProvider"));
+            assertThat(resolveInfo.get(1).providerInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(1).providerInfo.name,
+                    is("com.android.cts.normalapp.NormalProvider"));
+            assertThat(resolveInfo.get(1).instantAppAvailable,
+                    is(false));
+        }
+
+        // query content providers asking for ephemeral apps [we should only get normal apps]
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            final int MATCH_EPHEMERAL = 0x00800000;
+
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentContentProviders(
+                            queryIntent, MATCH_EPHEMERAL);
+            if (resolveInfo == null || resolveInfo.size() == 0) {
+                fail("didn't resolve any intents");
+            }
+            assertThat(resolveInfo.size(), is(2));
+            assertThat(resolveInfo.get(0).providerInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(0).providerInfo.name,
+                    is("com.android.cts.normalapp.ExposedProvider"));
+            assertThat(resolveInfo.get(1).providerInfo.packageName,
+                    is("com.android.cts.normalapp"));
+            assertThat(resolveInfo.get(1).providerInfo.name,
+                    is("com.android.cts.normalapp.NormalProvider"));
+            assertThat(resolveInfo.get(1).instantAppAvailable,
+                    is(false));
+        }
+
+        // query content providers; directed package
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setPackage("com.android.cts.ephemeralapp1");
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
+
+        // query content providers; directed component
+        {
+            final Intent queryIntent = new Intent(ACTION_QUERY);
+            queryIntent.setComponent(
+                    new ComponentName("com.android.cts.ephemeralapp1",
+                            "com.android.cts.ephemeralapp1.EphemeralProvider"));
+            final List<ResolveInfo> resolveInfo = InstrumentationRegistry.getContext()
+                    .getPackageManager().queryIntentContentProviders(queryIntent, 0 /*flags*/);
+            assertThat(resolveInfo.size(), is(0));
+        }
     }
 
     @Test
@@ -220,6 +332,24 @@
             assertThat(testResult.getException(),
                     is("android.content.pm.PackageManager$NameNotFoundException"));
         }
+
+        // connect to the normal provider
+        {
+            final String provider = "content://com.android.cts.normalapp.provider/table";
+            final Cursor testCursor = InstrumentationRegistry
+                    .getContext().getContentResolver().query(
+                            Uri.parse(provider),
+                            null /*projection*/,
+                            null /*selection*/,
+                            null /*selectionArgs*/,
+                            null /*sortOrder*/);
+            assertThat(testCursor, is(notNullValue()));
+            assertThat(testCursor.getCount(), is(1));
+            assertThat(testCursor.getColumnCount(), is(2));
+            assertThat(testCursor.moveToFirst(), is(true));
+            assertThat(testCursor.getInt(0), is(1));
+            assertThat(testCursor.getString(1), is("NormalProvider"));
+        }
     }
 
     @Test
@@ -269,6 +399,19 @@
             assertThat("com.android.cts.ephemeralapp1", is(testResult.getPackageName()));
             assertThat("EphemeralActivity", is(testResult.getComponentName()));
         }
+
+        // connect to the instant app provider
+        {
+            final String provider = "content://com.android.cts.ephemeralapp1.provider/table";
+            final Cursor testCursor = InstrumentationRegistry
+                    .getContext().getContentResolver().query(
+                            Uri.parse(provider),
+                            null /*projection*/,
+                            null /*selection*/,
+                            null /*selectionArgs*/,
+                            null /*sortOrder*/);
+            assertThat(testCursor, is(nullValue()));
+        }
     }
 
     private TestResult getResult() {
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java
new file mode 100644
index 0000000..99658d4
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/ExposedProvider.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.normalapp;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+import com.android.cts.util.TestResult;
+
+public class ExposedProvider extends ContentProvider {
+    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+    static {
+        sUriMatcher.addURI("com.android.cts.normalapp.exposed.provider", "table", 1);
+    }
+    private static final String[] sColumnNames = { "_ID", "name" };
+    private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+    static {
+        sCursor.newRow().add(1).add("ExposedProvider");
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        boolean canAccessInstantApp = false;
+        String exception = null;
+        try {
+            canAccessInstantApp = tryAccessingInstantApp();
+        } catch (Throwable t) {
+            exception = t.getClass().getName();
+        }
+
+        TestResult.getBuilder()
+                .setPackageName("com.android.cts.normalapp")
+                .setComponentName("ExposedProvider")
+                .setStatus("PASS")
+                .setException(exception)
+                .setEphemeralPackageInfoExposed(canAccessInstantApp)
+                .build()
+                .broadcast(getContext());
+
+        return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+    }
+
+    private boolean tryAccessingInstantApp() throws NameNotFoundException {
+        final PackageInfo info = getContext().getPackageManager()
+                .getPackageInfo("com.android.cts.ephemeralapp1", 0 /*flags*/);
+        return (info != null);
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java
new file mode 100644
index 0000000..8351a27
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/EphemeralTestApp/NormalApp/src/com/android/cts/normalapp/NormalProvider.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.normalapp;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.CharArrayBuffer;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.database.DataSetObserver;
+import android.database.MatrixCursor;
+import android.net.Uri;
+import android.os.Bundle;
+
+public class NormalProvider extends ContentProvider {
+    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+    static {
+        sUriMatcher.addURI("com.android.cts.normalapp.provider", "table", 1);
+    }
+    private static final String[] sColumnNames = { "_ID", "name" };
+    private static final MatrixCursor sCursor = new MatrixCursor(sColumnNames, 1);
+    static {
+        sCursor.newRow().add(1).add("NormalProvider");
+    }
+
+    @Override
+    public boolean onCreate() {
+        return true;
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return (sUriMatcher.match(uri) != 1) ? null : sCursor;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return null;
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        return null;
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        return 0;
+    }
+
+}
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
index 7a937d5..31f653d 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/AndroidManifest.xml
@@ -17,7 +17,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="test.instant.cookie"
         android:versionCode="1"
-        android:versionName="1.0">
+        android:versionName="1.0"
+        android:targetSandboxVersion="2">
 
     <application/>
 
diff --git a/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
index 37f6bba..774296b 100644
--- a/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
+++ b/hostsidetests/appsecurity/test-apps/InstantCookieApp/src/test/instant/cookie/CookieTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 @RunWith(AndroidJUnit4.class)
 public class CookieTest {
@@ -36,18 +37,23 @@
         assertTrue(pm.isInstantApp());
 
         // The max cookie size is greater than zero
-        assertTrue(pm.getInstantAppCookieMaxSize() > 0);
+        assertTrue(pm.getInstantAppCookieMaxBytes() > 0);
 
         // Initially there is no cookie
         byte[] cookie = pm.getInstantAppCookie();
         assertTrue(cookie != null && cookie.length == 0);
 
         // Setting a cookie below max size should work
-        assertTrue(pm.setInstantAppCookie("1".getBytes()));
+        pm.updateInstantAppCookie("1".getBytes());
 
         // Setting a cookie above max size should not work
-        assertFalse(pm.setInstantAppCookie(
-                new byte[pm.getInstantAppCookieMaxSize() + 1]));
+        try {
+            pm.updateInstantAppCookie(
+                    new byte[pm.getInstantAppCookieMaxBytes() + 1]);
+            fail("Shouldn't be able to set a cookie larger than max size");
+        } catch (IllegalArgumentException e) {
+            /* expected */
+        }
 
         // Ensure cookie not modified
         assertEquals("1", new String(pm.getInstantAppCookie()));
@@ -58,7 +64,7 @@
         PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
 
         // Set a cookie to later check when reinstalled as instant app
-        assertTrue(pm.setInstantAppCookie("2".getBytes()));
+        pm.updateInstantAppCookie("2".getBytes());
     }
 
     @Test
@@ -77,7 +83,7 @@
         assertTrue(pm.isInstantApp());
 
         // Set a cookie to later check when upgrade to a normal app
-        assertTrue(pm.setInstantAppCookie("3".getBytes()));
+        pm.updateInstantAppCookie("3".getBytes());
     }
 
     @Test
@@ -96,7 +102,7 @@
         PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
 
         // Set a cookie to later check when reinstalled as normal app
-        assertTrue(pm.setInstantAppCookie("4".getBytes()));
+        pm.updateInstantAppCookie("4".getBytes());
     }
 
     @Test
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 22eaaea..9778f12 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -41,6 +41,7 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.util.UUID;
 
 /**
  * Client app for verifying storage behaviors.
@@ -85,8 +86,10 @@
     public void testVerifySpaceApi() throws Exception {
         final StorageManager sm = getContext().getSystemService(StorageManager.class);
 
-        final long cacheSize = sm.getCacheSizeBytes(getContext().getCacheDir());
-        final long extCacheSize = sm.getCacheSizeBytes(getContext().getExternalCacheDir());
+        final long cacheSize = sm.getCacheSizeBytes(
+                sm.getUuidForPath(getContext().getCacheDir()));
+        final long extCacheSize = sm.getCacheSizeBytes(
+                sm.getUuidForPath(getContext().getExternalCacheDir()));
         if (cacheSize == extCacheSize) {
             assertMostlyEquals(CACHE_ALL, cacheSize);
         } else {
@@ -97,22 +100,28 @@
 
     public void testVerifyQuotaApi() throws Exception {
         final StorageManager sm = getContext().getSystemService(StorageManager.class);
-        assertTrue("Apps must have at least 10MB quota",
-                sm.getCacheQuotaBytes(getContext().getCacheDir()) > 10 * MB_IN_BYTES);
+
+        final long cacheSize = sm.getCacheQuotaBytes(
+                sm.getUuidForPath(getContext().getCacheDir()));
+        assertTrue("Apps must have at least 10MB quota", cacheSize > 10 * MB_IN_BYTES);
     }
 
     public void testVerifyAllocateApi() throws Exception {
         final StorageManager sm = getContext().getSystemService(StorageManager.class);
 
         final File filesDir = getContext().getFilesDir();
-        assertTrue("Apps must be able to allocate internal space",
-                sm.getAllocatableBytes(filesDir, 0) > 10 * MB_IN_BYTES);
         final File extDir = Environment.getExternalStorageDirectory();
+
+        final UUID filesUuid = sm.getUuidForPath(filesDir);
+        final UUID extUuid = sm.getUuidForPath(extDir);
+
+        assertTrue("Apps must be able to allocate internal space",
+                sm.getAllocatableBytes(filesUuid, 0) > 10 * MB_IN_BYTES);
         assertTrue("Apps must be able to allocate external space",
-                sm.getAllocatableBytes(extDir, 0) > 10 * MB_IN_BYTES);
+                sm.getAllocatableBytes(extUuid, 0) > 10 * MB_IN_BYTES);
 
         // Should always be able to allocate 1MB indirectly
-        sm.allocateBytes(filesDir, 1 * MB_IN_BYTES, 0);
+        sm.allocateBytes(filesUuid, 1 * MB_IN_BYTES, 0);
 
         // Should always be able to allocate 1MB directly
         final File filesFile = makeUniqueFile(filesDir);
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
index 64495a4..e47f6ed 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/Utils.java
@@ -25,10 +25,12 @@
 
 import junit.framework.AssertionFailedError;
 
+import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
+import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -152,7 +154,21 @@
         return success;
     }
 
-    public static boolean shouldHaveQuota(StructUtsname uname) {
+    public static boolean shouldHaveQuota(StructUtsname uname) throws Exception {
+        try (BufferedReader br = new BufferedReader(new FileReader("/proc/mounts"))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                final String[] fields = line.split(" ");
+                final String target = fields[1];
+                final String format = fields[2];
+
+                if (target.equals("/data") && !format.equals("ext4")) {
+                    Log.d(TAG, "Assuming no quota support because /data is " + format);
+                    return false;
+                }
+            }
+        }
+
         final Matcher matcher = Pattern.compile("(\\d+)\\.(\\d+)").matcher(uname.release);
         if (!matcher.find()) {
             throw new IllegalStateException("Failed to parse version: " + uname.release);
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
index bab84aa..2845185 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/UtilsReceiver.java
@@ -50,13 +50,13 @@
     public static Bundle doAllocation(Context context, Bundle extras) {
         final StorageManager sm = context.getSystemService(StorageManager.class);
 
-        final double fraction = extras.getDouble(EXTRA_FRACTION, 0);
-        final long quota = sm.getCacheQuotaBytes(context.getCacheDir());
-        final long bytes = (long) (quota * fraction);
-        final long time = extras.getLong(EXTRA_TIME, System.currentTimeMillis());
-
         long allocated = 0;
         try {
+            final double fraction = extras.getDouble(EXTRA_FRACTION, 0);
+            final long quota = sm.getCacheQuotaBytes(sm.getUuidForPath(context.getCacheDir()));
+            final long bytes = (long) (quota * fraction);
+            final long time = extras.getLong(EXTRA_TIME, System.currentTimeMillis());
+
             while (allocated < bytes) {
                 final File f = makeUniqueFile(context.getCacheDir());
                 final long size = 1024 * 1024;
@@ -64,15 +64,15 @@
                 f.setLastModified(time);
                 allocated += Os.stat(f.getAbsolutePath()).st_blocks * 512;
             }
+
+            Log.d(TAG, "Quota " + quota + ", target " + bytes + ", allocated " + allocated);
+
+            final Bundle res = new Bundle();
+            res.putLong(EXTRA_BYTES, allocated);
+            return res;
         } catch (Exception e) {
             Log.e(TAG, "Failed to allocate cache files", e);
             return null;
         }
-
-        Log.d(TAG, "Quota " + quota + ", target " + bytes + ", allocated " + allocated);
-
-        final Bundle res = new Bundle();
-        res.putLong(EXTRA_BYTES, allocated);
-        return res;
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
index 8066f70..41439f0 100644
--- a/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageStatsApp/src/com/android/cts/storagestatsapp/StorageStatsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.cts.storagestatsapp;
 
+import static android.os.storage.StorageManager.UUID_DEFAULT;
+
 import static com.android.cts.storageapp.Utils.CACHE_ALL;
 import static com.android.cts.storageapp.Utils.DATA_ALL;
 import static com.android.cts.storageapp.Utils.MB_IN_BYTES;
@@ -54,6 +56,7 @@
 import com.android.cts.storageapp.UtilsReceiver;
 
 import java.io.File;
+import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -81,15 +84,18 @@
                     .getSystemService(StorageStatsManager.class);
             assertTrue("You're running kernel 3.18 or newer (" + uname.release + ") which "
                     + "means that CONFIG_QUOTA, CONFIG_QFMT_V2, CONFIG_QUOTACTL and the "
-                    + "'quota' fstab option on /data are required", stats.isQuotaSupported(null));
+                    + "'quota' fstab option on /data are required",
+                    stats.isQuotaSupported(UUID_DEFAULT));
         }
     }
 
     public void testVerifySummary() throws Exception {
         final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
 
-        assertAtLeast(Environment.getDataDirectory().getTotalSpace(), stats.getTotalBytes(null));
-        assertAtLeast(Environment.getDataDirectory().getUsableSpace(), stats.getFreeBytes(null));
+        assertAtLeast(Environment.getDataDirectory().getTotalSpace(),
+                stats.getTotalBytes(UUID_DEFAULT));
+        assertAtLeast(Environment.getDataDirectory().getUsableSpace(),
+                stats.getFreeBytes(UUID_DEFAULT));
     }
 
     public void testVerifyStats() throws Exception {
@@ -97,13 +103,13 @@
         final int uid = android.os.Process.myUid();
         final UserHandle user = UserHandle.getUserHandleForUid(uid);
 
-        final StorageStats beforeApp = stats.queryStatsForUid(null, uid);
-        final StorageStats beforeUser = stats.queryStatsForUser(null, user);
+        final StorageStats beforeApp = stats.queryStatsForUid(UUID_DEFAULT, uid);
+        final StorageStats beforeUser = stats.queryStatsForUser(UUID_DEFAULT, user);
 
         useSpace(getContext());
 
-        final StorageStats afterApp = stats.queryStatsForUid(null, uid);
-        final StorageStats afterUser = stats.queryStatsForUser(null, user);
+        final StorageStats afterApp = stats.queryStatsForUid(UUID_DEFAULT, uid);
+        final StorageStats afterUser = stats.queryStatsForUser(UUID_DEFAULT, user);
 
         final long deltaData = DATA_ALL;
         assertMostlyEquals(deltaData, afterApp.getDataBytes() - beforeApp.getDataBytes());
@@ -121,8 +127,8 @@
         final ApplicationInfo a = pm.getApplicationInfo(PKG_A, 0);
         final ApplicationInfo b = pm.getApplicationInfo(PKG_B, 0);
 
-        final StorageStats as = stats.queryStatsForUid(null, a.uid);
-        final StorageStats bs = stats.queryStatsForUid(null, b.uid);
+        final StorageStats as = stats.queryStatsForUid(UUID_DEFAULT, a.uid);
+        final StorageStats bs = stats.queryStatsForUid(UUID_DEFAULT, b.uid);
 
         assertMostlyEquals(DATA_ALL * 2, as.getDataBytes());
         assertMostlyEquals(CACHE_ALL * 2, as.getCacheBytes());
@@ -140,7 +146,7 @@
         final int uid = android.os.Process.myUid();
         final UserHandle user = UserHandle.getUserHandleForUid(uid);
 
-        final ExternalStorageStats before = stats.queryExternalStatsForUser(null, user);
+        final ExternalStorageStats before = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
 
         final File dir = Environment.getExternalStorageDirectory();
         final File downloadsDir = Environment.getExternalStoragePublicDirectory(
@@ -158,7 +164,7 @@
         useWrite(audio, 5 * MB_IN_BYTES);
         useWrite(internal, 7 * MB_IN_BYTES);
 
-        final ExternalStorageStats afterInit = stats.queryExternalStatsForUser(null, user);
+        final ExternalStorageStats afterInit = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
 
         assertMostlyEquals(17 * MB_IN_BYTES, afterInit.getTotalBytes() - before.getTotalBytes());
         assertMostlyEquals(5 * MB_IN_BYTES, afterInit.getAudioBytes() - before.getAudioBytes());
@@ -168,7 +174,7 @@
         // Rename to ensure that stats are updated
         video.renameTo(new File(dir, System.nanoTime() + ".PnG"));
 
-        final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(null, user);
+        final ExternalStorageStats afterRename = stats.queryExternalStatsForUser(UUID_DEFAULT, user);
 
         assertMostlyEquals(17 * MB_IN_BYTES, afterRename.getTotalBytes() - before.getTotalBytes());
         assertMostlyEquals(5 * MB_IN_BYTES, afterRename.getAudioBytes() - before.getAudioBytes());
@@ -199,9 +205,9 @@
         logCommand("sync");
 
         final long manualSize = getSizeManual(Environment.getExternalStorageDirectory());
-        final long statsSize = stats.queryExternalStatsForUser(null, user).getTotalBytes();
+        final long statsSize = stats.queryExternalStatsForUser(UUID_DEFAULT, user).getTotalBytes();
 
-        assertEquals(manualSize, statsSize);
+        assertMostlyEquals(manualSize, statsSize);
     }
 
     public void testVerifyCategory() throws Exception {
@@ -220,9 +226,10 @@
         final UserHandle user = android.os.Process.myUserHandle();
 
         final File filesDir = context.getFilesDir();
+        final UUID filesUuid = sm.getUuidForPath(filesDir);
 
-        final long beforeAllocatable = sm.getAllocatableBytes(filesDir, 0);
-        final long beforeFree = stats.getFreeBytes(null);
+        final long beforeAllocatable = sm.getAllocatableBytes(filesUuid, 0);
+        final long beforeFree = stats.getFreeBytes(UUID_DEFAULT);
         final long beforeRaw = filesDir.getUsableSpace();
 
         Log.d(TAG, "Before raw " + beforeRaw + ", free " + beforeFree + ", allocatable "
@@ -234,16 +241,24 @@
         // Ask apps to allocate some cached data
         final long targetA = doAllocateProvider(PKG_A, 0.5, 1262304000);
         final long targetB = doAllocateProvider(PKG_B, 2.0, 1420070400);
+        final long totalAllocated = targetA + targetB;
 
         // Apps using up some cache space shouldn't change how much we can
         // allocate, or how much we think is free; but it should decrease real
         // disk space.
-        assertMostlyEquals(beforeAllocatable, sm.getAllocatableBytes(filesDir, 0),
-                10 * MB_IN_BYTES);
-        assertMostlyEquals(beforeFree, stats.getFreeBytes(null),
-                10 * MB_IN_BYTES);
-        assertMostlyEquals(targetA + targetB, beforeRaw - filesDir.getUsableSpace(),
-                10 * MB_IN_BYTES);
+        if (stats.isQuotaSupported(UUID_DEFAULT)) {
+            assertMostlyEquals(beforeAllocatable,
+                    sm.getAllocatableBytes(filesUuid, 0), 10 * MB_IN_BYTES);
+            assertMostlyEquals(beforeFree,
+                    stats.getFreeBytes(UUID_DEFAULT), 10 * MB_IN_BYTES);
+        } else {
+            assertMostlyEquals(beforeAllocatable - totalAllocated,
+                    sm.getAllocatableBytes(filesUuid, 0), 10 * MB_IN_BYTES);
+            assertMostlyEquals(beforeFree - totalAllocated,
+                    stats.getFreeBytes(UUID_DEFAULT), 10 * MB_IN_BYTES);
+        }
+        assertMostlyEquals(beforeRaw - totalAllocated,
+                filesDir.getUsableSpace(), 10 * MB_IN_BYTES);
 
         assertMostlyEquals(targetA, getCacheBytes(PKG_A, user));
         assertMostlyEquals(targetB, getCacheBytes(PKG_B, user));
@@ -251,7 +266,7 @@
         // Allocate some space for ourselves, which should trim away at
         // over-quota app first, even though its files are newer.
         final long clear1 = filesDir.getUsableSpace() + (targetB / 2);
-        sm.allocateBytes(filesDir, clear1, 0);
+        sm.allocateBytes(filesUuid, clear1, 0);
 
         assertMostlyEquals(targetA, getCacheBytes(PKG_A, user));
         assertMostlyEquals(targetB / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES);
@@ -261,7 +276,7 @@
         // they're tied for cache ratios, we expect to clear about half of the
         // remaining space from each of them.
         final long clear2 = filesDir.getUsableSpace() + (targetB / 2);
-        sm.allocateBytes(filesDir, clear2, 0);
+        sm.allocateBytes(filesUuid, clear2, 0);
 
         assertMostlyEquals(targetA / 2, getCacheBytes(PKG_A, user), 2 * MB_IN_BYTES);
         assertMostlyEquals(targetA / 2, getCacheBytes(PKG_B, user), 2 * MB_IN_BYTES);
@@ -305,7 +320,7 @@
         tomb.setLastModified(tombTime);
 
         final long clear1 = group.getUsableSpace() + (8 * MB_IN_BYTES);
-        sm.allocateBytes(group, clear1, 0);
+        sm.allocateBytes(sm.getUuidForPath(group), clear1, 0);
 
         assertTrue(a.exists());
         assertTrue(b.exists());
@@ -319,9 +334,9 @@
         assertTrue(i.exists()); assertEquals(0, i.length());
     }
 
-    private long getCacheBytes(String pkg, UserHandle user) {
+    private long getCacheBytes(String pkg, UserHandle user) throws Exception {
         return getContext().getSystemService(StorageStatsManager.class)
-                .queryStatsForPackage(null, pkg, user).getCacheBytes();
+                .queryStatsForPackage(UUID_DEFAULT, pkg, user).getCacheBytes();
     }
 
     private long doAllocateReceiver(String pkg, double fraction, long time) throws Exception {
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index f8f6d92..4340c87 100755
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -267,6 +267,11 @@
         getUiDevice().pressBack();
         waitForIdle();
 
+        if (isTv()) {
+            getUiDevice().pressHome();
+            waitForIdle();
+        }
+
         // Open the app details settings
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
@@ -506,4 +511,9 @@
         getInstrumentation().getUiAutomation().waitForIdle(IDLE_TIMEOUT_MILLIS,
                 GLOBAL_TIMEOUT_MILLIS);
     }
+
+    private static boolean isTv() {
+        return getInstrumentation().getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
  }
diff --git a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
index 40bf530..ce8f760 100644
--- a/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
+++ b/hostsidetests/compilation/src/android/cts/compilation/AdbRootDependentCompilationTest.java
@@ -75,8 +75,7 @@
     private byte[] profileBytes;
     private File localProfileFile;
     private File apkFile;
-    private boolean mIsRoot;
-    private boolean mNewlyObtainedRoot;
+    private boolean mCanEnableDeviceRootAccess;
 
     @Override
     protected void setUp() throws Exception {
@@ -87,11 +86,8 @@
         assertTrue("Unknown build type: " + buildType,
                 Arrays.asList("user", "userdebug", "eng").contains(buildType));
         boolean wasRoot = mDevice.isAdbRoot();
-        mIsRoot = (!buildType.equals("user"));
-        mNewlyObtainedRoot = (mIsRoot && !wasRoot);
-        if (mNewlyObtainedRoot) {
-            mDevice.enableAdbRoot();
-        }
+        // We can only enable root access on userdebug and eng builds.
+        mCanEnableDeviceRootAccess = buildType.equals("userdebug") || buildType.equals("eng");
 
         apkFile = File.createTempFile("CtsCompilationApp", ".apk");
         try (OutputStream outputStream = new FileOutputStream(apkFile)) {
@@ -111,9 +107,6 @@
 
     @Override
     protected void tearDown() throws Exception {
-        if (mNewlyObtainedRoot) {
-            mDevice.disableAdbRoot();
-        }
         FileUtil.deleteFile(apkFile);
         FileUtil.deleteFile(localProfileFile);
         mDevice.uninstallPackage(APPLICATION_PACKAGE);
@@ -165,7 +158,7 @@
                  EnumSet.of(ProfileLocation.CUR));
         if (didRun) {
             assertTrue("ref profile should have been created by the compiler",
-                    mDevice.doesFileExist(ProfileLocation.REF.getPath()));
+                    doesFileExist(ProfileLocation.REF.getPath()));
         }
     }
 
@@ -184,10 +177,10 @@
 
     private byte[] readFileOnClient(String clientPath) throws Exception {
         assertTrue("File not found on client: " + clientPath,
-                mDevice.doesFileExist(clientPath));
+                doesFileExist(clientPath));
         File copyOnHost = File.createTempFile("host", "copy");
         try {
-            executeAdbCommand("pull", clientPath, copyOnHost.getPath());
+            executePull(clientPath, copyOnHost.getPath());
             return Files.toByteArray(copyOnHost);
         } finally {
             FileUtil.deleteFile(copyOnHost);
@@ -209,8 +202,8 @@
         // ensure no profiles initially present
         for (ProfileLocation profileLocation : ProfileLocation.values()) {
             String clientPath = profileLocation.getPath();
-            if (mDevice.doesFileExist(clientPath)) {
-                executeAdbCommand(0, "shell", "rm", clientPath);
+            if (doesFileExist(clientPath)) {
+                executeSuShellAdbCommand(0, "rm", clientPath);
             }
         }
         executeCompile("-m", "speed-profile", "-f");
@@ -247,11 +240,11 @@
      * @param compileOptions extra options to pass to the compiler on the command line
      */
     private void executeCompile(String... compileOptions) throws Exception {
-        List<String> command = new ArrayList<>(Arrays.asList("shell", "cmd", "package", "compile"));
+        List<String> command = new ArrayList<>(Arrays.asList("cmd", "package", "compile"));
         command.addAll(Arrays.asList(compileOptions));
         command.add(APPLICATION_PACKAGE);
         String[] commandArray = command.toArray(new String[0]);
-        assertEquals("Success", executeAdbCommand(1, commandArray)[0]);
+        assertEquals("Success", executeSuShellAdbCommand(1, commandArray)[0]);
     }
 
     /**
@@ -261,21 +254,21 @@
         String targetPath = location.getPath();
         // Get the owner of the parent directory so we can set it on the file
         String targetDir = location.getDirectory();
-        if (!mDevice.doesFileExist(targetDir)) {
+        if (!doesFileExist(targetDir)) {
             fail("Not found: " + targetPath);
         }
         // in format group:user so we can directly pass it to chown
-        String owner = executeAdbCommand(1, "shell", "stat", "-c", "%U:%g", targetDir)[0];
+        String owner = executeSuShellAdbCommand(1, "stat", "-c", "%U:%g", targetDir)[0];
         // for some reason, I've observed the output starting with a single space
         while (owner.startsWith(" ")) {
             owner = owner.substring(1);
         }
-        mDevice.executeAdbCommand("push", localProfileFile.getAbsolutePath(), targetPath);
-        executeAdbCommand(0, "shell", "chown", owner, targetPath);
+        executePush(localProfileFile.getAbsolutePath(), targetPath);
+        executeSuShellAdbCommand(0, "chown", owner, targetPath);
         // Verify that the file was written successfully
-        assertTrue("failed to create profile file", mDevice.doesFileExist(targetPath));
+        assertTrue("failed to create profile file", doesFileExist(targetPath));
         assertEquals(Integer.toString(profileBytes.length),
-                executeAdbCommand(1, "shell", "stat", "-c", "%s", targetPath)[0]);
+                executeSuShellAdbCommand(1, "stat", "-c", "%s", targetPath)[0]);
     }
 
     /**
@@ -283,8 +276,8 @@
      * {@code oatdump --header-only}.
      */
     private String getCompilerFilter(String odexFilePath) throws DeviceNotAvailableException {
-        String[] response = executeAdbCommand(
-                "shell", "oatdump", "--header-only", "--oat-file=" + odexFilePath);
+        String[] response = executeSuShellAdbCommand(
+                "oatdump", "--header-only", "--oat-file=" + odexFilePath);
         String prefix = "compiler-filter =";
         for (String line : response) {
             line = line.trim();
@@ -302,14 +295,14 @@
      */
     private String getOdexFilePath() throws DeviceNotAvailableException {
         // Something like "package:/data/app/android.cts.compilation-1/base.apk"
-        String pathSpec = executeAdbCommand(1, "shell", "pm", "path", APPLICATION_PACKAGE)[0];
+        String pathSpec = executeSuShellAdbCommand(1, "pm", "path", APPLICATION_PACKAGE)[0];
         Matcher matcher = Pattern.compile("^package:(.+/)base\\.apk$").matcher(pathSpec);
         boolean found = matcher.find();
         assertTrue("Malformed spec: " + pathSpec, found);
         String apkDir = matcher.group(1);
         // E.g. /data/app/android.cts.compilation-1/oat/arm64/base.odex
-        String result = executeAdbCommand(1, "shell", "find", apkDir, "-name", "base.odex")[0];
-        assertTrue("odex file not found: " + result, mDevice.doesFileExist(result));
+        String result = executeSuShellAdbCommand(1, "find", apkDir, "-name", "base.odex")[0];
+        assertTrue("odex file not found: " + result, doesFileExist(result));
         return result;
     }
 
@@ -323,23 +316,24 @@
      * TODO: Use Assume.assumeTrue() if this test gets converted to JUnit 4.
      */
     private boolean canRunTest(Set<ProfileLocation> profileLocations) throws Exception {
-        boolean result = mIsRoot && (profileLocations.isEmpty() || isUseJitProfiles());
+        boolean result = mCanEnableDeviceRootAccess &&
+                (profileLocations.isEmpty() || isUseJitProfiles());
         if (!result) {
-            System.err.printf("Skipping test [isRoot=%s, %d profiles] on %s\n",
-                    mIsRoot, profileLocations.size(), mDevice);
+            System.err.printf("Skipping test [mCanEnableDeviceRootAccess=%s, %d profiles] on %s\n",
+                    mCanEnableDeviceRootAccess, profileLocations.size(), mDevice);
         }
         return result;
     }
 
     private boolean isUseJitProfiles() throws Exception {
         boolean propUseJitProfiles = Boolean.parseBoolean(
-                executeAdbCommand(1, "shell", "getprop", "dalvik.vm.usejitprofiles")[0]);
+                executeSuShellAdbCommand(1, "getprop", "dalvik.vm.usejitprofiles")[0]);
         return propUseJitProfiles;
     }
 
-    private String[] executeAdbCommand(int numLinesOutputExpected, String... command)
+    private String[] executeSuShellAdbCommand(int numLinesOutputExpected, String... command)
             throws DeviceNotAvailableException {
-        String[] lines = executeAdbCommand(command);
+        String[] lines = executeSuShellAdbCommand(command);
         assertEquals(
                 String.format(Locale.US, "Expected %d lines output, got %d running %s: %s",
                         numLinesOutputExpected, lines.length, Arrays.toString(command),
@@ -348,10 +342,38 @@
         return lines;
     }
 
-    private String[] executeAdbCommand(String... command) throws DeviceNotAvailableException {
-        String output = mDevice.executeAdbCommand(command);
+    private String[] executeSuShellAdbCommand(String... command)
+            throws DeviceNotAvailableException {
+        // Add `shell su root` to the adb command.
+        String cmdString = String.join(" ", command);
+        String output = mDevice.executeShellCommand("su root " + cmdString);
         // "".split() returns { "" }, but we want an empty array
         String[] lines = output.equals("") ? new String[0] : output.split("\n");
         return lines;
     }
+
+    private void executePush(String hostPath, String targetPath)
+            throws DeviceNotAvailableException {
+        String tmpPath = "/data/local/tmp/" + APPLICATION_PACKAGE + ".push.tmp";
+        assertTrue(mDevice.pushFile(new File(hostPath), tmpPath));
+        executeSuShellAdbCommand("mv", tmpPath, targetPath);
+    }
+
+    private void executePull(String targetPath, String hostPath)
+            throws DeviceNotAvailableException {
+        String tmpPath = "/data/local/tmp/" + APPLICATION_PACKAGE + ".pull.tmp";
+        executeSuShellAdbCommand("cp", targetPath, tmpPath);
+        try {
+            executeSuShellAdbCommand("chmod", "606", tmpPath);
+            assertTrue(mDevice.pullFile(tmpPath, new File(hostPath)));
+        } finally {
+            executeSuShellAdbCommand("rm", tmpPath);
+        }
+    }
+
+    private boolean doesFileExist(String path) throws DeviceNotAvailableException {
+        String[] result = executeSuShellAdbCommand("ls", path);
+        // Testing for empty directories will return an empty array.
+        return !(result.length > 0 && result[0].contains("No such file"));
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
index 302f9da..c9cf648 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegationTest.java
@@ -44,6 +44,7 @@
     private static final String DELEGATE_PKG = "com.android.cts.delegate";
     private static final String DELEGATE_ACTIVITY_NAME =
             DELEGATE_PKG + ".DelegatedScopesReceiverActivity";
+    private static final String TEST_PKG = "com.android.cts.apprestrictions.targetapp";
 
     // Broadcasts received from the delegate app.
     private static final String ACTION_REPORT_SCOPES = "com.android.cts.delegate.report_scopes";
@@ -130,6 +131,53 @@
                 .getDelegatedScopes(ADMIN_RECEIVER_COMPONENT, NON_EXISTENT_PKG).isEmpty());
     }
 
+    public void testCanRetrieveDelegates() {
+        final List<String> someScopes = Arrays.asList(
+                DELEGATION_APP_RESTRICTIONS,
+                DELEGATION_ENABLE_SYSTEM_APP);
+        final List<String> otherScopes = Arrays.asList(
+                DELEGATION_BLOCK_UNINSTALL,
+                DELEGATION_ENABLE_SYSTEM_APP);
+
+        // In the beginning there are no delegates.
+        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+                .isEmpty());
+        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+                .isEmpty());
+        assertTrue("No delegates should be found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+                .isEmpty());
+
+        // After delegating scopes to two packages.
+        mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT,
+                DELEGATE_PKG, someScopes);
+        mDevicePolicyManager.setDelegatedScopes(ADMIN_RECEIVER_COMPONENT,
+                TEST_PKG, otherScopes);
+
+        // The expected delegates are returned.
+        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+                .contains(DELEGATE_PKG));
+        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+                .contains(TEST_PKG));
+        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+                .contains(DELEGATE_PKG));
+        assertTrue("Expected delegate not found", getDelegatePackages(DELEGATION_ENABLE_SYSTEM_APP)
+                .contains(TEST_PKG));
+
+        // Packages are only returned in their recpective scopes.
+        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_APP_RESTRICTIONS)
+                .contains(TEST_PKG));
+        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_BLOCK_UNINSTALL)
+                .contains(DELEGATE_PKG));
+        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
+                .contains(DELEGATE_PKG));
+        assertFalse("Unexpected delegate package", getDelegatePackages(DELEGATION_CERT_INSTALL)
+                .contains(TEST_PKG));
+    }
+
+    private List<String> getDelegatePackages(String scope) {
+        return mDevicePolicyManager.getDelegatePackages(ADMIN_RECEIVER_COMPONENT, scope);
+    }
+
     private void startAndWaitDelegateActivity() throws InterruptedException {
         mContext.startActivity(new Intent()
                 .setComponent(new ComponentName(DELEGATE_PKG, DELEGATE_ACTIVITY_NAME))
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
index ff51e9e..0694d76 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -16,7 +16,6 @@
 package com.android.cts.deviceowner;
 
 import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Process;
@@ -25,7 +24,6 @@
 import com.android.org.conscrypt.TrustedCertificateStore;
 
 import java.io.ByteArrayInputStream;
-import java.lang.reflect.Method;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.util.List;
@@ -133,9 +131,7 @@
         mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), true);
 
         long timeBefore = System.currentTimeMillis();
-        final Method retrieveNetworkLogsMethod = DevicePolicyManager.class.getDeclaredMethod(
-                "retrieveNetworkLogs", ComponentName.class, long.class);
-        retrieveNetworkLogsMethod.invoke(mDevicePolicyManager, getWho(), 0 /* batchToken */);
+        mDevicePolicyManager.retrieveNetworkLogs(getWho(), 0 /* batchToken */);
         long timeAfter = System.currentTimeMillis();
 
         final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
index 4bd993e..a35574b 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/LauncherAppsTests.java
@@ -25,6 +25,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.LauncherActivityInfo;
 import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -126,7 +127,12 @@
     public void testAccessPrimaryProfileFromManagedProfile() throws Exception {
         // Try to access main profile from managed profile, which is not allowed.
         assertEquals(0, mLauncherApps.getActivityList(null, mUser).size());
-        assertNull(mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser));
+        try {
+            mLauncherApps.getApplicationInfo(SIMPLE_APP_PACKAGE, /* flags= */ 0, mUser);
+            fail("Missing exception");
+        } catch (PackageManager.NameNotFoundException e) {
+            // Expected.
+        }
         assertFalse(mLauncherApps.isPackageEnabled(SIMPLE_APP_PACKAGE, mUser));
 
         final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com/"));
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/incident/apps/batterystatsapp/AndroidManifest.xml b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
index d4937aa..5e1198f 100644
--- a/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
+++ b/hostsidetests/incident/apps/batterystatsapp/AndroidManifest.xml
@@ -18,6 +18,8 @@
         package="com.android.server.cts.device.batterystats" >
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+    <uses-permission android:name="android.permission.BLUETOOTH"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
     <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java
index a02fe83..496e61a 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBackgroundService.java
@@ -45,6 +45,7 @@
             Log.w(TAG, "Couldn't determine if app is in background. Proceeding with test anyway.");
         }
 
+        Log.i(TAG, "Starting action from background service");
         doAction(this, intent.getStringExtra(KEY_ACTION));
     }
 }
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
index 7528cac..480ca2f 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -16,11 +16,19 @@
 
 package com.android.server.cts.device.batterystats;
 
+import android.accounts.Account;
+import android.app.Activity;
 import android.app.ActivityManager;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.le.BluetoothLeScanner;
+import android.bluetooth.le.ScanCallback;
+import android.bluetooth.le.ScanResult;
+import android.bluetooth.le.ScanSettings;
 import android.content.BroadcastReceiver;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -31,6 +39,7 @@
 import android.os.Looper;
 import android.util.Log;
 
+
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -39,8 +48,13 @@
     private static final String TAG = BatteryStatsBgVsFgActions.class.getSimpleName();
 
     public static final String KEY_ACTION = "action";
+    public static final String ACTION_BLE_SCAN = "action.ble_scan";
     public static final String ACTION_JOB_SCHEDULE = "action.jobs";
+    public static final String ACTION_SYNC = "action.sync";
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
+    public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
+    public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
+
 
     /** Perform the action specified by the given action code (see constants above). */
     public static void doAction(Context ctx, String actionCode) {
@@ -50,11 +64,23 @@
         }
         sleep(100);
         switch(actionCode) {
+            case ACTION_BLE_SCAN:
+                doBleScan(ctx);
+                break;
             case ACTION_JOB_SCHEDULE:
                 doScheduleJob(ctx);
                 break;
+            case ACTION_SYNC:
+                doSync(ctx);
+                break;
             case ACTION_WIFI_SCAN:
-                doWifi(ctx);
+                doWifiScan(ctx);
+                break;
+            case ACTION_WIFI_DOWNLOAD:
+                doWifiDownload(ctx);
+                break;
+            case ACTION_WIFI_UPLOAD:
+                doWifiUpload(ctx);
                 break;
             default:
                 Log.e(TAG, "Intent had invalid action");
@@ -62,6 +88,48 @@
         sleep(100);
     }
 
+    private static void doBleScan(Context ctx) {
+        BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        if (bluetoothAdapter == null) {
+            Log.e(TAG, "Device does not support Bluetooth");
+            return;
+        }
+        if (!bluetoothAdapter.isEnabled()) {
+            Log.e(TAG, "Bluetooth is not enabled");
+            return;
+        }
+
+        BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
+        if (bleScanner == null) {
+            Log.e(TAG, "Cannot access BLE scanner");
+            return;
+        }
+
+        ScanCallback scanCallback = new ScanCallback() {
+            @Override
+            public void onScanResult(int callbackType, ScanResult result) {
+                Log.v(TAG, "called onScanResult");
+            }
+
+            @Override
+            public void onScanFailed(int errorCode) {
+                Log.v(TAG, "called onScanFailed");
+            }
+
+            @Override
+            public void onBatchScanResults(List<ScanResult> results) {
+                Log.v(TAG, "called onBatchScanResults");
+
+            }
+        };
+        ScanSettings scanSettings = new ScanSettings.Builder()
+                .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
+
+        bleScanner.startScan(null, scanSettings, scanCallback);
+        sleep(2_000);
+        bleScanner.stopScan(scanCallback);
+    }
+
     private static void doScheduleJob(Context ctx) {
         final ComponentName JOB_COMPONENT_NAME =
                 new ComponentName("com.android.server.cts.device.batterystats",
@@ -86,7 +154,42 @@
         }.execute();
     }
 
-    private static void doWifi(Context ctx) {
+    private static void doSync(Context ctx) {
+        BatteryStatsAuthenticator.removeAllAccounts(ctx);
+        final Account account = BatteryStatsAuthenticator.getTestAccount();
+        // Create the test account.
+        BatteryStatsAuthenticator.ensureTestAccount(ctx);
+        // Force set is syncable.
+        ContentResolver.setMasterSyncAutomatically(true);
+        ContentResolver.setIsSyncable(account, BatteryStatsProvider.AUTHORITY, 1);
+
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                try {
+                    Log.v(TAG, "Starting sync");
+                    BatteryStatsSyncAdapter.requestSync(account);
+                    sleep(500);
+                } catch (Exception e) {
+                    Log.e(TAG, "Exception trying to sync", e);
+                }
+                BatteryStatsAuthenticator.removeAllAccounts(ctx);
+                return null;
+            }
+
+            @Override
+            protected void onPostExecute(Void aVoid) {
+                super.onPostExecute(aVoid);
+                Log.v(TAG, "Finished sync method");
+                // If ctx is an Activity, finish it when sync is done. If it's a service, don't.
+                if(ctx instanceof Activity){
+                    ((Activity) ctx).finish();
+                }
+            }
+        }.execute();
+    }
+
+    private static void doWifiScan(Context ctx) {
         IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
         CountDownLatch onReceiveLatch = new CountDownLatch(1);
         BroadcastReceiver receiver = registerReceiver(ctx, onReceiveLatch, intentFilter);
@@ -94,6 +197,26 @@
         waitForReceiver(ctx, 3_000, onReceiveLatch, receiver);
     }
 
+    private static void doWifiDownload(Context ctx) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                BatteryStatsWifiTransferTests.download();
+                return null;
+            }
+        }.execute();
+    }
+
+    private static void doWifiUpload(Context ctx) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                BatteryStatsWifiTransferTests.upload();
+                return null;
+            }
+        }.execute();
+    }
+
     /** Register receiver to determine when given action is complete. */
     private static BroadcastReceiver registerReceiver(
             Context ctx, CountDownLatch onReceiveLatch, IntentFilter intentFilter) {
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
index d6869a1..c41b244 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions
         .ACTION_JOB_SCHEDULE;
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.ACTION_SYNC;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_ACTION;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.doAction;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.isAppInBackground;
@@ -51,7 +52,12 @@
             Log.w(TAG, "Couldn't determine if app is in foreground. Proceeding with test anyway");
         }
 
-        doAction(this, intent.getStringExtra(KEY_ACTION));
-        finish();
+        String action = intent.getStringExtra(KEY_ACTION);
+        doAction(this, action);
+
+        // ACTION_SYNC will finish itself. Others get finished here.
+        if (!ACTION_SYNC.equals(action)) {
+            finish();
+        }
     }
 }
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
index c619166..c40c950 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsProcessStateTests.java
@@ -34,12 +34,7 @@
     public void testForegroundService() throws Exception {
         Intent intent = new Intent();
         intent.setClass(mContext, SimpleForegroundService.class);
-        Notification notification = new Notification.Builder(mContext, "Foreground Service")
-                .setContentTitle("CTS Foreground")
-                .setSmallIcon(android.R.drawable.ic_secure)
-                .build();
-        mContext.getSystemService(NotificationManager.class).startServiceInForeground(intent,
-                1, notification);
+        mContext.startForegroundService(intent);
         Thread.sleep(3000);
     }
 
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
index 394a070..1633301 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsWifiTransferTests.java
@@ -45,177 +45,60 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-/**
- * Used by BatteryStatsValidationTest.
- */
-@RunWith(AndroidJUnit4.class)
-public class BatteryStatsWifiTransferTests extends BatteryStatsDeviceTestBase {
+public class BatteryStatsWifiTransferTests {
     private static final String TAG = "BatteryStatsWifiTransferTests";
 
-    /** String extra to instruct whether to download or upload. */
-    private static final String EXTRA_ACTION = "action";
-    private static final String ACTION_DOWNLOAD = "download";
-    private static final String ACTION_UPLOAD = "upload";
-
-    /** Action to notify the test that wifi transfer is complete. */
-    private static final String ACTION_TRANSFER_COMPLETE = "transfer_complete";
-
-    /** String extra of any error encountered during wifi transfer. */
-    private static final String EXTRA_TRANSFER_ERROR = "transfer_error";
-
     private static final int READ_BUFFER_SIZE = 4096;
 
     /** Server to send requests to. */
     private static final String SERVER_URL = "https://developer.android.com/index.html";
 
-    private Context mContext;
-    private CountDownLatch mResultsReceivedSignal;
-    private Intent mTransferService;
-    private boolean mHasFeature;
-    private volatile String mError;
+    public static String download() {
+        HttpURLConnection conn = null;
+        try {
+            URL url = new URL(SERVER_URL);
+            conn = (HttpURLConnection) url.openConnection();
+            conn.setUseCaches(false);
+            conn.setRequestProperty("Accept-Encoding", "identity"); // Disable compression.
 
-    @Before
-    public void setUp() {
-        mContext = InstrumentationRegistry.getTargetContext();
-        mHasFeature = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
-        if (!mHasFeature) {
-            return;
-        }
-        mResultsReceivedSignal = new CountDownLatch(1);
-        mTransferService = new Intent(mContext, TransferService.class);
-        registerReceiver(mContext, mResultsReceivedSignal);
-    }
+            InputStream in = new BufferedInputStream(conn.getInputStream());
+            byte[] data = new byte[READ_BUFFER_SIZE];
 
-    @Test
-    public void testBackgroundDownload() throws Exception {
-        doBackgroundTransfer(ACTION_DOWNLOAD);
-    }
-
-    @Test
-    public void testForegroundDownload() throws Exception {
-        doForegroundTransfer(ACTION_DOWNLOAD);
-    }
-
-    @Test
-    public void testBackgroundUpload() throws Exception {
-        doBackgroundTransfer(ACTION_UPLOAD);
-    }
-
-    @Test
-    public void testForegroundUpload() throws Exception {
-        doForegroundTransfer(ACTION_UPLOAD);
-    }
-
-    private void doBackgroundTransfer(String action) throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        mTransferService.putExtra(EXTRA_ACTION, action);
-        mContext.startService(mTransferService);
-        mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
-        assertTrue("Got error: " + mError, mError == null);
-    }
-
-    private void doForegroundTransfer(String action) throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-        mTransferService.putExtra(EXTRA_ACTION, action);
-        Notification notification =
-            new Notification.Builder(mContext, "Wifi Transfer Foreground Service")
-                    .setContentTitle("Wifi Transfer Foreground")
-                    .setContentText("Wifi Transfer Foreground")
-                    .setSmallIcon(android.R.drawable.ic_secure)
-                    .build();
-        mContext.getSystemService(NotificationManager.class).startServiceInForeground(mTransferService,
-                1, notification);
-
-        mResultsReceivedSignal.await(10, TimeUnit.SECONDS);
-        assertTrue("Got error: " + mError, mError == null);
-    }
-
-    private void registerReceiver(Context ctx, CountDownLatch onReceiveLatch) {
-        ctx.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                mError = intent.getStringExtra(EXTRA_TRANSFER_ERROR);
-                onReceiveLatch.countDown();
+            int total = 0;
+            int count;
+            while ((count = in.read(data)) != -1) {
+                total += count;
             }
-        }, new IntentFilter(ACTION_TRANSFER_COMPLETE));
-    }
-
-    public static class TransferService extends IntentService {
-        public TransferService() {
-            this(TransferService.class.getName());
+            Log.i(TAG, Integer.toString(total));
+        } catch (IOException e) {
+            Log.i(TAG, e.toString());
+            return "Caught exception";
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
         }
+        return null;
+   }
 
-        public TransferService(String name) {
-            super(name);
+
+   public static String upload() {
+        HttpURLConnection conn = null;
+        try {
+            // Append a long query string.
+            char[] queryChars = new char[2*1024];
+            Arrays.fill(queryChars, 'a');
+            URL url = new URL(SERVER_URL + "?" + new String(queryChars));
+            conn = (HttpURLConnection) url.openConnection();
+            InputStream in = conn.getInputStream();
+            in.close();
+        } catch (IOException e) {
+            return "IO exception";
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
         }
-
-        @Override
-        protected void onHandleIntent(Intent intent) {
-            String error = null;
-            switch (intent.getStringExtra(EXTRA_ACTION)) {
-                case ACTION_DOWNLOAD:
-                    error = download();
-                    break;
-                case ACTION_UPLOAD:
-                    error = upload();
-                    break;
-                default:
-                    error = "Unknown action " + intent.getStringExtra(EXTRA_ACTION);
-            }
-            Intent localIntent = new Intent(ACTION_TRANSFER_COMPLETE);
-            localIntent.putExtra(EXTRA_TRANSFER_ERROR, error);
-            sendBroadcast(localIntent);
-       }
-
-       private String download() {
-            HttpURLConnection conn = null;
-            try {
-                URL url = new URL(SERVER_URL);
-                conn = (HttpURLConnection) url.openConnection();
-                conn.setUseCaches(false);
-                conn.setRequestProperty("Accept-Encoding", "identity"); // Disable compression.
-
-                InputStream in = new BufferedInputStream(conn.getInputStream());
-                byte[] data = new byte[READ_BUFFER_SIZE];
-
-                int total = 0;
-                int count;
-                while ((count = in.read(data)) != -1) {
-                    total += count;
-                }
-                Log.i(TAG, Integer.toString(total));
-            } catch (IOException e) {
-                 return "Caught exception";
-            } finally {
-                if (conn != null) {
-                    conn.disconnect();
-                }
-            }
-            return null;
-       }
-
-       private String upload() {
-            HttpURLConnection conn = null;
-            try {
-                // Append a long query string.
-                char[] queryChars = new char[2*1024];
-                Arrays.fill(queryChars, 'a');
-                URL url = new URL(SERVER_URL + "?" + new String(queryChars));
-                conn = (HttpURLConnection) url.openConnection();
-                InputStream in = conn.getInputStream();
-                in.close();
-            } catch (IOException e) {
-                return "IO exception";
-            } finally {
-                if (conn != null) {
-                    conn.disconnect();
-                }
-            }
-            return null;
-       }
-    }
+        return null;
+   }
 }
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
index b8d4507..ed21615 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/SimpleForegroundService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.cts.device.batterystats;
 
+import android.app.Notification;
 import android.app.Service;
 import android.content.Intent;
 import android.os.Handler;
@@ -67,6 +68,12 @@
 
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {
+        Notification notification = new Notification.Builder(this, "Foreground Service")
+                .setContentTitle("CTS Foreground")
+                .setSmallIcon(android.R.drawable.ic_secure)
+                .build();
+        startForeground(1, notification);
+
         Message msg = mServiceHandler.obtainMessage();
         msg.arg1 = startId;
         mServiceHandler.sendMessage(msg);
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index f6e9e31..758c443 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -38,11 +38,19 @@
             = "com.android.server.cts.device.batterystats.provider/"
             + "com.android.server.cts.device.batterystats";
 
+    // Low end of packet size. TODO: Get exact packet size
+    private static final int LOW_MTU = 1500;
+    // High end of packet size. TODO: Get exact packet size
+    private static final int HIGH_MTU = 2500;
 
     // Constants from BatteryStatsBgVsFgActions.java (not directly accessible here).
     public static final String KEY_ACTION = "action";
+    public static final String ACTION_BLE_SCAN = "action.ble_scan";
     public static final String ACTION_JOB_SCHEDULE = "action.jobs";
+    public static final String ACTION_SYNC = "action.sync";
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
+    public static final String ACTION_WIFI_DOWNLOAD = "action.wifi_download";
+    public static final String ACTION_WIFI_UPLOAD = "action.wifi_upload";
 
     @Override
     protected void setUp() throws Exception {
@@ -117,6 +125,25 @@
         batteryOffScreenOn();
     }
 
+    public void testBleScans() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+
+        // Foreground test.
+        executeForeground(ACTION_BLE_SCAN);
+        Thread.sleep(2_500);
+        assertValueRange("blem", "", 5, 1, 1); // ble_scan_count
+        assertValueRange("blem", "", 6, 0, 0); // ble_scan_count_bg
+
+        // Background test.
+        executeBackground(ACTION_BLE_SCAN);
+        Thread.sleep(2_500);
+        assertValueRange("blem", "", 5, 2, 2); // ble_scan_count
+        assertValueRange("blem", "", 6, 1, 1); // ble_scan_count_bg
+
+        batteryOffScreenOn();
+    }
+
     public void testJobBgVsFg() throws Exception {
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);
@@ -136,6 +163,26 @@
         batteryOffScreenOn();
     }
 
+    public void testSyncBgVsFg() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+
+        // Foreground test.
+        executeForeground(ACTION_SYNC);
+        Thread.sleep(3_000);
+        // Allow one or two syncs in this time frame (not just one) due to unpredictable syncs.
+        assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 1, 2); // count
+        assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 0, 0); // background_count
+
+        // Background test.
+        executeBackground(ACTION_SYNC);
+        Thread.sleep(3_000);
+        assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 6, 2, 4); // count
+        assertValueRange("sy", DEVICE_SIDE_SYNC_COMPONENT, 8, 1, 2); // background_count
+
+        batteryOffScreenOn();
+    }
+
     public void testWifiScans() throws Exception {
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);
@@ -148,7 +195,7 @@
 
         // Background count test.
         executeBackground(ACTION_WIFI_SCAN);
-        Thread.sleep(4_000);
+        Thread.sleep(6_000);
         assertValueRange("wfl", "", 7, 2, 2); // scan_count
         assertValueRange("wfl", "", 11, 1, 1); // scan_count_bg
 
@@ -224,23 +271,34 @@
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);
 
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
-                "testForegroundDownload");
-        long foregroundBytes = getDownloadedBytes();
-        assertTrue(foregroundBytes > 0);
-        long min = foregroundBytes + MIN_HTTP_HEADER_BYTES;
-        long max = foregroundBytes + (30 * 1024); // Add some fuzzing.
-        assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
-        assertValueRange("nt", "", 11, 1, 40); // wifi_bytes_tx
+        final long FUZZ = 50 * 1024;
 
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
-                "testBackgroundDownload");
-        long backgroundBytes = getDownloadedBytes();
-        assertTrue(backgroundBytes > 0);
-        min += backgroundBytes + MIN_HTTP_HEADER_BYTES;
-        max += backgroundBytes + (30 * 1024);
+        long prevBytes = getLongValue(getUid(), "nt", "", 6);
+
+        executeForeground(ACTION_WIFI_DOWNLOAD);
+        long downloadedBytes = getDownloadedBytes();
+        assertTrue(downloadedBytes > 0);
+        long min = prevBytes + downloadedBytes + MIN_HTTP_HEADER_BYTES;
+        long max = prevBytes + downloadedBytes + FUZZ; // Add some fuzzing.
         assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
-        assertValueRange("nt", "", 11, 2, 80); // wifi_bytes_tx
+        assertValueRange("nt", "", 10, min / HIGH_MTU, max / LOW_MTU); // wifi_packets_rx
+
+        // Do the background download
+        long prevBgBytes = getLongValue(getUid(), "nt", "", 20);
+        executeBackground(ACTION_WIFI_DOWNLOAD);
+        Thread.sleep(4000);
+        downloadedBytes = getDownloadedBytes();
+
+        long minBg = prevBgBytes + downloadedBytes + MIN_HTTP_HEADER_BYTES;
+        long maxBg = prevBgBytes + downloadedBytes + FUZZ;
+        assertValueRange("nt", "", 20, minBg, maxBg); // wifi_bytes_bg_rx
+        assertValueRange("nt", "", 24, minBg / HIGH_MTU, maxBg / LOW_MTU); // wifi_packets_bg_rx
+
+        // Also increases total wifi counts.
+        min += downloadedBytes + MIN_HTTP_HEADER_BYTES;
+        max += downloadedBytes + FUZZ;
+        assertValueRange("nt", "", 6, min, max); // wifi_bytes_rx
+        assertValueRange("nt", "", 10, min / HIGH_MTU, max / LOW_MTU); // wifi_packets_rx
 
         batteryOffScreenOn();
     }
@@ -252,33 +310,37 @@
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);
 
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
-                "testForegroundUpload");
+        executeForeground(ACTION_WIFI_UPLOAD);
+        Thread.sleep(2000);
         int min = MIN_HTTP_HEADER_BYTES + (2 * 1024);
         int max = min + (6 * 1024); // Add some fuzzing.
         assertValueRange("nt", "", 7, min, max); // wifi_bytes_tx
 
-        runDeviceTests(DEVICE_SIDE_TEST_PACKAGE, ".BatteryStatsWifiTransferTests",
-                "testBackgroundUpload");
-        assertValueRange("nt", "", 7, min * 2, max * 2); // wifi_bytes_tx
+        executeBackground(ACTION_WIFI_UPLOAD);
+        Thread.sleep(4000);
+        assertValueRange("nt", "", 21, min * 2, max * 2); // wifi_bytes_bg_tx
 
         batteryOffScreenOn();
     }
 
+    private int getUid() throws Exception {
+        String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
+                + DEVICE_SIDE_TEST_PACKAGE);
+        String[] uidLineParts = uidLine.split(":");
+        // 3rd entry is package uid
+        assertTrue(uidLineParts.length > 2);
+        int uid = Integer.parseInt(uidLineParts[2].trim());
+        assertTrue(uid > 10000);
+        return uid;
+    }
+
     /**
      * Verifies that the recorded time for the specified tag and name in the test package
      * is within the specified range.
      */
     private void assertValueRange(String tag, String optionalAfterTag,
             int index, long min, long max) throws Exception {
-        String uidLine = getDevice().executeShellCommand("cmd package list packages -U "
-                + DEVICE_SIDE_TEST_PACKAGE);
-        String[] uidLineParts = uidLine.split(":");
-        // 3rd entry is package uid
-        assertTrue(uidLineParts.length > 2);
-        int uid = Integer.parseInt(uidLineParts[2].trim());
-        assertTrue(uid > 10000);
-
+        int uid = getUid();
         long value = getLongValue(uid, tag, optionalAfterTag, index);
 
         assertTrue("Value " + value + " is less than min " + min, value >= min);
@@ -344,13 +406,14 @@
         String log = getDevice().executeShellCommand(
                 "logcat -d -s BatteryStatsWifiTransferTests -e '\\d+'");
         String[] lines = log.split("\n");
+        long size = 0;
         for (int i = lines.length - 1; i >= 0; i--) {
             String[] parts = lines[i].split(":");
             String num = parts[parts.length - 1].trim();
             if (num.matches("\\d+")) {
-                return Integer.parseInt(num);
+                size = Integer.parseInt(num);
             }
         }
-        return 0;
+        return size;
     }
 }
diff --git a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
index d8f2f75..f4c0698 100644
--- a/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
+++ b/hostsidetests/inputmethodservice/deviceside/devicetest/src/android/inputmethodservice/cts/devicetest/InputMethodServiceDeviceTest.java
@@ -22,7 +22,6 @@
 import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_CREATE;
 import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_DESTROY;
 import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT;
-import static android.inputmethodservice.cts.common.DeviceEventConstants.DeviceEventType.ON_START_INPUT_VIEW;
 import static android.inputmethodservice.cts.common.ImeCommandConstants.ACTION_IME_COMMAND;
 import static android.inputmethodservice.cts.common.ImeCommandConstants.COMMAND_SWITCH_INPUT_METHOD;
 import static android.inputmethodservice.cts.common.ImeCommandConstants.EXTRA_ARG_STRING1;
@@ -54,9 +53,7 @@
 
     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
 
-    /**
-     * Test to check {@link Ime1Constants} receives onCreate, onStartInput, and onStartInputView.
-     */
+    /** Test to check CtsInputMethod1 receives onCreate and onStartInput. */
     @Test
     public void testCreateIme1() throws Throwable {
         final TestHelper helper = new TestHelper(getClass(), DeviceTestConstants.TEST_CREATE_IME1);
@@ -65,7 +62,7 @@
                         .collect(startingFrom(helper.isStartOfTest()))
                         .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
                         .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onCreate is called");
+                TIMEOUT, "CtsInputMethod1.onCreate is called");
 
         final long startActivityTime = SystemClock.uptimeMillis();
         helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -74,18 +71,10 @@
                         .filter(isNewerThan(startActivityTime))
                         .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
                         .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onStartInput is called");
-
-        final long touchEntryTime = SystemClock.uptimeMillis();
-        helper.findUiObject(R.id.text_entry).click();
-
-        pollingCheck(() -> helper.queryAllEvents()
-                        .filter(isNewerThan(touchEntryTime))
-                        .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
-                        .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onStartInputView is called");
+                TIMEOUT, "CtsInputMethod1.onStartInput is called");
     }
 
+    /** Test to check IME is switched from CtsInputMethod1 to CtsInputMethod2. */
     @Test
     public void testSwitchIme1ToIme2() throws Throwable {
         final TestHelper helper = new TestHelper(
@@ -95,7 +84,7 @@
                         .collect(startingFrom(helper.isStartOfTest()))
                         .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_CREATE)))
                         .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onCreate is called");
+                TIMEOUT, "CtsInputMethod1.onCreate is called");
 
         final long startActivityTime = SystemClock.uptimeMillis();
         helper.launchActivity(DeviceTestConstants.PACKAGE, DeviceTestConstants.TEST_ACTIVITY_CLASS);
@@ -104,18 +93,11 @@
                         .filter(isNewerThan(startActivityTime))
                         .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT)))
                         .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onStartInput is called");
+                TIMEOUT, "CtsInputMethod1.onStartInput is called");
 
-        final long touchEntryTime = SystemClock.uptimeMillis();
         helper.findUiObject(R.id.text_entry).click();
 
-        pollingCheck(() -> helper.queryAllEvents()
-                        .filter(isNewerThan(touchEntryTime))
-                        .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_START_INPUT_VIEW)))
-                        .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onStartInputView is called");
-
-        // Switch IME from Ime1Constants to Ime2Constants.
+        // Switch IME from CtsInputMethod1 to CtsInputMethod2.
         final long switchImeTime = SystemClock.uptimeMillis();
         helper.shell(ShellCommandUtils.broadcastIntent(
                 ACTION_IME_COMMAND, Ime1Constants.PACKAGE,
@@ -124,21 +106,22 @@
 
         pollingCheck(() -> helper.shell(ShellCommandUtils.getCurrentIme())
                         .equals(Ime2Constants.IME_ID),
-                TIMEOUT, "Ime2Constants is current IME");
+                TIMEOUT, "CtsInputMethod2 is current IME");
         pollingCheck(() -> helper.queryAllEvents()
                         .filter(isNewerThan(switchImeTime))
                         .filter(isFrom(Ime1Constants.CLASS).and(isType(ON_DESTROY)))
                         .findAny().isPresent(),
-                TIMEOUT, "Ime1Constants.onDestroy is called");
+                TIMEOUT, "CtsInputMethod1.onDestroy is called");
         pollingCheck(() -> helper.queryAllEvents()
                         .filter(isNewerThan(switchImeTime))
                         .filter(isFrom(Ime2Constants.CLASS))
-                        .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT, ON_START_INPUT_VIEW))
+                        .collect(sequenceOfTypes(ON_CREATE, ON_START_INPUT))
                         .matched(),
                 TIMEOUT,
-                "Ime2Constants.onCreate,onStartInput,onStartInputView are called in sequence");
+                "CtsInputMethod2.onCreate and onStartInput are called in sequence");
     }
 
+    /** Test to check CtsInputMethod1 isn't current IME. */
     @Test
     public void testIme1IsNotCurrentIme() throws Throwable {
         final TestHelper helper =
@@ -150,7 +133,7 @@
         pollingCheck(() -> !helper.shell(ShellCommandUtils.getCurrentIme())
                         .equals(Ime1Constants.IME_ID),
                 TIMEOUT,
-                "Ime1Constants is uninstalled or disabled, and current IME becomes other IME");
+                "CtsInputMethod1 is uninstalled or disabled, and current IME becomes other IME");
     }
 
     /**
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
index 2fc0bc2..0f2965c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractAppIdleTestCase.java
@@ -143,6 +143,8 @@
         assertBackgroundNetworkAccess(true);
         setBatterySaverMode(true);
         assertBackgroundNetworkAccess(false);
+        // Use setBatterySaverMode API to leave power-save mode instead of plugging in charger
+        setBatterySaverMode(false);
         turnBatteryOn();
         assertBackgroundNetworkAccess(true);
 
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 15daed9..577f62c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -100,6 +100,7 @@
     protected ConnectivityManager mCm;
     protected WifiManager mWfm;
     protected int mUid;
+    private int mMyUid;
     private String mMeteredWifi;
     private MyServiceClient mServiceClient;
     private boolean mHasWatch;
@@ -115,7 +116,7 @@
         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         mWfm = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mUid = getUid(TEST_APP2_PKG);
-        final int myUid = getUid(mContext.getPackageName());
+        mMyUid = getUid(mContext.getPackageName());
         mServiceClient = new MyServiceClient(mContext);
         mServiceClient.bind();
         mHasWatch = mContext.getPackageManager().hasSystemFeature(
@@ -128,7 +129,7 @@
         mSupported = setUpActiveNetworkMeteringState();
 
         Log.i(TAG, "Apps status on " + getName() + ":\n"
-                + "\ttest app: uid=" + myUid + ", state=" + getProcessStateByUid(myUid) + "\n"
+                + "\ttest app: uid=" + mMyUid + ", state=" + getProcessStateByUid(mMyUid) + "\n"
                 + "\tapp2: uid=" + mUid + ", state=" + getProcessStateByUid(mUid));
    }
 
@@ -204,6 +205,21 @@
         assertEquals("wrong status", toString(expectedStatus), actualStatus);
     }
 
+    protected void assertMyRestrictBackgroundStatus(int expectedStatus) throws Exception {
+        final int actualStatus = mCm.getRestrictBackgroundStatus();
+        assertEquals("Wrong status", toString(expectedStatus), toString(actualStatus));
+    }
+
+    protected boolean isMyRestrictBackgroundStatus(int expectedStatus) throws Exception {
+        final int actualStatus = mCm.getRestrictBackgroundStatus();
+        if (expectedStatus != actualStatus) {
+            Log.d(TAG, "Expected: " + toString(expectedStatus)
+                    + " but actual: " + toString(actualStatus));
+            return false;
+        }
+        return true;
+    }
+
     protected void assertBackgroundNetworkAccess(boolean expectAllowed) throws Exception {
         assertBackgroundState(); // Sanity check.
         assertNetworkAccess(expectAllowed);
@@ -700,9 +716,9 @@
         Log.i(TAG, "Setting Battery Saver Mode to " + enabled);
         if (enabled) {
             turnBatteryOff();
-            executeSilentShellCommand("settings put global low_power 1");
+            executeSilentShellCommand("cmd power set-mode 1");
         } else {
-            executeSilentShellCommand("settings put global low_power 0");
+            executeSilentShellCommand("cmd power set-mode 0");
             turnBatteryOn();
         }
     }
@@ -817,9 +833,7 @@
         }
         if (latch.await(FOREGROUND_PROC_NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
             if (!errors[0].isEmpty()) {
-                // TODO: revert this change once b/35523062 is fixed.
-//                fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
-                assertForegroundNetworkAccess();
+                fail("Network is not available for app2 (" + mUid + "): " + errors[0]);
             }
         } else {
             fail("Timed out waiting for network availability status from app2 (" + mUid + ")");
diff --git a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
index c3537c8..599a31c 100644
--- a/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
+++ b/hostsidetests/net/app/src/com/android/cts/net/hostside/DataSaverModeTest.java
@@ -20,16 +20,21 @@
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
 import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED;
 
+import android.util.Log;
+
 public class DataSaverModeTest extends AbstractRestrictBackgroundNetworkTestCase {
 
     private static final String[] REQUIRED_WHITELISTED_PACKAGES = {
         "com.android.providers.downloads"
     };
 
+    private boolean mIsDataSaverSupported;
+
     @Override
     public void setUp() throws Exception {
         super.setUp();
 
+        mIsDataSaverSupported = isDataSaverSupported();
         if (!isSupported()) return;
 
         // Set initial state.
@@ -59,6 +64,32 @@
         return setMeteredNetwork();
     }
 
+    @Override
+    protected boolean isSupported() throws Exception {
+        if (!mIsDataSaverSupported) {
+            Log.i(TAG, "Skipping " + getClass() + "." + getName()
+                    + "() because device does not support Data Saver Mode");
+        }
+        return mIsDataSaverSupported && super.isSupported();
+    }
+
+    /**
+     * As per CDD requirements, if the device doesn't support data saver mode then
+     * ConnectivityManager.getRestrictBackgroundStatus() will always return
+     * RESTRICT_BACKGROUND_STATUS_DISABLED. So, enable the data saver mode and check if
+     * ConnectivityManager.getRestrictBackgroundStatus() for an app in background returns
+     * RESTRICT_BACKGROUND_STATUS_DISABLED or not.
+     */
+    private boolean isDataSaverSupported() throws Exception {
+        assertMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+        try {
+            setRestrictBackground(true);
+            return !isMyRestrictBackgroundStatus(RESTRICT_BACKGROUND_STATUS_DISABLED);
+        } finally {
+            setRestrictBackground(false);
+        }
+    }
+
     public void testGetRestrictBackgroundStatus_disabled() throws Exception {
         if (!isSupported()) return;
 
diff --git a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
index ad77b03..4be6ffe 100644
--- a/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
+++ b/hostsidetests/os/test-apps/StaticSharedLibConsumerApp1/src/android/os/lib/consumer1/UseSharedLibraryTest.java
@@ -101,7 +101,7 @@
 
                 List<VersionedPackage> dependentPackages = sharedLib.getDependentPackages();
 
-                switch (sharedLib.getVersion()) {
+                switch ((int) sharedLib.getVersion()) {
                     case 1: {
                         firstLibFound = true;
                         assertSame(1, declaringPackage.getVersionCode());
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 8ed60e6..46779de 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -251,9 +251,9 @@
     /**
      * Asserts that no vendor domains are exempted from the prohibition on Binder use.
      *
-     * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
-     * during Android O development. This test will be removed before Android O.
-     * TODO(b/35870313): Remove this test once b/35870313 is fixed.
+     * <p>NOTE: binder_in_vendor_violators attribute is only there to help bring up Treble devices.
+     * It offers a convenient way to temporarily bypass the prohibition on Binder use in vendor
+     * domains. This attribute must not be used on production Treble devices.
      */
     public void testNoExemptionsForBinderInVendorBan() throws Exception {
         if (!isFullTrebleDevice()) {
@@ -273,9 +273,10 @@
      * Asserts that no domains are exempted from the prohibition on initiating socket communications
      * between core and vendor domains.
      *
-     * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
-     * during Android O development. This test will be removed before Android O.
-     * TODO(b/36577153): Remove this test once b/36577153 is fixed.
+     * <p>NOTE: socket_between_core_and_vendor_violators attribute is only there to help bring up
+     * Treble devices. It offers a convenient way to temporarily bypass the prohibition on
+     * initiating socket communications between core and vendor domains. This attribute must not be
+     * used on production Treble devices.
      */
     public void testNoExemptionsForSocketsBetweenCoreAndVendorBan() throws Exception {
         if (!isFullTrebleDevice()) {
@@ -295,52 +296,25 @@
 
     /**
      * Asserts that no vendor domains are exempted from the prohibition on directly
-     * accessing /data outside /data/vendor.
-     *
-     * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
-     * during Android O development. This test will be removed before Android O.
-     * TODO(b/34980020): Remove this test once b/34980020 is fixed.
-     */
-    public void testNoExemptionsForCoreDataInVendor() throws Exception {
+     * executing binaries from /system.
+     * */
+    public void testNoExemptionsForVendorExecutingCore() throws Exception {
         if (!isFullTrebleDevice()) {
             return;
         }
 
         Set<String> types =
                 sepolicyAnalyzeGetTypesAssociatedWithAttribute(
-                        "coredata_in_vendor_violators");
+                        "vendor_executes_system_violators");
         if (!types.isEmpty()) {
             List<String> sortedTypes = new ArrayList<>(types);
             Collections.sort(sortedTypes);
-            fail("Policy exempts domains from ban on vendor domains accessing data partition"
-                    + " outside /data/vendor: " + sortedTypes);
+            fail("Policy exempts vendor domains from ban on executing files in /system: "
+                    + sortedTypes);
         }
     }
 
     /**
-     * Asserts that no core domains are exempted from the prohibition on directly
-     * accessing /data/vendor.
-     *
-     * <p>NOTE: There's no explicit CDD requirement for this because this is a temporary crutch
-     * during Android O development. This test will be removed before Android O.
-     * TODO(b/34980020): Remove this test once b/34980020 is fixed.
-     */
-    public void testNoExemptionsForVendorDataInCore() throws Exception {
-        if (!isFullTrebleDevice()) {
-            return;
-        }
-
-        Set<String> types =
-                sepolicyAnalyzeGetTypesAssociatedWithAttribute(
-                        "vendordata_in_core_violators");
-        if (!types.isEmpty()) {
-            List<String> sortedTypes = new ArrayList<>(types);
-            Collections.sort(sortedTypes);
-            fail("Policy exempts domains from ban on core domains accessing vendor data"
-                    + " in /data/vendor: " + sortedTypes);
-        }
-    }
-    /**
      * Tests that mlstrustedsubject does not include untrusted_app
      * and that mlstrustedobject does not include app_data_file.
      * This helps prevent circumventing the per-user isolation of
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index 3cdc754..ade0963 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -27,8 +27,14 @@
     <application>
         <activity android:name=".TestActivity"
                 android:resizeableActivity="true"
+                android:supportsPictureInPicture="true"
                 android:exported="true"
         />
+        <activity android:name=".TranslucentTestActivity"
+                android:resizeableActivity="true"
+                android:supportsPictureInPicture="true"
+                android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                android:theme="@style/Theme.Transparent" />
         <activity android:name=".VrTestActivity"
                 android:resizeableActivity="true"
                 android:exported="true"
@@ -90,6 +96,14 @@
                 android:exported="true"
                 android:taskAffinity="nobody.but.PipActivity"
         />
+        <activity android:name=".PipActivity2"
+                  android:resizeableActivity="false"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
+                  android:exported="true"
+                  android:taskAffinity="nobody.but.PipActivity2"
+        />
+
         <activity android:name=".AlwaysFocusablePipActivity"
                   android:theme="@style/Theme.Transparent"
                   android:resizeableActivity="false"
@@ -105,12 +119,6 @@
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                   android:exported="true"
         />
-        <activity android:name=".VisibleBehindActivity"
-                  android:resizeableActivity="false"
-                  android:supportsPictureInPicture="true"
-                  android:exported="true"
-                  android:taskAffinity="nobody.but.VisibleBehindActivity"
-        />
         <activity android:name=".LaunchPipOnPipActivity"
                   android:resizeableActivity="false"
                   android:supportsPictureInPicture="true"
@@ -325,6 +333,11 @@
                  android:permission="android.permission.BIND_VOICE_INTERACTION"
                  android:exported="true" />
 
+        <activity android:name=".SplashscreenActivity"
+            android:taskAffinity="nobody.but.SplashscreenActivity"
+            android:theme="@style/SplashscreenTheme"
+            android:exported="true" />
+
         <service android:name="com.android.cts.verifier.vr.MockVrListenerService"
                  android:exported="true"
                  android:enabled="true"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
new file mode 100644
index 0000000..67e0b08
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/task_overlay.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ 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
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="#800000ff">
+</FrameLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml
new file mode 100644
index 0000000..2a51310
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/colors.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ 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
+  -->
+
+<resources>
+    <drawable name="red">#ff0000</drawable>
+</resources>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
index 7fc6725..5068ea9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/values/styles.xml
@@ -40,4 +40,7 @@
     <style name="NoPreview">
         <item name="android:windowDisablePreview">true</item>
     </style>
+    <style name="SplashscreenTheme" parent="@android:style/Theme.Material.NoActionBar">
+        <item name="android:windowSplashscreenContent">@drawable/red</item>
+    </style>
 </resources>
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 7e116a9..7b8a695 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -40,6 +40,12 @@
     }
 
     @Override
+    protected void onResume() {
+        super.onResume();
+        Log.i(getTag(), "onResume");
+    }
+
+    @Override
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
         Log.i(getTag(), "onConfigurationChanged");
@@ -76,6 +82,18 @@
     }
 
     @Override
+    protected void onPause() {
+        super.onPause();
+        Log.i(getTag(), "onPause");
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+        Log.i(getTag(), "onStop");
+    }
+
+    @Override
     protected void onDestroy() {
         super.onDestroy();
         Log.i(getTag(), "onDestroy");
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
index 0d49519..f60abfa 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity.java
@@ -50,6 +50,8 @@
     // Will apply the oriention to the value set in the EXTRA_FIXED_ORIENTATION extra.
     private static final String ACTION_SET_REQUESTED_ORIENTATION =
             "android.server.cts.PipActivity.set_requested_orientation";
+    // Intent action that will finish this activity
+    private static final String ACTION_FINISH = "android.server.cts.PipActivity.finish";
 
     // Sets the fixed orientation (can be one of {@link ActivityInfo.ScreenOrientation}
     private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -115,6 +117,9 @@
                         setRequestedOrientation(Integer.parseInt(intent.getStringExtra(
                                 EXTRA_FIXED_ORIENTATION)));
                         break;
+                    case ACTION_FINISH:
+                        finish();
+                        break;
                 }
             }
         }
@@ -177,17 +182,14 @@
             launchIntent.setComponent(ComponentName.unflattenFromString(launchActivityComponent));
             startActivity(launchIntent);
         }
-    }
 
-    @Override
-    protected void onStart() {
-        super.onStart();
-
+        // Register the broadcast receiver
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_ENTER_PIP);
         filter.addAction(ACTION_MOVE_TO_BACK);
         filter.addAction(ACTION_EXPAND_PIP);
         filter.addAction(ACTION_SET_REQUESTED_ORIENTATION);
+        filter.addAction(ACTION_FINISH);
         registerReceiver(mReceiver, filter);
     }
 
@@ -219,7 +221,6 @@
     @Override
     protected void onStop() {
         super.onStop();
-        unregisterReceiver(mReceiver);
 
         if (getIntent().hasExtra(EXTRA_ASSERT_NO_ON_STOP_BEFORE_PIP) && !mEnteredPictureInPicture) {
             Log.w("PipActivity", "Unexpected onStop() called before entering picture-in-picture");
@@ -228,6 +229,13 @@
     }
 
     @Override
+    protected void onDestroy() {
+        super.onDestroy();
+
+        unregisterReceiver(mReceiver);
+    }
+
+    @Override
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
         super.onPictureInPictureModeChanged(isInPictureInPictureMode);
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java
new file mode 100644
index 0000000..53b4f75
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/PipActivity2.java
@@ -0,0 +1,23 @@
+/*
+ * 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 android.server.cts;
+
+/**
+ * A secondary activity that has the same behavior as {@link PipActivity}.
+ */
+public class PipActivity2 extends PipActivity {
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java
new file mode 100644
index 0000000..22391bd
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/SplashscreenActivity.java
@@ -0,0 +1,36 @@
+/*
+ * 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 android.server.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.SystemClock;
+
+/**
+ * Activity that shows a custom splashscreen when being launched.
+ */
+public class SplashscreenActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        // Make sure splash screen is visible. The test won't take 5 seconds because the condition
+        // such that we can dump the state will trigger much earlier and then the test will just
+        // kill us.
+        SystemClock.sleep(5000);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
index 567cbbb..ec45357 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TestActivity.java
@@ -55,17 +55,22 @@
     }
 
     @Override
+    protected void onStart() {
+        super.onStart();
+        registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
-        registerReceiver(mReceiver, new IntentFilter(ACTION_FINISH_SELF));
         final Configuration config = getResources().getConfiguration();
         dumpDisplaySize(config);
         dumpConfiguration(config);
     }
 
     @Override
-    protected void onPause() {
-        super.onPause();
+    protected void onStop() {
+        super.onStop();
         unregisterReceiver(mReceiver);
     }
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
new file mode 100644
index 0000000..1d10a51
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TranslucentTestActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.cts;
+
+import android.os.Bundle;
+
+public class TranslucentTestActivity extends TestActivity {
+
+    private static final String TAG = TranslucentTestActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        setContentView(R.layout.task_overlay);
+    }
+
+    @Override
+    protected String getTag() {
+        return TAG;
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
index a31e985..8374f7c 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -18,8 +18,6 @@
 
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
-import static android.hardware.display.DisplayManager
-        .VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 
 import android.app.Activity;
 import android.content.Intent;
@@ -42,8 +40,6 @@
 
     private static final int DEFAULT_DENSITY_DPI = 160;
     private static final String KEY_DENSITY_DPI = "density_dpi";
-    private static final String KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD
-            = "can_show_with_insecure_keyguard";
     private static final String KEY_PUBLIC_DISPLAY = "public_display";
     private static final String KEY_RESIZE_DISPLAY = "resize_display";
     private static final String KEY_COUNT = "count";
@@ -165,20 +161,13 @@
 
         int flags = 0;
 
-        final boolean canShowWithInsecureKeyguard
-                = entry.extras.getBoolean(KEY_CAN_SHOW_WITH_INSECURE_KEYGUARD);
-        if (canShowWithInsecureKeyguard) {
-            flags |= VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
-        }
-
         final boolean publicDisplay = entry.extras.getBoolean(KEY_PUBLIC_DISPLAY);
         if (publicDisplay) {
             flags |= VIRTUAL_DISPLAY_FLAG_PUBLIC | VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
         }
 
         Log.d(TAG, "createVirtualDisplay: " + width + "x" + height + ", dpi: "
-                + densityDpi + ", canShowWithInsecureKeyguard=" + canShowWithInsecureKeyguard
-                + ", publicDisplay=" + publicDisplay);
+                + densityDpi + ", publicDisplay=" + publicDisplay);
         try {
             VirtualDisplay virtualDisplay = mDisplayManager.createVirtualDisplay(
                     "VirtualDisplay" + mVirtualDisplays.size(), width,
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
deleted file mode 100644
index 29feba9..0000000
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VisibleBehindActivity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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.server.cts;
-
-import android.app.Activity;
-import android.util.Log;
-
-public class VisibleBehindActivity extends Activity {
-    private static final String TAG = "VisibleBehindActivity";
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (requestVisibleBehind(true)) {
-            Log.e(TAG, "Failed to request visibility behind...");
-        }
-    }
-}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
index a7d4042..add7e42 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityAndWindowManagerOverrideConfigTests.java
@@ -40,12 +40,12 @@
         private ConfigurationChangeObserver() {
         }
 
-        private boolean findConfigurationChange(String activityName)
+        private boolean findConfigurationChange(String activityName, String logSeparator)
                 throws DeviceNotAvailableException, InterruptedException {
             int tries = 0;
             boolean observedChange = false;
             while (tries < 5 && !observedChange) {
-                final String[] lines = getDeviceLogsForComponent(activityName);
+                final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
                 log("Looking at logcat");
                 for (int i = lines.length - 1; i >= 0; i--) {
                     final String line = lines[i].trim();
@@ -72,16 +72,18 @@
         launchActivityInStack(TEST_ACTIVITY_NAME, FREEFORM_WORKSPACE_STACK_ID);
 
         setDeviceRotation(0);
-        clearLogcat();
+        String logSeparator = clearLogcat();
         resizeActivityTask(TEST_ACTIVITY_NAME, 0, 0, 100, 100);
         ConfigurationChangeObserver c = new ConfigurationChangeObserver();
-        final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+        final boolean reportedSizeAfterResize = c.findConfigurationChange(TEST_ACTIVITY_NAME,
+                logSeparator);
         assertTrue("Expected to observe configuration change when resizing",
                 reportedSizeAfterResize);
 
-        clearLogcat();
+        logSeparator = clearLogcat();
         setDeviceRotation(2);
-        final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME);
+        final boolean reportedSizeAfterRotation = c.findConfigurationChange(TEST_ACTIVITY_NAME,
+                logSeparator);
         assertFalse("Not expected to observe configuration change after flip rotation",
                 reportedSizeAfterRotation);
     }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index 697143f..d0db632 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -18,16 +18,21 @@
 
 import static android.server.cts.ActivityManagerState.STATE_RESUMED;
 
+import android.platform.test.annotations.Presubmit;
+
 import java.lang.Exception;
 import java.lang.String;
 
+import static com.android.ddmlib.Log.LogLevel.INFO;
+
+import com.android.tradefed.log.LogUtil.CLog;
+
 /**
  * Build: mmma -j32 cts/hostsidetests/services
  * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.ActivityManagerActivityVisibilityTests
  */
 public class ActivityManagerActivityVisibilityTests extends ActivityManagerTestBase {
     private static final String TRANSLUCENT_ACTIVITY = "AlwaysFocusablePipActivity";
-    private static final String VISIBLE_BEHIND_ACTIVITY = "VisibleBehindActivity";
     private static final String PIP_ON_PIP_ACTIVITY = "LaunchPipOnPipActivity";
     private static final String TEST_ACTIVITY_NAME = "TestActivity";
     private static final String TRANSLUCENT_ACTIVITY_NAME = "TranslucentActivity";
@@ -35,46 +40,6 @@
     private static final String TURN_SCREEN_ON_ACTIVITY_NAME = "TurnScreenOnActivity";
     private static final String MOVE_TASK_TO_BACK_ACTIVITY_NAME = "MoveTaskToBackActivity";
 
-    public void testVisibleBehindHomeActivity() throws Exception {
-        launchActivity(VISIBLE_BEHIND_ACTIVITY);
-        mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY,
-                FULLSCREEN_WORKSPACE_STACK_ID);
-        launchHomeActivity();
-
-        /* TODO: Find a proper way to wait until launcher activity
-         * becomes fully visible. It appears that both VisibleBehindActivity
-         * and home activity are visible at some point before the former
-         * disappears.*/
-        Thread.sleep(3000);
-        mAmWmState.computeState(mDevice, null);
-        mAmWmState.assertContainsStack(
-                "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
-        mAmWmState.assertFrontStack("Home stack must be the front stack.", HOME_STACK_ID);
-        mAmWmState.assertVisibility(
-                VISIBLE_BEHIND_ACTIVITY, hasDeviceFeature("android.software.leanback"));
-    }
-
-    public void testVisibleBehindOtherActivity_NotOverHome() throws Exception {
-        launchActivity(VISIBLE_BEHIND_ACTIVITY);
-        launchActivity(TRANSLUCENT_ACTIVITY);
-
-        mAmWmState.computeState(mDevice,
-                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-    }
-
-    public void testVisibleBehindOtherActivity_OverHome() throws Exception {
-        executeShellCommand(getAmStartCmdOverHome(VISIBLE_BEHIND_ACTIVITY));
-        mAmWmState.waitForValidState(mDevice, VISIBLE_BEHIND_ACTIVITY);
-        executeShellCommand(getAmStartCmdOverHome(TRANSLUCENT_ACTIVITY));
-
-        mAmWmState.computeState(mDevice,
-                new String[] {VISIBLE_BEHIND_ACTIVITY, TRANSLUCENT_ACTIVITY});
-        mAmWmState.assertVisibility(VISIBLE_BEHIND_ACTIVITY, true);
-        mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true);
-    }
-
     public void testTranslucentActivityOnTopOfPinnedStack() throws Exception {
         if (!supportsPip()) {
             return;
@@ -97,6 +62,10 @@
      * fullscreen stack over the home activity.
      */
     public void testTranslucentActivityOnTopOfHome() throws Exception {
+        if (noHomeScreen()) {
+            return;
+        }
+
         launchHomeActivity();
         launchActivity(TRANSLUCENT_ACTIVITY);
 
@@ -130,6 +99,11 @@
     }
 
     public void testTranslucentActivityOverDockedStack() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
         launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
@@ -145,6 +119,7 @@
         mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY_NAME, true);
     }
 
+    @Presubmit
     public void testTurnScreenOnActivity() throws Exception {
         sleepDevice();
         launchActivity(TURN_SCREEN_ON_ACTIVITY_NAME);
@@ -153,6 +128,11 @@
     }
 
     public void testFinishActivityInNonFocusedStack() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         // Launch two activities in docked stack.
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         getLaunchActivityBuilder().setTargetActivityName(BROADCAST_RECEIVER_ACTIVITY).execute();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
index b31fb16..f6df4a8 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAmStartOptionsTests.java
@@ -77,7 +77,8 @@
 
     private void startActivityAndVerifyResult(final String entryActivity,
             final String actualActivity, boolean shouldStart) throws Exception {
-        clearLogcat();
+        // See TODO below
+        // final String logSeparator = clearLogcat();
 
         // Pass in different data only when cold starting. This is to make the intent
         // different in subsequent warm/hot launches, so that the entrypoint alias
@@ -96,7 +97,7 @@
         // still catch most failures.
 
         // Verify adb logcat log
-        //verifyLogcat(actualActivity, shouldStart);
+        //verifyLogcat(actualActivity, shouldStart, logSeparator);
     }
 
     private static final Pattern sNotStartedWarningPattern = Pattern.compile(
@@ -149,12 +150,12 @@
     private static final Pattern sDisplayTimePattern =
             Pattern.compile("(.+): Displayed (.*): (\\+{0,1})([0-9]+)ms(.*)");
 
-    void verifyLogcat(String actualActivityName, boolean shouldStart)
+    void verifyLogcat(String actualActivityName, boolean shouldStart, String logSeparator)
             throws DeviceNotAvailableException {
         int displayCount = 0;
         String activityName = null;
 
-        for (String line : getDeviceLogsForComponent("ActivityManager")) {
+        for (String line : getDeviceLogsForComponent("ActivityManager", logSeparator)) {
             line = line.trim();
 
             Matcher matcher = sDisplayTimePattern.matcher(line);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
index 8d1a78e..31f82ac 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -55,11 +55,20 @@
      * docked state.
      */
     public void testConfigurationUpdatesWhenResizedFromFullscreen() throws Exception {
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
 
+        String logSeparator = clearLogcat();
+        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
+
+        logSeparator = clearLogcat();
         moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
 
         assertSizesAreSane(fullscreenSizes, dockedSizes);
     }
@@ -69,11 +78,20 @@
      * from docked state to fullscreen (reverse).
      */
     public void testConfigurationUpdatesWhenResizedFromDockedStack() throws Exception {
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
 
+        String logSeparator = clearLogcat();
+        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
+
+        logSeparator = clearLogcat();
         moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
 
         assertSizesAreSane(fullscreenSizes, dockedSizes);
     }
@@ -83,8 +101,10 @@
      */
     public void testConfigurationUpdatesWhenRotatingWhileFullscreen() throws Exception {
         setDeviceRotation(0);
+        final String logSeparator = clearLogcat();
         launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
 
         rotateAndCheckSizes(initialSizes);
     }
@@ -93,8 +113,15 @@
      * Same as {@link #testConfigurationUpdatesWhenRotatingWhileFullscreen()} but when the Activity
      * is in the docked stack.
      */
+    @Presubmit
     public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         setDeviceRotation(0);
+        final String logSeparator = clearLogcat();
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         // Launch our own activity to side in case Recents (or other activity to side) doesn't
         // support rotation.
@@ -102,7 +129,8 @@
                 .execute();
         // Launch target activity in docked stack.
         getLaunchActivityBuilder().setTargetActivityName(RESIZEABLE_ACTIVITY_NAME).execute();
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
 
         rotateAndCheckSizes(initialSizes);
     }
@@ -112,19 +140,26 @@
      * is launched to side from docked stack.
      */
     public void testConfigurationUpdatesWhenRotatingToSideFromDocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         setDeviceRotation(0);
 
+        final String logSeparator = clearLogcat();
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         getLaunchActivityBuilder().setToSide(true).setTargetActivityName(RESIZEABLE_ACTIVITY_NAME)
                 .execute();
-        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
 
         rotateAndCheckSizes(initialSizes);
     }
 
     private void rotateAndCheckSizes(ReportedSizes prevSizes) throws Exception {
         for (int rotation = 3; rotation >= 0; --rotation) {
-            clearLogcat();
+            final String logSeparator = clearLogcat();
             final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
                     RESIZEABLE_ACTIVITY_NAME).mStackId;
             final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
@@ -139,7 +174,8 @@
                 return;
             }
 
-            final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME);
+            final ReportedSizes rotatedSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
+                    logSeparator);
             assertSizesRotate(prevSizes, rotatedSizes);
             prevSizes = rotatedSizes;
         }
@@ -156,6 +192,7 @@
     /**
      * Same as {@link #testSameConfigurationFullSplitFullRelaunch} but without relaunch.
      */
+    @Presubmit
     public void testSameConfigurationFullSplitFullNoRelaunch() throws Exception {
         moveActivityFullSplitFull(RESIZEABLE_ACTIVITY_NAME);
     }
@@ -168,14 +205,22 @@
      * Asserts that initial and final reported sizes in fullscreen stack are the same.
      */
     private void moveActivityFullSplitFull(String activityName) throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         // Launch to fullscreen stack and record size.
+        String logSeparator = clearLogcat();
         launchActivityInStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes initialFullscreenSizes = getActivityDisplaySize(activityName,
+                logSeparator);
         final Rectangle displayRect = getDisplayRect(activityName);
 
         // Move to docked stack.
+        logSeparator = clearLogcat();
         moveActivityToStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes dockedSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes dockedSizes = getActivityDisplaySize(activityName, logSeparator);
         assertSizesAreSane(initialFullscreenSizes, dockedSizes);
         // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
         // will come up.
@@ -185,11 +230,13 @@
 
         // Resize docked stack to fullscreen size. This will trigger activity relaunch with
         // non-empty override configuration corresponding to fullscreen size.
+        logSeparator = clearLogcat();
         runCommandAndPrintOutput("am stack resize " + DOCKED_STACK_ID + " 0 0 "
                 + displayRect.width + " " + displayRect.height);
         // Move activity back to fullscreen stack.
         moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes finalFullscreenSizes = getActivityDisplaySize(activityName,
+                logSeparator);
 
         // After activity configuration was changed twice it must report same size as original one.
         assertSizesAreSame(initialFullscreenSizes, finalFullscreenSizes);
@@ -347,9 +394,15 @@
      * Asserts that initial and final reported sizes in docked stack are the same.
      */
     private void moveActivitySplitFullSplit(String activityName) throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         // Launch to docked stack and record size.
+        String logSeparator = clearLogcat();
         launchActivityInStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes initialDockedSizes = getActivityDisplaySize(activityName, logSeparator);
         // Make sure docked stack is focused. This way when we dismiss it later fullscreen stack
         // will come up.
         launchActivityInStack(activityName, DOCKED_STACK_ID);
@@ -357,13 +410,15 @@
                 false /* compareTaskAndStackBounds */);
 
         // Move to fullscreen stack.
+        logSeparator = clearLogcat();
         moveActivityToStack(activityName, FULLSCREEN_WORKSPACE_STACK_ID);
-        final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes fullscreenSizes = getActivityDisplaySize(activityName, logSeparator);
         assertSizesAreSane(fullscreenSizes, initialDockedSizes);
 
         // Move activity back to docked stack.
+        logSeparator = clearLogcat();
         moveActivityToStack(activityName, DOCKED_STACK_ID);
-        final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName);
+        final ReportedSizes finalDockedSizes = getActivityDisplaySize(activityName, logSeparator);
 
         // After activity configuration was changed twice it must report same size as original one.
         assertSizesAreSame(initialDockedSizes, finalDockedSizes);
@@ -424,10 +479,11 @@
         assertEquals(firstSize.smallestWidthDp, secondSize.smallestWidthDp);
     }
 
-    private ReportedSizes getActivityDisplaySize(String activityName) throws Exception {
+    private ReportedSizes getActivityDisplaySize(String activityName, String logSeparator)
+            throws Exception {
         mAmWmState.computeState(mDevice, new String[] { activityName },
                 false /* compareTaskAndStackBounds */);
-        final ReportedSizes details = getLastReportedSizesForActivity(activityName);
+        final ReportedSizes details = getLastReportedSizesForActivity(activityName, logSeparator);
         assertNotNull(details);
         return details;
     }
@@ -459,8 +515,6 @@
      * Test launching an activity which requests specific UI mode during creation.
      */
     public void testLaunchWithUiModeChange() throws Exception {
-        clearLogcat();
-
         // Launch activity that changes UI mode and handles this configuration change.
         launchActivity(NIGHT_MODE_ACTIVITY);
         mAmWmState.waitForActivityState(mDevice, NIGHT_MODE_ACTIVITY, STATE_RESUMED);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
index ede2b87..cf4f803 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerConfigChangeTests.java
@@ -16,7 +16,13 @@
 
 package android.server.cts;
 
+import android.platform.test.annotations.Presubmit;
+
 import static android.server.cts.ActivityManagerState.STATE_RESUMED;
+import static android.server.cts.StateLogger.logE;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -50,14 +56,16 @@
         testRotation(NO_RELAUNCH_ACTIVITY_NAME, 2, 0, 0);
     }
 
+    @Presubmit
     public void testChangeFontScaleRelaunch() throws Exception {
         // Should relaunch and receive no onConfigurationChanged()
-        testChangeFontScale(TEST_ACTIVITY_NAME, true);
+        testChangeFontScale(TEST_ACTIVITY_NAME, true /* relaunch */);
     }
 
+    @Presubmit
     public void testChangeFontScaleNoRelaunch() throws Exception {
         // Should receive onConfigurationChanged() and no relaunch
-        testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false);
+        testChangeFontScale(NO_RELAUNCH_ACTIVITY_NAME, false /* relaunch */);
     }
 
     private void testRotation(
@@ -68,14 +76,27 @@
         final String[] waitForActivitiesVisible = new String[] {activityName};
         mAmWmState.computeState(mDevice, waitForActivitiesVisible);
 
-        setDeviceRotation(4 - rotationStep);
+        final int initialRotation = 4 - rotationStep;
+        setDeviceRotation(initialRotation);
         mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+        final int actualStackId = mAmWmState.getAmState().getTaskByActivityName(
+                activityName).mStackId;
+        final int displayId = mAmWmState.getAmState().getStackById(actualStackId).mDisplayId;
+        final int newDeviceRotation = getDeviceRotation(displayId);
+        if (newDeviceRotation == INVALID_DEVICE_ROTATION) {
+            CLog.logAndDisplay(LogLevel.WARN, "Got an invalid device rotation value. "
+                    + "Continuing the test despite of that, but it is likely to fail.");
+        } else if (newDeviceRotation != initialRotation) {
+            CLog.logAndDisplay(LogLevel.INFO, "This device doesn't support user rotation "
+                    + "mode. Not continuing the rotation checks.");
+            return;
+        }
 
         for (int rotation = 0; rotation < 4; rotation += rotationStep) {
-            clearLogcat();
+            final String logSeparator = clearLogcat();
             setDeviceRotation(rotation);
             mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-            assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange);
+            assertRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange, logSeparator);
         }
     }
 
@@ -89,10 +110,11 @@
         mAmWmState.computeState(mDevice, waitForActivitiesVisible);
 
         for (float fontScale = 0.85f; fontScale <= 1.3f; fontScale += 0.15f) {
-            clearLogcat();
+            final String logSeparator = clearLogcat();
             setFontScale(fontScale);
             mAmWmState.computeState(mDevice, waitForActivitiesVisible);
-            assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1);
+            assertRelaunchOrConfigChanged(activityName, relaunch ? 1 : 0, relaunch ? 0 : 1,
+                    logSeparator);
         }
     }
 
@@ -101,29 +123,30 @@
      * must be recreated and its asset sequence number must be incremented.
      */
     public void testUpdateApplicationInfo() throws Exception {
-        clearLogcat();
+        final String firstLogSeparator = clearLogcat();
 
         // Launch an activity that prints applied config.
         launchActivity(TEST_ACTIVITY_NAME);
-        final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME);
-        clearLogcat();
+        final int assetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, firstLogSeparator);
 
+        final String logSeparator = clearLogcat();
         // Update package info.
         executeShellCommand("am update-appinfo all " + componentName);
         mAmWmState.waitForWithAmState(mDevice, (amState) -> {
             // Wait for activity to be resumed and asset seq number to be updated.
             try {
-                return readAssetSeqNumber(TEST_ACTIVITY_NAME) == assetSeq + 1
+                return readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator) == assetSeq + 1
                         && amState.hasActivityState(TEST_ACTIVITY_NAME, STATE_RESUMED);
             } catch (Exception e) {
+                logE("Error waiting for valid state: " + e.getMessage());
                 return false;
             }
         }, "Waiting asset sequence number to be updated and for activity to be resumed.");
 
         // Check if activity is relaunched and asset seq is updated.
         assertRelaunchOrConfigChanged(TEST_ACTIVITY_NAME, 1 /* numRelaunch */,
-                0 /* numConfigChange */);
-        final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME);
+                0 /* numConfigChange */, logSeparator);
+        final int newAssetSeq = readAssetSeqNumber(TEST_ACTIVITY_NAME, logSeparator);
         assertEquals("Asset sequence number must be incremented.", assetSeq + 1, newAssetSeq);
     }
 
@@ -131,8 +154,8 @@
             "(.+): Configuration: \\{(.*) as.(\\d+)(.*)\\}");
 
     /** Read asset sequence number in last applied configuration from logs. */
-    private int readAssetSeqNumber(String activityName) throws Exception {
-        final String[] lines = getDeviceLogsForComponent(activityName);
+    private int readAssetSeqNumber(String activityName, String logSeparator) throws Exception {
+        final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
         for (int i = lines.length - 1; i >= 0; i--) {
             final String line = lines[i].trim();
             final Matcher matcher = sConfigurationPattern.matcher(line);
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 2b34735..cda836f 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -15,6 +15,8 @@
  */
 package android.server.cts;
 
+import android.platform.test.annotations.Presubmit;
+
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
 
@@ -345,6 +347,7 @@
     /**
      * Tests launching an activity on virtual display.
      */
+    @Presubmit
     public void testLaunchActivityOnSecondaryDisplay() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -352,6 +355,7 @@
         final DisplayState newDisplay = new VirtualDisplayBuilder(this).build();
 
         // Launch activity on new secondary display.
+        final String logSeparator = clearLogcat();
         launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
 
@@ -369,7 +373,8 @@
         mAmWmState.assertFocusedStack("Focus must be on secondary display", frontStackId);
 
         // Check that activity config corresponds to display config.
-        final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME);
+        final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME,
+                logSeparator);
         assertEquals("Activity launched on secondary display must have proper configuration",
                 CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
     }
@@ -379,6 +384,7 @@
      * command and without specifying the display id - the second activity must appear on the
      * primary display.
      */
+    @Presubmit
     public void testConsequentLaunchActivity() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -411,6 +417,7 @@
      * Tests launching an activity on virtual display and then launching another activity from the
      * first one - it must appear on the secondary display, because it was launched from there.
      */
+    @Presubmit
     public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -472,6 +479,7 @@
      * Tests launching activities on secondary and then on primary display to see if the stack
      * visibility is not affected.
      */
+    @Presubmit
     public void testLaunchActivitiesAffectsVisibility() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -504,6 +512,7 @@
     /**
      * Test that move-task works when moving between displays.
      */
+    @Presubmit
     public void testMoveTaskBetweenDisplays() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -534,6 +543,7 @@
      * is moved correctly.
      * This version launches virtual display creator to fullscreen stack.
      */
+    @Presubmit
     public void testStackFocusSwitchOnDisplayRemoved() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -833,7 +843,7 @@
         assertTrue("Focused stack must be on secondary display",
                 FULLSCREEN_WORKSPACE_STACK_ID != externalFocusedStackId);
 
-        clearLogcat();
+        final String logSeparator = clearLogcat();
 
         // Launch other activity with different uid and check it is launched on primary display.
         final String broadcastAction = SECOND_PACKAGE_NAME + ".LAUNCH_BROADCAST_ACTION";
@@ -845,7 +855,7 @@
         boolean match = false;
         final Pattern pattern = Pattern.compile(".*SecurityException launching activity.*");
         while (tries < 5 && !match) {
-            String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver");
+            String[] logs = getDeviceLogsForComponent("LaunchBroadcastReceiver", logSeparator);
             for (String line : logs) {
                 Matcher m = pattern.matcher(line);
                 if (m.matches()) {
@@ -874,7 +884,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();
@@ -896,54 +906,9 @@
     }
 
     /**
-     * Test that show-with-insecure-keyguard virtual display is showing content when device is
-     * locked.
-     */
-    public void testShowWhenLockedVirtualDisplay() throws Exception {
-        if (!supportsMultiDisplay()) { return; }
-
-        // Create new show-with-insecure-keyguard virtual display.
-        final DisplayState newDisplay = new VirtualDisplayBuilder(this)
-                .setCanShowWithInsecureKeyguard(true)
-                .build();
-        mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
-
-        // Launch activity on new secondary display.
-        launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
-
-        // Lock the device.
-        sleepDevice();
-        mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_STOPPED);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
-
-        // Unlock and check if visibility is back.
-        wakeUpAndUnlockDevice();
-        mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_RESUMED);
-        mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true /* visible */);
-    }
-
-    /**
-     * Test that only private virtual display can show content with insecure keyguard.
-     */
-    public void testShowWhenLockedPublicVirtualDisplay() throws Exception {
-        if (!supportsMultiDisplay()) { return; }
-
-        // Try to create new show-with-insecure-keyguard public virtual display.
-        final DisplayState newDisplay = new VirtualDisplayBuilder(this)
-                .setPublicDisplay(true)
-                .setCanShowWithInsecureKeyguard(true)
-                .setMustBeCreated(false)
-                .build();
-
-        // Check that the display is not created.
-        mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
-        assertNull(newDisplay);
-    }
-
-    /**
      * Test that all activities that were on the private display are destroyed on display removal.
      */
+    @Presubmit
     public void testContentDestroyOnDisplayRemoved() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -961,7 +926,7 @@
                 RESIZEABLE_ACTIVITY_NAME);
 
         // Destroy the display and check if activities are removed from system.
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         destroyVirtualDisplays();
         final String activityName1
                 = ActivityManagerTestBase.getActivityComponentName(TEST_ACTIVITY_NAME);
@@ -991,13 +956,14 @@
         assertFalse("Activity windows from removed display must be destroyed",
                 mAmWmState.getWmState().containsWindow(windowName2));
         // Check activity logs.
-        assertActivityDestroyed(TEST_ACTIVITY_NAME);
-        assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME);
+        assertActivityDestroyed(TEST_ACTIVITY_NAME, logSeparator);
+        assertActivityDestroyed(RESIZEABLE_ACTIVITY_NAME, logSeparator);
     }
 
     /**
      * Test that the update of display metrics updates all its content.
      */
+    @Presubmit
     public void testDisplayResize() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -1012,22 +978,34 @@
         mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
 
         // Launch a resizeable activity on new secondary display.
-        clearLogcat();
+        final String initialLogSeparator = clearLogcat();
         launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId);
         mAmWmState.assertVisibility(RESIZEABLE_ACTIVITY_NAME, true /* visible */);
         mAmWmState.assertFocusedActivity("Launched activity must be focused",
                 RESIZEABLE_ACTIVITY_NAME);
 
         // Grab reported sizes and compute new with slight size change.
-        final ReportedSizes initialSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes initialSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME,
+                initialLogSeparator);
         final Rectangle initialBounds
                 = mAmWmState.getAmState().getStackById(DOCKED_STACK_ID).getBounds();
         final Rectangle newBounds = new Rectangle(initialBounds.x, initialBounds.y,
                 initialBounds.width + SIZE_VALUE_SHIFT, initialBounds.height + SIZE_VALUE_SHIFT);
 
         // Resize the docked stack, so that activity with virtual display will also be resized.
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+
+        mAmWmState.waitForWithAmState(mDevice, amState -> {
+            try {
+                return readConfigChangeNumber(RESIZEABLE_ACTIVITY_NAME, logSeparator) == 1
+                        && amState.hasActivityState(RESIZEABLE_ACTIVITY_NAME, STATE_RESUMED);
+            } catch (Exception e) {
+                logE("Error waiting for valid state: " + e.getMessage());
+                return false;
+            }
+        }, "Wait for the configuration change to happen and for activity to be resumed.");
+
         mAmWmState.computeState(mDevice, new String[] {RESIZEABLE_ACTIVITY_NAME, LAUNCHING_ACTIVITY,
                 VIRTUAL_DISPLAY_ACTIVITY}, false /* compareTaskAndStackBounds */);
         mAmWmState.assertDockedTaskBounds(newBounds.width, newBounds.height,
@@ -1043,9 +1021,10 @@
 
         // Check if activity in virtual display was resized properly.
         assertRelaunchOrConfigChanged(RESIZEABLE_ACTIVITY_NAME, 0 /* numRelaunch */,
-                1 /* numConfigChange */);
+                1 /* numConfigChange */, logSeparator);
 
-        final ReportedSizes updatedSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME);
+        final ReportedSizes updatedSize = getLastReportedSizesForActivity(RESIZEABLE_ACTIVITY_NAME,
+                logSeparator);
         assertTrue(updatedSize.widthDp <= initialSize.widthDp);
         assertTrue(updatedSize.heightDp <= initialSize.heightDp);
         assertTrue(updatedSize.displayWidth <= initialSize.displayWidth);
@@ -1056,10 +1035,16 @@
                 widthUpdated ^ heightUpdated);
     }
 
+    /** Read the number of configuration changes sent to activity from logs. */
+    private int readConfigChangeNumber(String activityName, String logSeparator) throws Exception {
+        return (new ActivityLifecycleCounts(activityName, logSeparator)).mConfigurationChangedCount;
+    }
+
     /**
      * Tests that when activities that handle configuration changes are moved between displays,
      * they receive onMovedToDisplay and onConfigurationChanged callbacks.
      */
+    @Presubmit
     public void testOnMovedToDisplayCallback() throws Exception {
         if (!supportsMultiDisplay()) { return; }
 
@@ -1072,7 +1057,7 @@
         mAmWmState.assertFocusedActivity("Focus must be on secondary display",
                 RESIZEABLE_ACTIVITY_NAME);
 
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         moveActivityToStack(RESIZEABLE_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
         mAmWmState.waitForFocusedStack(mDevice, FULLSCREEN_WORKSPACE_STACK_ID);
         mAmWmState.assertFocusedActivity("Focus must be on moved activity",
@@ -1081,8 +1066,8 @@
                 FULLSCREEN_WORKSPACE_STACK_ID);
 
         // Check if client received the callbacks.
-        assertMovedToDisplay(RESIZEABLE_ACTIVITY_NAME);
-        assertMovedToDisplay("LifecycleLogView");
+        assertMovedToDisplay(RESIZEABLE_ACTIVITY_NAME, logSeparator);
+        assertMovedToDisplay("LifecycleLogView", logSeparator);
     }
 
     /**
@@ -1155,11 +1140,12 @@
         mAmWmState.assertVisibility(VIRTUAL_DISPLAY_ACTIVITY, true /* visible */);
 
         // Launch activity on new secondary display.
+        String logSeparator = clearLogcat();
         launchActivityOnDisplay(RESIZEABLE_ACTIVITY_NAME, newDisplay.mDisplayId);
         mAmWmState.assertFocusedActivity("Focus must be on secondary display",
                 RESIZEABLE_ACTIVITY_NAME);
         final ReportedSizes initialSizes = getLastReportedSizesForActivity(
-                RESIZEABLE_ACTIVITY_NAME);
+                RESIZEABLE_ACTIVITY_NAME, logSeparator);
         assertNotNull("Test activity must have reported initial sizes on launch", initialSizes);
 
         // Rotate primary display and check that activity on secondary display is not affected.
@@ -1169,12 +1155,13 @@
         final int initialRotation = mAmWmState.getWmState().getRotation();
         setDeviceRotation((initialRotation + 1) % 4);
 
+        logSeparator = clearLogcat();
         launchActivityOnDisplay(TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
         mAmWmState.waitForActivityState(mDevice, TEST_ACTIVITY_NAME, STATE_RESUMED);
         mAmWmState.assertFocusedActivity("Focus must be on secondary display",
                 TEST_ACTIVITY_NAME);
         final ReportedSizes testActivitySizes = getLastReportedSizesForActivity(
-                TEST_ACTIVITY_NAME);
+                TEST_ACTIVITY_NAME, logSeparator);
         assertEquals("Sizes of secondary display must not change after rotation of primary display",
                 initialSizes, testActivitySizes);
     }
@@ -1251,7 +1238,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",
@@ -1278,9 +1265,10 @@
 
     private void rotateAndCheckSameSizes(String activityName) throws Exception {
         for (int rotation = 3; rotation >= 0; --rotation) {
-            clearLogcat();
+            final String logSeparator = clearLogcat();
             setDeviceRotation(rotation);
-            final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName);
+            final ReportedSizes rotatedSizes = getLastReportedSizesForActivity(activityName,
+                    logSeparator);
             assertNull("Sizes must not change after rotation", rotatedSizes);
         }
     }
@@ -1289,7 +1277,8 @@
      * Test that display overrides apply correctly and won't be affected by display changes.
      * This sets overrides to display size and density, initiates a display changed event by locking
      * and unlocking the phone and verifies that overrides are kept.
-     * */
+     */
+    @Presubmit
     public void testForceDisplayMetrics() throws Exception {
         launchHomeActivity();
 
@@ -1423,9 +1412,9 @@
     }
 
     /** Assert that component received onMovedToDisplay and onConfigurationChanged callbacks. */
-    private void assertMovedToDisplay(String componentName) throws Exception {
+    private void assertMovedToDisplay(String componentName, String logSeparator) throws Exception {
         final ActivityLifecycleCounts lifecycleCounts
-                = new ActivityLifecycleCounts(componentName);
+                = new ActivityLifecycleCounts(componentName, logSeparator);
         if (lifecycleCounts.mDestroyCount != 0) {
             fail(componentName + " has been destroyed " + lifecycleCounts.mDestroyCount
                     + " time(s), wasn't expecting any");
@@ -1462,8 +1451,6 @@
      * @param densityDpi provide custom density for the display.
      * @param launchInSplitScreen start {@link VirtualDisplayActivity} to side from
      *                            {@link LaunchingActivity} on primary display.
-     * @param canShowWithInsecureKeyguard allow showing content when device is showing an insecure
-     *                                    keyguard.
      * @param publicDisplay make display public.
      * @param mustBeCreated should assert if the display was or wasn't created.
      * @param resizeDisplay should resize display when surface size changes.
@@ -1471,8 +1458,8 @@
      * @throws Exception
      */
     private List<DisplayState> createVirtualDisplays(int densityDpi, boolean launchInSplitScreen,
-            boolean canShowWithInsecureKeyguard, boolean publicDisplay, boolean mustBeCreated,
-            boolean resizeDisplay, int displayCount) throws Exception {
+            boolean publicDisplay, boolean mustBeCreated, boolean resizeDisplay, int displayCount)
+            throws Exception {
         // Start an activity that is able to create virtual displays.
         if (launchInSplitScreen) {
             getLaunchActivityBuilder().setToSide(true)
@@ -1486,8 +1473,8 @@
         final int originalDisplayCount = originalDS.mDisplayStates.size();
 
         // Create virtual display with custom density dpi.
-        executeShellCommand(getCreateVirtualDisplayCommand(densityDpi, canShowWithInsecureKeyguard,
-                publicDisplay, resizeDisplay, displayCount));
+        executeShellCommand(getCreateVirtualDisplayCommand(densityDpi, publicDisplay, resizeDisplay,
+                displayCount));
         mVirtualDisplayCreated = true;
 
         // Wait for the virtual display to be created and get configurations.
@@ -1688,7 +1675,6 @@
 
         private int mDensityDpi = CUSTOM_DENSITY_DPI;
         private boolean mLaunchInSplitScreen = false;
-        private boolean mCanShowWithInsecureKeyguard = false;
         private boolean mPublicDisplay = false;
         private boolean mMustBeCreated = true;
         private boolean mResizeDisplay = true;
@@ -1707,12 +1693,6 @@
             return this;
         }
 
-        public VirtualDisplayBuilder setCanShowWithInsecureKeyguard(
-                boolean canShowWithInsecureKeyguard) {
-            mCanShowWithInsecureKeyguard = canShowWithInsecureKeyguard;
-            return this;
-        }
-
         public VirtualDisplayBuilder setPublicDisplay(boolean publicDisplay) {
             mPublicDisplay = publicDisplay;
             return this;
@@ -1733,15 +1713,13 @@
         }
 
         public List<DisplayState> build(int count) throws Exception {
-            return mTests.createVirtualDisplays(mDensityDpi, mLaunchInSplitScreen,
-                    mCanShowWithInsecureKeyguard, mPublicDisplay, mMustBeCreated, mResizeDisplay,
-                    count);
+            return mTests.createVirtualDisplays(mDensityDpi, mLaunchInSplitScreen, mPublicDisplay,
+                    mMustBeCreated, mResizeDisplay, count);
         }
     }
 
-    private static String getCreateVirtualDisplayCommand(int densityDpi,
-            boolean canShowWithInsecureKeyguard, boolean publicDisplay, boolean resizeDisplay,
-            int displayCount) {
+    private static String getCreateVirtualDisplayCommand(int densityDpi, boolean publicDisplay,
+            boolean resizeDisplay, int displayCount) {
         final StringBuilder commandBuilder
                 = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
         commandBuilder.append(" -f 0x20000000");
@@ -1750,8 +1728,6 @@
             commandBuilder.append(" --ei density_dpi ").append(densityDpi);
         }
         commandBuilder.append(" --ei count ").append(displayCount);
-        commandBuilder.append(" --ez can_show_with_insecure_keyguard ")
-                .append(canShowWithInsecureKeyguard);
         commandBuilder.append(" --ez public_display ").append(publicDisplay);
         commandBuilder.append(" --ez resize_display ").append(resizeDisplay);
         return commandBuilder.toString();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index fb87ec2..d5ba74e 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -16,6 +16,9 @@
 
 package android.server.cts;
 
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.log.LogUtil.CLog;
+
 import java.awt.Rectangle;
 
 /**
@@ -36,6 +39,11 @@
     private static final int STACK_SIZE = 300;
 
     public void testStackList() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivity(TEST_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
@@ -45,6 +53,11 @@
     }
 
     public void testDockActivity() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(TEST_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID);
@@ -52,6 +65,11 @@
     }
 
     public void testNonResizeableNotDocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME});
 
@@ -62,6 +80,11 @@
     }
 
     public void testLaunchToSide() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         getLaunchActivityBuilder().setToSide(true).execute();
@@ -72,6 +95,11 @@
     }
 
     public void testLaunchToSideAndBringToFront() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
         final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
@@ -107,6 +135,11 @@
     }
 
     public void testLaunchToSideMultiple() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         final String[] waitForActivitiesVisible =
@@ -148,6 +181,11 @@
 
     private void launchTargetToSide(String targetActivityName,
                                     boolean taskCountMustIncrement) throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
 
@@ -203,6 +241,11 @@
     }
 
     public void testLaunchToSideMultipleWithFlag() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         final String[] waitForActivitiesVisible =
@@ -232,6 +275,11 @@
     }
 
     public void testRotationWhenDocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         getLaunchActivityBuilder().setToSide(true).execute();
@@ -263,6 +311,11 @@
     }
 
     public void testRotationWhenDockedWhileLocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(LAUNCHING_ACTIVITY);
         mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
         getLaunchActivityBuilder().setToSide(true).execute();
@@ -283,6 +336,11 @@
     }
 
     public void testRotationWhileDockMinimized() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStackAndMinimize(TEST_ACTIVITY_NAME);
         assertDockMinimized();
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
@@ -314,6 +372,11 @@
     }
 
     public void testFinishDockActivityWhileMinimized() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStackAndMinimize(FINISHABLE_ACTIVITY_NAME);
         assertDockMinimized();
 
@@ -324,6 +387,11 @@
     }
 
     public void testDockedStackToMinimizeWhenUnlocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(TEST_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
         sleepDevice();
@@ -333,6 +401,11 @@
     }
 
     public void testMinimizedStateWhenUnlockedAndUnMinimized() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStackAndMinimize(FINISHABLE_ACTIVITY_NAME);
         assertDockMinimized();
 
@@ -346,6 +419,11 @@
     }
 
     public void testResizeDockedStack() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
         launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
@@ -364,6 +442,11 @@
     }
 
     public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
         launchActivity(TEST_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, waitTestActivityName);
@@ -379,7 +462,7 @@
         final Rectangle initialDockBounds =
                 mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds();
 
-        clearLogcat();
+        final String logSeparator = clearLogcat();
 
         Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
         resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
@@ -392,8 +475,8 @@
         resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
         mAmWmState.computeState(mDevice,
                 new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-        assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
-        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
+        assertActivityLifecycle(TEST_ACTIVITY_NAME, true /* relaunched */, logSeparator);
+        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false /* relaunched */, logSeparator);
     }
 
     private Rectangle computeNewDockBounds(
@@ -414,6 +497,11 @@
     }
 
     public void testStackListOrderLaunchDockedActivity() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(LogLevel.INFO, "Skipping test: no split multi-window support");
+            return;
+        }
+
         launchActivityInDockStack(TEST_ACTIVITY_NAME);
         mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY_NAME});
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
index cc36af1..df583d9 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerFreeformStackTests.java
@@ -101,14 +101,14 @@
 
         mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
 
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         resizeActivityTask(TEST_ACTIVITY,
                 TEST_TASK_OFFSET, TEST_TASK_OFFSET, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
         resizeActivityTask(NO_RELAUNCH_ACTIVITY,
                 TEST_TASK_OFFSET_2, TEST_TASK_OFFSET_2, TEST_TASK_SIZE_2, TEST_TASK_SIZE_1);
         mAmWmState.computeState(mDevice, new String[]{TEST_ACTIVITY, NO_RELAUNCH_ACTIVITY});
 
-        assertActivityLifecycle(TEST_ACTIVITY, true);
-        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false);
+        assertActivityLifecycle(TEST_ACTIVITY, true /* relaunched */, logSeparator);
+        assertActivityLifecycle(NO_RELAUNCH_ACTIVITY, false /* relaunched */, logSeparator);
     }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
index b7df926..e6df4b2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerManifestLayoutTests.java
@@ -82,6 +82,10 @@
     }
 
     public void testMinimalSizeDocked() throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+            return;
+        }
         testMinimalSize(DOCKED_STACK_ID);
     }
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index 9da97a2..038eb8d 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -35,14 +35,16 @@
  */
 public class ActivityManagerPinnedStackTests extends ActivityManagerTestBase {
     private static final String TEST_ACTIVITY = "TestActivity";
+    private static final String TRANSLUCENT_TEST_ACTIVITY = "TranslucentTestActivity";
     private static final String NON_RESIZEABLE_ACTIVITY = "NonResizeableActivity";
     private static final String RESUME_WHILE_PAUSING_ACTIVITY = "ResumeWhilePausingActivity";
     private static final String PIP_ACTIVITY = "PipActivity";
+    private static final String PIP_ACTIVITY2 = "PipActivity2";
     private static final String ALWAYS_FOCUSABLE_PIP_ACTIVITY = "AlwaysFocusablePipActivity";
     private static final String LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY =
             "LaunchIntoPinnedStackPipActivity";
     private static final String LAUNCH_IME_WITH_PIP_ACTIVITY = "LaunchImeWithPipActivity";
-    private static final String LAUNCHER_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
+    private static final String LAUNCH_ENTER_PIP_ACTIVITY = "LaunchEnterPipActivity";
     private static final String PIP_ON_STOP_ACTIVITY = "PipOnStopActivity";
 
     private static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
@@ -64,8 +66,12 @@
             "android.server.cts.PipActivity.move_to_back";
     private static final String PIP_ACTIVITY_ACTION_EXPAND_PIP =
             "android.server.cts.PipActivity.expand_pip";
-    private static final String ACTION_SET_REQUESTED_ORIENTATION =
+    private static final String PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION =
             "android.server.cts.PipActivity.set_requested_orientation";
+    private static final String PIP_ACTIVITY_ACTION_FINISH =
+            "android.server.cts.PipActivity.finish";
+    private static final String TEST_ACTIVITY_ACTION_FINISH =
+            "android.server.cts.TestActivity.finish_self";
 
     private static final int APP_OPS_OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
     private static final int APP_OPS_MODE_ALLOWED = 0;
@@ -92,22 +98,25 @@
     private static final float ABOVE_MAX_ASPECT_RATIO = MAX_ASPECT_RATIO + FLOAT_COMPARE_EPSILON;
 
     public void testEnterPictureInPictureMode() throws Exception {
-        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"),
-                PIP_ACTIVITY, false, false);
+        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true"), PIP_ACTIVITY,
+                false /* moveTopToPinnedStack */, false /* isFocusable */);
     }
 
     public void testMoveTopActivityToPinnedStack() throws Exception {
-        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY, true, false);
+        pinnedStackTester(getAmStartCmd(PIP_ACTIVITY), PIP_ACTIVITY,
+                true /* moveTopToPinnedStack */, false /* isFocusable */);
     }
 
     public void testAlwaysFocusablePipActivity() throws Exception {
         pinnedStackTester(getAmStartCmd(ALWAYS_FOCUSABLE_PIP_ACTIVITY),
-                ALWAYS_FOCUSABLE_PIP_ACTIVITY, true, true);
+                ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+                true /* isFocusable */);
     }
 
     public void testLaunchIntoPinnedStack() throws Exception {
         pinnedStackTester(getAmStartCmd(LAUNCH_INTO_PINNED_STACK_PIP_ACTIVITY),
-                ALWAYS_FOCUSABLE_PIP_ACTIVITY, false, true);
+                ALWAYS_FOCUSABLE_PIP_ACTIVITY, false /* moveTopToPinnedStack */,
+                true /* isFocusable */);
     }
 
     public void testNonTappablePipActivity() throws Exception {
@@ -467,6 +476,30 @@
                 ALWAYS_FOCUSABLE_PIP_ACTIVITY)));
     }
 
+    public void testDisallowMultipleTasksInPinnedStack() throws Exception {
+        if (!supportsPip()) return;
+
+        // Launch a test activity so that we have multiple fullscreen tasks
+        launchActivity(TEST_ACTIVITY);
+
+        // Launch first PIP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+
+        // Launch second PIP activity
+        launchActivity(PIP_ACTIVITY2, EXTRA_ENTER_PIP, "true");
+
+        final ActivityStack pinnedStack = mAmWmState.getAmState().getStackById(PINNED_STACK_ID);
+        assertEquals(1, pinnedStack.getTasks().size());
+
+        assertTrue(pinnedStack.getTasks().get(0).mRealActivity.equals(getActivityComponentName(
+                PIP_ACTIVITY2)));
+
+        final ActivityStack fullScreenStack = mAmWmState.getAmState().getStackById(
+                FULLSCREEN_WORKSPACE_STACK_ID);
+        assertTrue(fullScreenStack.getBottomTask().mRealActivity.equals(getActivityComponentName(
+                PIP_ACTIVITY)));
+    }
+
     public void testPipUnPipOverHome() throws Exception {
         if (!supportsPip()) return;
 
@@ -559,7 +592,7 @@
         // stack, but that the home stack is still focused
         removeStacks(PINNED_STACK_ID);
         assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
-                true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+                false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
     }
 
     public void testMovePipToBackWithNoFullscreenStack() throws Exception {
@@ -576,7 +609,7 @@
         // fullscreen stack existed before)
         executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
         assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
-                true /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
+                false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
     }
 
     public void testMovePipToBackWithVisibleFullscreenStack() throws Exception {
@@ -608,7 +641,7 @@
         // stack, but that the home stack is still focused
         executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_MOVE_TO_BACK);
         assertPinnedStackStateOnMoveToFullscreen(PIP_ACTIVITY, HOME_STACK_ID,
-                true /* expectTopTaskHasActivity */, false /* expectBottomTaskHasActivity */);
+                false /* expectTopTaskHasActivity */, true /* expectBottomTaskHasActivity */);
     }
 
     public void testPinnedStackAlwaysOnTop() throws Exception {
@@ -655,7 +688,7 @@
 
         // Try to enter picture-in-picture from an activity that has more than one activity in the
         // task and ensure that it works
-        launchActivity(LAUNCHER_ENTER_PIP_ACTIVITY);
+        launchActivity(LAUNCH_ENTER_PIP_ACTIVITY);
         mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
         assertPinnedStackExists();
     }
@@ -715,17 +748,54 @@
         // Launch a PiP activity and ensure configuration change only happened once, and that the
         // configuration change happened after the picture-in-picture and multi-window callbacks
         launchActivity(PIP_ACTIVITY);
-        clearLogcat();
+        String logSeparator = clearLogcat();
         executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_ENTER_PIP);
         mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, PINNED_STACK_ID);
         assertPinnedStackExists();
-        assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY);
+        assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
 
         // Trigger it to go back to fullscreen and ensure that only triggered one configuration
         // change as well
-        clearLogcat();
+        logSeparator = clearLogcat();
         launchActivity(PIP_ACTIVITY);
-        assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY);
+        assertValidPictureInPictureCallbackOrder(PIP_ACTIVITY, logSeparator);
+    }
+
+    public void testStopBeforeMultiWindowCallbacksOnDismiss() throws Exception {
+        if (!supportsPip()) return;
+
+        // Launch a PiP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        assertPinnedStackExists();
+
+        // Dismiss it
+        String logSeparator = clearLogcat();
+        removeStacks(PINNED_STACK_ID);
+        mAmWmState.waitForValidState(mDevice, PIP_ACTIVITY, FULLSCREEN_WORKSPACE_STACK_ID);
+
+        // Confirm that we get stop before the multi-window and picture-in-picture mode change
+        // callbacks
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+                logSeparator);
+        if (lifecycleCounts.mStopCount != 1) {
+            fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mStopCount
+                    + " onStop() calls, expecting 1");
+        } else if (lifecycleCounts.mPictureInPictureModeChangedCount != 1) {
+            fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mPictureInPictureModeChangedCount
+                    + " onMultiWindowModeChanged() calls, expecting 1");
+        } else if (lifecycleCounts.mMultiWindowModeChangedCount != 1) {
+            fail(PIP_ACTIVITY + " has received " + lifecycleCounts.mMultiWindowModeChangedCount
+                    + " onPictureInPictureModeChanged() calls, expecting 1");
+        } else {
+            int lastStopLine = lifecycleCounts.mLastStopLineIndex;
+            int lastPipLine = lifecycleCounts.mLastPictureInPictureModeChangedLineIndex;
+            int lastMwLine = lifecycleCounts.mLastMultiWindowModeChangedLineIndex;
+            if (!(lastStopLine < lastPipLine && lastPipLine < lastMwLine)) {
+                fail(PIP_ACTIVITY + " has received callbacks in unexpected order.  Expected:"
+                        + " stop < pip < mw, but got line indices: " + lastStopLine + ", "
+                        + lastPipLine + ", " + lastMwLine + " respectively");
+            }
+        }
     }
 
     public void testPreventSetAspectRatioWhileExpanding() throws Exception {
@@ -752,7 +822,8 @@
         assertPinnedStackExists();
 
         // Request that the orientation is set to landscape
-        executeShellCommand("am broadcast -a " + ACTION_SET_REQUESTED_ORIENTATION + " -e "
+        executeShellCommand("am broadcast -a "
+                + PIP_ACTIVITY_ACTION_SET_REQUESTED_ORIENTATION + " -e "
                 + EXTRA_FIXED_ORIENTATION + " " + String.valueOf(ORIENTATION_LANDSCAPE));
 
         // Launch the activity back into fullscreen and ensure that it is now in landscape
@@ -772,6 +843,53 @@
         assertPinnedStackExists();
     }
 
+    public void testFinishPipActivityWithTaskOverlay() throws Exception {
+        if (!supportsPip()) return;
+
+        // Launch PiP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        assertPinnedStackExists();
+        int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+        // Launch task overlay activity into PiP activity task
+        launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+        // Finish the PiP activity and ensure that there is no pinned stack
+        executeShellCommand("am broadcast -a " + PIP_ACTIVITY_ACTION_FINISH);
+        mAmWmState.waitForWithAmState(mDevice, (amState) -> {
+            ActivityStack stack = amState.getStackById(PINNED_STACK_ID);
+            if (stack != null) {
+                return false;
+            }
+            return true;
+        }, "Waiting for pinned stack to be removed...");
+        assertPinnedStackDoesNotExist();
+    }
+
+    public void testNoResumeAfterTaskOverlayFinishes() throws Exception {
+        if (!supportsPip()) return;
+
+        // Launch PiP activity
+        launchActivity(PIP_ACTIVITY, EXTRA_ENTER_PIP, "true");
+        assertPinnedStackExists();
+        int taskId = mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getTopTask().mTaskId;
+
+        // Launch task overlay activity into PiP activity task
+        launchActivityAsTaskOverlay(TRANSLUCENT_TEST_ACTIVITY, taskId, PINNED_STACK_ID);
+
+        // Finish the task overlay activity while animating and ensure that the PiP activity never
+        // got resumed
+        String logSeparator = clearLogcat();
+        executeShellCommand("am stack resize-animated 4 20 20 500 500");
+        executeShellCommand("am broadcast -a " + TEST_ACTIVITY_ACTION_FINISH);
+        mAmWmState.waitFor(mDevice, (amState, wmState) -> !amState.containsActivity(
+                TRANSLUCENT_TEST_ACTIVITY), "Waiting for test activity to finish...");
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(PIP_ACTIVITY,
+                logSeparator);
+        assertTrue(lifecycleCounts.mResumeCount == 0);
+        assertTrue(lifecycleCounts.mPauseCount == 0);
+    }
+
     /**
      * Called after the given {@param activityName} has been moved to the fullscreen stack. Ensures
      * that the {@param focusedStackId} is focused, and checks the top and/or bottom tasks in the
@@ -864,8 +982,10 @@
      * Asserts that the activity received exactly one of each of the callbacks when entering and
      * exiting picture-in-picture.
      */
-    private void assertValidPictureInPictureCallbackOrder(String activityName) throws Exception {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+    private void assertValidPictureInPictureCallbackOrder(String activityName, String logSeparator)
+            throws Exception {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+                logSeparator);
 
         if (lifecycleCounts.mConfigurationChangedCount != 1) {
             fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
@@ -918,6 +1038,16 @@
     }
 
     /**
+     * Launches the given {@param activityName} into the {@param taskId} as a task overlay.
+     */
+    private void launchActivityAsTaskOverlay(String activityName, int taskId, int stackId)
+            throws Exception {
+        executeShellCommand(getAmStartCmd(activityName) + " --task " + taskId + " --task-overlay");
+
+        mAmWmState.waitForValidState(mDevice, activityName, stackId);
+    }
+
+    /**
      * Sets an app-ops op for a given package to a given mode.
      */
     private void setAppOpsOpToMode(String packageName, int op, int mode) throws Exception {
@@ -931,6 +1061,10 @@
         executeShellCommand(INPUT_KEYEVENT_WINDOW);
     }
 
+    /**
+     * TODO: Improve tests check to actually check that apps are not interactive instead of checking
+     *       if the stack is focused.
+     */
     private void pinnedStackTester(String startActivityCmd, String topActivityName,
             boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
 
@@ -958,8 +1092,8 @@
                 // Not checking for resumed state here because PiP overlay can be launched on top
                 // in different task by SystemUI.
             } else {
-                mAmWmState.assertNotFocusedStack(
-                        "Pinned stack can't be the focused stack.", PINNED_STACK_ID);
+                // Don't assert that the stack is not focused as a focusable PiP overlay can be
+                // launched on top as a task overlay by SystemUI.
                 mAmWmState.assertNotFocusedActivity(
                         "Pinned activity can't be the focused activity.", topActivityName);
                 mAmWmState.assertNotResumedActivity(
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
index 59d632a..3aa3ce0 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerReplaceWindowTests.java
@@ -49,6 +49,11 @@
     }
 
     private void testReplaceWindow_Dock(boolean relaunch) throws Exception {
+        if (!supportsSplitScreenMultiWindow()) {
+            CLog.logAndDisplay(INFO, "Skipping test: no multi-window support");
+            return;
+        }
+
         final String activityName =
                 relaunch ? SLOW_CREATE_ACTIVITY_NAME : NO_RELAUNCH_ACTIVITY_NAME;
         final String windowName = getWindowName(activityName);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
index 4afd607..a3099ae 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -45,6 +45,9 @@
     }
 
     public void testLockAndUnlock() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
         gotoKeyguard();
         mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
         assertShowingAndNotOccluded();
@@ -54,6 +57,9 @@
     }
 
     public void testDismissKeyguard() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
         gotoKeyguard();
         mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
         assertShowingAndNotOccluded();
@@ -65,6 +71,9 @@
     }
 
     public void testDismissKeyguard_whileOccluded() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
         gotoKeyguard();
         mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
         assertShowingAndNotOccluded();
@@ -80,6 +89,9 @@
     }
 
     public void testDismissKeyguard_fromShowWhenLocked_notAllowed() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
         gotoKeyguard();
         mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
         assertShowingAndNotOccluded();
@@ -98,7 +110,7 @@
         if (!isHandheld()) {
             return;
         }
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         gotoKeyguard();
         mAmWmState.computeState(mDevice, null);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -108,20 +120,20 @@
         mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
         mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
-        assertOnDismissSucceededInLogcat();
+        assertOnDismissSucceededInLogcat(logSeparator);
     }
 
     public void testDismissKeyguardActivity_method_cancelled() throws Exception {
         if (!isHandheld()) {
             return;
         }
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         gotoKeyguard();
         mAmWmState.computeState(mDevice, null);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
         launchActivity("DismissKeyguardMethodActivity");
         pressBackButton();
-        assertOnDismissCancelledInLogcat();
+        assertOnDismissCancelledInLogcat(logSeparator);
         mAmWmState.computeState(mDevice, new String[] {});
         mAmWmState.assertVisibility("DismissKeyguardMethodActivity", false);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
index ca86637..d578644 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
@@ -37,23 +37,24 @@
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
     }
 
-    protected void assertOnDismissSucceededInLogcat() throws Exception {
-        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded");
+    protected void assertOnDismissSucceededInLogcat(String logSeparator) throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded", logSeparator);
     }
 
-    protected void assertOnDismissCancelledInLogcat() throws Exception {
-        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled");
+    protected void assertOnDismissCancelledInLogcat(String logSeparator) throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled", logSeparator);
     }
 
-    protected void assertOnDismissErrorInLogcat() throws Exception {
-        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError");
+    protected void assertOnDismissErrorInLogcat(String logSeparator) throws Exception {
+        assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError", logSeparator);
     }
 
-    private void assertInLogcat(String activityName, String entry) throws Exception {
+    private void assertInLogcat(String activityName, String entry, String logSeparator)
+            throws Exception {
         final Pattern pattern = Pattern.compile("(.+)" + entry);
         int tries = 0;
         while (tries < 5) {
-            final String[] lines = getDeviceLogsForComponent(activityName);
+            final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
             log("Looking at logcat");
             for (int i = lines.length - 1; i >= 0; i--) {
                 final String line = lines[i].trim();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
index fa611ad..877369a 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -174,7 +174,7 @@
         if (!isHandheld()) {
             return;
         }
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         gotoKeyguard();
         mAmWmState.computeState(mDevice, null);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -183,28 +183,28 @@
         mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
         mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
-        assertOnDismissSucceededInLogcat();
+        assertOnDismissSucceededInLogcat(logSeparator);
     }
 
     public void testDismissKeyguardActivity_method_notTop() throws Exception {
         if (!isHandheld()) {
             return;
         }
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         gotoKeyguard();
         mAmWmState.computeState(mDevice, null);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
         launchActivity("BroadcastReceiverActivity");
         launchActivity("TestActivity");
         executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguardMethod true");
-        assertOnDismissErrorInLogcat();
+        assertOnDismissErrorInLogcat(logSeparator);
     }
 
     public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
         if (!isHandheld()) {
             return;
         }
-        clearLogcat();
+        final String logSeparator = clearLogcat();
         sleepDevice();
         mAmWmState.computeState(mDevice, null);
         assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
@@ -213,10 +213,13 @@
         mAmWmState.computeState(mDevice, new String[] { "TurnScreenOnDismissKeyguardActivity"});
         mAmWmState.assertVisibility("TurnScreenOnDismissKeyguardActivity", true);
         assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
-        assertOnDismissSucceededInLogcat();
+        assertOnDismissSucceededInLogcat(logSeparator);
     }
 
     public void testDismissKeyguard_fromShowWhenLocked_notAllowed() throws Exception {
+        if (!isHandheld()) {
+            return;
+        }
         gotoKeyguard();
         mAmWmState.waitForKeyguardShowingAndNotOccluded(mDevice);
         assertShowingAndNotOccluded();
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java
new file mode 100644
index 0000000..4694d7a
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/SplashscreenTests.java
@@ -0,0 +1,47 @@
+/*
+ * 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 android.server.cts;
+
+import java.awt.Color;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsServicesHostTestCases android.server.cts.SplashscreenTests
+ */
+public class SplashscreenTests extends ActivityManagerTestBase {
+
+    public void testSplashscreenContent() throws Exception {
+        launchActivityNoWait("SplashscreenActivity");
+        mAmWmState.waitForAppTransitionIdle(mDevice);
+        mAmWmState.getWmState().getStableBounds();
+        final BufferedImage image = takeScreenshot();
+        assertAllColor(image, mAmWmState.getWmState().getStableBounds(), Color.RED.getRGB());
+    }
+
+    private void assertAllColor(BufferedImage img, Rectangle bounds, int expectedColor) {
+        for (int x = bounds.x; x < bounds.x + bounds.width; x++) {
+            for (int y = bounds.y; y < bounds.y + bounds.height; y++) {
+                assertTrue(x < img.getWidth());
+                assertTrue(y < img.getHeight());
+                final int color = img.getRGB(x, y);
+                assertEquals("Colors must match at x=" + x + " y=" + y, expectedColor, color);
+            }
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
index ece45f2..9f4cf6c 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -34,13 +34,12 @@
 
 import junit.framework.Assert;
 
-import java.awt.*;
+import java.awt.Rectangle;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.function.BiPredicate;
 import java.util.function.Predicate;
-import java.util.regex.Pattern;
 
 /** Combined state of the activity manager and window manager. */
 public class ActivityAndWindowManagersState extends Assert {
@@ -195,7 +194,8 @@
             mAmState.computeState(device);
             mWmState.computeState(device);
             if (shouldWaitForValidStacks(compareTaskAndStackBounds)
-                    || shouldWaitForActivities(waitForActivitiesVisible, stackIds, packageName)) {
+                    || shouldWaitForActivities(waitForActivitiesVisible, stackIds, packageName)
+                    || shouldWaitForWindows()) {
                 log("***Waiting for valid stacks and activities states...");
                 try {
                     Thread.sleep(1000);
@@ -252,6 +252,12 @@
                 "***Waiting for focused stack...");
     }
 
+    void waitForAppTransitionIdle(ITestDevice device) throws Exception {
+        waitForWithWmState(device,
+                state -> WindowManagerState.APP_STATE_IDLE.equals(state.getAppTransitionState()),
+                "***Waiting for app transition idle...");
+    }
+
     void waitForWithAmState(ITestDevice device, Predicate<ActivityManagerState> waitCondition,
             String message) throws Exception{
         waitFor(device, (amState, wmState) -> waitCondition.test(amState), message);
@@ -283,6 +289,7 @@
         } while (retriesLeft-- > 0);
     }
 
+    /** @return true if should wait for valid stacks state. */
     private boolean shouldWaitForValidStacks(boolean compareTaskAndStackBounds) {
         if (!taskListsInAmAndWmAreEqual()) {
             // We want to wait for equal task lists in AM and WM in case we caught them in the
@@ -304,9 +311,24 @@
             log("***taskBoundsInAMAndWMAreEqual=false : " + e.getMessage());
             return true;
         }
+        final int stackCount = mAmState.getStackCount();
+        if (stackCount == 0) {
+            log("***stackCount=" + stackCount);
+            return true;
+        }
+        final int resumedActivitiesCount = mAmState.getResumedActivitiesCount();
+        if (!mAmState.getKeyguardControllerState().keyguardShowing && resumedActivitiesCount != 1) {
+            log("***resumedActivitiesCount=" + resumedActivitiesCount);
+            return true;
+        }
+        if (mAmState.getFocusedActivity() == null) {
+            log("***focusedActivity=null");
+            return true;
+        }
         return false;
     }
 
+    /** @return true if should wait for some activities to become visible. */
     private boolean shouldWaitForActivities(String[] waitForActivitiesVisible, int[] stackIds,
             String packageName) {
         if (waitForActivitiesVisible == null || waitForActivitiesVisible.length == 0) {
@@ -353,6 +375,24 @@
         return !allActivityWindowsVisible || !tasksInCorrectStacks;
     }
 
+    /** @return true if should wait valid windows state. */
+    private boolean shouldWaitForWindows() {
+        if (mWmState.getFrontWindow() == null) {
+            log("***frontWindow=null");
+            return true;
+        }
+        if (mWmState.getFocusedWindow() == null) {
+            log("***focusedWindow=null");
+            return true;
+        }
+        if (mWmState.getFocusedApp() == null) {
+            log("***focusedApp=null");
+            return true;
+        }
+
+        return false;
+    }
+
     private boolean shouldWaitForDebuggerWindow() {
         List<WindowManagerState.WindowState> matchingWindowStates = new ArrayList<>();
         mWmState.getMatchingVisibleWindowState("android.server.cts", matchingWindowStates);
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 4f9c3ac..bfd6b5a 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -21,13 +21,17 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.result.InputStreamSource;
 import com.android.tradefed.testtype.DeviceTestCase;
 
+import java.awt.*;
+import java.awt.image.BufferedImage;
 import java.lang.Exception;
 import java.lang.Integer;
 import java.lang.String;
 import java.util.HashSet;
 import java.util.List;
+import java.util.UUID;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -36,9 +40,12 @@
 
 import android.server.cts.ActivityManagerState.ActivityStack;
 
+import javax.imageio.ImageIO;
+
 public abstract class ActivityManagerTestBase extends DeviceTestCase {
     private static final boolean PRETEND_DEVICE_SUPPORTS_PIP = false;
     private static final boolean PRETEND_DEVICE_SUPPORTS_FREEFORM = false;
+    private static final String LOG_SEPARATOR = "LOG_SEPARATOR";
 
     // Constants copied from ActivityManager.StackId. If they are changed there, these must be
     // updated.
@@ -113,6 +120,10 @@
 
     static final String AM_MOVE_TASK = "am stack move-task ";
 
+    private static final String AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW =
+            "am supports-split-screen-multiwindow";
+    private static final String AM_NO_HOME_SCREEN = "am no-home-screen";
+
     private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
     private static final String INPUT_KEYEVENT_BACK = "input keyevent 4";
     private static final String INPUT_KEYEVENT_APP_SWITCH = "input keyevent 187";
@@ -285,13 +296,25 @@
         mDevice.executeShellCommand(command, outputReceiver);
     }
 
+    protected BufferedImage takeScreenshot() throws Exception {
+        final InputStreamSource stream = mDevice.getScreenshot("PNG", false /* rescale */);
+        if (stream == null) {
+            fail("Failed to take screenshot of device");
+        }
+        return ImageIO.read(stream.createInputStream());
+    }
+
     protected void launchActivity(final String targetActivityName, final String... keyValuePairs)
             throws Exception {
         executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
-
         mAmWmState.waitForValidState(mDevice, targetActivityName);
     }
 
+    protected void launchActivityNoWait(final String targetActivityName,
+            final String... keyValuePairs) throws Exception {
+        executeShellCommand(getAmStartCmd(targetActivityName, keyValuePairs));
+    }
+
     protected void launchActivityInNewTask(final String targetActivityName) throws Exception {
         executeShellCommand(getAmStartCmdInNewTask(targetActivityName));
         mAmWmState.waitForValidState(mDevice, targetActivityName);
@@ -502,6 +525,20 @@
                 && !hasDeviceFeature("android.software.watch");
     }
 
+    protected boolean supportsSplitScreenMultiWindow() throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        executeShellCommand(AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW, outputReceiver);
+        String output = outputReceiver.getOutput();
+        return !output.startsWith("false");
+    }
+
+    protected boolean noHomeScreen() throws DeviceNotAvailableException {
+        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        executeShellCommand(AM_NO_HOME_SCREEN, outputReceiver);
+        String output = outputReceiver.getOutput();
+        return output.startsWith("true");
+    }
+
     protected boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
         if (mAvailableFeatures == null) {
             // TODO: Move this logic to ITestDevice.
@@ -687,93 +724,194 @@
         return output;
     }
 
-    protected void clearLogcat() throws DeviceNotAvailableException {
+    /**
+     * Tries to clear logcat and inserts log separator in case clearing didn't succeed, so we can
+     * always find the starting point from where to evaluate following logs.
+     * @return Unique log separator.
+     */
+    protected String clearLogcat() throws DeviceNotAvailableException {
         mDevice.executeAdbCommand("logcat", "-c");
+        final String uniqueString = UUID.randomUUID().toString();
+        executeShellCommand("log -t " + LOG_SEPARATOR + " " + uniqueString);
+        return uniqueString;
     }
 
-    protected void assertActivityLifecycle(String activityName, boolean relaunched)
-            throws DeviceNotAvailableException {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+    void assertActivityLifecycle(String activityName, boolean relaunched,
+            String logSeparator) throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = verifyLifecycleCondition(activityName, logSeparator, relaunched);
+            if (resultString != null) {
+                log("***Waiting for valid lifecycle state: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
 
+        assertNull(resultString, resultString);
+    }
+
+    /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+    private String verifyLifecycleCondition(String activityName, String logSeparator,
+            boolean relaunched) throws DeviceNotAvailableException {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+                logSeparator);
         if (relaunched) {
             if (lifecycleCounts.mDestroyCount < 1) {
-                fail(activityName + " must have been destroyed. mDestroyCount="
-                        + lifecycleCounts.mDestroyCount);
+                return activityName + " must have been destroyed. mDestroyCount="
+                        + lifecycleCounts.mDestroyCount;
             }
             if (lifecycleCounts.mCreateCount < 1) {
-                fail(activityName + " must have been (re)created. mCreateCount="
-                        + lifecycleCounts.mCreateCount);
+                return activityName + " must have been (re)created. mCreateCount="
+                        + lifecycleCounts.mCreateCount;
             }
         } else {
             if (lifecycleCounts.mDestroyCount > 0) {
-                fail(activityName + " must *NOT* have been destroyed. mDestroyCount="
-                        + lifecycleCounts.mDestroyCount);
+                return activityName + " must *NOT* have been destroyed. mDestroyCount="
+                        + lifecycleCounts.mDestroyCount;
             }
             if (lifecycleCounts.mCreateCount > 0) {
-                fail(activityName + " must *NOT* have been (re)created. mCreateCount="
-                        + lifecycleCounts.mCreateCount);
+                return activityName + " must *NOT* have been (re)created. mCreateCount="
+                        + lifecycleCounts.mCreateCount;
             }
             if (lifecycleCounts.mConfigurationChangedCount < 1) {
-                fail(activityName + " must have received configuration changed. "
+                return activityName + " must have received configuration changed. "
                         + "mConfigurationChangedCount="
-                        + lifecycleCounts.mConfigurationChangedCount);
+                        + lifecycleCounts.mConfigurationChangedCount;
             }
         }
+        return null;
     }
 
     protected void assertRelaunchOrConfigChanged(
-            String activityName, int numRelaunch, int numConfigChange)
+            String activityName, int numRelaunch, int numConfigChange, String logSeparator)
             throws DeviceNotAvailableException {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = verifyRelaunchOrConfigChanged(activityName, numRelaunch, numConfigChange,
+                    logSeparator);
+            if (resultString != null) {
+                log("***Waiting for relaunch or config changed: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+    private String verifyRelaunchOrConfigChanged(String activityName, int numRelaunch,
+            int numConfigChange, String logSeparator) throws DeviceNotAvailableException {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+                logSeparator);
 
         if (lifecycleCounts.mDestroyCount != numRelaunch) {
-            fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
-                    + " time(s), expecting " + numRelaunch);
+            return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+                    + " time(s), expecting " + numRelaunch;
         } else if (lifecycleCounts.mCreateCount != numRelaunch) {
-            fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
-                    + " time(s), expecting " + numRelaunch);
+            return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+                    + " time(s), expecting " + numRelaunch;
         } else if (lifecycleCounts.mConfigurationChangedCount != numConfigChange) {
-            fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
-                    + " onConfigurationChanged() calls, expecting " + numConfigChange);
+            return activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
+                    + " onConfigurationChanged() calls, expecting " + numConfigChange;
         }
+        return null;
     }
 
-    protected void assertActivityDestroyed(String activityName) throws DeviceNotAvailableException {
-        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName);
+    protected void assertActivityDestroyed(String activityName, String logSeparator)
+            throws DeviceNotAvailableException {
+        int retriesLeft = 5;
+        String resultString;
+        do {
+            resultString = verifyActivityDestroyed(activityName, logSeparator);
+            if (resultString != null) {
+                log("***Waiting for activity destroyed: " + resultString);
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+
+        assertNull(resultString, resultString);
+    }
+
+    /** @return Error string if lifecycle counts don't match, null if everything is fine. */
+    private String verifyActivityDestroyed(String activityName, String logSeparator)
+            throws DeviceNotAvailableException {
+        final ActivityLifecycleCounts lifecycleCounts = new ActivityLifecycleCounts(activityName,
+                logSeparator);
 
         if (lifecycleCounts.mDestroyCount != 1) {
-            fail(activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
-                    + " time(s), expecting single destruction.");
+            return activityName + " has been destroyed " + lifecycleCounts.mDestroyCount
+                    + " time(s), expecting single destruction.";
         } else if (lifecycleCounts.mCreateCount != 0) {
-            fail(activityName + " has been (re)created " + lifecycleCounts.mCreateCount
-                    + " time(s), not expecting any.");
+            return activityName + " has been (re)created " + lifecycleCounts.mCreateCount
+                    + " time(s), not expecting any.";
         } else if (lifecycleCounts.mConfigurationChangedCount != 0) {
-            fail(activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
-                    + " onConfigurationChanged() calls, not expecting any.");
+            return activityName + " has received " + lifecycleCounts.mConfigurationChangedCount
+                    + " onConfigurationChanged() calls, not expecting any.";
         }
+        return null;
     }
 
-    protected String[] getDeviceLogsForComponent(String componentName)
+    protected String[] getDeviceLogsForComponent(String componentName, String logSeparator)
             throws DeviceNotAvailableException {
-        return mDevice.executeAdbCommand(
-                "logcat", "-v", "brief", "-d", componentName + ":I", "*:S").split("\\n");
+        return getDeviceLogsForComponents(new String[]{componentName}, logSeparator);
     }
 
-    protected String[] getDeviceLogsForComponents(final String[] componentNames)
-            throws DeviceNotAvailableException {
-        String filters = "";
-        for (int i = 0; i < componentNames.length; i++) {
-            filters += componentNames[i] + ":I ";
+    protected String[] getDeviceLogsForComponents(final String[] componentNames,
+            String logSeparator) throws DeviceNotAvailableException {
+        String filters = LOG_SEPARATOR + ":I ";
+        for (String component : componentNames) {
+            filters += component + ":I ";
         }
-        return mDevice.executeAdbCommand(
+        final String[] result = mDevice.executeAdbCommand(
                 "logcat", "-v", "brief", "-d", filters, "*:S").split("\\n");
+        if (logSeparator == null) {
+            return result;
+        }
+
+        // Make sure that we only check logs after the separator.
+        int i = 0;
+        boolean lookingForSeparator = true;
+        while (i < result.length && lookingForSeparator) {
+            if (result[i].contains(logSeparator)) {
+                lookingForSeparator = false;
+            }
+            i++;
+        }
+        final String[] filteredResult = new String[result.length - i];
+        for (int curPos = 0; i < result.length; curPos++, i++) {
+            filteredResult[curPos] = result[i];
+        }
+        return filteredResult;
     }
 
     private static final Pattern sCreatePattern = Pattern.compile("(.+): onCreate");
+    private static final Pattern sResumePattern = Pattern.compile("(.+): onResume");
+    private static final Pattern sPausePattern = Pattern.compile("(.+): onPause");
     private static final Pattern sConfigurationChangedPattern =
             Pattern.compile("(.+): onConfigurationChanged");
     private static final Pattern sMovedToDisplayPattern =
             Pattern.compile("(.+): onMovedToDisplay");
+    private static final Pattern sStopPattern = Pattern.compile("(.+): onStop");
     private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
     private static final Pattern sMultiWindowModeChangedPattern =
             Pattern.compile("(.+): onMultiWindowModeChanged");
@@ -819,9 +957,30 @@
         }
     }
 
-    ReportedSizes getLastReportedSizesForActivity(String activityName)
+    ReportedSizes getLastReportedSizesForActivity(String activityName, String logSeparator)
             throws DeviceNotAvailableException {
-        final String[] lines = getDeviceLogsForComponent(activityName);
+        int retriesLeft = 5;
+        ReportedSizes result;
+        do {
+            result = readLastReportedSizes(activityName, logSeparator);
+            if (result == null) {
+                log("***Waiting for sizes to be reported...");
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    log(e.toString());
+                    // Well I guess we are not waiting...
+                }
+            } else {
+                break;
+            }
+        } while (retriesLeft-- > 0);
+        return result;
+    }
+
+    private ReportedSizes readLastReportedSizes(String activityName, String logSeparator)
+            throws DeviceNotAvailableException {
+        final String[] lines = getDeviceLogsForComponent(activityName, logSeparator);
         for (int i = lines.length - 1; i >= 0; i--) {
             final String line = lines[i].trim();
             final Matcher matcher = sNewConfigPattern.matcher(line);
@@ -843,6 +1002,7 @@
 
     class ActivityLifecycleCounts {
         int mCreateCount;
+        int mResumeCount;
         int mConfigurationChangedCount;
         int mLastConfigurationChangedLineIndex;
         int mMovedToDisplayCount;
@@ -850,11 +1010,15 @@
         int mLastMultiWindowModeChangedLineIndex;
         int mPictureInPictureModeChangedCount;
         int mLastPictureInPictureModeChangedLineIndex;
+        int mPauseCount;
+        int mStopCount;
+        int mLastStopLineIndex;
         int mDestroyCount;
 
-        public ActivityLifecycleCounts(String activityName) throws DeviceNotAvailableException {
+        public ActivityLifecycleCounts(String activityName, String logSeparator)
+                throws DeviceNotAvailableException {
             int lineIndex = 0;
-            for (String line : getDeviceLogsForComponent(activityName)) {
+            for (String line : getDeviceLogsForComponent(activityName, logSeparator)) {
                 line = line.trim();
                 lineIndex++;
 
@@ -864,6 +1028,12 @@
                     continue;
                 }
 
+                matcher = sResumePattern.matcher(line);
+                if (matcher.matches()) {
+                    mResumeCount++;
+                    continue;
+                }
+
                 matcher = sConfigurationChangedPattern.matcher(line);
                 if (matcher.matches()) {
                     mConfigurationChangedCount++;
@@ -891,6 +1061,19 @@
                     continue;
                 }
 
+                matcher = sPausePattern.matcher(line);
+                if (matcher.matches()) {
+                    mPauseCount++;
+                    continue;
+                }
+
+                matcher = sStopPattern.matcher(line);
+                if (matcher.matches()) {
+                    mStopCount++;
+                    mLastStopLineIndex = lineIndex;
+                    continue;
+                }
+
                 matcher = sDestroyPattern.matcher(line);
                 if (matcher.matches()) {
                     mDestroyCount++;
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index f9ad434..0cdf13e 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -37,7 +37,7 @@
 
 public class WindowManagerState {
 
-    public static  final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
+    public static final String TRANSIT_ACTIVITY_OPEN = "TRANSIT_ACTIVITY_OPEN";
     public static final String TRANSIT_ACTIVITY_CLOSE = "TRANSIT_ACTIVITY_CLOSE";
     public static final String TRANSIT_TASK_OPEN = "TRANSIT_TASK_OPEN";
     public static final String TRANSIT_TASK_CLOSE = "TRANSIT_TASK_CLOSE";
@@ -53,6 +53,8 @@
     public static final String TRANSIT_KEYGUARD_OCCLUDE = "TRANSIT_KEYGUARD_OCCLUDE";
     public static final String TRANSIT_KEYGUARD_UNOCCLUDE = "TRANSIT_KEYGUARD_UNOCCLUDE";
 
+    public static final String APP_STATE_IDLE = "APP_STATE_IDLE";
+
     private static final String DUMPSYS_WINDOW = "dumpsys window -a";
 
     private static final Pattern sWindowPattern =
@@ -87,6 +89,8 @@
 
     private static final Pattern sLastAppTransitionPattern =
             Pattern.compile("mLastUsedAppTransition=(.+)");
+    private static final Pattern sAppTransitionStatePattern =
+            Pattern.compile("mAppTransitionState=(.+)");
 
     private static final Pattern sStackIdPattern = Pattern.compile("mStackId=(\\d+)");
 
@@ -120,6 +124,7 @@
     private String mFocusedWindow = null;
     private String mFocusedApp = null;
     private String mLastTransition = null;
+    private String mAppTransitionState = null;
     private String mInputMethodWindowAppToken = null;
     private Rectangle mStableBounds = new Rectangle();
     private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
@@ -157,7 +162,7 @@
             dump = outputReceiver.getOutput();
             parseSysDump(dump);
 
-            retry = mWindowStates.isEmpty() || mFocusedWindow == null || mFocusedApp == null;
+            retry = mWindowStates.isEmpty() || mFocusedApp == null;
         } while (retry && retriesLeft-- > 0);
 
         if (retry) {
@@ -260,6 +265,15 @@
                 continue;
             }
 
+            matcher = sAppTransitionStatePattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                final String appTransitionState = matcher.group(1);
+                log(appTransitionState);
+                mAppTransitionState = appTransitionState;
+                continue;
+            }
+
             matcher = sLastAppTransitionPattern.matcher(line);
             if (matcher.matches()) {
                 log(line);
@@ -442,6 +456,10 @@
         return mLastTransition;
     }
 
+    String getAppTransitionState() {
+        return mAppTransitionState;
+    }
+
     int getFrontStackId(int displayId) {
         return mDisplayStacks.get(displayId).get(0).mStackId;
     }
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
index f594123..6281e16 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/src/android/server/cts/CrossAppDragAndDropTests.java
@@ -24,6 +24,7 @@
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 public class CrossAppDragAndDropTests extends DeviceTestCase {
     // Constants copied from ActivityManager.StackId. If they are changed there, these must be
@@ -42,12 +43,18 @@
 
     private static final String AM_FORCE_STOP = "am force-stop ";
     private static final String AM_MOVE_TASK = "am stack move-task ";
+    private static final String AM_RESIZE_TASK = "am task resize ";
     private static final String AM_REMOVE_STACK = "am stack remove ";
     private static final String AM_START_N = "am start -n ";
     private static final String AM_STACK_LIST = "am stack list";
     private static final String INPUT_MOUSE_SWIPE = "input mouse swipe ";
     private static final String TASK_ID_PREFIX = "taskId";
 
+    // Regex pattern to match adb shell am stack list output of the form:
+    // taskId=<TASK_ID>: <componentName> bounds=[LEFT,TOP][RIGHT,BOTTOM]
+    private static final String TASK_REGEX_PATTERN_STRING =
+            "taskId=[0-9]+: %s bounds=\\[[0-9]+,[0-9]+\\]\\[[0-9]+,[0-9]+\\]";
+
     private static final int SWIPE_DURATION_MS = 500;
 
     private static final String SOURCE_PACKAGE_NAME = "android.wm.cts.dndsourceapp";
@@ -94,6 +101,9 @@
     private static final String RESULT_EXCEPTION = "Exception";
     private static final String RESULT_NULL_DROP_PERMISSIONS = "Null DragAndDropPermissions";
 
+    private static final String AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW =
+            "am supports-split-screen-multiwindow";
+
     private ITestDevice mDevice;
 
     private Map<String, String> mSourceResults;
@@ -145,6 +155,12 @@
         return AM_MOVE_TASK + taskId + " " + stackId + " true";
     }
 
+    private String getResizeTaskCommand(int taskId, Point topLeft, Point bottomRight)
+            throws Exception {
+        return AM_RESIZE_TASK + taskId + " " + topLeft.x + " " + topLeft.y + " " + bottomRight.x
+                + " " + bottomRight.y;
+    }
+
     private String getComponentName(String packageName, String activityName) {
         return packageName + "/" + packageName + "." + activityName;
     }
@@ -195,6 +211,24 @@
         waitForResume(packageName, activityName);
     }
 
+    /**
+     * @param displaySize size of the display
+     * @param leftSide {@code true} to launch the app taking up the left half of the display,
+     *         {@code false} to launch the app taking up the right half of the display.
+     */
+    private void launchFreeformActivity(String packageName, String activityName, String mode,
+            Point displaySize, boolean leftSide) throws Exception{
+        clearLogs();
+        final String componentName = getComponentName(packageName, activityName);
+        executeShellCommand(getStartCommand(componentName, mode) + " --stack "
+                + FREEFORM_WORKSPACE_STACK_ID);
+        waitForResume(packageName, activityName);
+        Point topLeft = new Point(leftSide ? 0 : displaySize.x / 2, 0);
+        Point bottomRight = new Point(leftSide ? displaySize.x / 2 : displaySize.x, displaySize.y);
+        executeShellCommand(getResizeTaskCommand(getActivityTaskId(componentName), topLeft,
+                bottomRight));
+    }
+
     private void waitForResume(String packageName, String activityName) throws Exception {
         final String fullActivityName = packageName + "." + activityName;
         int retryCount = 3;
@@ -238,6 +272,7 @@
         builder.append("\nParsing adb shell am output: " );
         builder.append(output);
         CLog.i(builder.toString());
+        final Pattern pattern = Pattern.compile(String.format(TASK_REGEX_PATTERN_STRING, name));
         for (String line : output.split("\\n")) {
             final String truncatedLine;
             // Only look for the activity name before the "topActivity" string.
@@ -247,7 +282,7 @@
             } else {
                 truncatedLine = line;
             }
-            if (truncatedLine.contains(name)) {
+            if (pattern.matcher(truncatedLine).find()) {
                 return truncatedLine;
             }
         }
@@ -280,6 +315,12 @@
         return -1;
     }
 
+    private Point getDisplaySize() throws Exception {
+        final String output = executeShellCommand("wm size");
+        final String[] sizes = output.split(" ")[2].split("x");
+        return new Point(Integer.valueOf(sizes[0].trim()), Integer.valueOf(sizes[1].trim()));
+    }
+
     private Point getWindowCenter(String name) throws Exception {
         Point p1 = new Point();
         Point p2 = new Point();
@@ -343,8 +384,19 @@
             return;
         }
 
-        launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
-        launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
+        if (supportsSplitScreenMultiWindow()) {
+            launchDockedActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode);
+            launchFullscreenActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode);
+        } else if (supportsFreeformMultiWindow()) {
+            // Fallback to try to launch two freeform windows side by side.
+            Point displaySize = getDisplaySize();
+            launchFreeformActivity(mSourcePackageName, SOURCE_ACTIVITY_NAME, sourceMode,
+                    displaySize, true /* leftSide */);
+            launchFreeformActivity(mTargetPackageName, TARGET_ACTIVITY_NAME, targetMode,
+                    displaySize, false /* leftSide */);
+        } else {
+            return;
+        }
 
         clearLogs();
 
@@ -412,6 +464,14 @@
         }
     }
 
+    private boolean supportsSplitScreenMultiWindow() throws DeviceNotAvailableException {
+        return !executeShellCommand(AM_SUPPORTS_SPLIT_SCREEN_MULTIWINDOW).startsWith("false");
+    }
+
+    private boolean supportsFreeformMultiWindow() throws DeviceNotAvailableException {
+        return mDevice.hasFeature("feature:android.software.freeform_window_management");
+    }
+
     public void testCancelSoon() throws Exception {
         assertDropResult(CANCEL_SOON, REQUEST_NONE, RESULT_MISSING);
     }
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
index 595ee74..25f8317 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/ShortcutManagerBackupTest.java
@@ -19,6 +19,9 @@
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil.CLog;
 
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
 public class ShortcutManagerBackupTest extends BaseShortcutManagerHostTest {
     private static final String LAUNCHER1_APK = "CtsShortcutBackupLauncher1.apk";
     private static final String LAUNCHER2_APK = "CtsShortcutBackupLauncher2.apk";
@@ -40,6 +43,8 @@
     private static final String PUBLISHER3_PKG =
             "android.content.pm.cts.shortcut.backup.publisher3";
 
+    private static final int BROADCAST_TIMEOUT_SECONDS = 120;
+
     private static final String FEATURE_BACKUP = "android.software.backup";
 
     private boolean mSupportsBackup;
@@ -57,6 +62,15 @@
             clearShortcuts(PUBLISHER1_PKG, getPrimaryUserId());
             clearShortcuts(PUBLISHER2_PKG, getPrimaryUserId());
             clearShortcuts(PUBLISHER3_PKG, getPrimaryUserId());
+
+            uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+            uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+            uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+            uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+            uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+            uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
+
+            waitUntilPackagesGone();
         }
     }
 
@@ -106,10 +120,82 @@
 
     }
 
+    private void uninstallPackageAndWaitUntilBroadcastsDrain(String pkg) throws Exception {
+        getDevice().uninstallPackage(pkg);
+        waitUntilBroadcastsDrain();
+    }
+
+    /**
+     * Wait until the broadcasts queues all drain.
+     */
+    private void waitUntilBroadcastsDrain() throws Exception {
+        final long TIMEOUT = System.nanoTime() +
+                TimeUnit.SECONDS.toNanos(BROADCAST_TIMEOUT_SECONDS);
+
+        final Pattern re = Pattern.compile("^\\s+Active (ordered)? broadcasts \\[",
+                Pattern.MULTILINE);
+
+        String dumpsys = "";
+        while (System.nanoTime() < TIMEOUT) {
+            Thread.sleep(1000);
+
+            dumpsys = getDevice().executeShellCommand("dumpsys activity broadcasts");
+
+            if (re.matcher(dumpsys).find()) {
+                continue;
+            }
+
+            CLog.d("Broadcast queues drained:\n" + dumpsys);
+
+            dumpsys("Broadcast queues drained");
+
+            // All packages gone.
+            return;
+        }
+        fail("Broadcast queues didn't drain before time out."
+                + " Last dumpsys=\n" + dumpsys);
+    }
+
+    /**
+     * Wait until all the test packages are forgotten by the shortcut manager.
+     */
+    private void waitUntilPackagesGone() throws Exception {
+        CLog.i("Waiting until all packages are removed from shortcut manager...");
+
+        final String packages[] = {
+                LAUNCHER1_PKG,  LAUNCHER2_PKG, LAUNCHER3_PKG,
+                PUBLISHER1_PKG, PUBLISHER2_PKG, PUBLISHER3_PKG,
+        };
+
+        String dumpsys = "";
+        final long TIMEOUT = System.nanoTime() +
+                TimeUnit.SECONDS.toNanos(BROADCAST_TIMEOUT_SECONDS);
+
+        while (System.nanoTime() < TIMEOUT) {
+            Thread.sleep(2000);
+            dumpsys = getDevice().executeShellCommand("dumpsys shortcut");
+
+            if (dumpsys.contains("Launcher: " + LAUNCHER1_PKG)) continue;
+            if (dumpsys.contains("Launcher: " + LAUNCHER2_PKG)) continue;
+            if (dumpsys.contains("Launcher: " + LAUNCHER3_PKG)) continue;
+            if (dumpsys.contains("Package: " + PUBLISHER1_PKG)) continue;
+            if (dumpsys.contains("Package: " + PUBLISHER2_PKG)) continue;
+            if (dumpsys.contains("Package: " + PUBLISHER3_PKG)) continue;
+
+            dumpsys("Shortcut manager handled broadcasts");
+
+            // All packages gone.
+            return;
+        }
+        fail("ShortcutManager didn't handle all expected broadcasts before time out."
+                + " Last dumpsys=\n" + dumpsys);
+    }
+
     public void testBackupAndRestore() throws Exception {
         if (!mSupportsBackup) {
             return;
         }
+        dumpsys("Test start");
 
         installAppAsUser(LAUNCHER1_APK, getPrimaryUserId());
         installAppAsUser(LAUNCHER2_APK, getPrimaryUserId());
@@ -131,21 +217,31 @@
         // Tweak shortcuts a little bit to make disabled shortcuts.
         runDeviceTestsAsUser(PUBLISHER2_PKG, ".ShortcutManagerPreBackup2Test", getPrimaryUserId());
 
+        dumpsys("Before backup");
+
         // Backup
         doBackup();
 
         // Uninstall all apps
-        getDevice().uninstallPackage(LAUNCHER1_PKG);
-        getDevice().uninstallPackage(LAUNCHER2_PKG);
-        getDevice().uninstallPackage(LAUNCHER3_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER1_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER2_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(LAUNCHER3_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER1_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER2_PKG);
+        uninstallPackageAndWaitUntilBroadcastsDrain(PUBLISHER3_PKG);
 
-        getDevice().uninstallPackage(PUBLISHER1_PKG);
-        getDevice().uninstallPackage(PUBLISHER2_PKG);
-        getDevice().uninstallPackage(PUBLISHER3_PKG);
+
+        // Make sure the shortcut service handled all the uninstall broadcasts.
+        waitUntilPackagesGone();
+
+        // Do it one more time just in case...
+        waitUntilBroadcastsDrain();
 
         // Then restore
         doRestore();
 
+        dumpsys("After restore");
+
         // First, restore launcher 1, which shouldn't see any shortcuts from the packages yet.
         installAppAsUser(LAUNCHER1_APK, getPrimaryUserId());
         runDeviceTestsAsUser(LAUNCHER1_PKG, ".ShortcutManagerPostBackupTest",
diff --git a/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java b/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
index d599546..a8871a3 100644
--- a/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
+++ b/hostsidetests/trustedvoice/src/android/trustedvoice/cts/TrustedVoiceHostTest.java
@@ -99,6 +99,8 @@
             getDevice().executeShellCommand(SLEEP_COMMAND);
             // Start the APK and wait for it to complete.
             getDevice().executeShellCommand(START_COMMAND);
+            // Give the activity some time to start
+            Thread.sleep(500);
             // Dump logcat.
             String logs = getDevice().executeAdbCommand(
                     "logcat", "-v", "brief", "-d", CLASS + ":I", "*:S");
diff --git a/hostsidetests/webkit/AndroidTest.xml b/hostsidetests/webkit/AndroidTest.xml
index 8641395..5a0eeca 100644
--- a/hostsidetests/webkit/AndroidTest.xml
+++ b/hostsidetests/webkit/AndroidTest.xml
@@ -17,7 +17,6 @@
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsWebViewStartupApp.apk" />
-        <option name="test-file-name" value="CtsWebViewRendererCrash.apk" />
     </target_preparer>
 
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml b/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml
deleted file mode 100644
index d1744e5..0000000
--- a/hostsidetests/webkit/renderprocesscrash/AndroidManifest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.cts.webkit.renderprocesscrash">
-
-    <uses-permission android:name="android.permission.INTERNET" />
-
-    <application android:maxRecents="1">
-        <activity android:name=".RenderProcessCrashActivity"
-            android:label="RenderProcessCrashActivity"
-            android:screenOrientation="nosensor">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java b/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java
deleted file mode 100644
index 2f65afc..0000000
--- a/hostsidetests/webkit/src/com/android/cts/webkit/RenderProcessCrashTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.webkit;
-
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.device.TestDeviceOptions;
-import com.android.tradefed.testtype.DeviceTestCase;
-
-import java.util.Scanner;
-
-/**
- * This test lanuches RenderProcessCrashActivity which crashes render process, and
- * checks specific crash log in Logcat to verify Render process crashed.
- */
-public class RenderProcessCrashTest extends DeviceTestCase {
-    /**
-     * The package name of the APK.
-     */
-    private static final String PACKAGE = "com.android.cts.webkit.renderprocesscrash";
-
-    /**
-     * The class name of the main activity in the APK.
-     */
-    private static final String CLASS = "RenderProcessCrashActivity";
-
-    /**
-     * The command to launch the main activity.
-     */
-    private static final String START_COMMAND = String.format(
-            "am start -W -a android.intent.action.MAIN -n %s/%s.%s", PACKAGE, PACKAGE, CLASS);
-
-    /**
-     * The test string to look for.
-     */
-    private static final String TEST_STRING = "kill (OOM or update) wasn't handed by all associated"
-        + " webviews, killing application.";
-
-    /**
-     * Tests the string was successfully logged to Logcat from the activity.
-     *
-     * @throws Exception
-     */
-    public void testCrash() throws Exception {
-        ITestDevice device = getDevice();
-        // Clear logcat.
-        device.executeAdbCommand("logcat", "-c");
-        TestDeviceOptions options = new TestDeviceOptions();
-        options.setLogcatOptions("-v brief -d chromium:E *:S");
-        device.setOptions(options);
-
-        // Start the APK.
-        device.executeShellCommand(START_COMMAND);
-        // Dump logcat.
-        device.startLogcat();
-        // Search for string.
-        Scanner in = new Scanner(device.getLogcat().createInputStream());
-        boolean found = false;
-        int tryTimes = 10;
-        while (tryTimes-- > 0) {
-            while (in.hasNextLine()) {
-                String line = in.nextLine().trim();
-                if(line.endsWith(TEST_STRING)) {
-                    found = true;
-                    break;
-                }
-            }
-            if (found) break;
-            Thread.sleep(1000);
-        }
-        in.close();
-        device.stopLogcat();
-        assertTrue("Can't not find crash log " + TEST_STRING, found);
-    }
-}
diff --git a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
index e914ee2..1955483 100644
--- a/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
+++ b/tests/JobScheduler/src/android/jobscheduler/MockJobService.java
@@ -17,14 +17,22 @@
 package android.jobscheduler;
 
 import android.annotation.TargetApi;
+import android.app.job.JobInfo;
 import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
 import android.app.job.JobService;
+import android.app.job.JobWorkItem;
 import android.content.ClipData;
+import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.net.Uri;
 import android.os.Process;
 import android.util.Log;
 
+import junit.framework.Assert;
+
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -40,15 +48,29 @@
     /** Wait this long before timing out the test. */
     private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
 
+    private JobParameters mParams;
+
+    ArrayList<Intent> mReceivedWork = new ArrayList<Intent>();
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        if (TestEnvironment.getTestEnvironment().getExpectedWork() != null) {
+            TestEnvironment.getTestEnvironment().notifyExecution(mParams, 0, 0, mReceivedWork,
+                    null);
+        }
+    }
+
     @Override
     public void onCreate() {
         super.onCreate();
-        Log.e(TAG, "Created test service.");
+        Log.i(TAG, "Created test service.");
     }
 
     @Override
     public boolean onStartJob(JobParameters params) {
         Log.i(TAG, "Test job executing: " + params.getJobId());
+        mParams = params;
 
         int permCheckRead = PackageManager.PERMISSION_DENIED;
         int permCheckWrite = PackageManager.PERMISSION_DENIED;
@@ -60,8 +82,118 @@
                     Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
         }
 
-        TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead, permCheckWrite);
-        return false;  // No work to do.
+        TestWorkItem[] expectedWork = TestEnvironment.getTestEnvironment().getExpectedWork();
+        if (expectedWork != null) {
+            try {
+                if (TestEnvironment.getTestEnvironment().awaitDoWork()) {
+                    TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+                            permCheckWrite, null, "Spent too long waiting to start executing work");
+                    return false;
+                }
+            } catch (InterruptedException e) {
+                TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+                        permCheckWrite, null, "Failed waiting for work: " + e);
+                return false;
+            }
+            JobWorkItem work;
+            int index = 0;
+            while ((work = params.dequeueWork()) != null) {
+                Log.i(TAG, "Received work #" + index + ": " + work.getIntent());
+                mReceivedWork.add(work.getIntent());
+
+                if (index < expectedWork.length) {
+                    TestWorkItem expected = expectedWork[index];
+                    int grantFlags = work.getIntent().getFlags();
+                    if (expected.requireUrisGranted != null) {
+                        for (int ui = 0; ui < expected.requireUrisGranted.length; ui++) {
+                            if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+                                if (checkUriPermission(expected.requireUrisGranted[ui],
+                                        Process.myPid(), Process.myUid(),
+                                        Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                                        != PackageManager.PERMISSION_GRANTED) {
+                                    TestEnvironment.getTestEnvironment().notifyExecution(params,
+                                            permCheckRead, permCheckWrite, null,
+                                            "Expected read permission but not granted: "
+                                                    + expected.requireUrisGranted[ui]
+                                                    + " @ #" + index);
+                                    return false;
+                                }
+                            }
+                            if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+                                if (checkUriPermission(expected.requireUrisGranted[ui],
+                                        Process.myPid(), Process.myUid(),
+                                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+                                        != PackageManager.PERMISSION_GRANTED) {
+                                    TestEnvironment.getTestEnvironment().notifyExecution(params,
+                                            permCheckRead, permCheckWrite, null,
+                                            "Expected write permission but not granted: "
+                                                    + expected.requireUrisGranted[ui]
+                                                    + " @ #" + index);
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                    if (expected.requireUrisNotGranted != null) {
+                        // XXX note no delay here, current impl will have fully revoked the
+                        // permission by the time we return from completing the last work.
+                        for (int ui = 0; ui < expected.requireUrisNotGranted.length; ui++) {
+                            if ((grantFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+                                if (checkUriPermission(expected.requireUrisNotGranted[ui],
+                                        Process.myPid(), Process.myUid(),
+                                        Intent.FLAG_GRANT_READ_URI_PERMISSION)
+                                        != PackageManager.PERMISSION_DENIED) {
+                                    TestEnvironment.getTestEnvironment().notifyExecution(params,
+                                            permCheckRead, permCheckWrite, null,
+                                            "Not expected read permission but granted: "
+                                                    + expected.requireUrisNotGranted[ui]
+                                                    + " @ #" + index);
+                                    return false;
+                                }
+                            }
+                            if ((grantFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+                                if (checkUriPermission(expected.requireUrisNotGranted[ui],
+                                        Process.myPid(), Process.myUid(),
+                                        Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
+                                        != PackageManager.PERMISSION_DENIED) {
+                                    TestEnvironment.getTestEnvironment().notifyExecution(params,
+                                            permCheckRead, permCheckWrite, null,
+                                            "Not expected write permission but granted: "
+                                                    + expected.requireUrisNotGranted[ui]
+                                                    + " @ #" + index);
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                params.completeWork(work);
+
+                if (index < expectedWork.length) {
+                    TestWorkItem expected = expectedWork[index];
+                    if (expected.subitems != null) {
+                        final TestWorkItem[] sub = expected.subitems;
+                        final JobInfo ji = expected.jobInfo;
+                        final JobScheduler js = (JobScheduler) getSystemService(
+                                Context.JOB_SCHEDULER_SERVICE);
+                        for (int subi = 0; subi < sub.length; subi++) {
+                            js.enqueue(ji, new JobWorkItem(sub[subi].intent));
+                        }
+                    }
+                }
+
+                index++;
+            }
+            Log.i(TAG, "Done with all work at #" + index);
+            // We don't notifyExecution here because we want to make sure the job properly
+            // stops itself.
+            return true;
+        } else {
+            TestEnvironment.getTestEnvironment().notifyExecution(params, permCheckRead,
+                    permCheckWrite, null, null);
+            return false;  // No work to do.
+        }
     }
 
     @Override
@@ -69,6 +201,39 @@
         return false;
     }
 
+    public static final class TestWorkItem {
+        public final Intent intent;
+        public final JobInfo jobInfo;
+        public final TestWorkItem[] subitems;
+        public final Uri[] requireUrisGranted;
+        public final Uri[] requireUrisNotGranted;
+
+        public TestWorkItem(Intent _intent) {
+            intent = _intent;
+            jobInfo = null;
+            subitems = null;
+            requireUrisGranted = null;
+            requireUrisNotGranted = null;
+        }
+
+        public TestWorkItem(Intent _intent, JobInfo _jobInfo, TestWorkItem[] _subitems) {
+            intent = _intent;
+            jobInfo = _jobInfo;
+            subitems = _subitems;
+            requireUrisGranted = null;
+            requireUrisNotGranted = null;
+        }
+
+        public TestWorkItem(Intent _intent, Uri[] _requireUrisGranted,
+                Uri[] _requireUrisNotGranted) {
+            intent = _intent;
+            jobInfo = null;
+            subitems = null;
+            requireUrisGranted = _requireUrisGranted;
+            requireUrisNotGranted = _requireUrisNotGranted;
+        }
+    }
+
     /**
      * Configures the expected behaviour for each test. This object is shared across consecutive
      * tests, so to clear state each test is responsible for calling
@@ -80,9 +245,13 @@
         //public static final int INVALID_JOB_ID = -1;
 
         private CountDownLatch mLatch;
+        private CountDownLatch mDoWorkLatch;
+        private TestWorkItem[] mExpectedWork;
         private JobParameters mExecutedJobParameters;
         private int mExecutedPermCheckRead;
         private int mExecutedPermCheckWrite;
+        private ArrayList<Intent> mExecutedReceivedWork;
+        private String mExecutedErrorMessage;
 
         public static TestEnvironment getTestEnvironment() {
             if (kTestEnvironment == null) {
@@ -91,6 +260,10 @@
             return kTestEnvironment;
         }
 
+        public TestWorkItem[] getExpectedWork() {
+            return mExpectedWork;
+        }
+
         public JobParameters getLastJobParameters() {
             return mExecutedJobParameters;
         }
@@ -103,12 +276,23 @@
             return mExecutedPermCheckWrite;
         }
 
+        public ArrayList<Intent> getLastReceivedWork() {
+            return mExecutedReceivedWork;
+        }
+
+        public String getLastErrorMessage() {
+            return mExecutedErrorMessage;
+        }
+
         /**
          * Block the test thread, waiting on the JobScheduler to execute some previously scheduled
          * job on this service.
          */
         public boolean awaitExecution() throws InterruptedException {
             final boolean executed = mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+            if (getLastErrorMessage() != null) {
+                Assert.fail(getLastErrorMessage());
+            }
             return executed;
         }
 
@@ -121,11 +305,18 @@
             return !mLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
         }
 
-        private void notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite) {
+        public boolean awaitDoWork() throws InterruptedException {
+            return !mDoWorkLatch.await(DEFAULT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
+        }
+
+        private void notifyExecution(JobParameters params, int permCheckRead, int permCheckWrite,
+                ArrayList<Intent> receivedWork, String errorMsg) {
             //Log.d(TAG, "Job executed:" + params.getJobId());
             mExecutedJobParameters = params;
             mExecutedPermCheckRead = permCheckRead;
             mExecutedPermCheckWrite = permCheckWrite;
+            mExecutedReceivedWork = receivedWork;
+            mExecutedErrorMessage = errorMsg;
             mLatch.countDown();
         }
 
@@ -138,6 +329,15 @@
             }
         }
 
+        public void setExpectedWork(TestWorkItem[] work) {
+            mExpectedWork = work;
+            mDoWorkLatch = new CountDownLatch(1);
+        }
+
+        public void readyToWork() {
+            mDoWorkLatch.countDown();
+        }
+
         /** Called in each testCase#setup */
         public void setUp() {
             mLatch = null;
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
index be3f9c9..5ffa347 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
@@ -54,8 +54,6 @@
 
         mBuilder = new JobInfo.Builder(BATTERY_JOB_ID, kJobServiceComponent);
         SystemUtil.runShellCommand(getInstrumentation(), "cmd jobscheduler monitor-battery on");
-        String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
-                + mContext.getPackageName() + " false");
     }
 
     @Override
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
index 9a8b642..03d941e 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ClipDataJobTest.java
@@ -19,16 +19,10 @@
 
 import android.annotation.TargetApi;
 import android.app.job.JobInfo;
-import android.content.ClipData;
 import android.content.ContentProviderClient;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.net.Uri;
-import android.os.Bundle;
 import android.os.Process;
-import android.os.SystemClock;
-
-import com.android.compatibility.common.util.SystemUtil;
 
 /**
  * Schedules jobs with the {@link android.app.job.JobScheduler} that grant permissions through
@@ -41,16 +35,7 @@
     /** Unique identifier for the job scheduled by this suite of tests. */
     public static final int CLIP_DATA_JOB_ID = ClipDataJobTest.class.hashCode();
 
-    static final String MY_PACKAGE = "android.jobscheduler.cts";
-
-    static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
-    static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
-    static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
-
-    private JobInfo.Builder mBuilder;
-    private Uri mFirstUri;
-    private Bundle mFirstUriBundle;
-    private ClipData mClipData;
+    JobInfo.Builder mBuilder;
     private ContentProviderClient mProvider;
 
     @Override
@@ -58,62 +43,15 @@
         super.setUp();
 
         mBuilder = new JobInfo.Builder(CLIP_DATA_JOB_ID, kJobServiceComponent);
-        mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
-        mFirstUriBundle = new Bundle();
-        mFirstUriBundle.putParcelable("uri", mFirstUri);
-        mClipData = new ClipData("JobPerm", new String[] { "application/*" },
-                new ClipData.Item(mFirstUri));
         mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
-        String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
-                + mContext.getPackageName() + " false");
+        assertNotNull(mProvider);
     }
 
     @Override
     public void tearDown() throws Exception {
+        super.tearDown();
         mProvider.close();
         mJobScheduler.cancel(CLIP_DATA_JOB_ID);
-        // Put storage service back in to normal operation.
-        SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
-    }
-
-    // Note we are just using storage state as a way to control when the job gets executed.
-    void setStorageState(boolean low) throws Exception {
-        String res;
-        if (low) {
-            res = SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd devicestoragemonitor force-low -f");
-        } else {
-            res = SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd devicestoragemonitor force-not-low -f");
-        }
-        int seq = Integer.parseInt(res.trim());
-        long startTime = SystemClock.elapsedRealtime();
-
-        // Wait for the storage update to be processed by job scheduler before proceeding.
-        int curSeq;
-        do {
-            curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd jobscheduler get-storage-seq").trim());
-            if (curSeq == seq) {
-                return;
-            }
-        } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
-
-        fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
-    }
-
-    void waitPermissionRevoke(Uri uri, int access, long timeout) {
-        long startTime = SystemClock.elapsedRealtime();
-        while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
-                 != PackageManager.PERMISSION_GRANTED) {
-            try {
-                Thread.sleep(50);
-            } catch (InterruptedException e) {
-            }
-            if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
-                fail("Timed out waiting for permission revoke");
-            }
-        }
     }
 
     /**
@@ -135,7 +73,7 @@
         // Schedule the job, the system should now also be holding a URI grant for us.
         kTestEnvironment.setExpectedExecutions(1);
         mJobScheduler.schedule(mBuilder.setRequiresStorageNotLow(true)
-                .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
                         | Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
 
         // Remove the explicit grant, we should still have a grant due to the job.
@@ -167,7 +105,7 @@
     public void testClipDataGrant_Failed() throws Exception {
         try {
             mJobScheduler.schedule(mBuilder.setRequiresStorageNotLow(true)
-                    .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                    .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
                             | Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
         } catch (SecurityException e) {
             return;
@@ -193,7 +131,7 @@
         // Schedule the job, the system should now also be holding a URI grant for us.
         kTestEnvironment.setExpectedExecutions(1);
         mJobScheduler.schedule(mBuilder.setMinimumLatency(60*60*1000)
-                .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
                         | Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
 
         // Remove the explicit grant, we should still have a grant due to the job.
@@ -207,7 +145,7 @@
 
         // Now reschedule the job to have it happen right now.
         mJobScheduler.schedule(mBuilder.setMinimumLatency(0)
-                .setClipData(mClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                .setClipData(mFirstClipData, Intent.FLAG_GRANT_READ_URI_PERMISSION
                         | Intent.FLAG_GRANT_WRITE_URI_PERMISSION).build());
         assertTrue("Job with storage not low constraint did not fire when storage not low.",
                 kTestEnvironment.awaitExecution());
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index a7c7003..0a3ff9c 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -163,6 +163,27 @@
                 kTestEnvironment.awaitExecution());
     }
 
+    /**
+     * Schedule a job with a metered connectivity constraint, and ensure that it executes
+     * on on a mobile data connection.
+     */
+    public void testConnectivityConstraintExecutes_metered() throws Exception {
+        if (!checkDeviceSupportsMobileData()) {
+            return;
+        }
+        disconnectWifiToConnectToMobile();
+
+        kTestEnvironment.setExpectedExecutions(1);
+        mJobScheduler.schedule(
+                mBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_METERED)
+                        .build());
+
+        sendExpediteStableChargingBroadcast();
+
+        assertTrue("Job with metered connectivity constraint did not fire on mobile.",
+                kTestEnvironment.awaitExecution());
+    }
+
     // --------------------------------------------------------------------------------------------
     // Negatives - schedule jobs under conditions that require that they fail.
     // --------------------------------------------------------------------------------------------
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
index b2cf29c..bcc1e08 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConstraintTest.java
@@ -18,13 +18,23 @@
 import android.annotation.TargetApi;
 import android.app.Instrumentation;
 import android.app.job.JobScheduler;
+import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.jobscheduler.MockJobService;
 import android.jobscheduler.TriggerContentJobService;
-import android.test.AndroidTestCase;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Process;
+import android.os.SystemClock;
 import android.test.InstrumentationTestCase;
+import android.util.Log;
+
+import com.android.compatibility.common.util.SystemUtil;
+
+import java.io.IOException;
 
 /**
  * Common functionality from which the other test case classes derive.
@@ -47,10 +57,45 @@
 
     Context mContext;
 
+    static final String MY_PACKAGE = "android.jobscheduler.cts";
+
+    static final String JOBPERM_PACKAGE = "android.jobscheduler.cts.jobperm";
+    static final String JOBPERM_AUTHORITY = "android.jobscheduler.cts.jobperm.provider";
+    static final String JOBPERM_PERM = "android.jobscheduler.cts.jobperm.perm";
+
+    Uri mFirstUri;
+    Bundle mFirstUriBundle;
+    Uri mSecondUri;
+    Bundle mSecondUriBundle;
+    ClipData mFirstClipData;
+    ClipData mSecondClipData;
+
+    boolean mStorageStateChanged;
+
     @Override
     public void injectInstrumentation(Instrumentation instrumentation) {
         super.injectInstrumentation(instrumentation);
         mContext = instrumentation.getContext();
+        kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
+        kTriggerContentServiceComponent = new ComponentName(getContext(),
+                TriggerContentJobService.class);
+        mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
+        mFirstUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/foo");
+        mFirstUriBundle = new Bundle();
+        mFirstUriBundle.putParcelable("uri", mFirstUri);
+        mSecondUri = Uri.parse("content://" + JOBPERM_AUTHORITY + "/protected/bar");
+        mSecondUriBundle = new Bundle();
+        mSecondUriBundle.putParcelable("uri", mSecondUri);
+        mFirstClipData = new ClipData("JobPerm1", new String[] { "application/*" },
+                new ClipData.Item(mFirstUri));
+        mSecondClipData = new ClipData("JobPerm2", new String[] { "application/*" },
+                new ClipData.Item(mSecondUri));
+        try {
+            SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
+                    + mContext.getPackageName() + " false");
+        } catch (IOException e) {
+            Log.w("ConstraintTest", "Failed setting inactive false", e);
+        }
     }
 
     public Context getContext() {
@@ -62,13 +107,18 @@
         super.setUp();
         kTestEnvironment.setUp();
         kTriggerTestEnvironment.setUp();
-        kJobServiceComponent = new ComponentName(getContext(), MockJobService.class);
-        kTriggerContentServiceComponent = new ComponentName(getContext(),
-                TriggerContentJobService.class);
-        mJobScheduler = (JobScheduler) getContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
         mJobScheduler.cancelAll();
     }
 
+    @Override
+    public void tearDown() throws Exception {
+        if (mStorageStateChanged) {
+            // Put storage service back in to normal operation.
+            SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
+            mStorageStateChanged = false;
+        }
+    }
+
     /**
      * The scheduler will usually only flush its queue of unexpired jobs when the device is
      * considered to be on stable power - that is, plugged in for a period of 2 minutes.
@@ -77,4 +127,58 @@
     protected void sendExpediteStableChargingBroadcast() {
         getContext().sendBroadcast(EXPEDITE_STABLE_CHARGING);
     }
+
+    public void assertHasUriPermission(Uri uri, int grantFlags) {
+        if ((grantFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+            assertEquals(PackageManager.PERMISSION_GRANTED,
+                    getContext().checkUriPermission(uri, Process.myPid(),
+                            Process.myUid(), Intent.FLAG_GRANT_READ_URI_PERMISSION));
+        }
+        if ((grantFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+            assertEquals(PackageManager.PERMISSION_GRANTED,
+                    getContext().checkUriPermission(uri, Process.myPid(),
+                            Process.myUid(), Intent.FLAG_GRANT_WRITE_URI_PERMISSION));
+        }
+    }
+
+    void waitPermissionRevoke(Uri uri, int access, long timeout) {
+        long startTime = SystemClock.elapsedRealtime();
+        while (getContext().checkUriPermission(uri, Process.myPid(), Process.myUid(), access)
+                != PackageManager.PERMISSION_DENIED) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+            }
+            if ((SystemClock.elapsedRealtime()-startTime) >= timeout) {
+                fail("Timed out waiting for permission revoke");
+            }
+        }
+    }
+
+    // Note we are just using storage state as a way to control when the job gets executed.
+    void setStorageState(boolean low) throws Exception {
+        mStorageStateChanged = true;
+        String res;
+        if (low) {
+            res = SystemUtil.runShellCommand(getInstrumentation(),
+                    "cmd devicestoragemonitor force-low -f");
+        } else {
+            res = SystemUtil.runShellCommand(getInstrumentation(),
+                    "cmd devicestoragemonitor force-not-low -f");
+        }
+        int seq = Integer.parseInt(res.trim());
+        long startTime = SystemClock.elapsedRealtime();
+
+        // Wait for the storage update to be processed by job scheduler before proceeding.
+        int curSeq;
+        do {
+            curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
+                    "cmd jobscheduler get-storage-seq").trim());
+            if (curSeq == seq) {
+                return;
+            }
+        } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
+
+        fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
+    }
 }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java
new file mode 100644
index 0000000..402233b
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/EnqueueJobWorkTest.java
@@ -0,0 +1,237 @@
+/*
+ * 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 android.jobscheduler.cts;
+
+import android.annotation.TargetApi;
+import android.app.job.JobInfo;
+import android.app.job.JobWorkItem;
+import android.content.ContentProviderClient;
+import android.content.Intent;
+import android.jobscheduler.MockJobService.TestWorkItem;
+import android.net.Uri;
+
+import java.util.ArrayList;
+
+/**
+ * Schedules jobs with the {@link android.app.job.JobScheduler} by enqueue work in to
+ * them and processing it.
+ */
+@TargetApi(26)
+public class EnqueueJobWorkTest extends ConstraintTest {
+    private static final String TAG = "ClipDataJobTest";
+
+    /** Unique identifier for the job scheduled by this suite of tests. */
+    public static final int ENQUEUE_WORK_JOB_ID = EnqueueJobWorkTest.class.hashCode();
+
+    private JobInfo.Builder mBuilder;
+    private ContentProviderClient mProvider;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        mBuilder = new JobInfo.Builder(ENQUEUE_WORK_JOB_ID, kJobServiceComponent);
+        mProvider = getContext().getContentResolver().acquireContentProviderClient(mFirstUri);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        super.tearDown();
+        mProvider.close();
+        mJobScheduler.cancel(ENQUEUE_WORK_JOB_ID);
+    }
+
+    private boolean intentEquals(Intent i1, Intent i2) {
+        if (i1 == i2) {
+            return true;
+        }
+        if (i1 == null || i2 == null) {
+            return false;
+        }
+        return i1.filterEquals(i2);
+    }
+
+    private void compareWork(TestWorkItem[] expected, ArrayList<Intent> received) {
+        if (received == null) {
+            fail("Didn't receive any expected work.");
+        }
+        ArrayList<TestWorkItem> expectedArray = new ArrayList<>();
+        for (int i = 0; i < expected.length; i++) {
+            expectedArray.add(expected[i]);
+        }
+        for (int i = 0; i < received.size(); i++) {
+            Intent work = received.get(i);
+            if (i < expected.length && expected[i].subitems != null) {
+                TestWorkItem[] sub = expected[i].subitems;
+                for (int j = 0; j < sub.length; j++) {
+                    expectedArray.add(sub[j]);
+                }
+            }
+            if (i >= expectedArray.size()) {
+                fail("Received more than " + expected.length + " work items, first extra is "
+                        + work);
+            }
+            if (!intentEquals(work, expectedArray.get(i).intent)) {
+                fail("Received work #" + i + " " + work + " but expected " + expected[i]);
+            }
+        }
+        if (received.size() < expected.length) {
+            fail("Received only " + received.size() + " work items, but expected "
+                            + expected.length);
+        }
+    }
+
+    /**
+     * Test basic enqueueing of work.
+     */
+    public void testEnqueueOneWork() throws Exception {
+        Intent work1 = new Intent("work1");
+        TestWorkItem[] work = new TestWorkItem[] { new TestWorkItem(work1) };
+        kTestEnvironment.setExpectedExecutions(1);
+        kTestEnvironment.setExpectedWork(work);
+        mJobScheduler.enqueue(mBuilder.setOverrideDeadline(0).build(), new JobWorkItem(work1));
+        kTestEnvironment.readyToWork();
+        assertTrue("Job with work enqueued did not fire.",
+                kTestEnvironment.awaitExecution());
+        compareWork(work, kTestEnvironment.getLastReceivedWork());
+        if (kTestEnvironment.getLastErrorMessage() != null) {
+            fail(kTestEnvironment.getLastErrorMessage());
+        }
+    }
+
+    /**
+     * Test basic enqueueing batches of work.
+     */
+    public void testEnqueueMultipleWork() throws Exception {
+        Intent work1 = new Intent("work1");
+        Intent work2 = new Intent("work2");
+        Intent work3 = new Intent("work3");
+        Intent work4 = new Intent("work4");
+        Intent work5 = new Intent("work5");
+        Intent work6 = new Intent("work6");
+        Intent work7 = new Intent("work7");
+        Intent work8 = new Intent("work8");
+        TestWorkItem[] work = new TestWorkItem[] {
+                new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
+                new TestWorkItem(work4), new TestWorkItem(work5), new TestWorkItem(work6),
+                new TestWorkItem(work7), new TestWorkItem(work8) };
+        kTestEnvironment.setExpectedExecutions(1);
+        kTestEnvironment.setExpectedWork(work);
+        JobInfo ji = mBuilder.setOverrideDeadline(0).build();
+        mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work3));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work4));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work5));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work6));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work7));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work8));
+        kTestEnvironment.readyToWork();
+        assertTrue("Job with work enqueued did not fire.",
+                kTestEnvironment.awaitExecution());
+        compareWork(work, kTestEnvironment.getLastReceivedWork());
+    }
+
+    /**
+     * Test basic enqueueing batches of work, with new work coming in while processing existing
+     * work.
+     */
+    public void testEnqueueMultipleSubWork() throws Exception {
+        Intent work1 = new Intent("work1");
+        Intent work2 = new Intent("work2");
+        Intent work3 = new Intent("work3");
+        Intent work4 = new Intent("work4");
+        Intent work5 = new Intent("work5");
+        Intent work6 = new Intent("work6");
+        Intent work7 = new Intent("work7");
+        Intent work8 = new Intent("work8");
+        JobInfo ji = mBuilder.setOverrideDeadline(0).build();
+        TestWorkItem[] work = new TestWorkItem[]{
+                new TestWorkItem(work1), new TestWorkItem(work2), new TestWorkItem(work3),
+                new TestWorkItem(work4, ji, new TestWorkItem[] {
+                        new TestWorkItem(work5), new TestWorkItem(work6),
+                        new TestWorkItem(work7), new TestWorkItem(work8)})
+        };
+        kTestEnvironment.setExpectedExecutions(1);
+        kTestEnvironment.setExpectedWork(work);
+        mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work3));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work4));
+        kTestEnvironment.readyToWork();
+        assertTrue("Job with work enqueued did not fire.",
+                kTestEnvironment.awaitExecution());
+        compareWork(work, kTestEnvironment.getLastReceivedWork());
+    }
+
+    /**
+     * Test basic enqueueing batches of work.
+     */
+    public void testEnqueueMultipleUriGrantWork() throws Exception {
+        // Start out with storage low, so job is enqueued but not executed yet.
+        setStorageState(true);
+
+        // We need to get a permission grant so that we can grant it to ourself.
+        mProvider.call("grant", MY_PACKAGE, mFirstUriBundle);
+        mProvider.call("grant", MY_PACKAGE, mSecondUriBundle);
+        assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+        Intent work1 = new Intent("work1");
+        work1.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        work1.setData(mFirstUri);
+        work1.setClipData(mSecondClipData);
+
+        Intent work2 = new Intent("work2");
+        work2.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        work2.setData(mFirstUri);
+
+        TestWorkItem[] work = new TestWorkItem[] {
+                new TestWorkItem(work1, new Uri[] { mFirstUri, mSecondUri}, new Uri[0]),
+                new TestWorkItem(work2, new Uri[] { mFirstUri }, new Uri[] { mSecondUri}) };
+        kTestEnvironment.setExpectedExecutions(1);
+        kTestEnvironment.setExpectedWork(work);
+        JobInfo ji = mBuilder.setOverrideDeadline(0).setRequiresStorageNotLow(true).build();
+        mJobScheduler.enqueue(ji, new JobWorkItem(work1));
+        mJobScheduler.enqueue(ji, new JobWorkItem(work2));
+
+        // Remove the explicit grant, we should still have a grant due to the job.
+        mProvider.call("revoke", MY_PACKAGE, mFirstUriBundle);
+        mProvider.call("revoke", MY_PACKAGE, mSecondUriBundle);
+        assertHasUriPermission(mFirstUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+        assertHasUriPermission(mSecondUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+        kTestEnvironment.readyToWork();
+
+        // Now allow the job to run.
+        setStorageState(false);
+
+        assertTrue("Job with work enqueued did not fire.",
+                kTestEnvironment.awaitExecution());
+        compareWork(work, kTestEnvironment.getLastReceivedWork());
+
+        // And wait for everything to be cleaned up.
+        waitPermissionRevoke(mFirstUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
+        waitPermissionRevoke(mSecondUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 5000);
+    }
+}
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
index f40dd66..aea4d84 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/StorageConstraintTest.java
@@ -40,40 +40,12 @@
         super.setUp();
 
         mBuilder = new JobInfo.Builder(STORAGE_JOB_ID, kJobServiceComponent);
-        String res = SystemUtil.runShellCommand(getInstrumentation(), "cmd activity set-inactive "
-                + mContext.getPackageName() + " false");
     }
 
     @Override
     public void tearDown() throws Exception {
+        super.tearDown();
         mJobScheduler.cancel(STORAGE_JOB_ID);
-        // Put storage service back in to normal operation.
-        SystemUtil.runShellCommand(getInstrumentation(), "cmd devicestoragemonitor reset");
-    }
-
-    void setStorageState(boolean low) throws Exception {
-        String res;
-        if (low) {
-            res = SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd devicestoragemonitor force-low -f");
-        } else {
-            res = SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd devicestoragemonitor force-not-low -f");
-        }
-        int seq = Integer.parseInt(res.trim());
-        long startTime = SystemClock.elapsedRealtime();
-
-        // Wait for the storage update to be processed by job scheduler before proceeding.
-        int curSeq;
-        do {
-            curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
-                    "cmd jobscheduler get-storage-seq").trim());
-            if (curSeq == seq) {
-                return;
-            }
-        } while ((SystemClock.elapsedRealtime()-startTime) < 1000);
-
-        fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq);
     }
 
     // --------------------------------------------------------------------------------------------
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
index 8b71171..fe48950 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/TriggerContentTest.java
@@ -42,7 +42,7 @@
  */
 @TargetApi(23)
 public class TriggerContentTest extends ConstraintTest {
-    public static final int TRIGGER_CONTENT_JOB_ID = ConnectivityConstraintTest.class.hashCode();
+    public static final int TRIGGER_CONTENT_JOB_ID = TriggerContentTest.class.hashCode();
 
     // The root URI of the media provider, to monitor for generic changes to its content.
     static final Uri MEDIA_URI = Uri.parse("content://" + MediaStore.AUTHORITY + "/");
@@ -120,7 +120,7 @@
     }
 
     @Override
-    protected void tearDown() throws Exception {
+    public void tearDown() throws Exception {
         super.tearDown();
         for (int i=0; i<mActiveFiles.length; i++) {
             cleanupActive(i);
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1185813..c081df9 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -23,7 +23,6 @@
 import android.test.InstrumentationTestCase;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
 
@@ -57,7 +56,6 @@
         mAccessibilityManager = (AccessibilityManager)
                 getInstrumentation().getContext().getSystemService(Service.ACCESSIBILITY_SERVICE);
         mTargetContext = getInstrumentation().getTargetContext();
-        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
     }
 
     @Override
@@ -83,16 +81,8 @@
         assertFalse(mAccessibilityManager.removeTouchExplorationStateChangeListener(listener));
     }
 
-    public void testAddAndRemoveServiceStateChangeListener() throws Exception {
-        AccessibilityServicesStateChangeListener listener = () -> {
-            // Do Nothing
-        };
-        assertTrue(mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener));
-        assertTrue(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
-        assertFalse(mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener));
-    }
-
     public void testIsTouchExplorationEnabled() throws Exception {
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         new PollingCheck() {
             @Override
             protected boolean check() {
@@ -125,6 +115,7 @@
     }
 
     public void testGetEnabledAccessibilityServiceList() throws Exception {
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         List<AccessibilityServiceInfo> enabledServices =
             mAccessibilityManager.getEnabledAccessibilityServiceList(
                     AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
@@ -148,6 +139,7 @@
     }
 
     public void testGetEnabledAccessibilityServiceListForType() throws Exception {
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         List<AccessibilityServiceInfo> enabledServices =
             mAccessibilityManager.getEnabledAccessibilityServiceList(
                     AccessibilityServiceInfo.FEEDBACK_SPOKEN);
@@ -165,6 +157,7 @@
     }
 
     public void testGetEnabledAccessibilityServiceListForTypes() throws Exception {
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         // For this test, also enable a service with multiple feedback types
         ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
 
@@ -224,6 +217,7 @@
     public void testInterrupt() throws Exception {
         // The APIs are heavily tested in the android.accessibilityservice package.
         // This just makes sure the call does not throw an exception.
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         waitForAccessibilityEnabled();
         mAccessibilityManager.interrupt();
     }
@@ -231,62 +225,71 @@
     public void testSendAccessibilityEvent() throws Exception {
         // The APIs are heavily tested in the android.accessibilityservice package.
         // This just makes sure the call does not throw an exception.
+        ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
         waitForAccessibilityEnabled();
         mAccessibilityManager.sendAccessibilityEvent(AccessibilityEvent.obtain(
                 AccessibilityEvent.TYPE_VIEW_CLICKED));
     }
 
-    public void testTouchExplorationStateChanged() throws Exception {
-        waitForTouchExplorationEnabled();
-    }
-
-    public void testServiceStateChanges_stateChangeListenersCalled() throws Exception {
+    public void testTouchExplorationListener() throws Exception {
         final Object waitObject = new Object();
-        final AtomicBoolean listenerCalled = new AtomicBoolean(false);
-        final SpeakingAccessibilityService service =
-                SpeakingAccessibilityService.sConnectedInstance;
-        final AccessibilityServicesStateChangeListener listener = () -> {
+        final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+        TouchExplorationStateChangeListener listener = (boolean b) -> {
             synchronized (waitObject) {
-                listenerCalled.set(true);
+                atomicBoolean.set(b);
                 waitObject.notifyAll();
             }
         };
-
-        mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
-        // Verify called on info change
-        final AccessibilityServiceInfo initialInfo = service.getServiceInfo();
-        AccessibilityServiceInfo tempInfo = service.getServiceInfo();
-        tempInfo.flags ^= AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
-        try {
-            service.setServiceInfo(tempInfo);
-            assertListenerCalled(listenerCalled, waitObject);
-        } finally {
-            service.setServiceInfo(initialInfo);
-        }
-
-        // Verify called on service disabled
-        listenerCalled.set(false);
-        ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
-        assertListenerCalled(listenerCalled, waitObject);
-
-        // Verify called on service enabled
-        listenerCalled.set(false);
+        mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
         ServiceControlUtils.enableSpeakingAndVibratingServices(getInstrumentation());
-        assertListenerCalled(listenerCalled, waitObject);
-
-        mAccessibilityManager.removeAccessibilityServicesStateChangeListener(listener);
-
+        assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+                "Touch exploration state listener not called when services enabled");
+        assertTrue("Listener told that touch exploration is enabled, but manager says disabled",
+                mAccessibilityManager.isTouchExplorationEnabled());
+        ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+        assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+                "Touch exploration state listener not called when services disabled");
+        assertFalse("Listener told that touch exploration is disabled, but manager says it enabled",
+                mAccessibilityManager.isTouchExplorationEnabled());
+        mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
     }
 
-    private void assertListenerCalled(AtomicBoolean listenerCalled, Object waitObject)
+    public void testAccessibilityStateListener() throws Exception {
+        final Object waitObject = new Object();
+        final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
+
+        AccessibilityStateChangeListener listener = (boolean b) -> {
+            synchronized (waitObject) {
+                atomicBoolean.set(b);
+                waitObject.notifyAll();
+            }
+        };
+        mAccessibilityManager.addAccessibilityStateChangeListener(listener);
+        ServiceControlUtils.enableMultipleFeedbackTypesService(getInstrumentation());
+        assertAtomicBooleanBecomes(atomicBoolean, true, waitObject,
+                "Accessibility state listener not called when services enabled");
+        assertTrue("Listener told that accessibility is enabled, but manager says disabled",
+                mAccessibilityManager.isEnabled());
+        ServiceControlUtils.turnAccessibilityOff(getInstrumentation());
+        assertAtomicBooleanBecomes(atomicBoolean, false, waitObject,
+                "Accessibility state listener not called when services disabled");
+        assertFalse("Listener told that accessibility is disabled, but manager says enabled",
+                mAccessibilityManager.isEnabled());
+        mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
+    }
+
+    private void assertAtomicBooleanBecomes(AtomicBoolean atomicBoolean,
+            boolean expectedValue, Object waitObject, String message)
             throws Exception {
         long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
         synchronized (waitObject) {
-            while (!listenerCalled.get() && (System.currentTimeMillis() < timeoutTime)) {
+            while ((atomicBoolean.get() != expectedValue)
+                    && (System.currentTimeMillis() < timeoutTime)) {
                 waitObject.wait(timeoutTime - System.currentTimeMillis());
             }
         }
-        assertTrue("Timed out waiting for listener called", listenerCalled.get());
+        assertTrue(message, atomicBoolean.get() == expectedValue);
     }
 
     private void waitForAccessibilityEnabled() throws InterruptedException {
@@ -295,7 +298,7 @@
         AccessibilityStateChangeListener listener = (boolean b) -> {
             synchronized (waitObject) {
                 waitObject.notifyAll();
-                }
+            }
         };
         mAccessibilityManager.addAccessibilityStateChangeListener(listener);
         long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
@@ -308,25 +311,4 @@
         mAccessibilityManager.removeAccessibilityStateChangeListener(listener);
         assertTrue("Timed out enabling accessibility", mAccessibilityManager.isEnabled());
     }
-
-    private void waitForTouchExplorationEnabled() throws InterruptedException {
-        final Object waitObject = new Object();
-
-        TouchExplorationStateChangeListener listener = (boolean b) -> {
-            synchronized (waitObject) {
-                waitObject.notifyAll();
-            }
-        };
-        mAccessibilityManager.addTouchExplorationStateChangeListener(listener);
-        long timeoutTime = System.currentTimeMillis() + WAIT_FOR_ACCESSIBILITY_ENABLED_TIMEOUT;
-        synchronized (waitObject) {
-            while (!mAccessibilityManager.isTouchExplorationEnabled()
-                    && (System.currentTimeMillis() < timeoutTime)) {
-                waitObject.wait(timeoutTime - System.currentTimeMillis());
-            }
-        }
-        mAccessibilityManager.removeTouchExplorationStateChangeListener(listener);
-        assertTrue("Timed out enabling touch exploration",
-                mAccessibilityManager.isTouchExplorationEnabled());
-    }
 }
diff --git a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
index 9c4d9da..9783cb8 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/ServiceControlUtils.java
@@ -165,10 +165,14 @@
      * @param instrumentation A valid instrumentation
      */
     public static void turnAccessibilityOff(Instrumentation instrumentation) {
-        SpeakingAccessibilityService.sConnectedInstance.disableSelf();
-        SpeakingAccessibilityService.sConnectedInstance = null;
-        VibratingAccessibilityService.sConnectedInstance.disableSelf();
-        VibratingAccessibilityService.sConnectedInstance = null;
+        if (SpeakingAccessibilityService.sConnectedInstance != null) {
+            SpeakingAccessibilityService.sConnectedInstance.disableSelf();
+            SpeakingAccessibilityService.sConnectedInstance = null;
+        }
+        if (VibratingAccessibilityService.sConnectedInstance != null) {
+            VibratingAccessibilityService.sConnectedInstance.disableSelf();
+            VibratingAccessibilityService.sConnectedInstance = null;
+        }
         if (SpeakingAndVibratingAccessibilityService.sConnectedInstance != null) {
             SpeakingAndVibratingAccessibilityService.sConnectedInstance.disableSelf();
             SpeakingAndVibratingAccessibilityService.sConnectedInstance = null;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
index 23650a6..0f8b9c0 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTextActionTest.java
@@ -289,6 +289,8 @@
         final AccessibilityNodeInfo text = mUiAutomation.getRootInActiveWindow()
                 .findAccessibilityNodeInfosByText(getString(stringId)).get(0);
         CharSequence accessibilityTextWithSpan = text.getText();
+        // The span should work even with the node recycled
+        text.recycle();
         assertTrue(accessibilityTextWithSpan instanceof Spanned);
 
         T spans[] = ((Spanned) accessibilityTextWithSpan)
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
index 2ed4b39..8f9c51c 100755
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowQueryTest.java
@@ -653,7 +653,7 @@
                 numPictureInPictureWindows++;
             }
         }
-        assertEquals(1, numPictureInPictureWindows);
+        assertTrue(numPictureInPictureWindows >= 1);
     }
 
     private boolean isDividerWindowPresent(UiAutomation uiAutomation) {
diff --git a/tests/app/app/src/android/app/stubs/LocalForegroundService.java b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
index e0051a4..d60a1df 100644
--- a/tests/app/app/src/android/app/stubs/LocalForegroundService.java
+++ b/tests/app/app/src/android/app/stubs/LocalForegroundService.java
@@ -45,9 +45,13 @@
     private int mNotificationId = 0;
 
     @Override
-    public void onStart(Intent intent, int startId) {
-        super.onStart(intent, startId);
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "service created: " + this + " in " + android.os.Process.myPid());
+    }
 
+    @Override
+    public void onStart(Intent intent, int startId) {
         NotificationManager notificationManager = getSystemService(NotificationManager.class);
         notificationManager.createNotificationChannel(new NotificationChannel(
                 NOTIFICATION_CHANNEL_ID, NOTIFICATION_CHANNEL_ID,
@@ -56,6 +60,8 @@
         Context context = getApplicationContext();
         int command = intent.getIntExtra(EXTRA_COMMAND, -1);
 
+        Log.d(TAG, "service start cmd " + command + ", intent " + intent);
+
         switch (command) {
             case COMMAND_START_FOREGROUND:
                 mNotificationId ++;
@@ -89,11 +95,15 @@
             default:
                 Log.e(TAG, "Unknown command: " + command);
         }
+
+        // Do parent's onStart at the end, so we don't race with the test code waiting for us to
+        // execute.
+        super.onStart(intent, startId);
     }
 
     @Override
     public void onDestroy() {
-        Log.d(TAG, "service destroyed");
+        Log.d(TAG, "service destroyed: " + this + " in " + android.os.Process.myPid());
         super.onDestroy();
     }
 
diff --git a/tests/app/src/android/app/cts/ActionBarTest.java b/tests/app/src/android/app/cts/ActionBarTest.java
index 351339b..8bfaa59 100644
--- a/tests/app/src/android/app/cts/ActionBarTest.java
+++ b/tests/app/src/android/app/cts/ActionBarTest.java
@@ -24,7 +24,6 @@
 import android.test.UiThreadTest;
 import android.view.KeyEvent;
 import android.view.Window;
-import org.junit.Assume;
 
 public class ActionBarTest extends ActivityInstrumentationTestCase2<ActionBarActivity> {
 
@@ -85,7 +84,9 @@
     }
 
     public void testOptionsMenuKey() {
-        Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+        if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            return;
+        }
         final boolean menuIsVisible[] = {false};
         mActivity.getActionBar().addOnMenuVisibilityListener(
                 isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index e3e7c53..f29ae1e 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -36,6 +36,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ConfigurationInfo;
+import android.content.res.Resources;
 import android.platform.test.annotations.RestrictedBuildTest;
 import android.test.InstrumentationTestCase;
 
@@ -398,6 +399,20 @@
         Thread.sleep(WAIT_TIME);
     }
 
+   /**
+    * Gets the value of com.android.internal.R.bool.config_noHomeScreen.
+    * @return true if no home screen is supported, false otherwise.
+    */
+   private boolean noHomeScreen() {
+       try {
+           return getInstrumentation().getContext().getResources().getBoolean(
+                   Resources.getSystem().getIdentifier("config_noHomeScreen", "bool", "android"));
+       } catch (Resources.NotFoundException e) {
+           // Assume there's a home screen.
+           return false;
+       }
+    }
+
     /**
      * Verify that the TimeTrackingAPI works properly when starting and ending an activity.
      */
@@ -429,10 +444,20 @@
         assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
         appEndReceiver.close();
 
-        // At this time the timerReceiver should not fire, even though the activity has shut down,
-        // because we are back to the home screen.
-        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
-        assertTrue(timeReceiver.mTimeUsed == 0);
+        if (!noHomeScreen()) {
+            // At this time the timerReceiver should not fire, even though the activity has shut
+            // down, because we are back to the home screen. Going to the home screen does not
+            // qualify as the user leaving the activity's flow. The time tracking is considered
+            // complete only when the user switches to another activity that is not part of the
+            // tracked flow.
+            assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+            assertTrue(timeReceiver.mTimeUsed == 0);
+        } else {
+            // With platforms that have no home screen, focus is returned to something else that is
+            // considered a completion of the tracked activity flow, and hence time tracking is
+            // triggered.
+            assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+        }
 
         // Issuing now another activity will trigger the timing information release.
         final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
@@ -525,9 +550,20 @@
         assertEquals(RESULT_PASS, appEndReceiver.waitForActivity());
         appEndReceiver.close();
 
-        // At this time the timerReceiver should not fire, even though the activity has shut down.
-        assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
-        assertTrue(timeReceiver.mTimeUsed == 0);
+        if (!noHomeScreen()) {
+            // At this time the timerReceiver should not fire, even though the activity has shut
+            // down, because we are back to the home screen. Going to the home screen does not
+            // qualify as the user leaving the activity's flow. The time tracking is considered
+            // complete only when the user switches to another activity that is not part of the
+            // tracked flow.
+            assertEquals(RESULT_TIMEOUT, timeReceiver.waitForActivity());
+            assertTrue(timeReceiver.mTimeUsed == 0);
+        } else {
+            // With platforms that have no home screen, focus is returned to something else that is
+            // considered a completion of the tracked activity flow, and hence time tracking is
+            // triggered.
+            assertEquals(RESULT_PASS, timeReceiver.waitForActivity());
+        }
 
         // Issue another activity so that the timing information gets released.
         final Intent dummyIntent = new Intent(context, MockApplicationActivity.class);
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/app/src/android/app/cts/ActivityOptionsTest.java
similarity index 61%
copy from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
copy to tests/app/src/android/app/cts/ActivityOptionsTest.java
index d599eba..eab44c5 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/app/src/android/app/cts/ActivityOptionsTest.java
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.cts.webkit.renderprocesscrash;
+package android.app.cts;
 
-import android.app.Activity;
+import android.app.ActivityOptions;
 import android.os.Bundle;
-import android.webkit.WebView;
+import android.test.AndroidTestCase;
 
-public class RenderProcessCrashActivity extends Activity {
+public class ActivityOptionsTest extends AndroidTestCase {
 
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        WebView webView = new WebView(this);
-        setContentView(webView);
-        webView.loadUrl("chrome://kill");
+    public void testActivityOptionsBundle_makeBasic() throws Throwable {
+        ActivityOptions options = ActivityOptions.makeBasic();
+        Bundle bundle = options.toBundle();
+
+        assertNotNull(bundle);
     }
 }
diff --git a/tests/app/src/android/app/cts/AlertWindowsTests.java b/tests/app/src/android/app/cts/AlertWindowsTests.java
index 6d76d3b..f7c8ff8 100644
--- a/tests/app/src/android/app/cts/AlertWindowsTests.java
+++ b/tests/app/src/android/app/cts/AlertWindowsTests.java
@@ -17,41 +17,48 @@
 package android.app.cts;
 
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_PERCEPTIBLE_DEPRECATED;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
 import static android.content.Context.BIND_ALLOW_OOM_MANAGEMENT;
 import static android.content.Context.BIND_AUTO_CREATE;
 import static android.content.Context.BIND_NOT_FOREGROUND;
+
 import static com.android.app2.AlertWindowService.MSG_ADD_ALERT_WINDOW;
 import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_ADDED;
 import static com.android.app2.AlertWindowService.MSG_ON_ALERT_WINDOW_REMOVED;
 import static com.android.app2.AlertWindowService.MSG_REMOVE_ALERT_WINDOW;
 import static com.android.app2.AlertWindowService.MSG_REMOVE_ALL_ALERT_WINDOWS;
 import static com.android.app2.AlertWindowService.NOTIFICATION_MESSENGER_EXTRA;
+
 import static org.junit.Assert.assertEquals;
 
-import android.platform.test.annotations.Presubmit;
-import com.android.app2.AlertWindowService;
-import com.android.compatibility.common.util.SystemUtil;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.runner.RunWith;
-import org.junit.Test;
-
 import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Messenger;
+import android.platform.test.annotations.Presubmit;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import com.android.app2.AlertWindowService;
+import com.android.compatibility.common.util.SystemUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Function;
+
 /**
  * Build: mmma -j32 cts/tests/app
  * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test CtsAppTestCases android.app.cts.AlertWindowsTests
@@ -61,12 +68,20 @@
 public class AlertWindowsTests {
 
     private static final String TAG = "AlertWindowsTests";
+
     private static final boolean DEBUG = false;
     private static final long WAIT_TIME_MS = 2 * 1000;
 
+    private static final String SDK25_PACKAGE_NAME = "com.android.appSdk25";
+
     private Messenger mService;
     private String mServicePackageName;
+    private int mServiceUid;
+
+    private PackageManager mPm;
+
     private ActivityManager mAm;
+    private ActivityManager mAm25; // ActivityManager created for an SDK 25 app context.
 
     private final Messenger mMessenger = new Messenger(new IncomingHandler(Looper.getMainLooper()));
     private final Object mAddedLock = new Object();
@@ -76,7 +91,12 @@
     public void setUp() throws Exception {
         if (DEBUG) Log.e(TAG, "setUp");
         final Context context = InstrumentationRegistry.getTargetContext();
+
+        mPm = context.getPackageManager();
+
         mAm = context.getSystemService(ActivityManager.class);
+        mAm25 = context.createPackageContext(SDK25_PACKAGE_NAME, 0)
+                .getSystemService(ActivityManager.class);
 
         final Intent intent = new Intent();
         intent.setClassName(AlertWindowService.class.getPackage().getName(),
@@ -107,27 +127,34 @@
     public void testAlertWindowOomAdj() throws Exception {
         setAlertWindowPermission(true /* allow */);
 
-        assertImportance(IMPORTANCE_PERCEPTIBLE);
+        assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
+        assertUidImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
+
         addAlertWindow();
         // Process importance should be increased to visible when the service has an alert window.
-        assertImportance(IMPORTANCE_VISIBLE);
+        assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
+
+        // TODO: Somehow getUidImportance still returns 230 (IMPORTANCE_PERCEPTIBLE) instead of
+        // IMPORTANCE_VISIBLE(200)
+        // assertUidImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
+
         addAlertWindow();
-        assertImportance(IMPORTANCE_VISIBLE);
+        assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
 
         setAlertWindowPermission(false /* allow */);
         // Process importance should no longer be visible since its alert windows are not allowed to
         // be visible.
-        assertImportance(IMPORTANCE_PERCEPTIBLE);
+        assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
         setAlertWindowPermission(true /* allow */);
         // They can show again so importance should be visible again.
-        assertImportance(IMPORTANCE_VISIBLE);
+        assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
 
         removeAlertWindow();
-        assertImportance(IMPORTANCE_VISIBLE);
+        assertPackageImportance(IMPORTANCE_VISIBLE, IMPORTANCE_VISIBLE);
         removeAlertWindow();
         // Process importance should no longer be visible when the service no longer as alert
         // windows.
-        assertImportance(IMPORTANCE_PERCEPTIBLE);
+        assertPackageImportance(IMPORTANCE_PERCEPTIBLE, IMPORTANCE_PERCEPTIBLE_DEPRECATED);
     }
 
     private void addAlertWindow() throws Exception {
@@ -152,7 +179,8 @@
         SystemUtil.runShellCommand(InstrumentationRegistry.getInstrumentation(), cmd);
     }
 
-    private void assertImportance(int expected) throws Exception {
+    private void assertImportance(Function<ActivityManager, Integer> apiCaller,
+            int expectedForO, int expectedForPreO) throws Exception {
         int retry = 3;
         int actual;
 
@@ -161,10 +189,29 @@
             // for changes in the uid importance. However, the way it is currently structured
             // doesn't really work for this use case right now...
             Thread.sleep(500);
-            actual = mAm.getPackageImportance(mServicePackageName);
-        } while (actual != expected && --retry > 0);
+            actual = apiCaller.apply(mAm);
+        } while (actual != expectedForO && --retry > 0);
 
-        assertEquals(expected, actual);
+        assertEquals(expectedForO, actual);
+
+        // Check the result for pre-O apps.
+        assertEquals(expectedForPreO, (int) apiCaller.apply(mAm25));
+    }
+
+    /**
+     * Make sure {@link ActivityManager#getPackageImportance} returns the expected value.
+     */
+    private void assertPackageImportance(int expectedForO, int expectedForPreO) throws Exception {
+        assertImportance(am -> am.getPackageImportance(mServicePackageName),
+                expectedForO, expectedForPreO);
+    }
+
+    /**
+     * Make sure {@link ActivityManager#getUidImportance(int)} returns the expected value.
+     */
+    private void assertUidImportance(int expectedForO, int expectedForPreO) throws Exception {
+        assertImportance(am -> am.getUidImportance(mServiceUid),
+                expectedForO, expectedForPreO);
     }
 
     private final ServiceConnection mConnection = new ServiceConnection() {
@@ -173,6 +220,11 @@
             if (DEBUG) Log.e(TAG, "onServiceConnected");
             mService = new Messenger(service);
             mServicePackageName = name.getPackageName();
+            try {
+                mServiceUid = mPm.getPackageUid(mServicePackageName, 0);
+            } catch (NameNotFoundException e) {
+                throw new RuntimeException("getPackageUid() failed.", e);
+            }
             synchronized (mConnection) {
                 notifyAll();
             }
@@ -183,6 +235,7 @@
             if (DEBUG) Log.e(TAG, "onServiceDisconnected");
             mService = null;
             mServicePackageName = null;
+            mServiceUid = 0;
         }
     };
 
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 74047be..70ec9cf 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -25,6 +25,7 @@
 import android.media.AudioAttributes;
 import android.net.Uri;
 import android.os.Parcel;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
 
 public class NotificationChannelTest extends AndroidTestCase {
@@ -52,7 +53,7 @@
         assertEquals(false, channel.shouldVibrate());
         assertEquals(null, channel.getVibrationPattern());
         assertEquals(IMPORTANCE_DEFAULT, channel.getImportance());
-        assertEquals(null, channel.getSound());
+        assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, channel.getSound());
         assertTrue(channel.canShowBadge());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes());
         assertEquals(null, channel.getGroup());
diff --git a/tests/app/src/android/app/cts/ServiceTest.java b/tests/app/src/android/app/cts/ServiceTest.java
index 0e7b308..5f8202d 100644
--- a/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/app/src/android/app/cts/ServiceTest.java
@@ -574,12 +574,14 @@
         boolean success = false;
         try {
             // Start service as foreground - it should show notification #1
+            Log.d(TAG, "Expecting first start state...");
             mExpectedServiceState = STATE_START_1;
             startForegroundService(LocalForegroundService.COMMAND_START_FOREGROUND);
             waitForResultOrThrow(DELAY, "service to start first time");
             assertNotification(1, LocalForegroundService.getNotificationTitle(1));
 
             // Stop foreground removing notification
+            Log.d(TAG, "Expecting second start state...");
             mExpectedServiceState = STATE_START_2;
             if (usingFlags) {
                 startForegroundService(LocalForegroundService
@@ -730,7 +732,8 @@
         boolean success = false;
 
         PendingIntent pi = PendingIntent.getForegroundService(mContext, 1,
-                foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND), 0);
+                foregroundServiceIntent(LocalForegroundService.COMMAND_START_FOREGROUND),
+                PendingIntent.FLAG_CANCEL_CURRENT);
         TestSendCallback callback = new TestSendCallback();
 
         try {
diff --git a/tests/app/src/android/app/cts/ToolbarActionBarTest.java b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
index d625802..46ab200 100644
--- a/tests/app/src/android/app/cts/ToolbarActionBarTest.java
+++ b/tests/app/src/android/app/cts/ToolbarActionBarTest.java
@@ -21,7 +21,6 @@
 import android.view.KeyEvent;
 
 import android.view.Window;
-import org.junit.Assume;
 
 public class ToolbarActionBarTest extends ActivityInstrumentationTestCase2<ToolbarActivity> {
 
@@ -40,7 +39,9 @@
     }
 
     public void testOptionsMenuKey() {
-        Assume.assumeTrue(mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL));
+        if (!mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+            return;
+        }
         final boolean menuIsVisible[] = {false};
         mActivity.getActionBar().addOnMenuVisibilityListener(
                 isVisible -> menuIsVisible[0] = isVisible);
diff --git a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
index 5094366..46dd551 100644
--- a/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
+++ b/tests/app/src/android/app/cts/android/app/cts/tools/ServiceConnectionHandler.java
@@ -164,7 +164,7 @@
     }
 
     @Override
-    public void onBindingDead(ComponentName name) {
+    public void onBindingDied(ComponentName name) {
         synchronized (this) {
             // We want to remain connected to this service.
             if (mMonitoring) {
diff --git a/tests/autofillservice/AndroidManifest.xml b/tests/autofillservice/AndroidManifest.xml
index 663fe40..32bf5a5 100644
--- a/tests/autofillservice/AndroidManifest.xml
+++ b/tests/autofillservice/AndroidManifest.xml
@@ -51,8 +51,10 @@
             </intent-filter>
         </activity>
         <activity android:name=".EmptyActivity"/>
+        <activity android:name=".DummyActivity"/>
         <activity android:name=".OutOfProcessLoginActivity"
             android:process="android.autofillservice.cts.outside"/>
+        <activity android:name=".FragmentContainerActivity" />
 
         <service
             android:name=".InstrumentedAutoFillService"
diff --git a/tests/autofillservice/res/layout/fragment_container.xml b/tests/autofillservice/res/layout/fragment_container.xml
new file mode 100644
index 0000000..156efad
--- /dev/null
+++ b/tests/autofillservice/res/layout/fragment_container.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  * 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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:id="@+id/rootContainer" />
diff --git a/tests/autofillservice/res/layout/fragment_with_edittext.xml b/tests/autofillservice/res/layout/fragment_with_edittext.xml
new file mode 100644
index 0000000..e0d4584
--- /dev/null
+++ b/tests/autofillservice/res/layout/fragment_with_edittext.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  * 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <EditText android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/editText1" />
+
+    <EditText android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/editText2" />
+</LinearLayout>
diff --git a/tests/autofillservice/res/layout/view_attribute_test_activity.xml b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
index e383d6c..96c0186 100644
--- a/tests/autofillservice/res/layout/view_attribute_test_activity.xml
+++ b/tests/autofillservice/res/layout/view_attribute_test_activity.xml
@@ -19,34 +19,6 @@
     android:layout_width="match_parent" android:layout_height="match_parent"
     android:orientation="vertical" android:id="@+id/rootContainer">
 
-    <EditText android:id="@+id/firstLevelDefault" android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
-
-    <EditText android:id="@+id/firstLevelInherit" android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:autofillMode="inherit" />
-
-    <EditText android:id="@+id/firstLevelAuto" android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:autofillMode="auto" />
-
-    <EditText android:id="@+id/firstLevelManual" android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:autofillMode="manual" />
-
-    <LinearLayout android:id="@+id/manualContainer" android:layout_width="wrap_content"
-        android:layout_height="wrap_content" android:autofillMode="manual"
-        android:orientation="vertical">
-        <EditText android:id="@+id/manualContainerDefault" android:layout_width="wrap_content"
-            android:layout_height="wrap_content" />
-
-        <EditText android:id="@+id/manualContainerInherit" android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:autofillMode="inherit" />
-
-        <EditText android:id="@+id/manualContainerAuto" android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:autofillMode="auto" />
-
-        <EditText android:id="@+id/manualContainerManual" android:layout_width="wrap_content"
-            android:layout_height="wrap_content" android:autofillMode="manual" />
-    </LinearLayout>
-
     <TextView android:id="@+id/textViewNoHint" android:layout_width="wrap_content"
         android:layout_height="wrap_content" />
     <TextView android:id="@+id/textViewHintCustom" android:layout_width="wrap_content"
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
index f0b56d4..efc0b2c 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AbstractAutoFillActivity.java
@@ -50,8 +50,8 @@
         });
         try {
             if (!latch.await(timeoutMs, TimeUnit.MILLISECONDS)) {
-                throw new AssertionError(
-                        "action on UI thread timed out after " + timeoutMs + " ms");
+                throw new RetryableException("action on UI thread timed out after %d ms",
+                        timeoutMs);
             }
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index df61e37..d18e621 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -32,6 +32,7 @@
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 
 /**
@@ -48,6 +49,9 @@
 
     protected static final Replier sReplier = InstrumentedAutoFillService.getReplier();
 
+    @Rule
+    public final RetryRule mRetryRule = new RetryRule(2);
+
     @BeforeClass
     public static void removeLockScreen() {
         runShellCommand("input keyevent KEYCODE_WAKEUP");
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
new file mode 100644
index 0000000..4a0e992
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFinishSessionTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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 android.autofillservice.cts;
+
+import static android.autofillservice.cts.FragmentContainerActivity.FRAGMENT_TAG;
+import static android.autofillservice.cts.Helper.FILL_TIMEOUT_MS;
+import static android.autofillservice.cts.Helper.eventually;
+import static android.autofillservice.cts.Helper.findNodeByResourceId;
+import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.Fragment;
+import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
+import android.content.Intent;
+import android.service.autofill.SaveInfo;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.rule.ActivityTestRule;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Tests that the session finishes when the views and fragments go away
+ */
+public class AutoFinishSessionTest extends AutoFillServiceTestCase {
+    @Rule
+    public final ActivityTestRule<FragmentContainerActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentContainerActivity.class);
+    private FragmentContainerActivity mActivity;
+    private EditText mEditText1;
+    private EditText mEditText2;
+    private Fragment mFragment;
+    private ViewGroup mParent;
+
+    @Before
+    public void initViews() {
+        mActivity = mActivityRule.getActivity();
+        mEditText1 = mActivity.findViewById(R.id.editText1);
+        mEditText2 = mActivity.findViewById(R.id.editText2);
+        mFragment = mActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
+        mParent = ((ViewGroup) mEditText1.getParent());
+
+        assertThat(mFragment).isNotNull();
+    }
+
+    private void removeViewsBaseTest(@NonNull Runnable firstRemove, @Nullable Runnable firstCheck,
+            @Nullable Runnable secondRemove, String... viewsToSave)
+            throws Exception {
+        enableService();
+        try {
+            // Set expectations.
+            sReplier.addResponse(new CannedFillResponse.Builder()
+                    .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
+                    .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, viewsToSave).build());
+
+            // Trigger autofill
+            eventually(() -> {
+                mActivity.syncRunOnUiThread(() -> mEditText2.requestFocus());
+                mActivity.syncRunOnUiThread(() -> mEditText1.requestFocus());
+
+                try {
+                    sReplier.getNextFillRequest();
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }, (int) (FILL_TIMEOUT_MS * 2));
+
+            sUiBot.assertNoDatasets();
+
+            // remove first set of views
+            mActivity.syncRunOnUiThread(() -> {
+                mEditText1.setText("editText1-filled");
+                mEditText2.setText("editText2-filled");
+            });
+            firstRemove.run();
+
+            // Check state between remove operations
+            if (firstCheck != null) {
+                firstCheck.run();
+            }
+
+            // remove second set of views
+            if (secondRemove != null) {
+                secondRemove.run();
+            }
+
+            // Save should be shows after all remove operations were executed
+            sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+
+            SaveRequest saveRequest = sReplier.getNextSaveRequest();
+            for (String view : viewsToSave) {
+                assertThat(findNodeByResourceId(saveRequest.structure, view)
+                        .getAutofillValue().getTextValue().toString()).isEqualTo(view + "-filled");
+            }
+        } finally {
+            disableService();
+        }
+    }
+
+    @Test
+    public void removeBothViewsToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(
+                        () -> ((ViewGroup) mEditText1.getParent()).removeView(mEditText1)),
+                () -> sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC),
+                () -> mActivity.syncRunOnUiThread(
+                        () -> ((ViewGroup) mEditText2.getParent()).removeView(mEditText2)),
+                "editText1", "editText2");
+    }
+
+    @Test
+    public void removeOneViewToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(() -> {
+                    // Do not trigger new partition when switching to editText2
+                    mEditText2.setFocusable(false);
+
+                    mParent.removeView(mEditText1);
+                }),
+                null,
+                null,
+                "editText1");
+    }
+
+    @Test
+    public void hideOneViewToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(
+                        () -> mEditText1.setVisibility(ViewGroup.INVISIBLE)),
+                null,
+                null,
+                "editText1");
+    }
+
+    @Test
+    public void removeFragmentToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(
+                        () -> mActivity.getFragmentManager().beginTransaction().remove(
+                                mFragment).commitNow()),
+                null,
+                null,
+                "editText1", "editText2");
+    }
+
+    @Test
+    public void removeParentToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(
+                        () -> ((ViewGroup) mParent.getParent()).removeView(mParent)),
+                null,
+                null,
+                "editText1", "editText2");
+    }
+
+    @Test
+    public void hideParentToFinishSession() throws Exception {
+        removeViewsBaseTest(
+                () -> mActivity.syncRunOnUiThread(() -> mParent.setVisibility(ViewGroup.INVISIBLE)),
+                null,
+                null,
+                "editText1", "editText2");
+    }
+
+    /**
+     * An activity that is currently getting autofilled might go into the background. While the
+     * tracked views are not visible on the screen anymore, this should not trigger a save.
+     */
+    public void activityToBackgroundShouldNotTriggerSave(@Nullable Runnable removeInBackGround,
+            @Nullable Runnable removeInForeGroup) throws Exception {
+        enableService();
+        try {
+            // Set expectations.
+            sReplier.addResponse(new CannedFillResponse.Builder()
+                    .setFlags(SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE)
+                    .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, "editText1").build());
+
+            // Trigger autofill
+            eventually(() -> {
+                mActivity.syncRunOnUiThread(() -> mEditText2.requestFocus());
+                mActivity.syncRunOnUiThread(() -> mEditText1.requestFocus());
+
+                try {
+                    sReplier.getNextFillRequest();
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }, (int) (FILL_TIMEOUT_MS * 2));
+
+            sUiBot.assertNoDatasets();
+
+            mActivity.syncRunOnUiThread(() -> {
+                mEditText1.setText("editText1-filled");
+                mEditText2.setText("editText2-filled");
+            });
+
+            // Start activity on top
+            mActivity.startActivity(new Intent(getContext(),
+                    ManualAuthenticationActivity.class));
+            mActivity.waitUntilStopped();
+
+            if (removeInBackGround != null) {
+                removeInBackGround.run();
+            }
+
+            sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+
+            // Remove previously started activity from top
+            sUiBot.selectById("android.autofillservice.cts:id/button");
+            mActivity.waitUntilResumed();
+
+            if (removeInForeGroup != null) {
+                sUiBot.assertSaveNotShowing(SAVE_DATA_TYPE_GENERIC);
+
+                removeInForeGroup.run();
+            }
+
+            // Save should be shows after all remove operations were executed
+            sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_GENERIC);
+
+            SaveRequest saveRequest = sReplier.getNextSaveRequest();
+            assertThat(findNodeByResourceId(saveRequest.structure, "editText1")
+                    .getAutofillValue().getTextValue().toString()).isEqualTo("editText1-filled");
+        } finally {
+            disableService();
+        }
+    }
+
+    @Test
+    public void removeViewInBackground() throws Exception {
+        activityToBackgroundShouldNotTriggerSave(
+                () -> mActivity.syncRunOnUiThread(() -> {
+                    // Do not trigger new partition when switching to editText2
+                    mEditText2.setFocusable(false);
+
+                    mParent.removeView(mEditText1);
+                }),
+                null);
+    }
+
+    @Test
+    public void hideViewInBackground() throws Exception {
+        activityToBackgroundShouldNotTriggerSave(
+                () -> mActivity.syncRunOnUiThread(() -> {
+                    // Do not trigger new partition when switching to editText2
+                    mEditText2.setFocusable(false);
+
+                    mEditText1.setVisibility(ViewGroup.INVISIBLE);
+                }),
+                null);
+    }
+
+    @Test
+    public void hideParentInBackground() throws Exception {
+        activityToBackgroundShouldNotTriggerSave(
+                () -> mActivity.syncRunOnUiThread(() -> mParent.setVisibility(ViewGroup.INVISIBLE)),
+                null);
+    }
+
+    @Test
+    public void removeParentInBackground() throws Exception {
+        activityToBackgroundShouldNotTriggerSave(
+                () -> mActivity.syncRunOnUiThread(
+                        () -> ((ViewGroup) mParent.getParent()).removeView(mParent)),
+                null);
+    }
+
+    @Test
+    public void removeViewAfterBackground() throws Exception {
+        activityToBackgroundShouldNotTriggerSave(
+                () -> mActivity.syncRunOnUiThread(() -> {
+                    // Do not trigger new fill request when closing activity
+                    mEditText1.setFocusable(false);
+                    mEditText2.setFocusable(false);
+                }),
+                () -> mActivity.syncRunOnUiThread(() -> {
+                    mParent.removeView(mEditText1);
+                }));
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
index 2fa29ce..b456dd7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CannedFillResponse.java
@@ -22,6 +22,7 @@
 import static android.autofillservice.cts.Helper.getAutofillIds;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
+import android.autofillservice.cts.CannedFillResponse.Builder;
 import android.content.IntentSender;
 import android.os.Bundle;
 import android.service.autofill.Dataset;
@@ -64,8 +65,10 @@
     private final RemoteViews mPresentation;
     private final IntentSender mAuthentication;
     private final String[] mAuthenticationIds;
+    private final String[] mIgnoredIds;
     private final CharSequence mNegativeActionLabel;
     private final IntentSender mNegativeActionListener;
+    private final int mFlags;
 
     private CannedFillResponse(Builder builder) {
         mDatasets = builder.mDatasets;
@@ -77,8 +80,10 @@
         mPresentation = builder.mPresentation;
         mAuthentication = builder.mAuthentication;
         mAuthenticationIds = builder.mAuthenticationIds;
+        mIgnoredIds = builder.mIgnoredIds;
         mNegativeActionLabel = builder.mNegativeActionLabel;
         mNegativeActionListener = builder.mNegativeActionListener;
+        mFlags = builder.mFlags;
     }
 
     /**
@@ -101,8 +106,17 @@
             }
         }
         if (mRequiredSavableIds != null) {
-            final SaveInfo.Builder saveInfo = new SaveInfo.Builder(mSaveType,
-                    getAutofillIds(structure, mRequiredSavableIds));
+            final SaveInfo.Builder saveInfo;
+
+            if (mRequiredSavableIds == null) {
+                saveInfo = new SaveInfo.Builder(mSaveType, null);
+            } else {
+                saveInfo = new SaveInfo.Builder(mSaveType,
+                        getAutofillIds(structure, mRequiredSavableIds));
+            }
+
+            saveInfo.setFlags(mFlags);
+
             if (mOptionalSavableIds != null) {
                 saveInfo.setOptionalIds(getAutofillIds(structure, mOptionalSavableIds));
             }
@@ -114,8 +128,11 @@
             }
             builder.setSaveInfo(saveInfo.build());
         }
+        if (mIgnoredIds != null) {
+            builder.setIgnoredIds(getAutofillIds(structure, mIgnoredIds));
+        }
         return builder
-                .setExtras(mExtras)
+                .setClientState(mExtras)
                 .setAuthentication(getAutofillIds(structure, mAuthenticationIds), mAuthentication,
                         mPresentation)
                 .build();
@@ -126,10 +143,12 @@
         return "CannedFillResponse: [datasets=" + mDatasets
                 + ", requiredSavableIds=" + Arrays.toString(mRequiredSavableIds)
                 + ", optionalSavableIds=" + Arrays.toString(mOptionalSavableIds)
+                + ", mFlags=" + mFlags
                 + ", saveDescription=" + mSaveDescription
                 + ", hasPresentation=" + (mPresentation != null)
                 + ", hasAuthentication=" + (mAuthentication != null)
                 + ", authenticationIds=" + Arrays.toString(mAuthenticationIds)
+                + ", ignoredIds=" + Arrays.toString(mIgnoredIds)
                 + "]";
     }
 
@@ -143,8 +162,10 @@
         private RemoteViews mPresentation;
         private IntentSender mAuthentication;
         private String[] mAuthenticationIds;
+        private String[] mIgnoredIds;
         private CharSequence mNegativeActionLabel;
         private IntentSender mNegativeActionListener;
+        private int mFlags;
 
         public Builder addDataset(CannedDataset dataset) {
             mDatasets.add(dataset);
@@ -160,6 +181,11 @@
             return this;
         }
 
+        public Builder setFlags(int flags) {
+            mFlags = flags;
+            return this;
+        }
+
         /**
          * Sets the optional savable ids based on they {@code resourceId}.
          */
@@ -178,7 +204,7 @@
 
         /**
          * Sets the extra passed to {@link
-         * android.service.autofill.FillResponse.Builder#setExtras(Bundle)}.
+         * android.service.autofill.FillResponse.Builder#setClientState(Bundle)}.
          */
         public Builder setExtras(Bundle data) {
             mExtras = data;
@@ -210,6 +236,14 @@
         }
 
         /**
+         * Sets the ignored fields based on resource ids.
+         */
+        public Builder setIgnoreFields(String...ids) {
+            mIgnoredIds = ids;
+            return this;
+        }
+
+        /**
          * Sets the negative action spec.
          */
         public Builder setNegativeAction(CharSequence label,
@@ -244,12 +278,14 @@
         private final Map<String, RemoteViews> mFieldPresentations;
         private final RemoteViews mPresentation;
         private final IntentSender mAuthentication;
+        private final String mId;
 
         private CannedDataset(Builder builder) {
             mFieldValues = builder.mFieldValues;
             mFieldPresentations = builder.mFieldPresentations;
             mPresentation = builder.mPresentation;
             mAuthentication = builder.mAuthentication;
+            mId = builder.mId;
         }
 
         /**
@@ -278,13 +314,13 @@
                     }
                 }
             }
-            builder.setAuthentication(mAuthentication);
+            builder.setId(mId).setAuthentication(mAuthentication);
             return builder.build();
         }
 
         @Override
         public String toString() {
-            return "CannedDataset: [hasPresentation=" + (mPresentation != null)
+            return "CannedDataset " + mId + " : [hasPresentation=" + (mPresentation != null)
                     + ", fieldPresentations=" + (mFieldPresentations)
                     + ", hasAuthentication=" + (mAuthentication != null)
                     + ", fieldValuess=" + mFieldValues + "]";
@@ -295,6 +331,7 @@
             private final Map<String, RemoteViews> mFieldPresentations = new HashMap<>();
             private RemoteViews mPresentation;
             private IntentSender mAuthentication;
+            private String mId;
 
             public Builder() {
 
@@ -365,6 +402,14 @@
                 return this;
             }
 
+            /**
+             * Sets the name.
+             */
+            public Builder setId(String id) {
+                mId = id;
+                return this;
+            }
+
             public CannedDataset build() {
                 return new CannedDataset(this);
             }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
index 03be6a4..b04b45f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivity.java
@@ -28,6 +28,7 @@
 import android.widget.RadioButton;
 import android.widget.RadioGroup;
 import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -64,6 +65,7 @@
 
     private EditText mCcNumber;
     private Spinner mCcExpiration;
+    private ArrayAdapter<CharSequence> mCcExpirationAdapter;
     private RadioGroup mAddress;
     private RadioButton mHomeAddress;
     private CheckBox mSaveCc;
@@ -87,11 +89,11 @@
         mBuyButton = (Button) findViewById(R.id.buy);
         mClearButton = (Button) findViewById(R.id.clear);
 
-        final ArrayAdapter<CharSequence> expirationValuesAdapter = createFromResource(this,
+        mCcExpirationAdapter = createFromResource(this,
                 R.array.cc_expiration_values, android.R.layout.simple_spinner_item);
-        expirationValuesAdapter
+        mCcExpirationAdapter
                 .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-        mCcExpiration.setAdapter(expirationValuesAdapter);
+        mCcExpiration.setAdapter(mCcExpirationAdapter);
 
         mBuyButton.setOnClickListener((v) -> buy());
         mClearButton.setOnClickListener((v) -> resetFields());
@@ -164,6 +166,13 @@
     }
 
     /**
+     * Visits the {@code ccExpirationDate} adapter in the UiThread.
+     */
+    void onCcExpirationAdapter(Visitor<ArrayAdapter<CharSequence>> v) {
+        syncRunOnUiThread(() -> v.visit(mCcExpirationAdapter));
+    }
+
+    /**
      * Visits the {@code address} in the UiThread.
      */
     void onAddress(Visitor<RadioGroup> v) {
diff --git a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
index 7289b5a..5a46c78 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/CheckoutActivityTest.java
@@ -41,10 +41,7 @@
 import android.autofillservice.cts.CannedFillResponse.CannedDataset;
 import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
 import android.autofillservice.cts.InstrumentedAutoFillService.SaveRequest;
-import android.content.Context;
 import android.support.test.rule.ActivityTestRule;
-import android.view.View;
-import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.Spinner;
 
@@ -54,8 +51,6 @@
 import org.junit.Test;
 
 import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Test case for an activity containing non-TextField views.
@@ -79,7 +74,7 @@
     }
 
     @Test
-    public void testAutoFill() throws Exception {
+    public void testAutofill() throws Exception {
         // Set service.
         enableService();
 
@@ -103,11 +98,12 @@
                 assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
         assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
         assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
-        final String[] options = ccExpirationNode.getAutofillOptions();
+        final CharSequence[] options = ccExpirationNode.getAutofillOptions();
         assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
         assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
                 .containsExactly(
-                        getContext().getResources().getStringArray(R.array.cc_expiration_values));
+                        getContext().getResources().getStringArray(R.array.cc_expiration_values))
+                .inOrder();
 
         // Auto-fill it.
         sUiBot.selectDataset("ACME CC");
@@ -117,7 +113,7 @@
     }
 
     @Test
-    public void testAutoFillDynamicAdapter() throws Exception {
+    public void testAutofillDynamicAdapter() throws Exception {
         // Set activity.
         mActivity.onCcExpiration((v) -> v.setAdapter(new ArrayAdapter<String>(getContext(),
                 android.R.layout.simple_spinner_item,
@@ -146,10 +142,8 @@
                 assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
         assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
         assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
-        final String[] options = ccExpirationNode.getAutofillOptions();
-        assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
-        assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
-                .containsExactly("YESTERDAY", "TODAY", "TOMORROW", "NEVER");
+        final CharSequence[] options = ccExpirationNode.getAutofillOptions();
+        assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNull();
 
         // Auto-fill it.
         sUiBot.selectDataset("ACME CC");
@@ -161,26 +155,25 @@
     // TODO(b/33197203): this should be a pure unit test exercising onProvideAutofillStructure(),
     // but that would require creating a custom ViewStructure.
     @Test
-    public void testAutoFillDynamicAdapterWithNullItems() throws Exception {
-        // Set activity.
-        final MyAdapter adapter = new MyAdapter(getContext(),
-                android.R.layout.simple_spinner_item,
-                Arrays.asList("YESTERDAY", null, "TOMORROW", "NEVER"));
-        mActivity.onCcExpiration((v) -> v.setAdapter(adapter));
-
+    public void testGetAutofillOptionsSorted() throws Exception {
         // Set service.
         enableService();
 
+        // Set activity.
+        mActivity.onCcExpirationAdapter((adapter) -> adapter.sort((a, b) -> {
+            return ((String) a).compareTo((String) b);
+        }));
+
         // Set expectations.
-        final int autoFilledIndex = 2; // NEVER
         sReplier.addResponse(new CannedDataset.Builder()
                 .setPresentation(createPresentation("ACME CC"))
                 .setField(ID_CC_NUMBER, "4815162342")
-                .setField(ID_CC_EXPIRATION, autoFilledIndex)
+                .setField(ID_CC_EXPIRATION, INDEX_CC_EXPIRATION_NEVER)
                 .setField(ID_ADDRESS, 1)
                 .setField(ID_SAVE_CC, true)
                 .build());
-        mActivity.expectAutoFill("4815162342", autoFilledIndex, R.id.work_address, true);
+        mActivity.expectAutoFill("4815162342", INDEX_CC_EXPIRATION_NEVER, R.id.work_address,
+                true);
 
         // Trigger auto-fill.
         mActivity.onCcNumber((v) -> v.requestFocus());
@@ -191,25 +184,20 @@
                 assertTextIsSanitized(fillRequest.structure, ID_CC_EXPIRATION);
         assertThat(ccExpirationNode.getClassName()).isEqualTo(Spinner.class.getName());
         assertThat(ccExpirationNode.getAutofillType()).isEqualTo(AUTOFILL_TYPE_LIST);
-        final String[] options = ccExpirationNode.getAutofillOptions();
-        assertWithMessage("ccExpirationNode.getAutoFillOptions()").that(options).isNotNull();
+        final CharSequence[] options = ccExpirationNode.getAutofillOptions();
         assertWithMessage("Wrong auto-fill options for spinner").that(options).asList()
-                .containsExactly("YESTERDAY", "TOMORROW", "NEVER");
+                .containsExactly("never", "today", "tomorrow", "yesterday").inOrder();
 
         // Auto-fill it.
         sUiBot.selectDataset("ACME CC");
 
         // Check the results.
         mActivity.assertAutoFilled();
-
-        // Make sure proper index was set.
-        final AtomicInteger selected = new AtomicInteger();
-        mActivity.onCcExpiration((v) -> selected.set(v.getSelectedItemPosition()));
-        assertThat(selected.get()).isEqualTo(autoFilledIndex);
     }
 
     @Test
     public void testSanitization() throws Exception {
+        // Set service.
         enableService();
 
         // Set expectations.
@@ -254,37 +242,4 @@
         assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_WORK_ADDRESS), true);
         assertToggleValue(findNodeByResourceId(saveRequest.structure, ID_SAVE_CC), false);
     }
-
-    /**
-     * Custom adapter used to change values after Spinner was rendered.
-     */
-    static class MyAdapter extends ArrayAdapter<String> {
-
-        private final List<String> mList;
-
-        public MyAdapter(Context context, int resource, List<String> objects) {
-            super(context, resource, objects);
-            mList = objects;
-        }
-
-        void setItem(int position, String value) {
-            mList.set(position, value);
-        }
-
-        @Override
-        public String getItem(int position) {
-            return mList.get(position);
-        }
-
-        @Override
-        public View getView(int position, View convertView, ViewGroup parent) {
-            // Hack: always return non-null item, otherwise Spinner.measure() will crash.
-            for (int i = 0; i < mList.size(); i++) {
-                if (mList.get(i) != null) {
-                    return super.getView(i, convertView, parent);
-                }
-            }
-            return null;
-        }
-    }
 }
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
similarity index 69%
copy from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
copy to tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
index d599eba..a1f5bd9 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/DummyActivity.java
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.cts.webkit.renderprocesscrash;
+package android.autofillservice.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.webkit.WebView;
+import android.widget.TextView;
 
-public class RenderProcessCrashActivity extends Activity {
-
+public class DummyActivity extends Activity {
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WebView webView = new WebView(this);
-        setContentView(webView);
-        webView.loadUrl("chrome://kill");
+        TextView text = new TextView(this);
+        text.setText("foo");
+        setContentView(text);
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java b/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java
new file mode 100644
index 0000000..7be4496
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/FragmentContainerActivity.java
@@ -0,0 +1,80 @@
+/*
+ * 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 android.autofillservice.cts;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Activity containing an fragment
+ */
+public class FragmentContainerActivity extends AbstractAutoFillActivity {
+    static final String FRAGMENT_TAG =
+            FragmentContainerActivity.class.getName() + "#FRAGMENT_TAG";
+    private CountDownLatch mResumed = new CountDownLatch(1);
+    private CountDownLatch mStopped = new CountDownLatch(0);
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.fragment_container);
+
+        // have to manually add fragment as we cannot remove it otherwise
+        getFragmentManager().beginTransaction().add(R.id.rootContainer,
+                new FragmentWithEditText(), FRAGMENT_TAG).commitNow();
+    }
+
+    @Override
+    protected void onStart() {
+        super.onStart();
+
+        mStopped = new CountDownLatch(1);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        mResumed.countDown();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        mResumed = new CountDownLatch(1);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        mStopped.countDown();
+    }
+
+    public boolean waitUntilResumed() throws InterruptedException {
+        return mResumed.await(Helper.UI_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+
+    public boolean waitUntilStopped() throws InterruptedException {
+        return mStopped.await(Helper.UI_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java b/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java
new file mode 100644
index 0000000..963daff
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/FragmentWithEditText.java
@@ -0,0 +1,36 @@
+/*
+ * 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 android.autofillservice.cts;
+
+import android.support.annotation.Nullable;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+/**
+ * A fragment with containing a single {@link EditText}
+ */
+public class FragmentWithEditText extends Fragment {
+    @Override
+    @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.fragment_with_edittext, null);
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
index 6df6f10..c9b6d30 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/GridActivity.java
@@ -113,7 +113,7 @@
         onCell(row, column, (c) -> queue.offer(c.getText().toString()));
         final String text = queue.poll(100, TimeUnit.MILLISECONDS);
         if (text == null) {
-            throw new AssertionError("text not set in 100ms");
+            throw new RetryableException("text not set in 100ms");
         }
         return text;
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
index c78a6e1..bd69587 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/InstrumentedAutoFillService.java
@@ -107,7 +107,7 @@
         final String state = sConnectionStates.poll(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
         if (state == null) {
             dumpAutofillService();
-            throw new AssertionError("not connected in " + CONNECTION_TIMEOUT_MS + " ms");
+            throw new RetryableException("not connected in %d ms", CONNECTION_TIMEOUT_MS);
         }
         assertWithMessage("Invalid connection state").that(state).isEqualTo(STATE_CONNECTED);
     }
@@ -122,7 +122,7 @@
         final String state = sConnectionStates.poll(2 * IDLE_UNBIND_TIMEOUT_MS,
                 TimeUnit.MILLISECONDS);
         if (state == null) {
-            throw new AssertionError("not disconnected in " + IDLE_UNBIND_TIMEOUT_MS + " ms");
+            throw new RetryableException("not disconnected in %d ms", IDLE_UNBIND_TIMEOUT_MS);
         }
         assertWithMessage("Invalid connection state").that(state).isEqualTo(STATE_DISCONNECTED);
     }
@@ -221,8 +221,8 @@
         FillRequest getNextFillRequest() throws InterruptedException {
             final FillRequest request = mFillRequests.poll(FILL_TIMEOUT_MS, TimeUnit.MILLISECONDS);
             if (request == null) {
-                throw new AssertionError(
-                        "onFillRequest() not called in " + FILL_TIMEOUT_MS + " ms");
+                throw new RetryableException("onFillRequest() not called in %s ms",
+                        FILL_TIMEOUT_MS);
             }
             return request;
         }
@@ -245,8 +245,8 @@
         SaveRequest getNextSaveRequest() throws InterruptedException {
             final SaveRequest request = mSaveRequests.poll(SAVE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
             if (request == null) {
-                throw new AssertionError(
-                        "onSaveRequest() not called in " + SAVE_TIMEOUT_MS + " ms");
+                throw new RetryableException(
+                        "onSaveRequest() not called in %d ms", SAVE_TIMEOUT_MS);
             }
             return request;
         }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
index db11ca1..ecfdb43 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/LoginActivityTest.java
@@ -31,6 +31,10 @@
 import static android.autofillservice.cts.LoginActivity.AUTHENTICATION_MESSAGE;
 import static android.autofillservice.cts.LoginActivity.ID_USERNAME_CONTAINER;
 import static android.autofillservice.cts.LoginActivity.getWelcomeMessage;
+import static android.service.autofill.FillEventHistory.Event.TYPE_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_AUTHENTICATION_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_DATASET_SELECTED;
+import static android.service.autofill.FillEventHistory.Event.TYPE_SAVE_SHOWN;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_ADDRESS;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_CREDIT_CARD;
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_EMAIL_ADDRESS;
@@ -39,7 +43,6 @@
 import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_USERNAME;
 import static android.text.InputType.TYPE_NULL;
 import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
-import static android.view.View.AUTOFILL_MODE_MANUAL;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.autofill.AutofillManager.FLAG_MANUAL_REQUEST;
 
@@ -57,6 +60,7 @@
 import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.os.Bundle;
+import android.service.autofill.FillEventHistory;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.uiautomator.UiObject2;
 import android.view.View;
@@ -64,6 +68,7 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.autofill.AutofillManager;
+import android.widget.RemoteViews;
 
 import org.junit.After;
 import org.junit.Before;
@@ -789,6 +794,52 @@
 
         // Set credentials...
         mActivity.onUsername((v) -> v.setText("malkovich"));
+        mActivity.onPassword(View::requestFocus);
+        mActivity.onPassword((v) -> v.setText("malkovich"));
+
+        // ...and login
+        final String expectedMessage = getWelcomeMessage("malkovich");
+        final String actualMessage = mActivity.tapLogin();
+        assertWithMessage("Wrong welcome msg").that(actualMessage).isEqualTo(expectedMessage);
+
+        // Assert the snack bar is shown and tap "Save".
+        sUiBot.saveForAutofill(true, SAVE_DATA_TYPE_PASSWORD);
+
+        final SaveRequest saveRequest = sReplier.getNextSaveRequest();
+
+        // Assert value of expected fields - should not be sanitized.
+        final ViewNode username = findNodeByResourceId(saveRequest.structure, ID_USERNAME);
+        assertTextAndValue(username, "malkovich");
+        final ViewNode password = findNodeByResourceId(saveRequest.structure, ID_PASSWORD);
+        assertTextAndValue(password, "malkovich");
+
+        // Sanity check: once saved, the session should be finsihed.
+        assertNoDanglingSessions();
+    }
+
+    @Test
+    public void testSaveOnlyOptionalField() throws Exception {
+        enableService();
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME)
+                .setOptionalSavableIds(ID_PASSWORD)
+                .build());
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Sanity check.
+        sUiBot.assertNoDatasets();
+
+        // Wait for onFill() before proceeding, otherwise the fields might be changed before
+        // the session started
+        sReplier.getNextFillRequest();
+
+        // Set credentials...
+        mActivity.onUsername((v) -> v.setText("malkovich"));
+        mActivity.onPassword(View::requestFocus);
         mActivity.onPassword((v) -> v.setText("malkovich"));
 
         // ...and login
@@ -1097,53 +1148,18 @@
     }
 
     @Test
-    public void testDisableSelfWhenConnected() throws Exception {
+    public void testDisableSelf() throws Exception {
         enableService();
 
-        // Set no-op behavior.
-        sReplier.addResponse(new CannedFillResponse.Builder()
-                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
-                .build());
-
-        // Trigger auto-fill.
-        mActivity.onUsername(View::requestFocus);
-        waitUntilConnected();
-        sReplier.getNextFillRequest();
-
         // Can disable while connected.
-        mActivity.runOnUiThread(() ->
-                InstrumentedAutoFillService.peekInstance().disableSelf());
+        mActivity.runOnUiThread(() -> getContext().getSystemService(
+                AutofillManager.class).disableOwnedAutofillServices());
 
         // Ensure disabled.
         assertServiceDisabled();
     }
 
     @Test
-    public void testDisableSelfWhenDisconnected() throws Exception {
-        enableService();
-
-        // Set no-op behavior.
-        sReplier.addResponse(new CannedFillResponse.Builder()
-                .setRequiredSavableIds(SAVE_DATA_TYPE_PASSWORD, ID_USERNAME, ID_PASSWORD)
-                .build());
-
-        // Trigger auto-fill.
-        mActivity.onUsername(View::requestFocus);
-        waitUntilConnected();
-        sReplier.getNextFillRequest();
-
-        // Wait until we timeout and disconnect.
-        waitUntilDisconnected();
-
-        // Cannot disable while disconnected.
-        mActivity.runOnUiThread(() ->
-                InstrumentedAutoFillService.peekInstance().disableSelf());
-
-        // Ensure enabled.
-        assertServiceEnabled();
-    }
-
-    @Test
     public void testCustomNegativeSaveButton() throws Exception {
         enableService();
 
@@ -1251,14 +1267,13 @@
         assertThat(usernameContainer.getChildCount()).isEqualTo(2);
     }
 
-    @Test
     public void testAutofillManuallyOneDataset() throws Exception {
         // Set service.
         enableService();
 
         // And activity.
         mActivity.onUsername((v) -> {
-            v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+            // v.setAutofillMode(AUTOFILL_MODE_MANUAL);
             // TODO(b/33197203, b/33802548): setting an empty text, otherwise longPress() does not
             // display the AUTOFILL context menu. Need to fix it, but it's a test case issue...
             v.setText("");
@@ -1285,12 +1300,10 @@
         mActivity.assertAutoFilled();
     }
 
-    @Test
     public void testAutofillManuallyTwoDatasetsPickFirst() throws Exception {
         autofillManuallyTwoDatasets(true);
     }
 
-    @Test
     public void testAutofillManuallyTwoDatasetsPickSecond() throws Exception {
         autofillManuallyTwoDatasets(false);
     }
@@ -1301,7 +1314,7 @@
 
         // And activity.
         mActivity.onUsername((v) -> {
-            v.setAutofillMode(AUTOFILL_MODE_MANUAL);
+            //v.setAutofillMode(AUTOFILL_MODE_MANUAL);
             // TODO(b/33197203, b/33802548): setting an empty text, otherwise longPress() does not
             // display the AUTOFILL context menu. Need to fix it, but it's a test case issue...
             v.setText("");
@@ -1495,4 +1508,228 @@
             setUserRestrictionForAutofill(false);
         }
     }
+
+    @Test
+    public void testClickCustomButton() throws Exception {
+        // Set service.
+        enableService();
+
+        Intent intent = new Intent(getContext(), EmptyActivity.class);
+        IntentSender sender = PendingIntent.getActivity(getContext(), 0, intent,
+                PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT)
+                .getIntentSender();
+
+        RemoteViews presentation = new RemoteViews(getContext().getPackageName(),
+                R.layout.list_item);
+        presentation.setTextViewText(R.id.text1, "Poke");
+        Intent firstIntent = new Intent(getContext(), DummyActivity.class);
+        presentation.setOnClickPendingIntent(R.id.text1, PendingIntent.getActivity(
+                getContext(), 0, firstIntent, PendingIntent.FLAG_ONE_SHOT
+                        | PendingIntent.FLAG_CANCEL_CURRENT));
+
+        // Set expectations.
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .setAuthentication(sender)
+                .setPresentation(presentation)
+                .build());
+
+        // Trigger auto-fill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Wait for onFill() before proceeding.
+        sReplier.getNextFillRequest();
+
+        // Click on the custom button
+        sUiBot.selectByText("Poke");
+
+        // Make sure the click worked
+        sUiBot.selectByText("foo");
+
+        // Go back to the filled app.
+        sUiBot.pressBack();
+
+        // The session should be gone
+        assertNoDanglingSessions();
+    }
+
+    @Test
+    public void checkFillSelectionAfterSelectingDatasetAuthentication() throws Exception {
+        enableService();
+
+        // Set up FillResponse with dataset authentication
+        Bundle clientState = new Bundle();
+        clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+        // Prepare the authenticated response
+        AuthenticationActivity.setDataset(new CannedDataset.Builder()
+                .setField(ID_USERNAME, "dude")
+                .setField(ID_PASSWORD, "sweet")
+                .setPresentation(createPresentation("Dataset"))
+                .build());
+
+        IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+                new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setId("name")
+                        .setPresentation(createPresentation("authentication"))
+                        .setAuthentication(authentication)
+                        .build()).setExtras(clientState).build());
+
+        // Trigger autofill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Authenticate
+        sUiBot.selectDataset("authentication");
+        sReplier.getNextFillRequest();
+
+        eventually(() -> {
+            // Verify fill selection
+            FillEventHistory selection =
+                    InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+            assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
+
+            assertThat(selection.getEvents().size()).isEqualTo(1);
+            FillEventHistory.Event event = selection.getEvents().get(0);
+            assertThat(event.getType()).isEqualTo(TYPE_DATASET_AUTHENTICATION_SELECTED);
+            assertThat(event.getDatasetId()).isEqualTo("name");
+        });
+    }
+
+    @Test
+    public void checkFillSelectionAfterSelectingAuthentication() throws Exception {
+        enableService();
+
+        // Set up FillResponse with response wide authentication
+        Bundle clientState = new Bundle();
+        clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+        // Prepare the authenticated response
+        AuthenticationActivity.setResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setId("name")
+                        .setPresentation(createPresentation("dataset"))
+                        .build())
+                .setExtras(clientState).build());
+
+        IntentSender authentication = PendingIntent.getActivity(getContext(), 0,
+                new Intent(getContext(), AuthenticationActivity.class), 0).getIntentSender();
+
+        sReplier.addResponse(new CannedFillResponse.Builder().setExtras(clientState)
+                .setPresentation(createPresentation("authentication"))
+                .setAuthentication(authentication)
+                .build());
+
+        // Trigger autofill.
+        mActivity.onUsername(View::requestFocus);
+
+        // Authenticate
+        sUiBot.selectDataset("authentication");
+        sReplier.getNextFillRequest();
+
+        eventually(() -> {
+            // Verify fill selection
+            FillEventHistory selection =
+                    InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+            assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
+
+            assertThat(selection.getEvents().size()).isEqualTo(1);
+            FillEventHistory.Event event = selection.getEvents().get(0);
+            assertThat(event.getType()).isEqualTo(TYPE_AUTHENTICATION_SELECTED);
+            assertThat(event.getDatasetId()).isNull();
+        });
+    }
+
+    @Test
+    public void checkFillSelectionAfterSelectingTwoDatasets() throws Exception {
+        enableService();
+
+        // Set up first partition with an anonymous dataset
+        sReplier.addResponse(new CannedFillResponse.Builder().addDataset(
+                new CannedDataset.Builder()
+                        .setField(ID_USERNAME, "username")
+                        .setPresentation(createPresentation("dataset1"))
+                        .build())
+                .build());
+
+        // Trigger autofill on username
+        mActivity.onUsername(View::requestFocus);
+        sUiBot.selectDataset("dataset1");
+        sReplier.getNextFillRequest();
+
+        eventually(() -> {
+            // Verify fill selection
+            FillEventHistory selection =
+                    InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+            assertThat(selection.getClientState()).isNull();
+
+            assertThat(selection.getEvents().size()).isEqualTo(1);
+            FillEventHistory.Event event = selection.getEvents().get(0);
+            assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+            assertThat(event.getDatasetId()).isNull();
+        });
+
+        // Set up second partition with a named dataset
+        Bundle clientState = new Bundle();
+        clientState.putCharSequence("clientStateKey", "clientStateValue");
+
+        sReplier.addResponse(new CannedFillResponse.Builder()
+                .addDataset(
+                        new CannedDataset.Builder()
+                                .setField(ID_PASSWORD, "password2")
+                                .setPresentation(createPresentation("dataset2"))
+                                .setId("name2")
+                                .build())
+                .addDataset(
+                        new CannedDataset.Builder()
+                                .setField(ID_PASSWORD, "password3")
+                                .setPresentation(createPresentation("dataset3"))
+                                .setId("name3")
+                                .build())
+                .setExtras(clientState)
+                .setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_PASSWORD).build());
+
+        // Trigger autofill on password
+        mActivity.onPassword(View::requestFocus);
+        sUiBot.selectDataset("dataset3");
+        sReplier.getNextFillRequest();
+
+        eventually(() -> {
+            // Verify fill selection
+            FillEventHistory selection =
+                    InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+            assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
+
+            assertThat(selection.getEvents().size()).isEqualTo(1);
+            FillEventHistory.Event event = selection.getEvents().get(0);
+            assertThat(event.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+            assertThat(event.getDatasetId()).isEqualTo("name3");
+        });
+
+        mActivity.onPassword((v) -> v.setText("new password"));
+        mActivity.syncRunOnUiThread(() -> mActivity.finish());
+
+        eventually(() -> {
+            // Verify fill selection
+            FillEventHistory selection =
+                    InstrumentedAutoFillService.peekInstance().getFillEventHistory();
+            assertThat(selection.getClientState().getCharSequence("clientStateKey")).isEqualTo(
+                    "clientStateValue");
+
+            assertThat(selection.getEvents().size()).isEqualTo(2);
+            FillEventHistory.Event event1 = selection.getEvents().get(0);
+            assertThat(event1.getType()).isEqualTo(TYPE_DATASET_SELECTED);
+            assertThat(event1.getDatasetId()).isEqualTo("name3");
+
+            FillEventHistory.Event event2 = selection.getEvents().get(1);
+            assertThat(event2.getType()).isEqualTo(TYPE_SAVE_SHOWN);
+            assertThat(event2.getDatasetId()).isNull();
+        });
+    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
index c2af4cc1..32844d4 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ManualAuthenticationActivity.java
@@ -49,25 +49,24 @@
         setContentView(R.layout.single_button_activity);
 
         findViewById(R.id.button).setOnClickListener((v) -> {
-            // We should get the assist structure
             AssistStructure structure = getIntent().getParcelableExtra(
                     AutofillManager.EXTRA_ASSIST_STRUCTURE);
-            assertWithMessage("structure not called").that(structure).isNotNull();
+            if (structure != null) {
+                Parcelable result;
+                if (sResponse != null) {
+                    result = sResponse.asFillResponse(structure);
+                } else if (sDataset != null) {
+                    result = sDataset.asDataset(structure);
+                } else {
+                    throw new IllegalStateException("no dataset or response");
+                }
 
-            Parcelable result = null;
-            if (sResponse != null) {
-                result = sResponse.asFillResponse(structure);
-            } else if (sDataset != null) {
-                result = sDataset.asDataset(structure);
-            } else {
-                throw new IllegalStateException("no dataset or response");
+                // Pass on the auth result
+                Intent intent = new Intent();
+                intent.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, result);
+                setResult(RESULT_OK, intent);
             }
 
-            // Pass on the auth result
-            Intent intent = new Intent();
-            intent.putExtra(AutofillManager.EXTRA_AUTHENTICATION_RESULT, result);
-            setResult(RESULT_OK, intent);
-
             // Done
             finish();
         });
diff --git a/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java b/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
index 13887fa..48b0c2f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/MyAutofillCallback.java
@@ -50,7 +50,7 @@
     MyEvent getEvent() throws InterruptedException {
         final MyEvent event = mEvents.poll(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS);
         if (event == null) {
-            throw new AssertionError("no event in " + CONNECTION_TIMEOUT_MS + " ms");
+            throw new RetryableException("no event in %d ms", CONNECTION_TIMEOUT_MS);
         }
         return event;
     }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
index 49ddf8f..b3902b3 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/PartitionedActivityTest.java
@@ -599,6 +599,41 @@
         assertValue(saveRequest.structure, ID_L4C1, "L4C1");
     }
 
+    @Test
+    public void testIgnoredFieldsDontTriggerAutofill() throws Exception {
+        // Set service.
+        enableService();
+
+        // Prepare 1st partition.
+        final CannedFillResponse response1 = new CannedFillResponse.Builder()
+                .addDataset(new CannedDataset.Builder()
+                        .setField(ID_L1C1, "l1c1", createPresentation("l1c1"))
+                        .setField(ID_L1C2, "l1c2", createPresentation("l1c2"))
+                        .build())
+                .setIgnoreFields(ID_L2C1, ID_L2C2)
+                .build();
+        sReplier.addResponse(response1);
+
+        // Trigger auto-fill on 1st partition.
+        mActivity.focusCell(1, 1);
+        final FillRequest fillRequest1 = sReplier.getNextFillRequest();
+        final ViewNode p1l1c1 = assertTextIsSanitized(fillRequest1.structure, ID_L1C1);
+        final ViewNode p1l1c2 = assertTextIsSanitized(fillRequest1.structure, ID_L1C2);
+        assertWithMessage("Focus on p1l1c1").that(p1l1c1.isFocused()).isTrue();
+        assertWithMessage("Focus on p1l1c2").that(p1l1c2.isFocused()).isFalse();
+
+        // Make sure UI is shown on 1st partition
+        sUiBot.assertDatasets("l1c1");
+        mActivity.focusCell(1, 2);
+        sUiBot.assertDatasets("l1c2");
+
+        // Make sure UI is not shown on ignored partition
+        mActivity.focusCell(2, 1);
+        sUiBot.assertNoDatasets();
+        mActivity.focusCell(2, 2);
+        sUiBot.assertNoDatasets();
+    }
+
     // TODO(b/33197203, b/35707731): test force autofill after autofilled
     // TODO(b/33197203, b/35707731): test save with different subtitles and custom no button
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
new file mode 100644
index 0000000..a4db0f4
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryRule.java
@@ -0,0 +1,62 @@
+/*
+ * 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 android.autofillservice.cts;
+
+import android.util.Log;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+/**
+ * Custom JUnit4 rule that retry tests when they fail due to a {@link RetryableException}.
+ */
+public class RetryRule implements TestRule {
+
+    private static final String TAG = "RetryRule";
+    private final int mMaxAttempts;
+
+    public RetryRule(int maxAttempts) {
+        if (maxAttempts < 2) {
+            throw new IllegalArgumentException(
+                    "Must retry at least once; otherwise, what's the point?");
+        }
+        mMaxAttempts = maxAttempts;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+
+            @Override
+            public void evaluate() throws Throwable {
+                RetryableException caught = null;
+                for (int i = 1; i <= mMaxAttempts; i++) {
+                    try {
+                        base.evaluate();
+                        return;
+                    } catch (RetryableException e) {
+                        caught = e;
+                        Log.w(TAG,
+                                description.getDisplayName() + ": attempt " + i + " failed: " + e);
+                    }
+                }
+                throw caught;
+            }
+        };
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java b/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java
new file mode 100644
index 0000000..50ae8c8
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryRuleTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.autofillservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.Statement;
+
+@RunWith(AndroidJUnit4.class)
+public class RetryRuleTest {
+
+    private final Description mDescription = Description.createSuiteDescription("Whatever");
+
+    private static final RetryableException sRetryableException =
+            new RetryableException("Y U NO RETRY?");
+
+    private static class RetryableStatement extends Statement {
+        private final int mNumberFailures;
+        private int mNumberCalls;
+
+        RetryableStatement(int numberFailures) {
+            mNumberFailures = numberFailures;
+        }
+
+        @Override
+        public void evaluate() throws Throwable {
+            mNumberCalls ++;
+            if (mNumberCalls <= mNumberFailures) {
+                throw sRetryableException;
+            }
+        }
+
+        @Override
+        public String toString() {
+            return "RetryableStatement: failures=" + mNumberFailures + ", calls=" + mNumberCalls;
+        }
+    }
+
+    @Test
+    public void testPass() throws Throwable {
+        final RetryRule rule = new RetryRule(2);
+        rule.apply(new RetryableStatement(1), mDescription).evaluate();
+    }
+
+    @Test
+    public void testFail() throws Throwable {
+        final RetryRule rule = new RetryRule(2);
+        try {
+            rule.apply(new RetryableStatement(2), mDescription).evaluate();
+            throw new AssertionError("2ND CALL, Y U NO FAIL?");
+        } catch (RetryableException e) {
+            assertThat(e).isSameAs(sRetryableException);
+        }
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java b/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java
new file mode 100644
index 0000000..9b9d651
--- /dev/null
+++ b/tests/autofillservice/src/android/autofillservice/cts/RetryableException.java
@@ -0,0 +1,31 @@
+/*
+ * 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 android.autofillservice.cts;
+
+/**
+ * Exception that cause the {@link RetryRule} to re-try a test.
+ */
+public class RetryableException extends RuntimeException {
+
+    public RetryableException(String msg) {
+        super(msg);
+    }
+
+    public RetryableException(String format, Object...args) {
+        this(String.format(format, args));
+    }
+}
diff --git a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
index a5f74c5..0454277 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/SessionLifecycleTest.java
@@ -174,8 +174,6 @@
             // Login
             sUiBot.selectById(LOGIN_FULL_ID);
 
-            /* TODO: b/37117412
-
             // Wait for save UI to be shown
             sUiBot.assertShownById("android:id/autofill_save_yes");
 
@@ -202,8 +200,6 @@
             final String extraValue = saveRequest.data.getString("numbers");
             assertWithMessage("extras not passed on save").that(extraValue).isEqualTo("4815162342");
 
-            */
-
             eventually(() -> assertNoDanglingSessions());
         } finally {
             disableService();
diff --git a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
index 1f98171..deba8b7 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/UiBot.java
@@ -92,7 +92,7 @@
             // not showing...
             return;
         }
-        throw new AssertionError("floating ui is shown: " + ui);
+        throw new RetryableException("floating ui is shown: %s", ui);
     }
 
     /**
@@ -202,6 +202,13 @@
     }
 
     /**
+     * Presses the back button.
+     */
+    void pressBack() {
+        mDevice.pressBack();
+    }
+
+    /**
      * Asserts the save snackbar is not showing and returns it.
      */
     void assertSaveNotShowing(int type) {
@@ -212,7 +219,7 @@
             // not showing (in which case it wouldn't need a type as parameter).
             return;
         }
-        throw new AssertionError("snack bar is showing");
+        throw new RetryableException("snack bar is showing");
     }
 
     private String getSaveTypeString(int type) {
@@ -328,7 +335,7 @@
             }
             menuNames.append("'").append(menuName).append("' ");
         }
-        throw new AssertionError("no '" + expectedText + "' on " + menuNames);
+        throw new RetryableException("no '%s' on '%s'", expectedText, menuNames);
     }
 
     /**
@@ -375,8 +382,8 @@
             }
             SystemClock.sleep(napTime);
         }
-        throw new AssertionError("Object with selector " + selector + " not found in "
-                + mTimeout + " ms");
+        throw new RetryableException("Object with selector '%s' not found in %d ms",
+                selector, mTimeout);
     }
 
     /**
@@ -405,9 +412,10 @@
             }
             SystemClock.sleep(napTime);
         }
-        throw new AssertionError("Objects with selector " + selector + " not found in "
-                + mTimeout + " ms");
+        throw new RetryableException("Objects with selector '%s' not found in %d ms",
+                selector, mTimeout);
     }
+
     private UiObject2 findDatasetPicker() {
         final UiObject2 picker = waitForObject(By.res("android", RESOURCE_ID_DATASET_PICKER));
 
@@ -429,6 +437,6 @@
                 return;
             }
         }
-        throw new AssertionError("Title (" + expectedTitle + ") not found for " + object);
+        throw new RetryableException("Title '%s' not found for %s", expectedTitle, object);
     }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
index 54b474e..763c57f 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/ViewAttributesTest.java
@@ -18,16 +18,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
-
-import android.autofillservice.cts.InstrumentedAutoFillService.FillRequest;
-import android.support.annotation.NonNull;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.View;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.TextView;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -41,227 +34,10 @@
             new ActivityTestRule<>(ViewAttributesTestActivity.class);
 
     private ViewAttributesTestActivity mActivity;
-    private EditText mFirstLevelDefault;
-    private EditText mFirstLevelManual;
-    private EditText mFirstLevelAuto;
-    private EditText mFirstLevelInherit;
-    private EditText mManualContainerInherit;
-    private EditText mManualContainerDefault;
-    private EditText mManualContainerManual;
-    private EditText mManualContainerAuto;
-    private OneTimeTextWatcher mFirstLevelDefaultTextWatcher;
 
     @Before
     public void setActivity() {
         mActivity = mActivityRule.getActivity();
-        mFirstLevelDefault = (EditText) mActivity.findViewById(R.id.firstLevelDefault);
-        mFirstLevelManual = (EditText) mActivity.findViewById(R.id.firstLevelManual);
-        mFirstLevelAuto = (EditText) mActivity.findViewById(R.id.firstLevelAuto);
-        mFirstLevelInherit = (EditText) mActivity.findViewById(R.id.firstLevelInherit);
-        mManualContainerDefault = (EditText) mActivity.findViewById(R.id.manualContainerDefault);
-        mManualContainerManual = (EditText) mActivity.findViewById(R.id.manualContainerManual);
-        mManualContainerAuto = (EditText) mActivity.findViewById(R.id.manualContainerAuto);
-        mManualContainerInherit = (EditText) mActivity.findViewById(R.id.manualContainerInherit);
-    }
-
-    private void runOnUiThreadSync(@NonNull Runnable r) throws InterruptedException {
-        RuntimeException exceptionOnUiThread[] = {null};
-
-        synchronized (this) {
-            mActivity.runOnUiThread(() -> {
-                synchronized (this) {
-                    try {
-                        r.run();
-                    } catch (RuntimeException e) {
-                        exceptionOnUiThread[0] = e;
-                    }
-                    this.notify();
-                }
-            });
-
-            wait();
-        }
-
-        if (exceptionOnUiThread[0] != null) {
-            throw exceptionOnUiThread[0];
-        }
-    }
-
-    /**
-     * Sets the expectation for an auto-fill request, so it can be asserted through
-     * {@link #assertAutoFilled()} later.
-     */
-    void expectAutoFill() {
-        mFirstLevelDefaultTextWatcher = new OneTimeTextWatcher("firstLevelDefault",
-                mFirstLevelDefault, "filled");
-        mFirstLevelDefault.addTextChangedListener(mFirstLevelDefaultTextWatcher);
-    }
-
-    /**
-     * Asserts the activity was auto-filled with the values passed to
-     * {@link #expectAutoFill()}.
-     */
-    void assertAutoFilled() throws Exception {
-        mFirstLevelDefaultTextWatcher.assertAutoFilled();
-    }
-
-    /**
-     * Try to auto-fill by moving the focus to {@code field}. If the field should trigger an
-     * auto-fill the auto-fill UI should show up.
-     *
-     * @param field    The field to move the focus to
-     * @param expectUI If the auto-fill UI is expected to show up
-     *
-     * @throws Exception If something unexpected happened
-     */
-    private void checkFieldBehavior(@NonNull EditText field, boolean expectUI) throws Exception {
-        if (expectUI) {
-            assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-        } else {
-            assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
-        }
-
-        // Make sure the requestFocus triggers a change
-        if (field == mFirstLevelManual) {
-            runOnUiThreadSync(() -> mFirstLevelDefault.requestFocus());
-        } else {
-            runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
-        }
-
-        enableService();
-
-        try {
-            sReplier.addResponse(new CannedFillResponse.Builder()
-                    .addDataset(new CannedFillResponse.CannedDataset.Builder()
-                            .setField("firstLevelDefault", "filled")
-                            .setField("firstLevelManual", "filled")
-                            .setField("firstLevelAuto", "filled")
-                            .setField("firstLevelInherit", "filled")
-                            .setField("manualContainerDefault", "filled")
-                            .setField("manualContainerManual", "filled")
-                            .setField("manualContainerAuto", "filled")
-                            .setField("manualContainerInherit", "filled")
-                            .setPresentation(createPresentation("dataset"))
-                            .build())
-                    .build());
-
-            expectAutoFill();
-
-            runOnUiThreadSync(() -> field.requestFocus());
-
-            Throwable exceptionDuringAutoFillTrigger = null;
-            try {
-                sReplier.getNextFillRequest();
-                sUiBot.selectDataset("dataset");
-            } catch (Throwable e) {
-                if (expectUI) {
-                    throw e;
-                } else {
-                    exceptionDuringAutoFillTrigger = e;
-                }
-            }
-
-            if (expectUI) {
-                assertAutoFilled();
-            } else {
-                assertThat(exceptionDuringAutoFillTrigger).isNotNull();
-            }
-        } finally {
-            disableService();
-        }
-    }
-
-    @Test
-    public void checkDefaultValue() {
-        assertThat(mFirstLevelDefault.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-    }
-
-    @Test
-    public void checkInheritValue() {
-        assertThat(mFirstLevelInherit.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-    }
-
-    @Test
-    public void checkAutoValue() {
-        assertThat(mFirstLevelAuto.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-    }
-
-    @Test
-    public void checkManualValue() {
-        assertThat(mFirstLevelManual.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
-    }
-
-    @Test
-    public void checkNestedDefaultValue() {
-        assertThat(mManualContainerDefault.getAutofillMode()).isEqualTo(
-                View.AUTOFILL_MODE_INHERIT);
-    }
-
-    @Test
-    public void checkNestedInheritValue() {
-        assertThat(mManualContainerInherit.getAutofillMode()).isEqualTo(
-                View.AUTOFILL_MODE_INHERIT);
-    }
-
-    @Test
-    public void checkNestedAutoValue() {
-        assertThat(mManualContainerAuto.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-    }
-
-    @Test
-    public void checkNestedManualValue() {
-        assertThat(mManualContainerManual.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
-    }
-
-    @Test
-    public void checkDefaultBehavior() throws Exception {
-        checkFieldBehavior(mFirstLevelDefault, true);
-    }
-
-    @Test
-    public void checkInheritBehavior() throws Exception {
-        checkFieldBehavior(mFirstLevelInherit, true);
-    }
-
-    @Test
-    public void checkAutoBehavior() throws Exception {
-        checkFieldBehavior(mFirstLevelAuto, true);
-    }
-
-    @Test
-    public void checkManualBehavior() throws Exception {
-        checkFieldBehavior(mFirstLevelManual, false);
-    }
-
-    @Test
-    public void checkNestedDefaultBehavior() throws Exception {
-        checkFieldBehavior(mManualContainerDefault, false);
-    }
-
-    @Test
-    public void checkNestedInheritBehavior() throws Exception {
-        checkFieldBehavior(mManualContainerInherit, false);
-    }
-
-    @Test
-    public void checkNestedAutoBehavior() throws Exception {
-        checkFieldBehavior(mManualContainerAuto, true);
-    }
-
-    @Test
-    public void checkNestedManualBehavior() throws Exception {
-        checkFieldBehavior(mManualContainerManual, false);
-    }
-
-    @Test
-    public void checksetAutofillMode() {
-        mFirstLevelDefault.setAutofillMode(View.AUTOFILL_MODE_MANUAL);
-        assertThat(mFirstLevelDefault.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
-    }
-
-    @Test
-    public void checkIllegalAutoFillModeSet() throws Exception {
-        assertThrows(IllegalArgumentException.class, () -> mFirstLevelDefault.setAutofillMode(-1));
     }
 
     @Test
@@ -317,85 +93,4 @@
         assertThat(v.getAutofillHints()).isEqualTo(new String[]{View.AUTOFILL_HINT_PASSWORD,
                 View.AUTOFILL_HINT_EMAIL_ADDRESS});
     }
-
-    @Test
-    public void attachViewToManualContainer() throws Exception {
-        runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
-        enableService();
-
-        try {
-            View view = new TextView(mActivity);
-
-            view.setLayoutParams(
-                    new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
-                            LinearLayout.LayoutParams.WRAP_CONTENT));
-
-            assertThat(view.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-            assertThat(view.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
-            // Requesting focus should not trigger any mishaps
-            runOnUiThreadSync(() -> view.requestFocus());
-
-            LinearLayout attachmentPoint = (LinearLayout) mActivity.findViewById(
-                    R.id.manualContainer);
-            runOnUiThreadSync(() -> attachmentPoint.addView(view));
-
-            assertThat(view.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_MANUAL);
-        } finally {
-            disableService();
-        }
-    }
-
-    @Test
-    public void attachNestedViewToContainer() throws Exception {
-        runOnUiThreadSync(() -> mFirstLevelManual.requestFocus());
-        enableService();
-
-        try {
-            // Create view and viewGroup but do not attach to window
-            LinearLayout container = (LinearLayout) mActivity.getLayoutInflater().inflate(
-                    R.layout.nested_layout, null);
-            EditText field = container.findViewById(R.id.field);
-
-            assertThat(field.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-            assertThat(container.getAutofillMode()).isEqualTo(View.AUTOFILL_MODE_INHERIT);
-
-            // Resolved mode for detached views should behave as documented
-            assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-            assertThat(container.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
-            // Requesting focus should not trigger any mishaps
-            runOnUiThreadSync(() -> field.requestFocus());
-
-            // Set up auto-fill service and response
-            sReplier.addResponse(new CannedFillResponse.Builder()
-                    .addDataset(new CannedFillResponse.CannedDataset.Builder()
-                            .setField("field", "filled")
-                            .setPresentation(createPresentation("dataset"))
-                            .build())
-                    .build());
-
-            OneTimeTextWatcher mViewWatcher = new OneTimeTextWatcher("field", field, "filled");
-            field.addTextChangedListener(mViewWatcher);
-
-            // As the focus is set to "field", attaching "container" should trigger an auto-fill
-            // request on "field"
-            LinearLayout attachmentPoint = (LinearLayout) mActivity.findViewById(
-                    R.id.rootContainer);
-            runOnUiThreadSync(() -> attachmentPoint.addView(container));
-
-            // Now the resolved auto-fill modes make sense, hence check them
-            assertThat(field.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-            assertThat(container.getResolvedAutofillMode()).isEqualTo(View.AUTOFILL_MODE_AUTO);
-
-            // We should now be able to select the data set
-            sReplier.getNextFillRequest();
-            sUiBot.selectDataset("dataset");
-
-            // Check if auto-fill operation worked
-            mViewWatcher.assertAutoFilled();
-        } finally {
-            disableService();
-        }
-    }
 }
diff --git a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
index 6b97195..0344830 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/VirtualContainerActivityTest.java
@@ -127,7 +127,7 @@
         try {
             VirtualContainerView.assertHtmlInfo(username);
             VirtualContainerView.assertHtmlInfo(password);
-        } catch (AssertionError e) {
+        } catch (AssertionError | RuntimeException e) {
             dumpStructure("HtmlInfo failed", request.structure);
             throw e;
         }
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 6ae3011..b51e338 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -1649,10 +1649,6 @@
                     checkMeteringRect(afRegions);
                 }
             }
-            // ZSL must default to OFF
-            if (request.get(CONTROL_ENABLE_ZSL) != null) {
-                mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false);
-            }
         }
 
         // Sensor settings.
@@ -1915,6 +1911,13 @@
             }
         }
 
+        // Enable ZSL
+        if (template != CameraDevice.TEMPLATE_STILL_CAPTURE) {
+            if (mStaticInfo.areKeysAvailable(CONTROL_ENABLE_ZSL)) {
+                    mCollector.expectKeyValueEquals(request, CONTROL_ENABLE_ZSL, false);
+            }
+        }
+
         int[] outputFormats = mStaticInfo.getAvailableFormats(
                 StaticMetadata.StreamDirection.Output);
         boolean supportRaw = false;
diff --git a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index 6c48418..e011131 100644
--- a/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -1262,7 +1262,11 @@
     private long getExposureValue(CaptureResult result) throws Exception {
         int expTimeUs = (int) (getValueNotNull(result, CaptureResult.SENSOR_EXPOSURE_TIME) / 1000);
         int sensitivity = getValueNotNull(result, CaptureResult.SENSOR_SENSITIVITY);
-        return expTimeUs * sensitivity;
+        Integer postRawSensitivity = result.get(CaptureResult.CONTROL_POST_RAW_SENSITIVITY_BOOST);
+        if (postRawSensitivity != null) {
+            return (long) sensitivity * postRawSensitivity / 100 * expTimeUs;
+        }
+        return (long) sensitivity * expTimeUs;
     }
 
     private long getMaxExposureValue(CaptureRequest.Builder request, long maxExposureTimeUs,
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 6bb3421..e4ca5af 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -240,6 +240,16 @@
    bug: 23827982
 },
 {
+   description: "VP9 encoder is not a standard requirement of android as of O.",
+   names: [
+     "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180",
+     "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360",
+     "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720",
+     "android.media.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080"
+   ],
+   bug: 33090965
+},
+{
   description: "protected broadcast not working",
   names: [
    "android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
index b5e9cad..dba0c07 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -28,14 +28,13 @@
 import android.app.FragmentController;
 import android.app.FragmentManager;
 import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
 import android.os.Parcelable;
-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.util.Pair;
 import android.view.View;
+import android.view.animation.TranslateAnimation;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -59,11 +58,8 @@
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
-    private Instrumentation mInstrumentation;
-
     @Before
     public void setupContainer() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
     }
 
@@ -105,8 +101,9 @@
     }
 
     // Ensure that showing and popping a Fragment uses the enter and popExit animators
+    // This tests optimized transactions
     @Test
-    public void showAnimators() throws Throwable {
+    public void showAnimatorsOptimized() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
 
         // One fragment with a view
@@ -114,6 +111,10 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
         FragmentTestUtil.waitForExecution(mActivityRule);
 
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.GONE, fragment.getView().getVisibility());
+        });
+
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .show(fragment)
@@ -121,7 +122,51 @@
                 .commit();
         FragmentTestUtil.waitForExecution(mActivityRule);
 
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+        });
         assertEnterPopExit(fragment);
+
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.GONE, fragment.getView().getVisibility());
+        });
+    }
+
+    // Ensure that showing and popping a Fragment uses the enter and popExit animators
+    // This tests unoptimized transactions
+    @Test
+    public void showAnimatorsUnoptimized() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment)
+                .hide(fragment)
+                .setAllowOptimization(false)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.GONE, fragment.getView().getVisibility());
+        });
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .show(fragment)
+                .setAllowOptimization(false)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.VISIBLE, fragment.getView().getVisibility());
+        });
+        assertEnterPopExit(fragment);
+
+        mActivityRule.runOnUiThread(() -> {
+            assertEquals(View.GONE, fragment.getView().getVisibility());
+        });
     }
 
     // Ensure that hiding and popping a Fragment uses the exit and popEnter animators
@@ -365,12 +410,12 @@
                 .replace(R.id.fragmentContainer, fragment2, "2")
                 .addToBackStack(null)
                 .commit();
-        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        mActivityRule.runOnUiThread(fm1::executePendingTransactions);
         FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm1.popBackStack();
 
-        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        mActivityRule.runOnUiThread(fm1::executePendingTransactions);
         FragmentTestUtil.waitForExecution(mActivityRule);
         // Now fragment2 should be animating away
         assertFalse(fragment2.isAdded());
@@ -391,6 +436,68 @@
         assertNotNull(fragment1restored.getView());
     }
 
+    // When an animation is running on a Fragment's View, the view shouldn't be
+    // prevented from being removed. There's no way to directly test this, so we have to
+    // test to see if the animation is still running.
+    @Test
+    public void clearAnimations() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View fragmentView = fragment1.getView();
+
+        final TranslateAnimation xAnimation = new TranslateAnimation(0, 1000, 0, 0);
+        xAnimation.setDuration(10000);
+        mActivityRule.runOnUiThread(() -> {
+            fragmentView.startAnimation(xAnimation);
+            assertEquals(xAnimation, fragmentView.getAnimation());
+        });
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        mActivityRule.runOnUiThread(() -> {
+            assertNull(fragmentView.getAnimation());
+        });
+    }
+
+    /**
+     * When a fragment container is null, you shouldn't see an NPE even with an animation.
+     */
+    @Test
+    public void animationOnNullContainer() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        // One fragment with a view
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .add(fragment, "1")
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .hide(fragment)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .show(fragment)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+    }
+
     private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
         assertFragmentAnimation(fragment, 1, true, ENTER);
 
diff --git a/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
index 7d65b8c..6e6cda9 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
@@ -41,11 +41,8 @@
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
-    private Instrumentation mInstrumentation;
-
     @Before
     public void setupContentView() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
     }
 
@@ -58,7 +55,7 @@
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictViewFragment fragment = new StrictViewFragment();
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 fm.beginTransaction()
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index ebda7a2..abf7fd8 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -870,6 +870,45 @@
         });
     }
 
+    /**
+     * When the FragmentManager state changes, the pending transactions should execute.
+     */
+    @Test
+    public void runTransactionsOnChange() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, null);
+            FragmentManager fm = fc.getFragmentManager();
+
+            RemoveHelloInOnResume fragment1 = new RemoveHelloInOnResume();
+            StrictFragment fragment2 = new StrictFragment();
+            fm.beginTransaction()
+                    .add(fragment1, "1")
+                    .setAllowOptimization(false)
+                    .commit();
+            fm.beginTransaction()
+                    .add(fragment2, "Hello")
+                    .setAllowOptimization(false)
+                    .commit();
+            fm.executePendingTransactions();
+
+            assertEquals(2, fm.getFragments().size());
+            assertTrue(fm.getFragments().contains(fragment1));
+            assertTrue(fm.getFragments().contains(fragment2));
+
+            Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                    FragmentTestUtil.destroy(mActivityRule, fc);
+            fc = FragmentTestUtil.createController(mActivityRule);
+            FragmentTestUtil.resume(mActivityRule, fc, savedState);
+            fm = fc.getFragmentManager();
+
+            assertEquals(1, fm.getFragments().size());
+            for (Fragment fragment : fm.getFragments()) {
+                assertTrue(fragment instanceof RemoveHelloInOnResume);
+            }
+        });
+    }
+
     private void executePendingTransactions(final FragmentManager fm) throws Throwable {
         mActivityRule.runOnUiThread(new Runnable() {
             @Override
@@ -1065,4 +1104,15 @@
             return mValue;
         }
     }
+
+    public static class RemoveHelloInOnResume extends Fragment {
+        @Override
+        public void onResume() {
+            super.onResume();
+            Fragment fragment = getFragmentManager().findFragmentByTag("Hello");
+            if (fragment != null) {
+                getFragmentManager().beginTransaction().remove(fragment).commit();
+            }
+        }
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
index f91eb65..bbd8d10 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
@@ -15,11 +15,11 @@
  */
 package android.fragment.cts;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import android.app.FragmentManager;
-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;
@@ -39,14 +39,12 @@
 
     private ViewGroup mContainer;
     private FragmentManager mFM;
-    private Instrumentation mInstrumentation;
 
     @Before
     public void setup() {
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
         mContainer = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
         mFM = mActivityRule.getActivity().getFragmentManager();
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
     }
 
     // Test that when you add and replace a fragment that only the replace's add
@@ -55,7 +53,7 @@
     public void addReplace() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final StrictViewFragment fragment2 = new StrictViewFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
@@ -69,7 +67,7 @@
         assertEquals(0, fragment1.onCreateViewCount);
         FragmentTestUtil.assertChildren(mContainer, fragment2);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.popBackStack();
@@ -92,7 +90,7 @@
         FragmentTestUtil.assertChildren(mContainer, fragment1);
 
         // Now pop and add
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.popBackStack();
@@ -116,7 +114,7 @@
     public void middlePop() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final CountCallsFragment fragment2 = new CountCallsFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -146,7 +144,7 @@
     public void optimizeRemove() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final int[] id = new int[1];
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 id[0] = mFM.beginTransaction()
@@ -186,7 +184,7 @@
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         assertEquals(1, fragment1.onCreateViewCount);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -224,7 +222,7 @@
         assertEquals(1, fragment1.onAttachCount);
         FragmentTestUtil.assertChildren(mContainer, fragment1);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
@@ -274,7 +272,7 @@
         assertEquals(0, fragment1.onCreateViewCount);
         FragmentTestUtil.assertChildren(mContainer);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
@@ -318,7 +316,7 @@
         assertEquals(1, fragment1.onHideCount);
         FragmentTestUtil.assertChildren(mContainer, fragment1);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -353,7 +351,7 @@
         assertEquals(0, fragment1.onShowCount);
         assertEquals(1, fragment1.onHideCount);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
@@ -373,7 +371,7 @@
         assertEquals(0, fragment1.onShowCount);
         assertEquals(1, fragment1.onHideCount);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
@@ -408,7 +406,7 @@
         assertEquals(0, fragment1.onHideCount);
         FragmentTestUtil.assertChildren(mContainer, fragment1);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
@@ -445,7 +443,7 @@
 
         final CountCallsFragment fragment2 = new CountCallsFragment();
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -470,7 +468,7 @@
     @Test
     public void addPopBackStack() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -493,7 +491,7 @@
     public void popNonBackStack() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final CountCallsFragment fragment2 = new CountCallsFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
@@ -519,7 +517,7 @@
     public void noOptimization() throws Throwable {
         final CountCallsFragment fragment1 = new CountCallsFragment();
         final CountCallsFragment fragment2 = new CountCallsFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFM.beginTransaction()
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
index c175164..62c4906 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -23,10 +23,8 @@
 import android.app.FragmentController;
 import android.app.FragmentManager;
 import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
 import android.os.Looper;
 import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Pair;
 import android.view.View;
@@ -42,9 +40,14 @@
         // the UI thread and then the execution will be added onto the queue after that.
         // The two-cycle wait makes sure fragments have the opportunity to complete both
         // before returning.
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        instrumentation.runOnMainSync(() -> {});
-        instrumentation.runOnMainSync(() -> {});
+        try {
+            rule.runOnUiThread(() -> {
+            });
+            rule.runOnUiThread(() -> {
+            });
+        } catch (Throwable t) {
+            throw new RuntimeException(t);
+        }
     }
 
     private static void runOnUiThreadRethrow(ActivityTestRule<? extends Activity> rule,
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
index aec30c1..7deea1b 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransactionTest.java
@@ -20,6 +20,10 @@
 import static junit.framework.TestCase.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -354,6 +358,51 @@
         }
     }
 
+    @Test
+    public void testGetLayoutInflater() throws Throwable {
+        mActivityRule.runOnUiThread(() -> {
+            final OnGetLayoutInflaterFragment fragment1 = new OnGetLayoutInflaterFragment();
+            assertEquals(0, fragment1.onGetLayoutInflaterCalls);
+            mActivity.getFragmentManager().beginTransaction()
+                    .add(android.R.id.content, fragment1)
+                    .addToBackStack(null)
+                    .commit();
+            mActivity.getFragmentManager().executePendingTransactions();
+            assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+            assertEquals(fragment1.layoutInflater, fragment1.getLayoutInflater());
+            // getLayoutInflater() didn't force onGetLayoutInflater()
+            assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+            LayoutInflater layoutInflater = fragment1.layoutInflater;
+            // Replacing fragment1 won't detach it, so the value won't be cleared
+            final OnGetLayoutInflaterFragment fragment2 = new OnGetLayoutInflaterFragment();
+            mActivity.getFragmentManager().beginTransaction()
+                    .replace(android.R.id.content, fragment2)
+                    .addToBackStack(null)
+                    .commit();
+            mActivity.getFragmentManager().executePendingTransactions();
+
+            assertSame(layoutInflater, fragment1.getLayoutInflater());
+            assertEquals(1, fragment1.onGetLayoutInflaterCalls);
+
+            // Popping it should cause onCreateView again, so a new LayoutInflater...
+            mActivity.getFragmentManager().popBackStackImmediate();
+            assertNotSame(layoutInflater, fragment1.getLayoutInflater());
+            assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+            layoutInflater = fragment1.layoutInflater;
+            assertSame(layoutInflater, fragment1.getLayoutInflater());
+
+            // Popping it should detach it, clearing the cached value again
+            mActivity.getFragmentManager().popBackStackImmediate();
+
+            // once it is detached, the getLayoutInflater() will default to throw
+            // an exception, but we've made it return null instead.
+            assertEquals(2, fragment1.onGetLayoutInflaterCalls);
+            assertNull(fragment1.getLayoutInflater());
+            assertEquals(3, fragment1.onGetLayoutInflaterCalls);
+        });
+    }
+
     private void getFragmentsUntilSize(int expectedSize) {
         final long endTime = SystemClock.uptimeMillis() + 3000;
 
@@ -377,4 +426,26 @@
             return inflater.inflate(R.layout.text_a, container, false);
         }
     }
+
+    public static class OnGetLayoutInflaterFragment extends Fragment {
+        public int onGetLayoutInflaterCalls = 0;
+        public LayoutInflater layoutInflater;
+
+        @Override
+        public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+            onGetLayoutInflaterCalls++;
+            try {
+                layoutInflater = super.onGetLayoutInflater(savedInstanceState);
+            } catch (Exception e) {
+                return null;
+            }
+            return layoutInflater;
+        }
+
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.text_a, container, false);
+        }
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
index 43a9590..742137706 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -15,7 +15,8 @@
  */
 package android.fragment.cts;
 
-import static junit.framework.Assert.*;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.fail;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
@@ -23,22 +24,20 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 
-import com.android.compatibility.common.util.transition.TargetTracking;
-import com.android.compatibility.common.util.transition.TrackingTransition;
-
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
-import android.app.Instrumentation;
 import android.app.SharedElementCallback;
 import android.graphics.Rect;
 import android.os.Bundle;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.transition.TransitionSet;
 import android.view.View;
 
+import com.android.compatibility.common.util.transition.TargetTracking;
+import com.android.compatibility.common.util.transition.TrackingTransition;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -68,7 +67,6 @@
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
-    private Instrumentation mInstrumentation;
     private FragmentManager mFragmentManager;
 
     public FragmentTransitionTest(final boolean optimize) {
@@ -77,7 +75,6 @@
 
     @Before
     public void setup() throws Throwable {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mFragmentManager = mActivityRule.getActivity().getFragmentManager();
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
     }
@@ -163,7 +160,7 @@
         final TransitionFragment fragment2 = new TransitionFragment();
         fragment2.setLayoutId(R.layout.scene2);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 mFragmentManager.beginTransaction()
@@ -966,7 +963,7 @@
         final View startRed = findRed();
         final Rect startSharedRect = getBoundsOnScreen(startBlue);
 
-        mInstrumentation.runOnMainSync(() -> {
+        mActivityRule.runOnUiThread(() -> {
             for (int i = 0; i < numPops; i++) {
                 mFragmentManager.popBackStack();
             }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
index 6f96811..e9c80e0 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -46,13 +46,6 @@
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
-    private Instrumentation mInstrumentation;
-
-    @Before
-    public void setupInstrumentation() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-    }
-
     // Test that adding a fragment adds the Views in the proper order. Popping the back stack
     // should remove the correct Views.
     @Test
@@ -156,7 +149,7 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment1).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 try {
@@ -917,7 +910,7 @@
 
         final StrictViewFragment fragment2 = new StrictViewFragment();
         final StrictViewFragment fragment3 = new StrictViewFragment();
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 fm.popBackStack();
diff --git a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
index a3c43aa..2b89bc2 100644
--- a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
@@ -26,10 +26,8 @@
 import android.app.FragmentController;
 import android.app.FragmentManager;
 import android.app.FragmentManagerNonConfig;
-import android.app.Instrumentation;
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -50,12 +48,10 @@
     public ActivityTestRule<FragmentTestActivity> mActivityRule =
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
-    private Instrumentation mInstrumentation;
     private PostponedFragment1 mBeginningFragment;
 
     @Before
     public void setupContainer() throws Throwable {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         mBeginningFragment = new PostponedFragment1();
@@ -119,7 +115,7 @@
         final int commit[] = new int[1];
         // Need to run this on the UI thread so that the transaction doesn't start
         // between the two
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 commit[0] = fm.beginTransaction()
@@ -489,7 +485,7 @@
         final TransitionFragment fragment4 = new PostponedFragment2();
         final StrictFragment strictFragment2 = new StrictFragment();
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 fm.beginTransaction()
@@ -539,7 +535,7 @@
 
         final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
 
-        mInstrumentation.runOnMainSync(new Runnable() {
+        mActivityRule.runOnUiThread(new Runnable() {
             @Override
             public void run() {
                 fm.beginTransaction()
@@ -664,7 +660,7 @@
         assertTrue(fragment2.isAdded());
         assertTrue(fragment2.getView().isAttachedToWindow());
 
-        mInstrumentation.runOnMainSync(() -> {
+        mActivityRule.runOnUiThread(() -> {
             assertTrue(fm2.popBackStackImmediate());
         });
 
diff --git a/hostsidetests/webkit/renderprocesscrash/Android.mk b/tests/pdf/Android.mk
similarity index 70%
rename from hostsidetests/webkit/renderprocesscrash/Android.mk
rename to tests/pdf/Android.mk
index 846cdc8..1e4a1ca 100644
--- a/hostsidetests/webkit/renderprocesscrash/Android.mk
+++ b/tests/pdf/Android.mk
@@ -1,4 +1,3 @@
-#
 # Copyright (C) 2017 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,25 +11,34 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-#
 
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
-# Don't include this package in any target.
 LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES :=
+
+LOCAL_MULTILIB := both
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target-minus-junit4 \
+    compatibility-device-util \
+    ctstestrunner \
+    android-support-annotations \
+    junit \
+    legacy-android-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := CtsWebViewRendererCrash
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts
 
-include $(BUILD_CTS_SUPPORT_PACKAGE)
+LOCAL_PACKAGE_NAME := CtsPdfTestCases
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_CTS_PACKAGE)
+
diff --git a/tests/pdf/AndroidManifest.xml b/tests/pdf/AndroidManifest.xml
new file mode 100644
index 0000000..495b5da
--- /dev/null
+++ b/tests/pdf/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * 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.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.graphics.pdf.cts">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.graphics.pdf.cts"
+                     android:label="CTS tests of android.graphics.pdf">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/pdf/AndroidTest.xml b/tests/pdf/AndroidTest.xml
new file mode 100644
index 0000000..e7c0794
--- /dev/null
+++ b/tests/pdf/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for CTS Pdf test cases">
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsPdfTestCases.apk" />
+    </target_preparer>
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.graphics.pdf.cts" />
+        <option name="runtime-hint" value="5m" />
+    </test>
+</configuration>
diff --git a/tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf b/tests/pdf/res/raw/a4_portrait_rgbb.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a4_portrait_rgbb.pdf
rename to tests/pdf/res/raw/a4_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf b/tests/pdf/res/raw/a5_portrait_rgbb.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf b/tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_default.pdf
Binary files differ
diff --git a/tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf b/tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
rename to tests/pdf/res/raw/a5_portrait_rgbb_1_6_printscaling_none.pdf
Binary files differ
diff --git a/tests/pdf/res/raw/testimage.jpg b/tests/pdf/res/raw/testimage.jpg
new file mode 100644
index 0000000..d3dae03
--- /dev/null
+++ b/tests/pdf/res/raw/testimage.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/raw/two_pages.pdf b/tests/pdf/res/raw/two_pages.pdf
similarity index 100%
rename from tests/tests/graphics/res/raw/two_pages.pdf
rename to tests/pdf/res/raw/two_pages.pdf
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfDocumentTest.java
similarity index 100%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfDocumentTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfDocumentTest.java
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
similarity index 99%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
index 530ac1b..2f0158e 100644
--- a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTest.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTest.java
@@ -34,7 +34,7 @@
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.graphics.cts.R;
+import android.graphics.pdf.cts.R;
 import android.graphics.pdf.PdfRenderer;
 import android.graphics.pdf.PdfRenderer.Page;
 import android.os.ParcelFileDescriptor;
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java b/tests/pdf/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
similarity index 100%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
rename to tests/pdf/src/android/graphics/pdf/cts/PdfRendererTransformTest.java
diff --git a/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java b/tests/pdf/src/android/graphics/pdf/cts/Utils.java
similarity index 98%
rename from tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
rename to tests/pdf/src/android/graphics/pdf/cts/Utils.java
index 2e2de3e..4d43e09 100644
--- a/tests/tests/graphics/src/android/graphics/pdf/cts/Utils.java
+++ b/tests/pdf/src/android/graphics/pdf/cts/Utils.java
@@ -53,8 +53,8 @@
 
     static final int A4_WIDTH_PTS = 595;
     static final int A4_HEIGHT_PTS = 841;
-    static final int A4_PORTRAIT = android.graphics.cts.R.raw.a4_portrait_rgbb;
-    static final int A5_PORTRAIT = android.graphics.cts.R.raw.a5_portrait_rgbb;
+    static final int A4_PORTRAIT = android.graphics.pdf.cts.R.raw.a4_portrait_rgbb;
+    static final int A5_PORTRAIT = android.graphics.pdf.cts.R.raw.a5_portrait_rgbb;
 
     /**
      * Create a {@link PdfRenderer} pointing to a file copied from a resource.
diff --git a/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
index 40a5ff7..4c8b323 100644
--- a/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
+++ b/tests/sensor/jni/android_hardware_cts_SensorNativeTest.cpp
@@ -54,7 +54,7 @@
     std::vector<int32_t> rates = {
         ASENSOR_DIRECT_RATE_NORMAL, ASENSOR_DIRECT_RATE_FAST, ASENSOR_DIRECT_RATE_VERY_FAST};
     std::vector<int32_t> channelTypes =
-        {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY};
+        {ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER};
     for (auto s : sensorTypes) {
         for (auto c : channelTypes) {
             for (auto r : rates) {
diff --git a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
index 547f44c..8866a39 100644
--- a/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
+++ b/tests/sensor/src/android/hardware/cts/SensorDirectReportTest.java
@@ -40,7 +40,6 @@
  *
  * This testcase tests operation of:
  *   - SensorManager.createDirectChannel()
- *   - SensorManager.configureDirectReport()
  *   - SensorDirectChannel.*
  *   - Sensor.getHighestDirectReportRateLevel()
  *   - Sensor.isDirectChannelTypeSupported()
@@ -89,7 +88,7 @@
     protected void setUp() throws Exception {
         mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
 
-        mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_ASHMEM);
+        mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_MEMORY_FILE);
         mNeedHardwareBuffer = isMemoryTypeNeeded(SensorDirectChannel.TYPE_HARDWARE_BUFFER);
 
         if (mNeedMemoryFile) {
@@ -129,28 +128,28 @@
     public void testAccelerometerAshmemNormal() {
         runSensorDirectReportTest(
                 Sensor.TYPE_ACCELEROMETER,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_NORMAL);
     }
 
     public void testGyroscopeAshmemNormal() {
         runSensorDirectReportTest(
                 Sensor.TYPE_GYROSCOPE,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_NORMAL);
     }
 
     public void testMagneticFieldAshmemNormal() {
         runSensorDirectReportTest(
                 Sensor.TYPE_MAGNETIC_FIELD,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_NORMAL);
     }
 
     public void testAccelerometerAshmemFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_ACCELEROMETER,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_FAST);
 
     }
@@ -158,21 +157,21 @@
     public void testGyroscopeAshmemFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_GYROSCOPE,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_FAST);
     }
 
     public void testMagneticFieldAshmemFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_MAGNETIC_FIELD,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_FAST);
     }
 
     public void testAccelerometerAshmemVeryFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_ACCELEROMETER,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_VERY_FAST);
 
     }
@@ -180,14 +179,14 @@
     public void testGyroscopeAshmemVeryFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_GYROSCOPE,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_VERY_FAST);
     }
 
     public void testMagneticFieldAshmemVeryFast() {
         runSensorDirectReportTest(
                 Sensor.TYPE_MAGNETIC_FIELD,
-                SensorDirectChannel.TYPE_ASHMEM,
+                SensorDirectChannel.TYPE_MEMORY_FILE,
                 SensorDirectChannel.RATE_VERY_FAST);
     }
 
@@ -263,39 +262,40 @@
             return;
         }
 
-        mChannel = null;
         try {
             switch(memType) {
-                case SensorDirectChannel.TYPE_ASHMEM:
+                case SensorDirectChannel.TYPE_MEMORY_FILE:
                     assertTrue("MemoryFile is null", mMemoryFile != null);
                     mChannel = mSensorManager.createDirectChannel(mMemoryFile);
-                    assertTrue("createDirectChannel(MemoryFile) failed", mChannel != null);
                     break;
                 case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
                     assertTrue("HardwareBuffer is null", mHardwareBuffer != null);
                     mChannel = mSensorManager.createDirectChannel(mHardwareBuffer);
-                    assertTrue("createDirectChannel(HardwareBuffer) failed", mChannel != null);
                     break;
                 default:
                     Log.e(TAG, "Specified illegal memory type " + memType);
                     return;
             }
+        } catch (IllegalStateException e) {
+            mChannel = null;
+        }
+        assertTrue("createDirectChannel failed", mChannel != null);
+
+        try {
             assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
             waitBeforeStartSensor();
 
-            int token = mSensorManager.configureDirectChannel(mChannel, s, rateLevel);
+            int token = mChannel.configure(s, rateLevel);
             assertTrue("configure direct mChannel failed", token > 0);
 
             waitSensorCollection();
 
             //stop sensor and analyze content
-            mSensorManager.configureDirectChannel(mChannel, s, SensorDirectChannel.RATE_STOP);
+            mChannel.configure(s, SensorDirectChannel.RATE_STOP);
             checkSharedMemoryContent(s, memType, rateLevel, token);
         } finally {
-            if (mChannel != null) {
-                mChannel.close();
-                mChannel = null;
-            }
+            mChannel.close();
+            mChannel = null;
         }
     }
 
@@ -348,7 +348,7 @@
     }
 
     private boolean isSharedMemoryFormatted(int memType) {
-        if (memType == SensorDirectChannel.TYPE_ASHMEM) {
+        if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
             if (!readMemoryFileContent()) {
                 Log.e(TAG, "Read MemoryFile content fail");
                 return false;
@@ -369,7 +369,7 @@
     }
 
     private void checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token) {
-        if (memType == SensorDirectChannel.TYPE_ASHMEM) {
+        if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
             assertTrue("read MemoryFile content failed", readMemoryFileContent());
         } else {
             assertTrue("read HardwareBuffer content failed", readHardwareBufferContent());
diff --git a/tests/signature/Android.mk b/tests/signature/Android.mk
index 6a8dcf9..8502c59 100644
--- a/tests/signature/Android.mk
+++ b/tests/signature/Android.mk
@@ -27,7 +27,9 @@
 
 LOCAL_SDK_VERSION := current
 
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner \
+    compatibility-device-util \
+    android-support-test
 
 include $(BUILD_CTS_PACKAGE)
 
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/AndroidManifest.xml
index 52090ce..41a4233 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/AndroidManifest.xml
@@ -17,6 +17,7 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.signature.cts">
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
 
     <application>
@@ -27,4 +28,4 @@
                      android:targetPackage="android.signature.cts"
                      android:label="API Signature Test"/>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/AndroidTest.xml
index 038d0d0..6d23620 100644
--- a/tests/signature/AndroidTest.xml
+++ b/tests/signature/AndroidTest.xml
@@ -14,6 +14,11 @@
      limitations under the License.
 -->
 <configuration description="Config for CTS Signature test cases">
+   <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+        <option name="target" value="device" />
+        <option name="config-filename" value="CtsSignatureTestCases" />
+        <option name="version" value="1.0" />
+    </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="run-command" value="mkdir -p /data/local/tmp/signature-test-packages" />
         <option name='run-command'
diff --git a/tests/signature/DynamicConfig.xml b/tests/signature/DynamicConfig.xml
new file mode 100644
index 0000000..e078476
--- /dev/null
+++ b/tests/signature/DynamicConfig.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 Google Inc.
+
+     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.
+-->
+<!--
+    Bug: 33305737 android.intent.action.ACTION_CARRIER_SETUP
+    Bug: 36980009 android.intent.action.QUICKBOOT_POWERON
+    Bug: 36977779 android.intent.action.MASTER_CLEAR
+-->
+<dynamicConfig>
+    <entry key ="intent_whitelist">
+      <value>android.intent.action.ACTION_CARRIER_SETUP</value>
+      <value>android.intent.action.QUICKBOOT_POWERON</value>
+    </entry>
+</dynamicConfig>
diff --git a/tests/signature/src/android/signature/cts/IntentTest.java b/tests/signature/src/android/signature/cts/IntentTest.java
index c0d3e84..3d674ab 100644
--- a/tests/signature/src/android/signature/cts/IntentTest.java
+++ b/tests/signature/src/android/signature/cts/IntentTest.java
@@ -57,6 +57,8 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 
+import com.android.compatibility.common.util.DynamicConfigDeviceSide;
+
 import java.io.BufferedReader;
 import java.io.InputStreamReader;
 import java.io.IOException;
@@ -90,19 +92,21 @@
             new File("/data/local/tmp/signature-test-packages");
     private static final String ANDROID_INTENT_PREFIX = "android.intent.action";
     private static final String ACTION_LINE_PREFIX = "          Action: ";
-    private static final Set<String> INTENT_WHITELIST = getIntentWhitelist();
+    private static final String MODULE_NAME = "CtsSignatureTestCases";
 
     private PackageManager mPackageManager;
+    private Set<String> intentWhitelist;
 
     @Before
-    public void setupPackageManager() {
+    public void setupPackageManager() throws Exception {
       mPackageManager = InstrumentationRegistry.getContext().getPackageManager();
+      intentWhitelist = getIntentWhitelist();
     }
 
     @Test
     public void shouldNotFindUnexpectedIntents() throws Exception {
         Set<String> platformIntents = lookupPlatformIntents();
-        platformIntents.addAll(INTENT_WHITELIST);
+        platformIntents.addAll(intentWhitelist);
 
         Set<String> allInvalidIntents = new HashSet<>();
 
@@ -268,9 +272,18 @@
         }
     }
 
-    private static Set<String> getIntentWhitelist() {
+    private static Set<String> getIntentWhitelist() throws Exception {
         Set<String> whitelist = new HashSet<>();
 
+        DynamicConfigDeviceSide dcds = new DynamicConfigDeviceSide(MODULE_NAME);
+        List<String> intentWhitelist = dcds.getValues("intent_whitelist");
+
+        // Log the whitelist Intent
+        for (String intent : intentWhitelist) {
+           Log.d(TAG, String.format("whitelist add: %s", intent));
+           whitelist.add(intent);
+        }
+
         return whitelist;
     }
 }
diff --git a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
index a017b6c..747a8bd 100644
--- a/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
+++ b/tests/tests/appwidget/src/android/appwidget/cts/AppWidgetTest.java
@@ -174,6 +174,38 @@
         }
     }
 
+    public void testGetAppWidgetIdsForHost() throws Exception {
+        if (!hasAppWidgets()) {
+            return;
+        }
+        AppWidgetHost host1 = new AppWidgetHost(getInstrumentation().getTargetContext(), 1);
+        AppWidgetHost host2 = new AppWidgetHost(getInstrumentation().getTargetContext(), 2);
+
+        host1.deleteHost();
+        host2.deleteHost();
+
+        assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+        assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+        int id1 = host1.allocateAppWidgetId();
+        assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1}));
+        assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+        int id2 = host1.allocateAppWidgetId();
+        assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+        assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{}));
+
+        int id3 = host2.allocateAppWidgetId();
+        assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{id1, id2}));
+        assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+        host1.deleteHost();
+        assertTrue(Arrays.equals(host1.getAppWidgetIds(), new int[]{}));
+        assertTrue(Arrays.equals(host2.getAppWidgetIds(), new int[]{id3}));
+
+        host2.deleteHost();
+    }
+
     public void testAppWidgetProviderCallbacks() throws Exception {
         if (!hasAppWidgets()) {
             return;
@@ -380,7 +412,7 @@
         }
     }
 
-    public void testGetAppWidgetIds() throws Exception {
+    public void testGetAppWidgetIdsForProvider() throws Exception {
         if (!hasAppWidgets()) {
             return;
         }
diff --git a/tests/tests/bluetooth/Android.mk b/tests/tests/bluetooth/Android.mk
index d980e37..c02b23d 100644
--- a/tests/tests/bluetooth/Android.mk
+++ b/tests/tests/bluetooth/Android.mk
@@ -25,6 +25,7 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
+LOCAL_JAVA_LIBRARIES += android.test.runner
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index fd1c7d2..066de74 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.PackageManager;
 import android.os.ParcelUuid;
 import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Log;
@@ -85,6 +86,9 @@
         if (!mLocationOn) {
             TestUtils.enableLocation(getContext());
         }
+        InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                "pm grant android.bluetooth.cts android.permission.ACCESS_COARSE_LOCATION"
+        );
     }
 
     @Override
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index 6d8126c..f9a5915 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -94,6 +94,11 @@
         android:requiredFeature="android.software.cts"
         android:requiredNotFeature="android.software.cts.undefined" />
 
+    <permission android:name="android.content.cts.SIGNATURE_PERMISSION"
+        android:protectionLevel="signature" />
+
+    <uses-permission android:name="android.content.cts.SIGNATURE_PERMISSION" />
+
     <!-- Used for PackageManager test, don't delete! -->
     <uses-configuration/>
     <uses-feature android:name="android.hardware.camera" />
@@ -154,7 +159,8 @@
                 <action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_TESTABORT" />
             </intent-filter>
         </receiver>
-        <receiver android:name="android.content.cts.MockReceiver">
+        <receiver android:name="android.content.cts.MockReceiver"
+                android:permission="android.content.cts.SIGNATURE_PERMISSION">
             <intent-filter android:priority="1">
                 <action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_MOCKTEST" />
                 <action android:name="android.content.cts.BroadcastReceiverTest.BROADCAST_TESTABORT" />
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 096eef9..e34aa6e 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -331,14 +331,20 @@
     }
  
     public void testVoiceCommand() {
-        Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
-        assertCanBeHandled(intent);
-        assertDefaultHandlerValidPriority(intent);
+        PackageManager packageManager = mContext.getPackageManager();
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+            Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
+            assertCanBeHandled(intent);
+            assertDefaultHandlerValidPriority(intent);
+        }
     }
 
     public void testVoiceSearchHandsFree() {
-        Intent intent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
-        assertCanBeHandled(intent);
-        assertDefaultHandlerValidPriority(intent);
+        PackageManager packageManager = mContext.getPackageManager();
+        if (packageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE)) {
+            Intent intent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
+            assertCanBeHandled(intent);
+            assertDefaultHandlerValidPriority(intent);
+        }
     }
 }
diff --git a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
index 8f9aba69..d62d322 100644
--- a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
+++ b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
@@ -51,6 +51,8 @@
             "android.content.cts.BroadcastReceiverTest.BROADCAST_DISABLED";
     private static final String TEST_PACKAGE_NAME = "android.content.cts";
 
+    private static final String SIGNATURE_PERMISSION = "android.content.cts.SIGNATURE_PERMISSION";
+
     private static final long SEND_BROADCAST_TIMEOUT = 15000;
     private static final long START_SERVICE_TIMEOUT  = 3000;
 
@@ -183,8 +185,8 @@
         activity.unregisterReceiver(internalReceiver);
     }
 
-    public void testOnReceiverOrdered() throws InterruptedException {
-        MockReceiverInternalOrder internalOrderReceiver = new MockReceiverInternalOrder();
+    public void testManifestReceiverPackage() throws InterruptedException {
+        MockReceiverInternal internalReceiver = new MockReceiverInternal();
 
         Bundle map = new Bundle();
         map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
@@ -194,14 +196,15 @@
         getInstrumentation().getContext().sendOrderedBroadcast(
                 new Intent(ACTION_BROADCAST_MOCKTEST)
                         .setPackage(TEST_PACKAGE_NAME).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
-                null, internalOrderReceiver,
+                null, internalReceiver,
                 null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
-        internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+        internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
 
-        assertEquals(RESULT_INTERNAL_FINAL_CODE, internalOrderReceiver.getResultCode());
-        assertEquals(RESULT_INTERNAL_FINAL_DATA, internalOrderReceiver.getResultData());
+        // These are set by MockReceiver.
+        assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+        assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
 
-        Bundle resultExtras = internalOrderReceiver.getResultExtras(false);
+        Bundle resultExtras = internalReceiver.getResultExtras(false);
         assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
                 resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
         assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
@@ -209,6 +212,87 @@
         assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
     }
 
+    public void testManifestReceiverComponent() throws InterruptedException {
+        MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+        Bundle map = new Bundle();
+        map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+                MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+        map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+                MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+        getInstrumentation().getContext().sendOrderedBroadcast(
+                new Intent(ACTION_BROADCAST_MOCKTEST)
+                        .setClass(getActivity(), MockReceiver.class)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                null, internalReceiver,
+                null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+        internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+        // These are set by MockReceiver.
+        assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+        assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
+
+        Bundle resultExtras = internalReceiver.getResultExtras(false);
+        assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+        assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+        assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+    }
+
+    public void testManifestReceiverPermission() throws InterruptedException {
+        MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+        Bundle map = new Bundle();
+        map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+                MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+        map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+                MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+        getInstrumentation().getContext().sendOrderedBroadcast(
+                new Intent(ACTION_BROADCAST_MOCKTEST)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                SIGNATURE_PERMISSION, internalReceiver,
+                null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+        internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+        // These are set by MockReceiver.
+        assertEquals(MockReceiver.RESULT_CODE, internalReceiver.getResultCode());
+        assertEquals(MockReceiver.RESULT_DATA, internalReceiver.getResultData());
+
+        Bundle resultExtras = internalReceiver.getResultExtras(false);
+        assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+        assertEquals(MockReceiver.RESULT_EXTRAS_ADD_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+        assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+    }
+
+    public void testNoManifestReceiver() throws InterruptedException {
+        MockReceiverInternal internalReceiver = new MockReceiverInternal();
+
+        Bundle map = new Bundle();
+        map.putString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY,
+                MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE);
+        map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
+                MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
+        getInstrumentation().getContext().sendOrderedBroadcast(
+                new Intent(ACTION_BROADCAST_MOCKTEST).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                null, internalReceiver,
+                null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
+        internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
+
+        // The MockReceiver should not have run, so we should still have the initial result.
+        assertEquals(RESULT_INITIAL_CODE, internalReceiver.getResultCode());
+        assertEquals(RESULT_INITIAL_DATA, internalReceiver.getResultData());
+
+        Bundle resultExtras = internalReceiver.getResultExtras(false);
+        assertEquals(MockReceiver.RESULT_EXTRAS_INVARIABLE_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_INVARIABLE_KEY));
+        assertNull(resultExtras.getString(MockReceiver.RESULT_EXTRAS_ADD_KEY));
+        assertEquals(MockReceiver.RESULT_EXTRAS_REMOVE_VALUE,
+                resultExtras.getString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY));
+    }
+
     public void testAbortBroadcast() throws InterruptedException {
         MockReceiverInternalOrder internalOrderReceiver = new MockReceiverInternalOrder();
 
diff --git a/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java b/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
index a69a3f8..bd9756e 100644
--- a/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
+++ b/tests/tests/content/src/android/content/cts/ClipDescriptionTest.java
@@ -21,7 +21,6 @@
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.Context;
-import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
@@ -30,6 +29,12 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Calendar;
+
+/**
+ * To run:
+ * cts-tradefed run singleCommand cts-dev -m CtsContentTestCases -t android.content.cts.ClipDescriptionTest
+ */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class ClipDescriptionTest {
@@ -37,17 +42,35 @@
     @Test
     public void testGetTimestamp() {
         final ClipboardManager clipboardManager = (ClipboardManager)
-                InstrumentationRegistry.getTargetContext().getSystemService(Context.CLIPBOARD_SERVICE);
-        final long timestampBeforeSet = SystemClock.elapsedRealtime();
+                InstrumentationRegistry.getTargetContext().getSystemService(
+                        Context.CLIPBOARD_SERVICE);
+        final long timestampBeforeSet = System.currentTimeMillis();
         clipboardManager.setPrimaryClip(ClipData.newPlainText("Dummy text", "Text"));
-        final long timestampAfterSet = SystemClock.elapsedRealtime();
+        final long timestampAfterSet = System.currentTimeMillis();
         final long timestamp = clipboardManager.getPrimaryClipDescription().getTimestamp();
         if (timestamp < timestampBeforeSet || timestamp > timestampAfterSet) {
             fail("Value of timestamp is not as expected.\n"
-                    + "timestamp before setting clip: " + timestampBeforeSet + "\n"
-                    + "timestamp after setting clip: " + timestampAfterSet + "\n"
-                    + "actual timestamp: " + timestamp
+                    + "timestamp before setting clip: " + logTime(timestampBeforeSet) + "\n"
+                    + "timestamp after setting clip: " + logTime(timestampAfterSet) + "\n"
+                    + "actual timestamp: " + logTime(timestamp) + "\n"
                     + "clipdata: " + clipboardManager.getPrimaryClip());
         }
     }
+
+    /**
+     * Convert a System.currentTimeMillis() value to a time of day value like
+     * that printed in logs. MM-DD-YY HH:MM:SS.MMM
+     *
+     * @param millis since the epoch (1/1/1970)
+     * @return String representation of the time.
+     */
+    public static String logTime(long millis) {
+        Calendar c = Calendar.getInstance();
+        if (millis >= 0) {
+            c.setTimeInMillis(millis);
+            return String.format("%tm-%td-%ty %tH:%tM:%tS.%tL", c, c, c, c, c, c, c);
+        } else {
+            return Long.toString(millis);
+        }
+    }
 }
\ No newline at end of file
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index 0ceda3a..e5e8fe4 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -24,7 +24,6 @@
 import android.content.res.AssetFileDescriptor;
 import android.database.ContentObserver;
 import android.database.Cursor;
-import android.database.PageViewCursor;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -35,6 +34,7 @@
 import android.util.Log;
 
 import com.android.compatibility.common.util.PollingCheck;
+import com.android.internal.util.ArrayUtils;
 
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -419,41 +419,10 @@
     }
 
     /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
+     * Verifies that paging information is correctly relayed, and that
+     * honored arguments from a supporting client are returned correctly.
      */
-    public void testQuery_InProcessProvider_NoAutoPaging() {
-
-        mContentResolver.delete(TABLE1_URI, null, null);
-        ContentValues values = new ContentValues();
-
-        for (int i = 0; i < 100; i++) {
-            values.put(COLUMN_KEY_NAME, i);
-            mContentResolver.insert(TABLE1_URI, values);
-        }
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
-
-        mCursor = mContentResolver.query(TABLE1_URI, null, queryArgs, null);
-        int col = mCursor.getColumnIndexOrThrow(COLUMN_KEY_NAME);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(100, mCursor.getCount());
-        assertFalse(extras.containsKey(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertFalse(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
-     */
-    public void testQuery_OutOfProcessProvider_AutoPaging() {
+    public void testQuery_PagedResults() {
 
         Bundle queryArgs = new Bundle();
         queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
@@ -461,88 +430,30 @@
         queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
 
         mCursor = mContentResolver.query(
-                TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(3, mCursor.getCount());
-        assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
-        mCursor.moveToNext();
-        assertEquals(10, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(11, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(12, mCursor.getInt(col));
-
-        assertFalse(mCursor.moveToNext());
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that paging arguments are handled correctly
-     * when the provider supports paging.
-     */
-    public void testQuery_OutOfProcessProvider_AutoPaging_OffsetOutOfBounds() {
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 10);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 3);
-        queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 100);
-
-        mCursor = mContentResolver.query(
-                TestPagingContentProvider.UNPAGED_DATA_URI, null, queryArgs, null);
-
-        Bundle extras = mCursor.getExtras();
-        extras = extras != null ? extras : Bundle.EMPTY;
-
-        assertEquals(3, mCursor.getCount());
-        assertTrue(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
-        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
-        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
-
-        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
-
-        mCursor.moveToNext();
-        assertEquals(10, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(11, mCursor.getInt(col));
-        mCursor.moveToNext();
-        assertEquals(12, mCursor.getInt(col));
-
-        assertFalse(mCursor.moveToNext());
-
-        mCursor.close();
-    }
-
-    /**
-     * Verifies that auto-paging isn't applied when the underlying remote
-     * provider has already applied paging.
-     */
-    public void testQuery_OutOfProcessProvider_NoAutoPagingForAlreadyPagedResults() {
-
-        Bundle queryArgs = new Bundle();
-        queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 20);
-        queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 2);
-        queryArgs.putInt(TestPagingContentProvider.RECORDSET_SIZE, 500);
-
-        mCursor = mContentResolver.query(
                 TestPagingContentProvider.PAGED_DATA_URI, null, queryArgs, null);
 
         Bundle extras = mCursor.getExtras();
         extras = extras != null ? extras : Bundle.EMPTY;
 
-        assertFalse(extras.getBoolean(PageViewCursor.EXTRA_AUTO_PAGED));
+        assertEquals(3, mCursor.getCount());
+        assertTrue(extras.containsKey(ContentResolver.EXTRA_TOTAL_SIZE));
+        assertEquals(100, extras.getInt(ContentResolver.EXTRA_TOTAL_SIZE));
 
-        // we don't test the contents of the self-paged cursor
-        // because that's provided by TestPagingContentProvider
-        // a test-only test support class.
+        String[] honoredArgs = extras.getStringArray(ContentResolver.EXTRA_HONORED_ARGS);
+        assertNotNull(honoredArgs);
+        assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_OFFSET));
+        assertTrue(ArrayUtils.contains(honoredArgs, ContentResolver.QUERY_ARG_LIMIT));
+
+        int col = mCursor.getColumnIndexOrThrow(TestPagingContentProvider.COLUMN_POS);
+
+        mCursor.moveToNext();
+        assertEquals(10, mCursor.getInt(col));
+        mCursor.moveToNext();
+        assertEquals(11, mCursor.getInt(col));
+        mCursor.moveToNext();
+        assertEquals(12, mCursor.getInt(col));
+
+        assertFalse(mCursor.moveToNext());
 
         mCursor.close();
     }
diff --git a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
index 5137d8a..c937e2a 100644
--- a/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ComponentInfoTest.java
@@ -20,11 +20,11 @@
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.graphics.drawable.BitmapDrawable;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.test.AndroidTestCase;
-import android.util.LauncherIcons;
 import android.util.Printer;
 import android.util.StringBuilderPrinter;
 
@@ -68,9 +68,15 @@
         }
     }
 
-    public void testLoadIcon() {
+    private Bitmap createIconBitmap(Drawable d) {
+        int size = Math.round(100 * getContext().getResources().getDisplayMetrics().density) + 100;
+        Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+        d.setBounds(0, 0, size, size);
+        d.draw(new Canvas(bitmap));
+        return bitmap;
+    }
 
-        LauncherIcons launcherIcons = new LauncherIcons(getContext());
+    public void testLoadIcon() {
         mComponentInfo = new ComponentInfo();
         mComponentInfo.applicationInfo = new ApplicationInfo();
 
@@ -83,14 +89,12 @@
         d = mComponentInfo.loadIcon(pm);
         assertNotNull(d);
         assertNotSame(d, defaultIcon);
-        WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
-                launcherIcons.createIconBitmap(defaultIcon));
+        WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(defaultIcon));
 
         d2 = mComponentInfo.loadIcon(pm);
         assertNotNull(d2);
         assertNotSame(d, d2);
-        WidgetTestUtils.assertEquals(launcherIcons.createIconBitmap(d),
-                launcherIcons.createIconBitmap(d2));
+        WidgetTestUtils.assertEquals(createIconBitmap(d), createIconBitmap(d2));
 
         try {
             mComponentInfo.loadIcon(null);
diff --git a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
index 45418cf..3015b07 100644
--- a/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
+++ b/tests/tests/dpi/src/android/dpi/cts/ConfigurationScreenLayoutTest.java
@@ -49,6 +49,11 @@
         // Check that all four orientations report the same configuration value.
         for (int i = 0; i < ORIENTATIONS.length; i++) {
             Activity activity = startOrientationActivity(ORIENTATIONS[i]);
+            if (activity.isInMultiWindowMode()) {
+                // activity.setRequestedOrientation has no effect in multiwindow mode.
+                tearDown();
+                return;
+            }
             Configuration mConfig = activity.getResources().getConfiguration();
             int actualSize = mConfig.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
             int actualLong = mConfig.screenLayout & Configuration.SCREENLAYOUT_LONG_MASK;
diff --git a/tests/tests/graphics/assets/red-adobergb.png b/tests/tests/graphics/assets/red-adobergb.png
new file mode 100644
index 0000000..adbff91
--- /dev/null
+++ b/tests/tests/graphics/assets/red-adobergb.png
Binary files differ
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/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
index 5012e1c..a296659 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapColorSpaceTest.java
@@ -38,6 +38,7 @@
 import java.util.Arrays;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
@@ -61,13 +62,14 @@
     public void createWithColorSpace() {
         Bitmap b;
         ColorSpace cs;
+        ColorSpace sRGB = ColorSpace.get(ColorSpace.Named.SRGB);
 
         // We don't test HARDWARE configs because they are not compatible with mutable bitmaps
 
-        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null);
+        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, sRGB);
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
         b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true,
                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
@@ -75,7 +77,7 @@
         assertNotNull(cs);
         assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
 
-        b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true, null);
+        b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGBA_F16, true, sRGB);
         cs = b.getColorSpace();
         assertNotNull(cs);
         assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
@@ -86,38 +88,43 @@
         assertNotNull(cs);
         assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
 
-        b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, null);
+        b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true, sRGB);
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
         b = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565, true,
                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
-        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, null);
+        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true, sRGB);
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
         b = Bitmap.createBitmap(32, 32, Bitmap.Config.ALPHA_8, true,
                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
-        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, null);
+        b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true, sRGB);
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
 
         b = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_4444, true,
                 ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
         cs = b.getColorSpace();
         assertNotNull(cs);
-        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+        assertSame(sRGB, cs);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void createWithoutColorSpace() {
+        Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888, true, null);
     }
 
     @Test(expected = IllegalArgumentException.class)
@@ -520,6 +527,22 @@
     }
 
     @Test
+    public void guessAdobeRGB() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inJustDecodeBounds = true;
+
+        try (InputStream in = mResources.getAssets().open("red-adobergb.png")) {
+            Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+            ColorSpace cs = opts.outColorSpace;
+            assertNull(b);
+            assertNotNull(cs);
+            assertSame(ColorSpace.get(ColorSpace.Named.ADOBE_RGB), cs);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test
     public void guessUnknown() {
         BitmapFactory.Options opts = new BitmapFactory.Options();
         opts.inJustDecodeBounds = true;
@@ -552,6 +575,99 @@
     }
 
     @Test
+    public void inColorSpaceP3ToSRGB() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+
+        try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+            Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+            ColorSpace cs = b.getColorSpace();
+            assertNotNull(cs);
+            assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+            assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+
+            verifyGetPixel(b, 0x3ff00ff, 0xff00ff00);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void inColorSpaceSRGBToP3() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+
+        try (InputStream in = mResources.getAssets().open("green-srgb.png")) {
+            Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+            ColorSpace cs = b.getColorSpace();
+            assertNotNull(cs);
+            assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), cs);
+            assertEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+
+            verifyGetPixel(b, 0x75fb4cff, 0xff00ff00);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void inColorSpaceRGBA16F() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+        try (InputStream in = mResources.getAssets().open("prophoto-rgba16f.png")) {
+            Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+            ColorSpace cs = b.getColorSpace();
+            assertNotNull(cs);
+            assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), cs);
+            assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void inColorSpace565() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+        opts.inPreferredConfig = Bitmap.Config.RGB_565;
+
+        try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+            Bitmap b = BitmapFactory.decodeStream(in, null, opts);
+            ColorSpace cs = b.getColorSpace();
+            assertNotNull(cs);
+            assertSame(ColorSpace.get(ColorSpace.Named.SRGB), cs);
+            assertNotEquals(opts.inPreferredColorSpace, opts.outColorSpace);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void inColorSpaceNotRGB() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+
+        try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+            BitmapFactory.decodeStream(in, null, opts);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void inColorSpaceNoTransferParameters() {
+        BitmapFactory.Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+
+        try (InputStream in = mResources.getAssets().open("green-p3.png")) {
+            BitmapFactory.decodeStream(in, null, opts);
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    @Test
     public void copy() {
         Bitmap b = BitmapFactory.decodeResource(mResources, R.drawable.robot);
         Bitmap c = b.copy(Bitmap.Config.ARGB_8888, false);
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index 04b4aba..aea201c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -31,9 +31,11 @@
 import android.graphics.BitmapRegionDecoder;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorSpace;
 import android.graphics.Rect;
 import android.os.ParcelFileDescriptor;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -63,9 +65,33 @@
             R.drawable.gif_test, R.drawable.bmp_test
     };
     private static final String[] NAMES_TEMP_FILES = new String[] {
-        "baseline_temp.jpg", "progressive_temp.jpg", "baseline_restart_temp.jpg",
-        "progressive_restart_temp.jpg", "png_temp.png", "webp_temp.webp",
-        "gif_temp.gif", "bmp_temp.bmp"
+            "baseline_temp.jpg", "progressive_temp.jpg", "baseline_restart_temp.jpg",
+            "progressive_restart_temp.jpg", "png_temp.png", "webp_temp.webp",
+            "gif_temp.gif", "bmp_temp.bmp"
+    };
+
+    // Do not change the order!
+    private static final String[] ASSET_NAMES = {
+            "prophoto-rgba16f.png",
+            "green-p3.png",
+            "red-adobergb.png",
+            "green-srgb.png",
+    };
+    private static final ColorSpace.Named[][] ASSET_COLOR_SPACES = {
+            // ARGB8888
+            {
+                    ColorSpace.Named.LINEAR_EXTENDED_SRGB,
+                    ColorSpace.Named.DISPLAY_P3,
+                    ColorSpace.Named.ADOBE_RGB,
+                    ColorSpace.Named.SRGB
+            },
+            // RGB565
+            {
+                    ColorSpace.Named.SRGB,
+                    ColorSpace.Named.SRGB,
+                    ColorSpace.Named.SRGB,
+                    ColorSpace.Named.SRGB
+            }
     };
 
     // The width and height of the above image.
@@ -78,6 +104,7 @@
     private static final int NUM_TEST_IMAGES = 6;
 
     private static final int TILE_SIZE = 256;
+    private static final int SMALL_TILE_SIZE = 16;
 
     // Configurations for BitmapFactory.Options
     private static final Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888,
@@ -171,6 +198,7 @@
         }
     }
 
+    @LargeTest
     @Test
     public void testDecodeRegionInputStream() throws IOException {
         Options opts = new BitmapFactory.Options();
@@ -197,6 +225,7 @@
         }
     }
 
+    @LargeTest
     @Test
     public void testDecodeRegionInputStreamInBitmap() throws IOException {
         Options opts = new BitmapFactory.Options();
@@ -228,6 +257,7 @@
         }
     }
 
+    @LargeTest
     @Test
     public void testDecodeRegionByteArray() throws IOException {
         Options opts = new BitmapFactory.Options();
@@ -255,6 +285,7 @@
         }
     }
 
+    @LargeTest
     @Test
     public void testDecodeRegionStringAndFileDescriptor() throws IOException {
         Options opts = new BitmapFactory.Options();
@@ -327,6 +358,7 @@
     //     (2) The width, height, and Config of inBitmap are never changed.
     //     (3) All of the pixels decoded into inBitmap exactly match the pixels
     //         of a decode where inBitmap is NULL.
+    @LargeTest
     @Test
     public void testInBitmapReuse() throws IOException {
         Options defaultOpts = new BitmapFactory.Options();
@@ -409,6 +441,145 @@
         assertEquals(Config.HARDWARE, hardwareBitmap.getConfig());
     }
 
+    @Test
+    public void testOutColorType() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
+            for (int j = 0; j < SAMPLESIZES.length; ++j) {
+                for (int k = 0; k < COLOR_CONFIGS.length; ++k) {
+                    opts.inSampleSize = SAMPLESIZES[j];
+                    opts.inPreferredConfig = COLOR_CONFIGS[k];
+
+                    InputStream is1 = obtainInputStream(RES_IDS[i]);
+                    BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+                    Bitmap region = decoder.decodeRegion(
+                            new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+                    decoder.recycle();
+
+                    assertSame(opts.inPreferredConfig, opts.outConfig);
+                    assertSame(opts.outConfig, region.getConfig());
+                    region.recycle();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testOutColorSpace() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        for (int i = 0; i < ASSET_NAMES.length; i++) {
+            for (int j = 0; j < SAMPLESIZES.length; ++j) {
+                for (int k = 0; k < COLOR_CONFIGS.length; ++k) {
+                    opts.inPreferredConfig = COLOR_CONFIGS[k];
+
+                    String assetName = ASSET_NAMES[i];
+                    InputStream is1 = obtainInputStream(assetName);
+                    BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+                    Bitmap region = decoder.decodeRegion(
+                            new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+                    decoder.recycle();
+
+                    ColorSpace expected = ColorSpace.get(ASSET_COLOR_SPACES[k][i]);
+                    assertSame(expected, opts.outColorSpace);
+                    assertSame(expected, region.getColorSpace());
+                    region.recycle();
+                }
+            }
+        }
+    }
+
+    @Test
+    public void testReusedColorSpace() throws IOException {
+        Bitmap b = Bitmap.createBitmap(SMALL_TILE_SIZE, SMALL_TILE_SIZE, Config.ARGB_8888,
+                false, ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+
+        Options opts = new BitmapFactory.Options();
+        opts.inBitmap = b;
+
+        // sRGB
+        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+                obtainInputStream(ASSET_NAMES[3]), false);
+        Bitmap region = decoder.decodeRegion(
+                new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+        decoder.recycle();
+
+        assertEquals(ColorSpace.get(ColorSpace.Named.SRGB), region.getColorSpace());
+
+        // DisplayP3
+        decoder = BitmapRegionDecoder.newInstance(obtainInputStream(ASSET_NAMES[1]), false);
+        region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+        decoder.recycle();
+
+        assertEquals(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), region.getColorSpace());
+    }
+
+    @Test
+    public void testInColorSpace() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        for (int i = 0; i < NUM_TEST_IMAGES; ++i) {
+            for (int j = 0; j < SAMPLESIZES.length; ++j) {
+                opts.inSampleSize = SAMPLESIZES[j];
+                opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+
+                InputStream is1 = obtainInputStream(RES_IDS[i]);
+                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+                Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+                decoder.recycle();
+
+                assertSame(ColorSpace.get(ColorSpace.Named.DISPLAY_P3), opts.outColorSpace);
+                assertSame(opts.outColorSpace, region.getColorSpace());
+                region.recycle();
+            }
+        }
+    }
+
+    @Test
+    public void testInColorSpaceRGBA16F() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+        InputStream is1 = obtainInputStream(ASSET_NAMES[0]); // ProPhoto 16 bit
+        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+        Bitmap region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+        decoder.recycle();
+
+        assertSame(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB), region.getColorSpace());
+        region.recycle();
+    }
+
+    @Test
+    public void testInColorSpace565() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        opts.inPreferredConfig = Config.RGB_565;
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.ADOBE_RGB);
+
+        InputStream is1 = obtainInputStream(ASSET_NAMES[1]); // Display P3
+        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+        Bitmap region = decoder.decodeRegion(new Rect(0, 0, SMALL_TILE_SIZE, SMALL_TILE_SIZE), opts);
+        decoder.recycle();
+
+        assertSame(ColorSpace.get(ColorSpace.Named.SRGB), region.getColorSpace());
+        region.recycle();
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInColorSpaceNotRgb() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+        InputStream is1 = obtainInputStream(RES_IDS[0]);
+        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+        Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInColorSpaceNoTransferParameters() throws IOException {
+        Options opts = new BitmapFactory.Options();
+        opts.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB);
+        InputStream is1 = obtainInputStream(RES_IDS[0]);
+        BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is1, false);
+        Bitmap region = decoder.decodeRegion(new Rect(0, 0, TILE_SIZE, TILE_SIZE), opts);
+    }
+
     private void compareRegionByRegion(BitmapRegionDecoder decoder,
             Options opts, int mseMargin, Bitmap wholeImage) {
         int width = decoder.getWidth();
@@ -459,6 +630,10 @@
         return mRes.openRawResource(resId);
     }
 
+    private InputStream obtainInputStream(String assetName) throws IOException {
+        return mRes.getAssets().open(assetName);
+    }
+
     private byte[] obtainByteArray(int resId) throws IOException {
         InputStream is = obtainInputStream(resId);
         ByteArrayOutputStream os = new ByteArrayOutputStream();
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
index 1cc81bf..0b4f29f 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapShaderTest.java
@@ -161,35 +161,4 @@
         Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.RED },
                 pixels);
     }
-
-    @Test
-    public void testSetTileMode() {
-        Bitmap bitmap = Bitmap.createBitmap(2, 1, Config.ARGB_8888);
-        bitmap.setPixel(0, 0, Color.RED);
-        bitmap.setPixel(1, 0, Color.BLUE);
-        Bitmap dstBitmap = Bitmap.createBitmap(4, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(dstBitmap);
-        Paint paint = new Paint();
-        int[] pixels = new int[4];
-
-
-        // use clamp, verify
-        BitmapShader shader = new BitmapShader(bitmap,
-                Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
-        paint.setShader(shader);
-        canvas.drawRect(0, 0, 4, 1, paint);
-
-        dstBitmap.getPixels(pixels, 0, 4, 0, 0, 4, 1);
-        Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.BLUE },
-                pixels);
-
-        // set to use mirror, verify
-        // Note: we don't need to re-apply shader on paint, it's picked up automatically.
-        shader.set(bitmap, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
-        canvas.drawRect(0, 0, 4, 1, paint);
-
-        dstBitmap.getPixels(pixels, 0, 4, 0, 0, 4, 1);
-        Assert.assertArrayEquals(new int[] { Color.RED, Color.BLUE, Color.BLUE, Color.RED },
-                pixels);
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index 05f74f8..a113afa 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -166,6 +166,35 @@
     }
 
     @Test
+    public void testSetBitmapCleanClip() {
+        mCanvas.setBitmap(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+        Rect r = new Rect(2, 2, 8, 8);
+        mCanvas.save();
+        mCanvas.clipRect(r);
+        assertEquals(r, mCanvas.getClipBounds());
+
+        // "reset" the canvas, and then check that the clip is wide open
+        // and not the previous value
+
+        mCanvas.setBitmap(Bitmap.createBitmap(20, 20, Config.ARGB_8888));
+        r = new Rect(0, 0, 20, 20);
+        assertEquals(r, mCanvas.getClipBounds());
+    }
+
+    @Test
+    public void testSetBitmapSaveCount() {
+        Canvas c = new Canvas(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+        int initialSaveCount = c.getSaveCount();
+
+        c.save();
+        assertEquals(c.getSaveCount(), initialSaveCount + 1);
+
+        // setBitmap should restore the saveCount to its original/base value
+        c.setBitmap(Bitmap.createBitmap(10, 10, Config.ARGB_8888));
+        assertEquals(c.getSaveCount(), initialSaveCount);
+    }
+
+    @Test
     public void testIsOpaque() {
         assertFalse(mCanvas.isOpaque());
     }
@@ -1083,6 +1112,19 @@
     }
 
     @Test
+    public void testClipInversePath() {
+        final Path p = new Path();
+        p.addRoundRect(new RectF(0, 0, 10, 10), 0.5f, 0.5f, Direction.CW);
+        p.setFillType(Path.FillType.INVERSE_WINDING);
+        assertTrue(mCanvas.clipPath(p, Op.INTERSECT));
+
+        mCanvas.drawColor(PAINT_COLOR);
+
+        assertEquals(Color.TRANSPARENT, mMutableBitmap.getPixel(0, 0));
+        assertEquals(PAINT_COLOR, mMutableBitmap.getPixel(0, 20));
+    }
+
+    @Test
     public void testGetDrawFilter() {
         assertNull(mCanvas.getDrawFilter());
         final DrawFilter dF = new DrawFilter();
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
index f8714ee..61d46b2 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorMatrixColorFilterTest.java
@@ -15,7 +15,6 @@
  */
 package android.graphics.cts;
 
-import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 
 import android.graphics.Bitmap;
@@ -98,55 +97,5 @@
         canvas.drawPoint(0, 0, paint);
         ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(0, 0));
     }
-
-    @Test
-    public void testGetSetMatrix() {
-        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new ColorMatrix());
-        ColorMatrix getMatrix = new ColorMatrix();
-        filter.getColorMatrix(getMatrix);
-        assertEquals(new ColorMatrix(), getMatrix);
-
-        ColorMatrix scaleTranslate = new ColorMatrix(new float[] {
-                2, 0, 0, 0, 5,
-                0, 2, 0, 0, 5,
-                0, 0, 2, 0, 5,
-                0, 0, 0, 2, 5
-        });
-
-        filter.setColorMatrix(scaleTranslate);
-
-        filter.getColorMatrix(getMatrix);
-        assertEquals(scaleTranslate, getMatrix);
-        assertArrayEquals(scaleTranslate.getArray(), getMatrix.getArray(), 0);
-
-        filter.setColorMatrixArray(null);
-        filter.getColorMatrix(getMatrix);
-        assertEquals(new ColorMatrix(), getMatrix);
-    }
-
-    @Test
-    public void testSetMatrixDraw() {
-        ColorMatrixColorFilter filter = new ColorMatrixColorFilter(new ColorMatrix(new float[] {
-                2, 0, 0, 0, 5,
-                0, 2, 0, 0, 5,
-                0, 0, 2, 0, 5,
-                0, 0, 0, 1, 0
-        }));
-
-        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        Paint paint = new Paint();
-        paint.setColorFilter(filter);
-
-
-        paint.setColor(0xFF101010);
-        canvas.drawPaint(paint);
-        ColorUtils.verifyColor(0xFF252525, bitmap.getPixel(0, 0));
-
-
-        filter.setColorMatrix(null);
-        canvas.drawPaint(paint);
-        ColorUtils.verifyColor(0xFF101010, bitmap.getPixel(0, 0));
-    }
 }
 
diff --git a/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java b/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
index 2e76b85..f7893c7 100644
--- a/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/Color_ColorLongTest.java
@@ -84,6 +84,11 @@
         assertEquals(p3, colorSpace(pack(0.5f, 0.7f, 1.0f, 1.0f, p3)));
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidColorSpace() {
+        colorSpace(0xffffffffffffffffL);
+    }
+
     @Test
     public void testIsSrgb() {
         ColorSpace p3 = ColorSpace.get(Named.DISPLAY_P3);
diff --git a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
index 2a83f32..8c8911e 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ComposeShaderTest.java
@@ -101,72 +101,6 @@
     }
 
     @Test
-    public void testSet() {
-        Bitmap redBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        redBitmap.eraseColor(Color.RED);
-        Bitmap cyanBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        cyanBitmap.eraseColor(Color.CYAN);
-
-        BitmapShader redShader = new BitmapShader(redBitmap, TileMode.CLAMP, TileMode.CLAMP);
-        BitmapShader cyanShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
-        PorterDuffXfermode xferMode = new PorterDuffXfermode(PorterDuff.Mode.ADD);
-
-        ComposeShader shader = new ComposeShader(redShader, cyanShader, xferMode);
-
-        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        Paint paint = new Paint();
-        paint.setShader(shader);
-        canvas.drawPaint(paint);
-
-        // red + cyan = white
-        assertEquals(Color.WHITE, bitmap.getPixel(0, 0));
-
-        // set to be multiply mode, and immediately redraw
-        shader.set(redShader, cyanShader, PorterDuff.Mode.MULTIPLY);
-        canvas.drawPaint(paint);
-
-        // red * cyan = black
-        assertEquals(Color.BLACK, bitmap.getPixel(0, 0));
-    }
-
-    @Test
-    public void testInnerShaderMutate() {
-        // verify that calling a setter on a child shader updates this shader
-        Bitmap redBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        redBitmap.eraseColor(Color.RED);
-        Bitmap cyanBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        cyanBitmap.eraseColor(Color.CYAN);
-        Bitmap greenBitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        greenBitmap.eraseColor(Color.GREEN);
-
-        BitmapShader redShader = new BitmapShader(redBitmap, TileMode.CLAMP, TileMode.CLAMP);
-        BitmapShader cyanShader = new BitmapShader(cyanBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
-        ComposeShader shader = new ComposeShader(redShader, cyanShader, PorterDuff.Mode.ADD);
-
-
-        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        Paint paint = new Paint();
-        paint.setShader(shader);
-        canvas.drawPaint(paint);
-
-        // red + cyan = white
-        assertEquals(Color.WHITE, bitmap.getPixel(0, 0));
-
-        // update one of the child shaders to point at a different bitmap
-        cyanShader.set(greenBitmap, TileMode.CLAMP, TileMode.CLAMP);
-
-        // and verify the change is picked up immediately by next paint
-        canvas.drawPaint(paint);
-
-        // red + green = yellow
-        assertEquals(Color.YELLOW, bitmap.getPixel(0, 0));
-    }
-
-    @Test
     public void testChildLocalMatrix() {
         Matrix translate1x1 = new Matrix();
         translate1x1.setTranslate(1, 1);
diff --git a/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java b/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
index 929cd96..8aeefba 100644
--- a/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/FontVariationAxisTest.java
@@ -37,19 +37,18 @@
 
     @Test
     public void testConstruction() throws FontVariationAxis.InvalidFormatException {
-        new FontVariationAxis("abcd", 1.0f);
-        new FontVariationAxis("    ", 0.0f);
-        new FontVariationAxis("A X ", -1.0f);
+        new FontVariationAxis("wght", 1.0f);
+        new FontVariationAxis("PRIV", -1.0f);
     }
 
     @Test
     public void testGetterTest() throws FontVariationAxis.InvalidFormatException {
-        FontVariationAxis axis = new FontVariationAxis("abcd", 1.0f);
-        assertEquals("abcd", axis.getTag());
+        FontVariationAxis axis = new FontVariationAxis("wght", 1.0f);
+        assertEquals("wght", axis.getTag());
         assertEquals(1.0f, axis.getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axis = new FontVariationAxis("    ", -1.0f);
-        assertEquals("    ", axis.getTag());
+        axis = new FontVariationAxis("PRIV", -1.0f);
+        assertEquals("PRIV", axis.getTag());
         assertEquals(-1.0f, axis.getStyleValue(), FLOT_EQUALITY_PREC);
     }
 
@@ -94,36 +93,36 @@
         assertEquals("wdth", axes[0].getTag());
         assertEquals(0.5f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'AX  ' 1");
+        axes = FontVariationAxis.fromFontVariationSettings("'PRIV' 1");
         assertEquals(1, axes.length);
-        assertEquals("AX  ", axes[0].getTag());
+        assertEquals("PRIV", axes[0].getTag());
         assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'AX  '\t1");
+        axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\t1");
         assertEquals(1, axes.length);
-        assertEquals("AX  ", axes[0].getTag());
+        assertEquals("PRIV", axes[0].getTag());
         assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'AX  '\n1");
+        axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\n1");
         assertEquals(1, axes.length);
-        assertEquals("AX  ", axes[0].getTag());
+        assertEquals("PRIV", axes[0].getTag());
         assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'AX  '\r1");
+        axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\r1");
         assertEquals(1, axes.length);
-        assertEquals("AX  ", axes[0].getTag());
+        assertEquals("PRIV", axes[0].getTag());
         assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'AX  '\r\t\n 1");
+        axes = FontVariationAxis.fromFontVariationSettings("'PRIV'\r\t\n 1");
         assertEquals(1, axes.length);
-        assertEquals("AX  ", axes[0].getTag());
+        assertEquals("PRIV", axes[0].getTag());
         assertEquals(1.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
 
-        axes = FontVariationAxis.fromFontVariationSettings("'wdth' 10,'AX  '\r1");
+        axes = FontVariationAxis.fromFontVariationSettings("'wdth' 10,'PRIV'\r1");
         assertEquals(2, axes.length);
         assertEquals("wdth", axes[0].getTag());
         assertEquals(10.0f, axes[0].getStyleValue(), FLOT_EQUALITY_PREC);
-        assertEquals("AX  ", axes[1].getTag());
+        assertEquals("PRIV", axes[1].getTag());
         assertEquals(1.0f, axes[1].getStyleValue(), FLOT_EQUALITY_PREC);
     }
 
@@ -155,8 +154,7 @@
 
         final FontVariationAxis[] axes = {
             new FontVariationAxis("wght", 1.0f),
-            new FontVariationAxis("    ", 2.0f),
-            new FontVariationAxis("AX  ", 3.0f)
+            new FontVariationAxis("PRIV", 3.0f)
         };
 
         String stringData = FontVariationAxis.toFontVariationSettings(axes);
diff --git a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
index e4ba072..da2b934 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LightingColorFilterTest.java
@@ -16,8 +16,6 @@
 
 package android.graphics.cts;
 
-import static org.junit.Assert.assertEquals;
-
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
@@ -91,51 +89,4 @@
     private void verifyColor(int expected, int actual) {
         ColorUtils.verifyColor(expected, actual, TOLERANCE);
     }
-
-    @Test
-    public void testGetSet() {
-        LightingColorFilter filter = new LightingColorFilter(Color.WHITE, Color.BLACK);
-        assertEquals(Color.WHITE, filter.getColorMultiply());
-        assertEquals(Color.BLACK, filter.getColorAdd());
-
-        filter.setColorMultiply(Color.RED);
-        filter.setColorAdd(Color.BLUE);
-
-        assertEquals(Color.RED, filter.getColorMultiply());
-        assertEquals(Color.BLUE, filter.getColorAdd());
-    }
-
-    @Test
-    public void testSetDraw() {
-        LightingColorFilter filter = new LightingColorFilter(Color.CYAN, Color.BLACK);
-
-        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        Paint paint = new Paint();
-        paint.setColorFilter(filter);
-
-        // test initial state
-        paint.setColor(Color.YELLOW);
-        canvas.drawPaint(paint);
-        // Cyan * yellow = green
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
-
-
-        // test set color multiply
-        filter.setColorMultiply(Color.MAGENTA);
-        paint.setColor(Color.YELLOW);
-        canvas.drawPaint(paint);
-        // Magenta * yellow = red
-        ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0));
-
-
-        // test set color add
-        filter.setColorMultiply(Color.WHITE);
-        filter.setColorAdd(Color.MAGENTA);
-        paint.setColor(Color.GREEN);
-        canvas.drawPaint(paint);
-        // Magenta + green = white
-        ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(0, 0));
-
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
index 8555193..185e6a1 100644
--- a/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/LinearGradientTest.java
@@ -84,35 +84,6 @@
     }
 
     @Test
-    public void testSet() {
-        // only using 2 pixel wide gradient since we don't care about interpolation here.
-        // Note: we align start/end to be center pixel so colors at those pixels are exact.
-        LinearGradient gradient = new LinearGradient(0.5f, 0, 1.5f, 0,
-                Color.RED, Color.BLUE, TileMode.CLAMP);
-
-        Bitmap bitmap = Bitmap.createBitmap(3, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-
-        Paint paint = new Paint();
-        paint.setShader(gradient);
-        canvas.drawPaint(paint);
-
-
-        // red, blue, clamped to blue
-        ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
-        ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(2, 0), 5);
-
-        gradient.set(0.5f, 0, 1.5f, 0, Color.GREEN, Color.WHITE, TileMode.MIRROR);
-        canvas.drawPaint(paint);
-
-        // green, white, mirrored to green
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(1, 0), 5);
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(2, 0), 5);
-    }
-
-    @Test
     public void testZeroScaleMatrix() {
         LinearGradient gradient = new LinearGradient(0.5f, 0, 1.5f, 0,
                 Color.RED, Color.BLUE, TileMode.CLAMP);
diff --git a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
index f5c7aa3..22fa7c3 100644
--- a/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/MovieTest.java
@@ -28,7 +28,7 @@
 import android.graphics.Movie;
 import android.graphics.Paint;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.WidgetTestUtils;
@@ -44,7 +44,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 
-@MediumTest
+@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class MovieTest {
     private final int MOVIE = R.drawable.animated;
diff --git a/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
index a2438ee..0beadae 100644
--- a/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/PorterDuffColorFilterTest.java
@@ -27,8 +27,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import com.android.compatibility.common.util.ColorUtils;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -83,52 +81,4 @@
         assertEquals(Color.CYAN, target.getPixel(width / 4, height * 3 / 4));
         assertEquals(Color.CYAN, target.getPixel(width * 3 / 4, height * 3 / 4));
     }
-
-    @Test
-    public void testGetSet() {
-        PorterDuffColorFilter filter = new PorterDuffColorFilter(
-                Color.RED, PorterDuff.Mode.MULTIPLY);
-
-        assertEquals(Color.RED, filter.getColor());
-        assertEquals(PorterDuff.Mode.MULTIPLY, filter.getMode());
-
-        filter.setColor(Color.GREEN);
-        filter.setMode(PorterDuff.Mode.ADD);
-
-        assertEquals(Color.GREEN, filter.getColor());
-        assertEquals(PorterDuff.Mode.ADD, filter.getMode());
-    }
-
-    @Test
-    public void testSetDraw() {
-        PorterDuffColorFilter filter = new PorterDuffColorFilter(
-                Color.CYAN, PorterDuff.Mode.MULTIPLY);
-
-        Bitmap bitmap = Bitmap.createBitmap(1, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        Paint paint = new Paint();
-        paint.setColorFilter(filter);
-
-        // test initial state
-        paint.setColor(Color.YELLOW);
-        canvas.drawPaint(paint);
-        // Cyan * yellow = green
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0));
-
-
-        // test set color
-        filter.setColor(Color.MAGENTA);
-        paint.setColor(Color.YELLOW);
-        canvas.drawPaint(paint);
-        // Magenta * yellow = red
-        ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0));
-
-
-        // test set mode
-        filter.setMode(PorterDuff.Mode.ADD);
-        paint.setColor(Color.GREEN);
-        canvas.drawPaint(paint);
-        // Magenta + green = white
-        ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(0, 0));
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
index e8a0cbc..d133bb9 100644
--- a/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/RadialGradientTest.java
@@ -35,34 +35,6 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class RadialGradientTest {
-    @Test
-    public void testSet() {
-        // only using 1 pixel radius gradient since we don't care about interpolation here.
-        // Note: we align start/end to be center pixel so colors at those pixels are exact.
-        RadialGradient gradient = new RadialGradient(0.5f, 0.5f, 1,
-                Color.RED, Color.BLUE, TileMode.CLAMP);
-
-        Bitmap bitmap = Bitmap.createBitmap(3, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-
-        Paint paint = new Paint();
-        paint.setShader(gradient);
-        canvas.drawPaint(paint);
-
-
-        // red, blue, clamped to blue
-        ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
-        ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(2, 0), 5);
-
-        gradient.set(0.5f, 0.5f, 1, Color.GREEN, Color.WHITE, TileMode.MIRROR);
-        canvas.drawPaint(paint);
-
-        // green, white, mirrored to green
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.WHITE, bitmap.getPixel(1, 0), 5);
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(2, 0), 5);
-    }
 
     @Test
     public void testZeroScaleMatrix() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
index ceea7a7..cb7ec0a 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SweepGradientTest.java
@@ -22,7 +22,6 @@
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
@@ -148,33 +147,6 @@
     }
 
     @Test
-    public void testSet() {
-        // Only use two pixel wide bitmap since we don't care about interpolation here.
-        // Note: we place the gradient in between the two pixels, so both are solid colors.
-        SweepGradient gradient = new SweepGradient(1, 0.5f,
-                new int[] {Color.BLUE, Color.RED, Color.BLUE}, null);
-
-        Bitmap bitmap = Bitmap.createBitmap(2, 1, Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-
-        Paint paint = new Paint();
-        paint.setShader(gradient);
-        canvas.drawPaint(paint);
-
-        // red to left, blue to right
-        ColorUtils.verifyColor(Color.RED, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.BLUE, bitmap.getPixel(1, 0), 5);
-
-        gradient.set(1, 0.5f,
-                new int[] {Color.GREEN, Color.YELLOW, Color.GREEN}, null);
-        canvas.drawPaint(paint);
-
-        // yellow to left, green to right
-        ColorUtils.verifyColor(Color.YELLOW, bitmap.getPixel(0, 0), 5);
-        ColorUtils.verifyColor(Color.GREEN, bitmap.getPixel(1, 0), 5);
-    }
-
-    @Test
     public void testZeroScaleMatrix() {
         SweepGradient gradient = new SweepGradient(1, 0.5f,
                 new int[] {Color.BLUE, Color.RED, Color.BLUE}, null);
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index 36e3f12..3a1c1cf 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -21,11 +21,13 @@
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.content.Context;
+import android.content.res.AssetManager;
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.graphics.fonts.FontVariationAxis;
@@ -297,72 +299,53 @@
 
     @Test
     public void testTypefaceBuilder_AssetSource() throws FontVariationAxis.InvalidFormatException {
-        Typeface.Builder builder = Typeface.Builder.obtain();
-        try {
-            Typeface typeface1 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf").build();
-            assertNotNull(typeface1);
+        Typeface typeface1 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build();
+        assertNotNull(typeface1);
 
-            builder.reset();
-            Typeface typeface2 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf").build();
-            assertNotNull(typeface2);
-            assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
+        Typeface typeface2 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf").build();
+        assertNotNull(typeface2);
+        assertSame("Same font asset should return same Typeface object", typeface1, typeface2);
 
-            builder.reset();
-            Typeface typeface3 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont2.ttf").build();
-            assertNotNull(typeface3);
-            assertNotSame("Different font asset should return different Typeface object",
-                    typeface2, typeface3);
+        Typeface typeface3 = new Typeface.Builder(mContext.getAssets(), "samplefont2.ttf").build();
+        assertNotNull(typeface3);
+        assertNotSame("Different font asset should return different Typeface object",
+                typeface2, typeface3);
 
-            builder.reset();
-            Typeface typeface4 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont3.ttf").build();
-            assertNotNull(typeface4);
-            assertNotSame("Different font asset should return different Typeface object",
-                    typeface2, typeface4);
-            assertNotSame("Different font asset should return different Typeface object",
-                    typeface3, typeface4);
+        Typeface typeface4 = new Typeface.Builder(mContext.getAssets(), "samplefont3.ttf").build();
+        assertNotNull(typeface4);
+        assertNotSame("Different font asset should return different Typeface object",
+                typeface2, typeface4);
+        assertNotSame("Different font asset should return different Typeface object",
+                typeface3, typeface4);
 
-            builder.reset();
-            Typeface typeface5 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf")
-                    .setFontVariationSettings("'wdth' 1.0").build();
-            assertNotNull(typeface5);
-            assertNotSame("Different font font variation should return different Typeface object",
-                    typeface2, typeface5);
+        Typeface typeface5 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf")
+                .setFontVariationSettings("'wdth' 1.0").build();
+        assertNotNull(typeface5);
+        assertNotSame("Different font font variation should return different Typeface object",
+                typeface2, typeface5);
 
-            builder.reset();
-            Typeface typeface6 =
-                    builder.setSourceFromAsset(mContext.getAssets(), "samplefont.ttf")
-                    .setFontVariationSettings("'wdth' 2.0").build();
-            assertNotNull(typeface6);
-            assertNotSame("Different font font variation should return different Typeface object",
-                    typeface2, typeface6);
-            assertNotSame("Different font font variation should return different Typeface object",
-                    typeface5, typeface6);
+        Typeface typeface6 = new Typeface.Builder(mContext.getAssets(), "samplefont.ttf")
+                .setFontVariationSettings("'wdth' 2.0").build();
+        assertNotNull(typeface6);
+        assertNotSame("Different font font variation should return different Typeface object",
+                typeface2, typeface6);
+        assertNotSame("Different font font variation should return different Typeface object",
+                typeface5, typeface6);
 
-            // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640)
-        } finally {
-            builder.recycle();
-        }
+        // TODO: Add ttc index case. Need TTC file for CTS. (b/36731640)
     }
 
     @Test
     public void testTypefaceBuilder_FileSource() {
-        Typeface.Builder builder = Typeface.Builder.obtain();
         try {
             File file = new File(obtainPath());
-            Typeface typeface1 = builder.setSourceFromFile(file).build();
+            Typeface typeface1 = new Typeface.Builder(obtainPath()).build();
             assertNotNull(typeface1);
 
-            builder.reset();
-            Typeface typeface2 = builder.setSourceFromFilePath(file.getAbsolutePath()).build();
+            Typeface typeface2 = new Typeface.Builder(file).build();
             assertNotNull(typeface2);
 
-            builder.reset();
-            Typeface typeface3 = builder.setSourceFromFile(file)
+            Typeface typeface3 = new Typeface.Builder(file)
                     .setFontVariationSettings("'wdth' 1.0")
                     .build();
             assertNotNull(typeface3);
@@ -372,20 +355,97 @@
             // TODO: Add ttc index case. Need TTC file for CTS.
         } catch (IOException | FontVariationAxis.InvalidFormatException e) {
             throw new RuntimeException(e);
-        } finally {
-            builder.recycle();
         }
     }
 
     @Test
+    public void testTypefaceBuilder_fallback() throws IOException {
+        final File validFile = new File(obtainPath());
+        final File invalidFile = new File("/some/invalid/path/to/font/file");
+        final AssetManager assets = mContext.getAssets();
+        // By default, returns null if no fallback font is specified.
+        assertNull(new Typeface.Builder(invalidFile).build());
+
+        assertNull(new Typeface.Builder(validFile)
+                .setTtcIndex(100 /* non-existing ttc index */).build());
+
+        assertNull(new Typeface.Builder(assets, "invalid path").build());
+
+        assertNull(new Typeface.Builder(assets, "samplefont.ttf")
+                .setTtcIndex(100 /* non-existing ttc index */).build());
+
+        // If fallback is set, the builder never returns null.
+        assertNotNull(new Typeface.Builder(invalidFile).setFallback("").build());
+
+        assertNotNull(new Typeface.Builder(invalidFile).setFallback("invalid name").build());
+
+        Typeface sansSerifTypeface = new Typeface.Builder(invalidFile)
+                .setFallback("sans-serif").build();
+        assertNotNull(sansSerifTypeface);
+
+        Typeface serifTypeface = new Typeface.Builder(invalidFile).setFallback("serif").build();
+        assertNotNull(serifTypeface);
+
+        Typeface boldSansSerifTypeface = new Typeface.Builder(invalidFile)
+                .setFallback("sans-serif").setWeight(700).build();
+        assertNotNull(boldSansSerifTypeface);
+
+        Typeface boldSerifTypeface = new Typeface.Builder(invalidFile)
+                .setFallback("serif").setWeight(700).build();
+        assertNotNull(boldSerifTypeface);
+
+        Typeface italicSansSerifTypeface = new Typeface.Builder(invalidFile)
+                .setFallback("sans-serif").setItalic(true).build();
+        assertNotNull(italicSansSerifTypeface);
+
+        Typeface italicSerifTypeface = new Typeface.Builder(invalidFile)
+                .setFallback("serif").setItalic(true).build();
+        assertNotNull(italicSerifTypeface);
+
+        // All fallbacks should be different each other.
+        assertNotSame(sansSerifTypeface, serifTypeface);
+        assertNotSame(sansSerifTypeface, boldSansSerifTypeface);
+        assertNotSame(sansSerifTypeface, boldSerifTypeface);
+        assertNotSame(sansSerifTypeface, italicSansSerifTypeface);
+        assertNotSame(sansSerifTypeface, italicSerifTypeface);
+        assertNotSame(serifTypeface, boldSansSerifTypeface);
+        assertNotSame(serifTypeface, boldSerifTypeface);
+        assertNotSame(serifTypeface, italicSansSerifTypeface);
+        assertNotSame(serifTypeface, italicSerifTypeface);
+        assertNotSame(boldSansSerifTypeface, boldSerifTypeface);
+        assertNotSame(boldSansSerifTypeface, italicSansSerifTypeface);
+        assertNotSame(boldSansSerifTypeface, italicSerifTypeface);
+        assertNotSame(boldSerifTypeface, italicSansSerifTypeface);
+        assertNotSame(boldSerifTypeface, italicSerifTypeface);
+        assertNotSame(italicSansSerifTypeface, italicSerifTypeface);
+
+        // Cache should work for the same fallback.
+        assertSame(sansSerifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).build());
+        assertSame(serifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).build());
+        assertSame(boldSansSerifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build());
+        assertSame(boldSerifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).setWeight(700).build());
+        assertSame(italicSansSerifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("sans-serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build());
+        assertSame(italicSerifTypeface,
+                new Typeface.Builder(assets, "samplefont.ttf").setFallback("serif")
+                        .setTtcIndex(100 /* non-existing ttc index */).setItalic(true).build());
+    }
+
+    @Test
     public void testTypefaceBuilder_FileSourceFD() {
-        Typeface.Builder builder = Typeface.Builder.obtain();
         try (FileInputStream fis = new FileInputStream(obtainPath())) {
-            assertNotNull(builder.setSourceFromFile(fis.getFD()).build());
+            assertNotNull(new Typeface.Builder(fis.getFD()).build());
         } catch (IOException e) {
             throw new RuntimeException(e);
-        } finally {
-            builder.recycle();
         }
     }
 
@@ -416,4 +476,27 @@
             assertNotEquals(widthDefaultTypeface, widthCustomTypeface, 1.0f);
         }
     }
+
+    @Test
+    public void testTypefaceBuilder_customFallback() {
+        final String fontPath = "samplefont2.ttf";
+        final Typeface regularTypeface = new Typeface.Builder(mContext.getAssets(), fontPath)
+                .setWeight(400).build();
+        final Typeface blackTypeface = new Typeface.Builder(mContext.getAssets(), fontPath)
+                .setWeight(900).build();
+
+        // W is not supported by samplefont2.ttf
+        final String testString = "WWWWWWWWWWWWWWWWWWWWW";
+
+        final Paint p = new Paint();
+        p.setTextSize(128);
+
+        p.setTypeface(regularTypeface);
+        final float widthFromRegular = p.measureText(testString);
+
+        p.setTypeface(blackTypeface);
+        final float widthFromBlack = p.measureText(testString);
+
+        assertTrue(Math.abs(widthFromRegular - widthFromBlack) > 1.0f);
+    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
index f8cd816..2e986cb 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedStateListDrawableTest.java
@@ -204,9 +204,11 @@
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final StateListDrawable halfDrawable =
                 (StateListDrawable) cs.newDrawable(res);
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
         for (int i = 0; i < count; i++) {
             halfDrawable.selectDrawable(i);
-            assertEquals(Math.round(origWidth[i] / 2f), halfDrawable.getIntrinsicWidth());
+            assertEquals(Math.round(origWidth[i] * approxHalf), halfDrawable.getIntrinsicWidth());
         }
 
         // Set density to double original.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
index 1c9f9b3..29da030 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableParameterizedTest.java
@@ -30,7 +30,9 @@
 import android.graphics.cts.R;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.View;
@@ -50,7 +52,7 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-@MediumTest
+@LargeTest
 @RunWith(Parameterized.class)
 public class AnimatedVectorDrawableParameterizedTest {
     @Rule
@@ -183,6 +185,7 @@
         return frameLatch.await(timeout, TimeUnit.MILLISECONDS);
     }
 
+    @SmallTest
     @Test
     public void testSingleFrameAnimation() throws Throwable {
         int resId = R.drawable.avd_single_frame;
@@ -208,6 +211,7 @@
         });
     }
 
+    @MediumTest
     @Test
     public void testEmptyAnimatorSet() throws Throwable {
         int resId = R.drawable.avd_empty_animator;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
index 65aad83..d1f6282 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/AnimatedVectorDrawableTest.java
@@ -36,7 +36,8 @@
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
-import android.support.test.filters.MediumTest;
+import android.support.test.filters.LargeTest;
+import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
@@ -50,7 +51,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-@MediumTest
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class AnimatedVectorDrawableTest {
     private static final int IMAGE_WIDTH = 64;
@@ -75,6 +76,7 @@
         mResources = mActivity.getResources();
     }
 
+    @SmallTest
     @Test
     public void testInflate() throws Exception {
         // Setup AnimatedVectorDrawable from xml file
@@ -144,6 +146,7 @@
         assertEquals(1, constantState.getChangingConfigurations());
     }
 
+    @SmallTest
     @Test
     public void testMutate() {
         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -178,6 +181,7 @@
         }
     }
 
+    @SmallTest
     @Test
     public void testGetOpacity() {
         AnimatedVectorDrawable d1 = (AnimatedVectorDrawable) mResources.getDrawable(mResId);
@@ -186,6 +190,7 @@
         assertEquals("Still translucent", PixelFormat.TRANSLUCENT, d1.getOpacity());
     }
 
+    @SmallTest
     @Test
     public void testColorFilter() {
         PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, PorterDuff.Mode.SRC_IN);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
index 136ae2d..abba96e 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/CustomAnimationScaleListDrawableTest.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.DrawableContainer;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
+import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.After;
@@ -39,7 +40,7 @@
  * on animation duration scale. When the scale is 0, it is a static drawable, otherwise, it is an
  * animatable drawable.
  */
-@MediumTest
+@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class CustomAnimationScaleListDrawableTest {
     private static final int DRAWABLE_ID = R.drawable.custom_animation_scale_list_drawable;
@@ -58,7 +59,6 @@
         ValueAnimator.setDurationScale(mOriginalScale);
     }
 
-    @MediumTest
     @Test
     public void testNonZeroDurationScale() {
         // Set the duration scale to a non-zero value will cause the AnimationScaleListDrawable's
@@ -69,7 +69,6 @@
         assertTrue(dr.getCurrent() instanceof Animatable);
     }
 
-    @MediumTest
     @Test
     public void testZeroDurationScale() {
         // Set the duration scale to zero will cause the AnimationScaleListDrawable's current
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java
new file mode 100644
index 0000000..c8d057a
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DefaultFocusHighlightTest.java
@@ -0,0 +1,358 @@
+/*
+ * 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 android.graphics.drawable.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.NinePatch;
+import android.graphics.Picture;
+import android.graphics.cts.R;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.DrawableContainer;
+import android.graphics.drawable.DrawableContainer.DrawableContainerState;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.LevelListDrawable;
+import android.graphics.drawable.NinePatchDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.graphics.drawable.PictureDrawable;
+import android.graphics.drawable.RippleDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.StateSet;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class DefaultFocusHighlightTest {
+
+    // The target context.
+    private Context mContext;
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getTargetContext();
+    }
+
+    private static final int A_COLOR = 0x920424;
+    private static final int[] NO_STATE_FOCUSED = new int[] { android.R.attr.state_enabled };
+    private static final int[] ONLY_STATE_FOCUSED = new int[] { android.R.attr.state_focused };
+    private static final int[] STATE_FOCUSED_WITH_POS =
+            new int[] { android.R.attr.state_focused, android.R.attr.state_hovered };
+    private static final int[] STATE_FOCUSED_WITH_NEG =
+            new int[] { android.R.attr.state_focused,  -android.R.attr.state_hovered };
+    private static final int[] STATE_FOCUSED_WITH_ENABLED =
+            new int[] { android.R.attr.state_focused, android.R.attr.state_enabled };
+
+    final static int[] FOCUSED_STATE =
+            new int[] { android.R.attr.state_focused, android.R.attr.state_enabled };
+
+    @UiThreadTest
+    @Test
+    public void testStateListDrawable() {
+        Drawable d;
+        // Empty state spec
+        d = DrawableFactory.createStateListDrawable(
+                new int[][] {}
+            );
+        d.setState(FOCUSED_STATE);
+        assertFalse(d.hasFocusStateSpecified());
+
+        // Wild card
+        d = DrawableFactory.createStateListDrawable(
+                new int[][] { StateSet.WILD_CARD }
+            );
+        d.setState(FOCUSED_STATE);
+        assertFalse(d.hasFocusStateSpecified());
+
+        // No state spec of state_focused=true
+        d = DrawableFactory.createStateListDrawable(
+                new int[][] { NO_STATE_FOCUSED }
+            );
+        d.setState(FOCUSED_STATE);
+        assertFalse(d.hasFocusStateSpecified());
+
+        // One state spec of only state_focused=true
+        d = DrawableFactory.createStateListDrawable(
+                new int[][] { ONLY_STATE_FOCUSED }
+            );
+        d.setState(FOCUSED_STATE);
+        assertTrue(d.hasFocusStateSpecified());
+
+        // One state spec of state_focused=true and something=true, but no state spec of
+        // state_focused=true and something=false (something is not enabled)
+        d = DrawableFactory.createStateListDrawable(
+                new int[][] { STATE_FOCUSED_WITH_POS }
+            );
+        d.setState(FOCUSED_STATE);
+        assertTrue(d.hasFocusStateSpecified());
+
+        // One state spec of state_focused=true and something=true, and one spec of
+        // state_focused=true and something=false (something is not enabled)
+        d = DrawableFactory.createStateListDrawable(
+            new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG }
+        );
+        d.setState(FOCUSED_STATE);
+        assertTrue(d.hasFocusStateSpecified());
+
+        // One state spec of state_focused=true and enabled=true
+        d = DrawableFactory.createStateListDrawable(
+            new int[][] { STATE_FOCUSED_WITH_ENABLED }
+        );
+        d.setState(FOCUSED_STATE);
+        assertTrue(d.hasFocusStateSpecified());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testRippleDrawable() {
+        Drawable d = DrawableFactory.createRippleDrawable();
+        d.setState(FOCUSED_STATE);
+        assertTrue(d.hasFocusStateSpecified());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testPictureDrawable() {
+        Drawable d = DrawableFactory.createPictureDrawable(null);
+        d.setState(FOCUSED_STATE);
+        assertFalse(d.hasFocusStateSpecified());
+
+        d = DrawableFactory.createPictureDrawable(new Picture());
+        d.setState(FOCUSED_STATE);
+        assertFalse(d.hasFocusStateSpecified());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testColorStateListHandledDrawable() {
+        final Drawable[] drawables = new Drawable[] {
+            DrawableFactory.createShapeDrawable(),
+            DrawableFactory.createPaintDrawable(),
+            DrawableFactory.createBitmapDrawable(mContext),
+            DrawableFactory.createColorDrawable(),
+            DrawableFactory.createGradientDrawable(),
+            DrawableFactory.createNinePatchDrawable(mContext),
+        };
+        final ColorStateList[] stateLists = new ColorStateList[] {
+            // Empty state spec
+            new ColorStateList(
+                new int[][] {  },
+                new int[] {  }),
+            // Wild card
+            new ColorStateList(
+                new int[][] { StateSet.WILD_CARD },
+                new int[] { A_COLOR }),
+            // No state spec of state_focused=true
+            new ColorStateList(
+                new int[][] { NO_STATE_FOCUSED },
+                new int[] { A_COLOR }),
+            // One state spec of only state_focused=true
+            new ColorStateList(
+                new int[][] { ONLY_STATE_FOCUSED },
+                new int[] { A_COLOR }),
+            // One state spec of state_focused=true and something=true,
+            // but no state spec of state_focused=true and something=false
+            new ColorStateList(
+                new int[][] { STATE_FOCUSED_WITH_POS },
+                new int[] { A_COLOR }),
+            // One state spec of state_focused=true and something=true,
+            // and one spec of state_focused=true and something=false
+            new ColorStateList(
+                new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG },
+                new int[] { A_COLOR, A_COLOR }),
+        };
+        final boolean[] expectedResults = new boolean[] {
+            // Empty state spec
+            false,
+            // Wild card
+            false,
+            // No state spec of state_focused=true
+            false,
+            // One state spec of only state_focused=true
+            true,
+            // One state spec of state_focused=true and something=true,
+            // but no state spec of state_focused=true and something=false
+            true,
+            // One state spec of state_focused=true and something=true,
+            // and one spec of state_focused=true and something=false
+            true
+        };
+        assertEquals(stateLists.length, expectedResults.length);
+        for (Drawable drawable : drawables) {
+            // No ColorStateList set
+            String drawableName = drawable.getClass().toString();
+            String errorMsg = "[" + drawableName + "] Testing no ColorStateList failed.";
+            drawable.setState(FOCUSED_STATE);
+            assertFalse(errorMsg, drawable.hasFocusStateSpecified());
+            // With ColorStateList set
+            for (int i = 0; i < stateLists.length; i++) {
+                ColorStateList stateList = stateLists[i];
+                boolean expectedResult = expectedResults[i];
+                drawable.setTintList(stateList);
+                errorMsg = "[" + drawableName + "] Testing ColorStateList No." + i + " failed.";
+
+                drawable.setState(FOCUSED_STATE);
+                if (expectedResult) {
+                    assertTrue(errorMsg, drawable.hasFocusStateSpecified());
+                } else {
+                    assertFalse(errorMsg, drawable.hasFocusStateSpecified());
+                }
+            }
+        }
+    }
+
+    @UiThreadTest
+    @Test
+    public void testDrawableContainer() {
+        MockDrawableContainer container;
+        DrawableContainerState containerState;
+
+        // Empty
+        container = new MockDrawableContainer();
+        containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+        assertNotNull(containerState);
+        container.setConstantState(containerState);
+        container.setState(FOCUSED_STATE);
+        assertFalse(container.hasFocusStateSpecified());
+
+        // No drawable of state_focused=true
+        container = new MockDrawableContainer();
+        containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+        assertNotNull(containerState);
+        container.setConstantState(containerState);
+        containerState.addChild(DrawableFactory.createPaintDrawable());
+        containerState.addChild(DrawableFactory.createBitmapDrawable(mContext));
+        containerState.addChild(DrawableFactory.createColorDrawable());
+        container.selectDrawable(0);
+        container.setState(FOCUSED_STATE);
+        assertFalse(container.hasFocusStateSpecified());
+        container.selectDrawable(1);
+        container.setState(FOCUSED_STATE);
+        assertFalse(container.hasFocusStateSpecified());
+        container.selectDrawable(2);
+        container.setState(FOCUSED_STATE);
+        assertFalse(container.hasFocusStateSpecified());
+
+        // Only drawables of state_focused=true
+        container = new MockDrawableContainer();
+        containerState = (DrawableContainerState) new LevelListDrawable().getConstantState();
+        assertNotNull(containerState);
+        container.setConstantState(containerState);
+        containerState.addChild(DrawableFactory.createRippleDrawable());
+        containerState.addChild(
+            DrawableFactory.createStateListDrawable(
+                new int[][] { STATE_FOCUSED_WITH_POS, STATE_FOCUSED_WITH_NEG }
+            )
+        );
+        container.selectDrawable(0);
+        container.setState(FOCUSED_STATE);
+        assertTrue(container.hasFocusStateSpecified());
+        container.selectDrawable(1);
+        container.setState(FOCUSED_STATE);
+        assertTrue(container.hasFocusStateSpecified());
+
+        // Both drawables of state_focused=true and state_focused=false
+        containerState.addChild(DrawableFactory.createColorDrawable());
+        container.selectDrawable(2);
+        container.setState(FOCUSED_STATE);
+        assertFalse(container.hasFocusStateSpecified());
+        container.selectDrawable(1);
+        container.setState(FOCUSED_STATE);
+        assertTrue(container.hasFocusStateSpecified());
+        container.selectDrawable(0);
+        container.setState(FOCUSED_STATE);
+        assertTrue(container.hasFocusStateSpecified());
+    }
+
+    static class DrawableFactory {
+        static ShapeDrawable createShapeDrawable() {
+            return new ShapeDrawable(new RectShape());
+        }
+        static PaintDrawable createPaintDrawable() {
+            PaintDrawable paintDrawable = new PaintDrawable();
+            paintDrawable.setCornerRadius(1.5f);
+            return paintDrawable;
+        }
+        static BitmapDrawable createBitmapDrawable(Context context) {
+            Bitmap bitmap = Bitmap.createBitmap(200, 300, Config.ARGB_8888);
+            BitmapDrawable bitmapDrawable = new BitmapDrawable(context.getResources(), bitmap);
+            return bitmapDrawable;
+        }
+        static ColorDrawable createColorDrawable() {
+            return new ColorDrawable(A_COLOR);
+        }
+        static GradientDrawable createGradientDrawable() {
+            GradientDrawable gradientDrawable = new GradientDrawable();
+            gradientDrawable.setColor(A_COLOR);
+            gradientDrawable.setCornerRadius(10f);
+            return gradientDrawable;
+        }
+        static NinePatchDrawable createNinePatchDrawable(Context context) {
+            Resources res = context.getResources();
+            Bitmap bitmap = BitmapFactory.decodeResource(res, R.drawable.ninepatch_0);
+            NinePatch np = new NinePatch(bitmap, bitmap.getNinePatchChunk(), null);
+            NinePatchDrawable ninePatchDrawable = new NinePatchDrawable(res, np);
+            return ninePatchDrawable;
+        }
+        static RippleDrawable createRippleDrawable() {
+            RippleDrawable rippleDrawable =
+                    new RippleDrawable(ColorStateList.valueOf(A_COLOR), null, null);
+            return rippleDrawable;
+        }
+        static PictureDrawable createPictureDrawable(Picture picture) {
+            PictureDrawable pictureDrawable = new PictureDrawable(picture);
+            return pictureDrawable;
+        }
+        static StateListDrawable createStateListDrawable(int[][] stateList) {
+            StateListDrawable drawable = new StateListDrawable();
+            ColorDrawable colorDrawable = DrawableFactory.createColorDrawable();
+            for (int i = 0; i < stateList.length; i++) {
+                drawable.addState(stateList[i], colorDrawable);
+            }
+            return drawable;
+        }
+    }
+
+    // We're calling protected methods in DrawableContainer.
+    // So we have to extend it here to make it accessible.
+    private class MockDrawableContainer extends DrawableContainer {
+        @Override
+        protected void setConstantState(DrawableContainerState state) {
+            super.setConstantState(state);
+        }
+    }
+
+}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index eb660f3..b798fb8 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -52,6 +52,7 @@
 import java.io.IOException;
 import java.util.Arrays;
 
+@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class GradientDrawableTest {
     private Resources mResources;
@@ -61,7 +62,6 @@
         mResources = InstrumentationRegistry.getTargetContext().getResources();
     }
 
-    @SmallTest
     @Test
     public void testConstructor() {
         int[] color = new int[] {1, 2, 3};
@@ -71,7 +71,6 @@
         new GradientDrawable(null, null);
     }
 
-    @SmallTest
     @Test
     public void testGetOpacity() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -105,7 +104,6 @@
 
     }
 
-    @SmallTest
     @Test
     public void testSetOrientation() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -117,7 +115,6 @@
                 orientation, gradientDrawable.getOrientation());
     }
 
-    @SmallTest
     @Test
     public void testSetCornerRadii() {
         float[] radii = new float[] {1.0f, 2.0f, 3.0f};
@@ -136,7 +133,6 @@
         gradientDrawable.setCornerRadii(null);
     }
 
-    @SmallTest
     @Test
     public void testSetCornerRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -145,7 +141,6 @@
         gradientDrawable.setCornerRadius(-2.5f);
     }
 
-    @SmallTest
     @Test
     public void testGetCornerRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -160,7 +155,6 @@
         assertEquals(0, gradientDrawable.getCornerRadius(), 0);
     }
 
-    @SmallTest
     @Test
     public void testSetStroke() {
         helpTestSetStroke(2, Color.RED);
@@ -174,7 +168,6 @@
         // TODO: Verify stroke properties.
     }
 
-    @SmallTest
     @Test
     public void testSetStroke_WidthGap() {
         verifySetStroke_WidthGap(2, Color.RED, 3.4f, 5.5f);
@@ -189,7 +182,6 @@
         // TODO: Verify stroke properties.
     }
 
-    @SmallTest
     @Test
     public void testSetStrokeList() {
         verifySetStrokeList(2, ColorStateList.valueOf(Color.RED));
@@ -204,7 +196,6 @@
         // TODO: Verify stroke properties.
     }
 
-    @SmallTest
     @Test
     public void testSetStrokeList_WidthGap() {
         verifySetStrokeList_WidthGap(2, ColorStateList.valueOf(Color.RED), 3.4f, 5.5f);
@@ -219,7 +210,6 @@
         // TODO: Verify stroke properties.
     }
 
-    @SmallTest
     @Test
     public void testSetSize() {
         verifySetSize(6, 4);
@@ -235,7 +225,6 @@
         assertEquals(height, gradientDrawable.getIntrinsicHeight());
     }
 
-    @SmallTest
     @Test
     public void testSetShape() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -252,7 +241,6 @@
                 shape, gradientDrawable.getShape());
     }
 
-    @SmallTest
     @Test
     public void testSetGradientType() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -269,7 +257,6 @@
                 gradientType, gradientDrawable.getGradientType());
     }
 
-    @SmallTest
     @Test
     public void testSetGradientCenter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -294,7 +281,6 @@
         assertEquals(centerY, gradientDrawable.getGradientCenterY(), 0.01f);
     }
 
-    @SmallTest
     @Test
     public void testSetGradientRadius() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -303,7 +289,6 @@
         gradientDrawable.setGradientRadius(-3.6f);
     }
 
-    @SmallTest
     @Test
     public void testSetUseLevel() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -322,7 +307,6 @@
                 useLevel, gradientDrawable.getUseLevel());
     }
 
-    @SmallTest
     @Test
     public void testDraw() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -333,7 +317,6 @@
         gradientDrawable.draw(null);
     }
 
-    @SmallTest
     @Test
     public void testSetColor() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -350,7 +333,6 @@
                 gradientDrawable.getColor().getDefaultColor());
     }
 
-    @SmallTest
     @Test
     public void testSetColors() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -367,7 +349,6 @@
                 colors, gradientDrawable.getColors());
     }
 
-    @SmallTest
     @Test
     public void testSetColorList() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -382,7 +363,6 @@
         assertEquals("Color was set to null (TRANSPARENT)", color, gradientDrawable.getColor());
     }
 
-    @SmallTest
     @Test
     public void testGetChangingConfigurations() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -395,7 +375,6 @@
         assertEquals(-20, gradientDrawable.getChangingConfigurations());
     }
 
-    @SmallTest
     @Test
     public void testSetAlpha() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -404,7 +383,6 @@
         gradientDrawable.setAlpha(-1);
     }
 
-    @SmallTest
     @Test
     public void testSetDither() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -413,7 +391,6 @@
         gradientDrawable.setDither(false);
     }
 
-    @SmallTest
     @Test
     public void testSetColorFilter() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -424,7 +401,6 @@
         gradientDrawable.setColorFilter(null);
     }
 
-    @SmallTest
     @Test
     public void testInflate() throws XmlPullParserException, IOException {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -469,7 +445,6 @@
         }
     }
 
-    @SmallTest
     @Test
     public void testInflateGradientRadius() throws XmlPullParserException, IOException {
         Rect parentBounds = new Rect(0, 0, 100, 100);
@@ -490,7 +465,6 @@
         assertEquals(50.0f, radius, 0.0f);
     }
 
-    @SmallTest
     @Test
     public void testGetIntrinsicWidth() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -501,7 +475,6 @@
         assertEquals(-10, gradientDrawable.getIntrinsicWidth());
     }
 
-    @SmallTest
     @Test
     public void testGetIntrinsicHeight() {
         GradientDrawable gradientDrawable = new GradientDrawable();
@@ -512,14 +485,12 @@
         assertEquals(-15, gradientDrawable.getIntrinsicHeight());
     }
 
-    @SmallTest
     @Test
     public void testGetConstantState() {
         GradientDrawable gradientDrawable = new GradientDrawable();
         assertNotNull(gradientDrawable.getConstantState());
     }
 
-    @SmallTest
     @Test
     public void testMutate() {
         GradientDrawable d1 =
@@ -555,17 +526,28 @@
         assertEquals(40, d3.getIntrinsicWidth());
     }
 
-    @MediumTest
     @Test
     public void testPreloadDensity() throws XmlPullParserException, IOException {
         final int densityDpi = mResources.getConfiguration().densityDpi;
         try {
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
             verifyPreloadDensityInner(mResources, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
         }
     }
 
+    @Test
+    public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+        final int densityDpi = mResources.getConfiguration().densityDpi;
+        try {
+            DrawableTestUtils.setResourcesDensity(mResources, 213);
+            verifyPreloadDensityInner(mResources, 213);
+        } finally {
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+        }
+    }
+
     private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
@@ -581,15 +563,17 @@
         final Rect origPadding = new Rect();
         preloadedDrawable.getPadding(origPadding);
 
-        // Set density to half of original. Unlike offsets, which are
+        // Set density to approximately half of original. Unlike offsets, which are
         // truncated, dimensions are rounded to the nearest pixel.
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final GradientDrawable halfDrawable =
                 (GradientDrawable) preloadedConstantState.newDrawable(res);
-        assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
-        assertEquals(Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+        assertEquals(Math.round(origWidth * approxHalf), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(origHeight * approxHalf), halfDrawable.getIntrinsicHeight());
         assertTrue(halfDrawable.getPadding(tempPadding));
-        assertEquals((int) (origPadding.left / 2f), tempPadding.left);
+        assertEquals((int) (origPadding.left * approxHalf), tempPadding.left);
 
         // Set density to double original.
         DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
@@ -609,20 +593,21 @@
         assertTrue(origDrawable.getPadding(tempPadding));
         assertEquals(origPadding, tempPadding);
 
-        // Some precision is lost when scaling the half-density
-        // drawable back up to the original density. Padding is
-        // always truncated, rather than rounded.
+        // Reproduce imprecise truncated scale down, and back up. Note these aren't rounded.
+        final float approxDouble = 1 / approxHalf;
         final Rect sloppyOrigPadding = new Rect();
-        sloppyOrigPadding.left = 2 * (origPadding.left / 2);
-        sloppyOrigPadding.top = 2 * (origPadding.top / 2);
-        sloppyOrigPadding.right = 2 * (origPadding.right / 2);
-        sloppyOrigPadding.bottom = 2 * (origPadding.bottom / 2);
+        sloppyOrigPadding.left = (int)(approxDouble * ((int)(origPadding.left * approxHalf)));
+        sloppyOrigPadding.top = (int)(approxDouble * ((int)(origPadding.top * approxHalf)));
+        sloppyOrigPadding.right = (int)(approxDouble * ((int)(origPadding.right * approxHalf)));
+        sloppyOrigPadding.bottom = (int)(approxDouble * ((int)(origPadding.bottom * approxHalf)));
 
         // Ensure theme density is applied correctly.
         final Theme t = res.newTheme();
         halfDrawable.applyTheme(t);
-        assertEquals(2 * Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
-        assertEquals(2 * Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+        assertEquals(Math.round(approxDouble * Math.round(origWidth * approxHalf)),
+                halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(approxDouble * Math.round(origHeight * approxHalf)),
+                halfDrawable.getIntrinsicHeight());
         assertTrue(halfDrawable.getPadding(tempPadding));
         assertEquals(sloppyOrigPadding, tempPadding);
         doubleDrawable.applyTheme(t);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index 3fcdf82..2d42f3c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -26,12 +26,15 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.XmlResourceParser;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.cts.R;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.InsetDrawable;
 import android.support.test.InstrumentationRegistry;
@@ -141,9 +144,42 @@
     }
 
     @Test
-    public void testGetPadding() {
+    public void testGetPadding_dimension() {
         InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, 1, 2, 3, 4);
+        Rect r = new Rect();
+        assertEquals(0, r.left);
+        assertEquals(0, r.top);
+        assertEquals(0, r.right);
+        assertEquals(0, r.bottom);
 
+        assertTrue(insetDrawable.getPadding(r));
+
+        assertEquals(1, r.left);
+        assertEquals(2, r.top);
+        assertEquals(3, r.right);
+        assertEquals(4, r.bottom);
+
+        // padding is set to 0, then return value should be false
+        insetDrawable = new InsetDrawable(mPassDrawable, .0f);
+
+        r = new Rect();
+        assertEquals(0, r.left);
+        assertEquals(0, r.top);
+        assertEquals(0, r.right);
+        assertEquals(0, r.bottom);
+
+        assertFalse(insetDrawable.getPadding(r));
+
+        assertEquals(0, r.left);
+        assertEquals(0, r.top);
+        assertEquals(0, r.right);
+        assertEquals(0, r.bottom);
+    }
+
+    @Test
+    public void testGetPadding_fraction() {
+        InsetDrawable insetDrawable = new InsetDrawable(mPassDrawable, .1f, .2f, .3f, .4f);
+        insetDrawable.setBounds(0, 0, 10, 10);
         Rect r = new Rect();
         assertEquals(0, r.left);
         assertEquals(0, r.top);
@@ -242,7 +278,7 @@
     }
 
     @Test
-    public void testOnBoundsChange() {
+    public void testOnBoundsChange_dimension() {
         MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
 
         Rect bounds = mPassDrawable.getBounds();
@@ -260,6 +296,56 @@
         assertEquals(-5, bounds.bottom);
     }
 
+    @Test
+    public void testOnBoundsChange_fraction() {
+        float inset = .1f;
+        int size = 40;
+        MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 0.1f);
+
+        Rect bounds = mPassDrawable.getBounds();
+        assertEquals(0, bounds.left);
+        assertEquals(0, bounds.top);
+        assertEquals(0, bounds.right);
+        assertEquals(0, bounds.bottom);
+
+        Rect r = new Rect(0, 0, size, size);
+        insetDrawable.onBoundsChange(r);
+
+        assertEquals((int) (size * inset), bounds.left);
+        assertEquals((int) (size * inset), bounds.top);
+        assertEquals(size - (int) (size * inset), bounds.right);
+        assertEquals(size - (int) (size * inset), bounds.bottom);
+    }
+
+    @Test
+    public void testIsBoundsAndIntrinsicSizeInverse() {
+        float inset = .1f;
+
+        // Test that intrinsic Width and Height calculation logic is inverse of the onBoundsChange.
+        MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, inset);
+
+        assertEquals((int)(mPassDrawable.getIntrinsicWidth() / (1 - 2 * inset)),
+            insetDrawable.getIntrinsicWidth());
+        assertEquals((int)(mPassDrawable.getIntrinsicHeight() / (1 - 2 * inset)),
+            insetDrawable.getIntrinsicHeight());
+
+        Rect r = new Rect(0, 0, insetDrawable.getIntrinsicWidth(),
+            insetDrawable.getIntrinsicHeight());
+        insetDrawable.onBoundsChange(r);
+        r = mPassDrawable.getBounds();
+
+        assertEquals((int)(insetDrawable.getIntrinsicWidth() * inset), r.left);
+        assertEquals((int)(insetDrawable.getIntrinsicHeight() * inset), r.top);
+        assertEquals(insetDrawable.getIntrinsicWidth()
+            - (int)((inset) * insetDrawable.getIntrinsicWidth()), r.right);
+        assertEquals(insetDrawable.getIntrinsicHeight()
+            - (int)((inset) * insetDrawable.getIntrinsicHeight()), r.bottom);
+
+        // Verify inverse!!
+        assertEquals(r.width(), mPassDrawable.getIntrinsicWidth(), 1);
+        assertEquals(r.height(), mPassDrawable.getIntrinsicHeight(), 1);
+    }
+
     @Test(expected=NullPointerException.class)
     public void testOnBoundsChangeNull() {
         MockInsetDrawable insetDrawable = new MockInsetDrawable(mPassDrawable, 5);
@@ -287,6 +373,10 @@
         mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
         expected = -1;
         assertEquals(expected, mPassDrawable.getIntrinsicWidth());
+
+        mInsetDrawable = new InsetDrawable(mPassDrawable, .2f);
+        expected = (int)(mPassDrawable.getIntrinsicWidth() * (1.4f));
+        assertEquals(expected, mInsetDrawable.getIntrinsicWidth());
     }
 
     @Test
@@ -309,6 +399,10 @@
         mPassDrawable = mContext.getDrawable(R.drawable.inset_color);
         expected = -1;
         assertEquals(expected, mPassDrawable.getIntrinsicHeight());
+
+        mInsetDrawable = new InsetDrawable(mPassDrawable, .2f);
+        expected = (int)(mPassDrawable.getIntrinsicHeight() * (1.4f));
+        assertEquals(expected, mInsetDrawable.getIntrinsicHeight());
     }
 
     @Test
@@ -342,12 +436,25 @@
         final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
+            DrawableTestUtils.setResourcesDensity(res, densityDpi);
             verifyPreloadDensityInner(res, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
+    @Test
+    public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+        final Resources res = mContext.getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+        try {
+            DrawableTestUtils.setResourcesDensity(res, 213);
+            verifyPreloadDensityInner(res, 213);
+        } finally {
+            DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        }
+    }
+
     private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
@@ -359,12 +466,14 @@
         final int origInsetHoriz = preloadedDrawable.getIntrinsicWidth()
                 - preloadedDrawable.getDrawable().getIntrinsicWidth();
 
-        // Set density to half of original. Unlike offsets, which are
+        // Set density to approximately half of original. Unlike offsets, which are
         // truncated, dimensions are rounded to the nearest pixel.
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final InsetDrawable halfDrawable =
                 (InsetDrawable) preloadedConstantState.newDrawable(res);
-        assertEquals(Math.round(origInsetHoriz / 2f), halfDrawable.getIntrinsicWidth()
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+        assertEquals(Math.round(origInsetHoriz * approxHalf), halfDrawable.getIntrinsicWidth()
                 - halfDrawable.getDrawable().getIntrinsicWidth());
 
         // Set density to double original.
@@ -384,14 +493,20 @@
         // Ensure theme density is applied correctly.
         final Theme t = res.newTheme();
         halfDrawable.applyTheme(t);
-        assertEquals(origInsetHoriz, halfDrawable.getIntrinsicWidth()
-                - halfDrawable.getDrawable().getIntrinsicWidth());
+        float approxDouble = 1 / approxHalf;
+        // Reproduce imprecise truncated scale down, and back up. Note that we don't round.
+        assertEquals((int)(approxDouble * ((int)(origInsetHoriz * approxHalf))),
+                halfDrawable.getIntrinsicWidth() - halfDrawable.getDrawable().getIntrinsicWidth());
         doubleDrawable.applyTheme(t);
         assertEquals(origInsetHoriz, doubleDrawable.getIntrinsicWidth()
                 - doubleDrawable.getDrawable().getIntrinsicWidth());
     }
 
     private class MockInsetDrawable extends InsetDrawable {
+        public MockInsetDrawable(Drawable drawable, float inset) {
+            super(drawable, inset);
+        }
+
         public MockInsetDrawable(Drawable drawable, int inset) {
             super(drawable, inset);
         }
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index 22491ee..ed9a187 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -1678,12 +1678,25 @@
         final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
+            DrawableTestUtils.setResourcesDensity(res, densityDpi);
             verifyPreloadDensityInner(res, densityDpi);
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
+    @Test
+    public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+        final Resources res = mContext.getResources();
+        final int densityDpi = res.getConfiguration().densityDpi;
+        try {
+            DrawableTestUtils.setResourcesDensity(res, 213);
+            verifyPreloadDensityInner(res, 213);
+        } finally {
+            DrawableTestUtils.setResourcesDensity(res, densityDpi);
+        }
+    }
+
     private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
@@ -1714,11 +1727,13 @@
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final LayerDrawable halfDrawable =
                 (LayerDrawable) preloadedConstantState.newDrawable(res);
-        final int halfContentWidth = Math.round(initialContentWidth / 2f);
-        final int halfLeftPadding = initialLeftPadding / 2;
-        final int halfRightPadding = initialRightPadding / 2;
-        final int halfContentInsetL = initialContentInsetL / 2;
-        final int halfContentInsetR = initialContentInsetR / 2;
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+        final int halfContentWidth = Math.round(initialContentWidth * approxHalf);
+        final int halfLeftPadding = (int) (initialLeftPadding * approxHalf);
+        final int halfRightPadding = (int) (initialRightPadding * approxHalf);
+        final int halfContentInsetL = (int) (initialContentInsetL * approxHalf);
+        final int halfContentInsetR = (int) (initialContentInsetR * approxHalf);
         final int halfIntrinsicWidth = halfContentWidth + halfContentInsetL + halfContentInsetR;
         assertEquals(halfLeftPadding, halfDrawable.getLeftPadding());
         assertEquals(halfRightPadding, halfDrawable.getRightPadding());
@@ -1726,14 +1741,18 @@
         assertEquals(halfContentInsetR, halfDrawable.getLayerInsetLeft(0));
         assertEquals(halfContentWidth, halfDrawable.getLayerWidth(0));
         assertEquals(halfIntrinsicWidth, halfDrawable.getIntrinsicWidth());
-        assertEquals(initialBottomPadding / 2, halfDrawable.getBottomPadding());
-        assertEquals(initialTopPadding / 2, halfDrawable.getTopPadding());
-        assertEquals(initialLayerInsetLeft / 2,halfDrawable.getLayerInsetLeft(0));
-        assertEquals(initialLayerInsetRight / 2, halfDrawable.getLayerInsetRight(0));
-        assertEquals(initialLayerInsetTop / 2, halfDrawable.getLayerInsetTop(0));
-        assertEquals(initialLayerInsetBottom / 2, halfDrawable.getLayerInsetBottom(0));
-        assertEquals(Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
-        assertEquals(Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+        assertEquals((int) (initialBottomPadding * approxHalf), halfDrawable.getBottomPadding());
+        assertEquals((int) (initialTopPadding * approxHalf), halfDrawable.getTopPadding());
+        assertEquals((int) (initialLayerInsetLeft * approxHalf),
+                halfDrawable.getLayerInsetLeft(0));
+        assertEquals((int) (initialLayerInsetRight * approxHalf),
+                halfDrawable.getLayerInsetRight(0));
+        assertEquals((int) (initialLayerInsetTop * approxHalf),
+                halfDrawable.getLayerInsetTop(0));
+        assertEquals((int) (initialLayerInsetBottom * approxHalf),
+                halfDrawable.getLayerInsetBottom(0));
+        assertEquals(Math.round(initialLayerWidth * approxHalf), halfDrawable.getLayerWidth(0));
+        assertEquals(Math.round(initialLayerHeight * approxHalf), halfDrawable.getLayerHeight(0));
 
         // Set density to double original.
         DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
@@ -1779,20 +1798,31 @@
         // The half-density drawable will scale-up all of the values that were
         // previously scaled-down, so we need to capture the rounding errors.
         halfDrawable.applyTheme(t);
-        assertEquals(halfLeftPadding * 2, halfDrawable.getLeftPadding());
-        assertEquals(halfRightPadding * 2, halfDrawable.getRightPadding());
-        assertEquals(halfContentInsetL * 2, halfDrawable.getLayerInsetRight(0));
-        assertEquals(halfContentInsetR * 2, halfDrawable.getLayerInsetLeft(0));
-        assertEquals(halfContentWidth * 2, halfDrawable.getLayerWidth(0));
+
+        // Reproduce imprecise truncated scale down, and back up. Note that we don't round.
+        float approxDouble = 1 / approxHalf;
+        assertEquals((int) (halfLeftPadding * approxDouble), halfDrawable.getLeftPadding());
+        assertEquals((int) (halfRightPadding * approxDouble), halfDrawable.getRightPadding());
+        assertEquals((int) (halfContentInsetL * approxDouble), halfDrawable.getLayerInsetRight(0));
+        assertEquals((int) (halfContentInsetR * approxDouble), halfDrawable.getLayerInsetLeft(0));
+        assertEquals((int) (halfContentWidth * approxDouble), halfDrawable.getLayerWidth(0));
         assertEquals(halfIntrinsicWidth * 2, halfDrawable.getIntrinsicWidth());
-        assertEquals(2 * (initialBottomPadding / 2), halfDrawable.getBottomPadding());
-        assertEquals(2 * (initialTopPadding / 2), halfDrawable.getTopPadding());
-        assertEquals(2 * (initialLayerInsetLeft / 2), halfDrawable.getLayerInsetLeft(0));
-        assertEquals(2 * (initialLayerInsetRight / 2), halfDrawable.getLayerInsetRight(0));
-        assertEquals(2 * (initialLayerInsetTop / 2), halfDrawable.getLayerInsetTop(0));
-        assertEquals(2 * (initialLayerInsetBottom / 2), halfDrawable.getLayerInsetBottom(0));
-        assertEquals(2 * Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
-        assertEquals(2 * Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+        assertEquals((int) ((int) (initialBottomPadding * approxHalf) * approxDouble),
+                halfDrawable.getBottomPadding());
+        assertEquals((int) ((int) (initialTopPadding * approxHalf) * approxDouble),
+                halfDrawable.getTopPadding());
+        assertEquals((int) ((int) (initialLayerInsetLeft * approxHalf) * approxDouble),
+                halfDrawable.getLayerInsetLeft(0));
+        assertEquals((int) ((int) (initialLayerInsetRight * approxHalf) * approxDouble),
+                halfDrawable.getLayerInsetRight(0));
+        assertEquals((int) ((int) (initialLayerInsetTop * approxHalf) * approxDouble),
+                halfDrawable.getLayerInsetTop(0));
+        assertEquals((int) ((int) (initialLayerInsetBottom * approxHalf) * approxDouble),
+                halfDrawable.getLayerInsetBottom(0));
+        assertEquals(Math.round(Math.round(initialLayerWidth * approxHalf) * approxDouble),
+                halfDrawable.getLayerWidth(0));
+        assertEquals(Math.round(Math.round(initialLayerHeight * approxHalf) * approxDouble),
+                halfDrawable.getLayerHeight(0));
 
         // The double-density drawable will scale-down all of the values that
         // were previously scaled-up, so we don't need to worry about rounding.
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 80d604e..d563102 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -36,6 +36,7 @@
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.cts.R;
@@ -219,6 +220,18 @@
         assertNull(shapeDrawable.getShaderFactory());
     }
 
+    @Test
+    public void testSetXfermode() {
+        ShapeDrawable shapeDrawable = new ShapeDrawable();
+
+        PorterDuffXfermode xfermode = new PorterDuffXfermode(Mode.SRC_OVER);
+        shapeDrawable.setXfermode(xfermode);
+        assertSame(xfermode, shapeDrawable.getPaint().getXfermode());
+
+        shapeDrawable.setXfermode(null);
+        assertNull(shapeDrawable.getPaint().getXfermode());
+    }
+
     public static class MockShaderFactory extends ShaderFactory {
         public Shader resize(int width, int height) {
             return null;
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
index fb3445e..6499594 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/StateListDrawableTest.java
@@ -229,10 +229,12 @@
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final StateListDrawable halfDrawable =
                 (StateListDrawable) preloadedConstantState.newDrawable(res);
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
         halfDrawable.selectDrawable(0);
-        assertEquals(Math.round(origWidth0 / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(origWidth0 * approxHalf), halfDrawable.getIntrinsicWidth());
         halfDrawable.selectDrawable(1);
-        assertEquals(Math.round(origWidth1 / 2f), halfDrawable.getIntrinsicWidth());
+        assertEquals(Math.round(origWidth1 * approxHalf), halfDrawable.getIntrinsicWidth());
 
         // Set density to double original.
         DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index 16c6961..276bf50 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -33,7 +33,6 @@
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.VectorDrawable;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.MediumTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
@@ -50,6 +49,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 
+@SmallTest
 @RunWith(AndroidJUnit4.class)
 public class VectorDrawableTest {
     private static final String LOGTAG = "VectorDrawableTest";
@@ -200,31 +200,26 @@
         mResources = InstrumentationRegistry.getTargetContext().getResources();
     }
 
-    @MediumTest
     @Test
     public void testBasicVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(BASIC_ICON_RES_IDS, BASIC_GOLDEN_IMAGES, null);
     }
 
-    @MediumTest
     @Test
     public void testLMVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(L_M_ICON_RES_IDS, L_M_GOLDEN_IMAGES, null);
     }
 
-    @MediumTest
     @Test
     public void testNVectorDrawables() throws XmlPullParserException, IOException {
         verifyVectorDrawables(N_ICON_RES_IDS, N_GOLDEN_IMAGES, null);
     }
 
-    @MediumTest
     @Test
     public void testVectorDrawableGradient() throws XmlPullParserException, IOException {
         verifyVectorDrawables(GRADIENT_ICON_RES_IDS, GRADIENT_GOLDEN_IMAGES, null);
     }
 
-    @MediumTest
     @Test
     public void testColorStateList() throws XmlPullParserException, IOException {
         for (int i = 0; i < STATEFUL_STATE_SETS.length; i++) {
@@ -344,7 +339,6 @@
         return builder.toString();
     }
 
-    @SmallTest
     @Test
     public void testGetChangingConfigurations() {
         VectorDrawable vectorDrawable = new VectorDrawable();
@@ -369,7 +363,6 @@
         assertEquals(0xffff,  vectorDrawable.getChangingConfigurations());
     }
 
-    @SmallTest
     @Test
     public void testGetConstantState() {
         VectorDrawable vectorDrawable = new VectorDrawable();
@@ -383,7 +376,6 @@
         assertEquals(1, constantState.getChangingConfigurations());
     }
 
-    @SmallTest
     @Test
     public void testMutate() {
         // d1 and d2 will be mutated, while d3 will not.
@@ -419,7 +411,6 @@
         }
     }
 
-    @SmallTest
     @Test
     public void testColorFilter() {
         PorterDuffColorFilter filter = new PorterDuffColorFilter(Color.RED, Mode.SRC_IN);
@@ -429,18 +420,6 @@
         assertEquals(filter, vectorDrawable.getColorFilter());
     }
 
-    @SmallTest
-    @Test
-    public void testPreloadDensity() throws XmlPullParserException, IOException {
-        final int densityDpi = mResources.getConfiguration().densityDpi;
-        try {
-            verifyPreloadDensityInner(mResources, densityDpi);
-        } finally {
-            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
-        }
-    }
-
-    @SmallTest
     @Test
     public void testGetOpacity () throws XmlPullParserException, IOException {
         VectorDrawable vectorDrawable = new VectorDrawable();
@@ -455,6 +434,28 @@
                 vectorDrawable.getOpacity());
     }
 
+    @Test
+    public void testPreloadDensity() throws XmlPullParserException, IOException {
+        final int densityDpi = mResources.getConfiguration().densityDpi;
+        try {
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+            verifyPreloadDensityInner(mResources, densityDpi);
+        } finally {
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+        }
+    }
+
+    @Test
+    public void testPreloadDensity_tvdpi() throws XmlPullParserException, IOException {
+        final int densityDpi = mResources.getConfiguration().densityDpi;
+        try {
+            DrawableTestUtils.setResourcesDensity(mResources, 213);
+            verifyPreloadDensityInner(mResources, 213);
+        } finally {
+            DrawableTestUtils.setResourcesDensity(mResources, densityDpi);
+        }
+    }
+
     private void verifyPreloadDensityInner(Resources res, int densityDpi)
             throws XmlPullParserException, IOException {
         // Capture initial state at default density.
@@ -470,7 +471,9 @@
         DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
         final VectorDrawable halfDrawable =
                 (VectorDrawable) preloadedConstantState.newDrawable(res);
-        assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+        // NOTE: densityDpi may not be an even number, so account for *actual* scaling in asserts
+        final float approxHalf = (float)(densityDpi / 2) / densityDpi;
+        assertEquals(Math.round(origWidth * approxHalf), halfDrawable.getIntrinsicWidth());
 
         // Set density to double original.
         DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
index 3b890f2..4721afb 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
+++ b/tests/tests/jni/libjnitest/android_jni_cts_LinkerNamespacesTest.cpp
@@ -71,11 +71,21 @@
 }
 
 static bool already_loaded(const std::string& library, const std::string& err) {
-  if (err.find("dlopen failed: library \"" + library + "\"") != 0 ||
-      err.find("is not accessible for the namespace \"classloader-namespace\"") == std::string::npos) {
-    return false;
+  // SELinux denials for /vendor libraries may return with library not found
+  if (err.find("dlopen failed: library \"" + library + "\"") == 0 &&
+      (err.find("not found") != std::string::npos ||
+      err.find("is not accessible for the namespace \"classloader-namespace\"") != std::string::npos)) {
+    return true;
   }
-  return true;
+
+  return false;
+}
+
+static bool wrong_arch(const std::string& err) {
+  // https://issuetracker.google.com/37428428
+  // It's okay to not be able to load a library because it's for another
+  // architecture (typically on an x86 device, when we come across an arm library).
+  return err.find("unexpected e_machine: ") != std::string::npos;
 }
 
 static bool check_lib(const std::string& path,
@@ -104,7 +114,7 @@
   } else { // (handle == nullptr && !shouldBeAccessible(path))
     // Check the error message
     std::string err = dlerror();
-    if (!already_loaded(path, err)) {
+    if (!already_loaded(path, err) && !wrong_arch(err)) {
       errors->push_back("unexpected dlerror: " + err);
       return false;
     }
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 8bfd79b..b7f7c8e 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;
@@ -108,6 +109,7 @@
             .compile("([0-9]{4})-([0-9]{2})-[0-9]{2}");
 
     private static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+    private static final int KM_ERROR_PERMISSION_DENIED = 6;
 
     public void testVersionParser() throws Exception {
         // Non-numerics/empty give version 0
@@ -210,6 +212,29 @@
         }
     }
 
+    public void testEcAttestation_KeyStoreExceptionWhenRequestingUniqueId() throws Exception {
+        String keystoreAlias = "test_key";
+        KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(keystoreAlias, PURPOSE_SIGN)
+                .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
+                .setDigests(DIGEST_NONE, DIGEST_SHA256, DIGEST_SHA512)
+                .setAttestationChallenge(new byte[128])
+                .setUniqueIdIncluded(true)
+                .build();
+
+        try {
+            generateKeyPair(KEY_ALGORITHM_EC, spec);
+            fail("Attestation should have failed.");
+        } catch (ProviderException e) {
+            // Attestation is expected to fail because of lack of permissions.
+            KeyStoreException cause = (KeyStoreException) e.getCause();
+            assertEquals(KM_ERROR_PERMISSION_DENIED, cause.getErrorCode());
+        } finally {
+            KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+            keyStore.load(null);
+            keyStore.deleteEntry(keystoreAlias);
+        }
+    }
+
     public void testRsaAttestation() throws Exception {
         int[] keySizes = { // Smallish sizes to keep test runtimes down.
                 512, 768, 1024
@@ -357,9 +382,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 +880,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/location/src/android/location/cts/LocationTest.java b/tests/tests/location/src/android/location/cts/LocationTest.java
index bec6350..3e291cf 100644
--- a/tests/tests/location/src/android/location/cts/LocationTest.java
+++ b/tests/tests/location/src/android/location/cts/LocationTest.java
@@ -282,10 +282,6 @@
         location.setVerticalAccuracyMeters(1.0f);
         assertEquals(1.0, location.getVerticalAccuracyMeters(), DELTA);
         assertTrue(location.hasVerticalAccuracy());
-
-        location.removeVerticalAccuracy();
-        assertEquals(0.0, location.getVerticalAccuracyMeters(), DELTA);
-        assertFalse(location.hasVerticalAccuracy());
     }
 
     public void testAccessSpeedAccuracy() {
@@ -295,10 +291,6 @@
         location.setSpeedAccuracyMetersPerSecond(1.0f);
         assertEquals(1.0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
         assertTrue(location.hasSpeedAccuracy());
-
-        location.removeSpeedAccuracy();
-        assertEquals(0.0, location.getSpeedAccuracyMetersPerSecond(), DELTA);
-        assertFalse(location.hasSpeedAccuracy());
     }
 
     public void testAccessBearingAccuracy() {
@@ -308,10 +300,6 @@
         location.setBearingAccuracyDegrees(1.0f);
         assertEquals(1.0, location.getBearingAccuracyDegrees(), DELTA);
         assertTrue(location.hasBearingAccuracy());
-
-        location.removeBearingAccuracy();
-        assertEquals(0.0, location.getBearingAccuracyDegrees(), DELTA);
-        assertFalse(location.hasBearingAccuracy());
     }
 
 
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 1a3a2f0..891fa11 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -181,9 +181,9 @@
         int state = measurement.getState();
         softAssert.assertTrue("state: Satellite code sync state",
                 timeInNs,
-                "X > 0",
+                "X >= 0",
                 String.valueOf(state),
-                state >=0);
+                state >= 0);
 
         // Check received_gps_tow_uncertainty_ns
         softAssert.assertTrueAsWarning("received_gps_tow_uncertainty_ns:" +
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java b/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java
deleted file mode 100644
index 07d7290..0000000
--- a/tests/tests/media/src/android/media/cts/AudioRecordConcurrencyTest.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * 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 android.media.cts;
-
-import android.content.pm.PackageManager;
-import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioRecord;
-import android.media.MediaRecorder;
-import android.media.AudioRecordingConfiguration;
-import android.util.Log;
-
-import com.android.compatibility.common.util.CtsAndroidTestCase;
-
-import java.util.List;
-
-public class AudioRecordConcurrencyTest extends CtsAndroidTestCase {
-    static final String TAG = "AudioRecordConcurrencyTest";
-    static final String REPORT_LOG_NAME = "CtsMediaTestCases";
-    static final int RECORD_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
-    static final int RECORD_CHANNEL_MASK = AudioFormat.CHANNEL_IN_MONO;
-    static final int RECORD_SAMPLE_RATE = 16000;
-    static final long SLEEP_AFTER_STOP_FOR_INACTIVITY_MS = 1000;
-    static final int TEST_TIMING_TOLERANCE_MS = 70;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        if (!hasMicrophone()) {
-            Log.i(TAG, "AudioRecordConcurrencyTest skipped: no microphone");
-            return;
-        }
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
-    public void testConcurrentRecord() throws Exception {
-        final String TEST_NAME = "testConcurrentRecord";
-
-        if (!hasMicrophone()) {
-            Log.i(TAG, "testConcurrentRecord() skipped: no microphone");
-            return;
-        }
-
-        int[] foregroundSources = new int[] {
-                MediaRecorder.AudioSource.MIC,
-                MediaRecorder.AudioSource.CAMCORDER,
-                MediaRecorder.AudioSource.VOICE_COMMUNICATION,
-        };
-
-        int[] backgroundSources = new int[] {
-                MediaRecorder.AudioSource.VOICE_RECOGNITION,
-        };
-
-        for (int source1 : backgroundSources) {
-            for (int source2 : backgroundSources) {
-                assertTrue(TEST_NAME+" failed background source: "+source1+
-                           " background source: "+source2,
-                           doConcurrencyTest(TEST_NAME, source1, source2));
-            }
-        }
-
-        for (int source1 : backgroundSources) {
-            for (int source2 : foregroundSources) {
-                assertTrue(TEST_NAME+" failed background source: "+source1+
-                           " foreground source: "+source2,
-                           doConcurrencyTest(TEST_NAME, source1, source2));
-            }
-        }
-
-        for (int source1 : foregroundSources) {
-            for (int source2 : backgroundSources) {
-                assertTrue(TEST_NAME+" failed foreground source: "+source1+
-                           " background source: "+source2,
-                           doConcurrencyTest(TEST_NAME, source1, source2));
-            }
-        }
-
-        for (int source1 : foregroundSources) {
-            for (int source2 : foregroundSources) {
-                assertFalse(TEST_NAME+" failed foreground: "+ source1+
-                        " foreground source: "+ source2,
-                        doConcurrencyTest(TEST_NAME, source1, source2));
-            }
-        }
-    }
-
-    boolean doConcurrencyTest(String testName, int source1, int source2) {
-        AudioRecord record1 = null;
-        AudioRecord record2 = null;
-        boolean active1 = false;
-        boolean active2 = false;
-
-        try {
-
-            AudioFormat format = new AudioFormat.Builder()
-                    .setSampleRate(RECORD_SAMPLE_RATE)
-                    .setChannelMask(RECORD_CHANNEL_MASK)
-                    .setEncoding(RECORD_ENCODING)
-                    .build();
-
-            record1 = new AudioRecord.Builder()
-                    .setAudioSource(source1)
-                    .setAudioFormat(format)
-                    .build();
-            // AudioRecord creation may have silently failed, check state now
-            assertEquals(testName, AudioRecord.STATE_INITIALIZED, record1.getState());
-
-            record2 = new AudioRecord.Builder()
-                    .setAudioSource(source2)
-                    .setAudioFormat(format)
-                    .build();
-            // AudioRecord creation may have silently failed, check state now
-            assertEquals(testName, AudioRecord.STATE_INITIALIZED, record2.getState());
-
-            final int BUFFER_FRAMES = 512;
-            final int BUFFER_SAMPLES = BUFFER_FRAMES * format.getChannelCount();
-
-            short[] shortData = new short[BUFFER_SAMPLES];
-
-            record1.startRecording();
-            record2.startRecording();
-            try {
-                Thread.sleep(TEST_TIMING_TOLERANCE_MS);
-            } catch (InterruptedException e) {
-            }
-            if (record1.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
-                int ret = record1.read(shortData, 0, BUFFER_SAMPLES);
-                active1 = ret == BUFFER_SAMPLES;
-            }
-            if (record2.getRecordingState() == AudioRecord.RECORDSTATE_RECORDING) {
-                int ret = record2.read(shortData, 0, BUFFER_SAMPLES);
-                active2 = ret == BUFFER_SAMPLES;
-            }
-
-            if (active1 && active2) {
-                // verify we have at least 2 active recording configurations
-                AudioManager am = new AudioManager(getContext());
-                assertNotNull("Could not create AudioManager", am);
-                List<AudioRecordingConfiguration> configs = am.getActiveRecordingConfigurations();
-                assertNotNull("Invalid null array of record configurations during recording",
-                        configs);
-                assertTrue("no active record configurations (empty array) during recording",
-                        configs.size() > 1);
-            }
-
-            record2.stop();
-            record1.stop();
-        } finally {
-            if (record1 != null) {
-                record1.release();
-            }
-            if (record2 != null) {
-                record2.release();
-            }
-            // wait for stop to be completed at audio flinger level
-            try {
-                Thread.sleep(SLEEP_AFTER_STOP_FOR_INACTIVITY_MS);
-            } catch (InterruptedException e) {
-            }
-        }
-        return active1 && active2;
-    }
-
-    private boolean hasMicrophone() {
-        return getContext().getPackageManager().hasSystemFeature(
-                PackageManager.FEATURE_MICROPHONE);
-    }
-}
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/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 0cbbe7e..99c0ac1 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -36,13 +36,63 @@
             "android.media.cts", "android.media.cts.StubMediaBrowserService");
     private final Object mWaitLock = new Object();
 
-    private final ConnectionCallback mConnectionCallback = new ConnectionCallback();
-    private final SubscriptionCallback mSubscriptionCallback = new SubscriptionCallback();
-    private final ItemCallback mItemCallback = new ItemCallback();
-    private final SearchCallback mSearchCallback = new SearchCallback();
+    private final MediaBrowser.ConnectionCallback mConnectionCallback =
+            new MediaBrowser.ConnectionCallback() {
+        @Override
+        public void onConnected() {
+            synchronized (mWaitLock) {
+                mMediaBrowserService = StubMediaBrowserService.sInstance;
+                mWaitLock.notify();
+            }
+        }
+    };
+
+    private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
+            new MediaBrowser.SubscriptionCallback() {
+            @Override
+            public void onChildrenLoaded(String parentId, List<MediaItem> children) {
+                synchronized (mWaitLock) {
+                    mOnChildrenLoaded = true;
+                    if (children != null) {
+                        for (MediaItem item : children) {
+                            assertRootHints(item);
+                        }
+                    }
+                    mWaitLock.notify();
+                }
+            }
+
+            @Override
+            public void onChildrenLoaded(String parentId, List<MediaItem> children,
+                    Bundle options) {
+                synchronized (mWaitLock) {
+                    mOnChildrenLoadedWithOptions = true;
+                    if (children != null) {
+                        for (MediaItem item : children) {
+                            assertRootHints(item);
+                        }
+                    }
+                    mWaitLock.notify();
+                }
+            }
+        };
+
+    private final MediaBrowser.ItemCallback mItemCallback = new MediaBrowser.ItemCallback() {
+        @Override
+        public void onItemLoaded(MediaItem item) {
+            synchronized (mWaitLock) {
+                mOnItemLoaded = true;
+                assertRootHints(item);
+                mWaitLock.notify();
+            }
+        }
+    };
 
     private MediaBrowser mMediaBrowser;
     private StubMediaBrowserService mMediaBrowserService;
+    private boolean mOnChildrenLoaded;
+    private boolean mOnChildrenLoadedWithOptions;
+    private boolean mOnItemLoaded;
     private Bundle mRootHints;
 
     @Override
@@ -72,15 +122,14 @@
 
     public void testNotifyChildrenChanged() throws Exception {
         synchronized (mWaitLock) {
-            mSubscriptionCallback.reset();
             mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+            assertTrue(mOnChildrenLoaded);
 
-            mSubscriptionCallback.reset();
+            mOnChildrenLoaded = false;
             mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+            assertTrue(mOnChildrenLoaded);
         }
     }
 
@@ -92,54 +141,53 @@
             options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
             options.putInt(MediaBrowser.EXTRA_PAGE, page);
 
-            mSubscriptionCallback.reset();
             mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
                     mSubscriptionCallback);
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
+            assertTrue(mOnChildrenLoadedWithOptions);
 
-            mSubscriptionCallback.reset();
+            mOnChildrenLoadedWithOptions = false;
             mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoadedWithOptions);
+            assertTrue(mOnChildrenLoadedWithOptions);
         }
     }
 
     public void testDelayedNotifyChildrenChanged() throws Exception {
         synchronized (mWaitLock) {
-            mSubscriptionCallback.reset();
+            mOnChildrenLoaded = false;
             mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
                     mSubscriptionCallback);
             mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
+            assertFalse(mOnChildrenLoaded);
 
             mMediaBrowserService.sendDelayedNotifyChildrenChanged();
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+            assertTrue(mOnChildrenLoaded);
 
-            mSubscriptionCallback.reset();
+            mOnChildrenLoaded = false;
             mMediaBrowserService.notifyChildrenChanged(
                     StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED);
             mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertFalse(mSubscriptionCallback.mOnChildrenLoaded);
+            assertFalse(mOnChildrenLoaded);
 
             mMediaBrowserService.sendDelayedNotifyChildrenChanged();
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mSubscriptionCallback.mOnChildrenLoaded);
+            assertTrue(mOnChildrenLoaded);
         }
     }
 
     public void testDelayedItem() throws Exception {
         synchronized (mWaitLock) {
-            mItemCallback.reset();
-            mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED, mItemCallback);
+            mOnItemLoaded = false;
+            mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
+                    mItemCallback);
             mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertFalse(mItemCallback.mOnItemLoaded);
+            assertFalse(mOnItemLoaded);
 
-            mItemCallback.reset();
             mMediaBrowserService.sendDelayedItemLoaded();
             mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mItemCallback.mOnItemLoaded);
+            assertTrue(mOnItemLoaded);
         }
     }
 
@@ -155,60 +203,6 @@
         assertEquals(val, browserRoot.getExtras().getString(key));
     }
 
-    public void testSearch() throws Exception {
-        final String key = "test-key";
-        final String val = "test-val";
-
-        final MediaBrowser.SearchCallback searchCallback =
-                (MediaBrowser.SearchCallback) mSearchCallback;
-        final MediaBrowserService mediaBrowserService = (MediaBrowserService) mMediaBrowserService;
-
-        synchronized (mWaitLock) {
-            mSearchCallback.reset();
-            mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT, null,
-                    mSearchCallback);
-            mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertTrue(mSearchCallback.mOnSearchResult);
-            assertTrue(mSearchCallback.mSearchResults != null
-                    && mSearchCallback.mSearchResults.size() == 0);
-            assertEquals(null, mSearchCallback.mSearchExtras);
-            // just call the callback once directly so it's marked as tested
-            mediaBrowserService.onSearch(
-                    StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT, null, null);
-            searchCallback.onSearchResult(StubMediaBrowserService.SEARCH_QUERY_FOR_NO_RESULT,
-                    mSearchCallback.mSearchExtras, mSearchCallback.mSearchResults);
-
-            mSearchCallback.reset();
-            mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null,
-                    mSearchCallback);
-            mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertTrue(mSearchCallback.mOnSearchResult);
-            assertNull(mSearchCallback.mSearchResults);
-            assertEquals(null, mSearchCallback.mSearchExtras);
-            // just call the callback once directly so it's marked as tested
-            mediaBrowserService.onSearch(
-                    StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null, null);
-            searchCallback.onError(StubMediaBrowserService.SEARCH_QUERY_FOR_ERROR, null);
-
-            mSearchCallback.reset();
-            Bundle extras = new Bundle();
-            extras.putString(key, val);
-            mMediaBrowser.search(StubMediaBrowserService.SEARCH_QUERY, extras, mSearchCallback);
-            mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
-            assertTrue(mSearchCallback.mOnSearchResult);
-            assertNotNull(mSearchCallback.mSearchResults);
-            for (MediaItem item : mSearchCallback.mSearchResults) {
-                assertTrue(item.getMediaId().contains(StubMediaBrowserService.SEARCH_QUERY));
-            }
-            assertNotNull(mSearchCallback.mSearchExtras);
-            assertEquals(val, mSearchCallback.mSearchExtras.getString(key));
-            // just call the callback once directly so it's marked as tested
-            mediaBrowserService.onSearch(StubMediaBrowserService.SEARCH_QUERY, extras, null);
-            searchCallback.onSearchResult(StubMediaBrowserService.SEARCH_QUERY,
-                    mSearchCallback.mSearchExtras, mSearchCallback.mSearchResults);
-        }
-    }
-
     private void assertRootHints(MediaItem item) {
         Bundle rootHints = item.getDescription().getExtras();
         assertNotNull(rootHints);
@@ -219,100 +213,4 @@
         assertEquals(mRootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED),
                 rootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED));
     }
-
-    private class ConnectionCallback extends MediaBrowser.ConnectionCallback {
-        @Override
-        public void onConnected() {
-            synchronized (mWaitLock) {
-                mMediaBrowserService = StubMediaBrowserService.sInstance;
-                mWaitLock.notify();
-            }
-        }
-    }
-
-    private class SubscriptionCallback extends MediaBrowser.SubscriptionCallback {
-        boolean mOnChildrenLoaded;
-        boolean mOnChildrenLoadedWithOptions;
-
-        @Override
-        public void onChildrenLoaded(String parentId, List<MediaItem> children) {
-            synchronized (mWaitLock) {
-                mOnChildrenLoaded = true;
-                if (children != null) {
-                    for (MediaItem item : children) {
-                        assertRootHints(item);
-                    }
-                }
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onChildrenLoaded(String parentId, List<MediaItem> children,
-                Bundle options) {
-            synchronized (mWaitLock) {
-                mOnChildrenLoadedWithOptions = true;
-                if (children != null) {
-                    for (MediaItem item : children) {
-                        assertRootHints(item);
-                    }
-                }
-                mWaitLock.notify();
-            }
-        }
-
-        public void reset() {
-            mOnChildrenLoaded = false;
-            mOnChildrenLoadedWithOptions = false;
-        }
-    }
-
-    private class ItemCallback extends MediaBrowser.ItemCallback {
-        boolean mOnItemLoaded;
-
-        @Override
-        public void onItemLoaded(MediaItem item) {
-            synchronized (mWaitLock) {
-                mOnItemLoaded = true;
-                assertRootHints(item);
-                mWaitLock.notify();
-            }
-        }
-
-        public void reset() {
-            mOnItemLoaded = false;
-        }
-    }
-
-    private class SearchCallback extends MediaBrowser.SearchCallback {
-        boolean mOnSearchResult;
-        Bundle mSearchExtras;
-        List<MediaItem> mSearchResults;
-
-        @Override
-        public void onSearchResult(String query, Bundle extras, List<MediaItem> items) {
-            synchronized (mWaitLock) {
-                mOnSearchResult = true;
-                mSearchResults = items;
-                mSearchExtras = extras;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onError(String query, Bundle extras) {
-            synchronized (mWaitLock) {
-                mOnSearchResult = true;
-                mSearchResults = null;
-                mSearchExtras = extras;
-                mWaitLock.notify();
-            }
-        }
-
-        public void reset() {
-            mOnSearchResult = false;
-            mSearchExtras = null;
-            mSearchResults = null;
-        }
-    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaCasTest.java b/tests/tests/media/src/android/media/cts/MediaCasTest.java
index d2ae849..a3cdefc 100644
--- a/tests/tests/media/src/android/media/cts/MediaCasTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCasTest.java
@@ -18,6 +18,7 @@
 
 import android.media.MediaCas;
 import android.media.MediaCas.PluginDescriptor;
+import android.media.MediaCas.Session;
 import android.media.MediaCasException;
 import android.media.MediaCasException.UnsupportedCasException;
 import android.media.MediaCasStateException;
@@ -181,10 +182,10 @@
                 }, null);
             } finally {
                 if (mediaCas != null) {
-                    mediaCas.release();
+                    mediaCas.close();
                 }
                 if (descrambler != null) {
-                    descrambler.release();
+                    descrambler.close();
                 }
             }
         }
@@ -213,10 +214,10 @@
             }
         } finally {
             if (unsupportedCAS != null) {
-                unsupportedCAS.release();
+                unsupportedCAS.close();
             }
             if (unsupportedDescrambler != null) {
-                unsupportedDescrambler.release();
+                unsupportedDescrambler.close();
             }
         }
     }
@@ -247,24 +248,22 @@
             byte[] pvtData = new byte[256];
             mediaCas.setPrivateData(pvtData);
 
-            int program_number = 72849;
-            int elementary_PID = 256;
-            byte[] sessionId = mediaCas.openSession(72849);
-            if (sessionId == null || sessionId.length == 0) {
+            Session session = mediaCas.openSession();
+            if (session == null) {
                 fail("Can't open session for program");
             }
 
-            mediaCas.setSessionPrivateData(sessionId, pvtData);
+            session.setPrivateData(pvtData);
 
-            byte[] streamSessionId = mediaCas.openSession(72849, 256);
-            if (streamSessionId == null || streamSessionId.length == 0) {
+            Session streamSession = mediaCas.openSession();
+            if (streamSession == null) {
                 fail("Can't open session for stream");
             }
-            mediaCas.setSessionPrivateData(streamSessionId, pvtData);
+            streamSession.setPrivateData(pvtData);
 
-            descrambler.setMediaCasSession(sessionId);
+            descrambler.setMediaCasSession(session);
 
-            descrambler.setMediaCasSession(streamSessionId);
+            descrambler.setMediaCasSession(streamSession);
 
             mediaCas.refreshEntitlements(3, null);
 
@@ -291,8 +290,8 @@
             mediaCas.processEmm(emmData);
 
             byte[] ecmData = loadByteArrayFromString(sEcmBufferStr);
-            mediaCas.processEcm(sessionId, ecmData);
-            mediaCas.processEcm(streamSessionId, ecmData);
+            session.processEcm(ecmData);
+            streamSession.processEcm(ecmData);
 
             ByteBuffer outputBuf = descrambleTestInputBuffer(descrambler);
             ByteBuffer expectedOutputBuf = ByteBuffer.wrap(
@@ -300,14 +299,14 @@
             assertTrue("Incorrect decryption result",
                     expectedOutputBuf.compareTo(outputBuf) == 0);
 
-            mediaCas.closeSession(sessionId);
-            mediaCas.closeSession(streamSessionId);
+            session.close();
+            streamSession.close();
         } finally {
             if (mediaCas != null) {
-                mediaCas.release();
+                mediaCas.close();
             }
             if (descrambler != null) {
-                descrambler.release();
+                descrambler.close();
             }
         }
     }
@@ -324,28 +323,28 @@
             descrambler = new MediaDescrambler(sClearKeySystemId);
             mediaCas.provision(sProvisionStr);
 
-            byte[] sessionId = mediaCas.openSession(72849);
-            if (sessionId == null || sessionId.length == 0) {
+            Session session = mediaCas.openSession();
+            if (session == null) {
                 fail("Can't open session for program");
             }
 
-            byte[] streamSessionId = mediaCas.openSession(72849, 256);
-            if (streamSessionId == null || streamSessionId.length == 0) {
+            Session streamSession = mediaCas.openSession();
+            if (streamSession == null) {
                 fail("Can't open session for stream");
             }
 
-            mediaCas.release();
+            mediaCas.close();
             mediaCas = null;
 
             try {
-                descrambler.setMediaCasSession(sessionId);
+                descrambler.setMediaCasSession(session);
                 fail("Program session not closed after MediaCas is released");
             } catch (MediaCasStateException e) {
                 Log.d(TAG, "setMediaCasSession throws "
                         + e.getDiagnosticInfo() + " (as expected)");
             }
             try {
-                descrambler.setMediaCasSession(streamSessionId);
+                descrambler.setMediaCasSession(streamSession);
                 fail("Stream session not closed after MediaCas is released");
             } catch (MediaCasStateException e) {
                 Log.d(TAG, "setMediaCasSession throws "
@@ -353,10 +352,10 @@
             }
         } finally {
             if (mediaCas != null) {
-                mediaCas.release();
+                mediaCas.close();
             }
             if (descrambler != null) {
-                descrambler.release();
+                descrambler.close();
             }
         }
     }
@@ -393,26 +392,31 @@
                 Log.d(TAG, "processEmm throws ArrayIndexOutOfBoundsException (as expected)");
             }
 
-            byte[] invalidSessionId = new byte[] {};
+            // open a session, then close it so that it should become invalid
+            Session invalidSession = mediaCas.openSession();
+            if (invalidSession == null) {
+                fail("Can't open session for program");
+            }
+            invalidSession.close();
 
             byte[] ecmData = loadByteArrayFromString(sEcmBufferStr);
 
             // processEcm should fail with an invalid session id
             try {
-                mediaCas.processEcm(invalidSessionId, ecmData);
+                invalidSession.processEcm(ecmData);
                 fail("processEcm shouldn't succeed with invalid session id");
             } catch (MediaCasStateException e) {
                 Log.d(TAG, "processEcm throws " + e.getDiagnosticInfo() + " (as expected)");
             }
 
-            byte[] sessionId = mediaCas.openSession(72849);
-            if (sessionId == null || sessionId.length == 0) {
+            Session session = mediaCas.openSession();
+            if (session == null) {
                 fail("Can't open session for program");
             }
 
             // processEcm should fail without provisioning
             try {
-                mediaCas.processEcm(sessionId, ecmData);
+                session.processEcm(ecmData);
                 fail("processEcm shouldn't succeed without provisioning");
             } catch (MediaCasException.NotProvisionedException e) {
                 Log.d(TAG, "processEcm throws NotProvisionedException (as expected)");
@@ -423,7 +427,7 @@
 
             // processEcm should fail with ecm buffer that's too short
             try {
-                mediaCas.processEcm(sessionId, ecmData, 0, 8);
+                session.processEcm(ecmData, 0, 8);
                 fail("processEcm shouldn't succeed with truncated ecm");
             } catch (IllegalArgumentException e) {
                 Log.d(TAG, "processEcm throws " + e.toString() + " (as expected)");
@@ -432,7 +436,7 @@
             // processEcm should fail with ecm with bad descriptor count
             try {
                 ecmData[17] = 3; // change the descriptor count field to 3 (invalid)
-                mediaCas.processEcm(sessionId, ecmData);
+                session.processEcm(ecmData);
                 fail("processEcm shouldn't succeed with altered descriptor count");
             } catch (MediaCasStateException e) {
                 Log.d(TAG, "processEcm throws " + e.getDiagnosticInfo() + " (as expected)");
@@ -444,7 +448,7 @@
 
             // setMediaCasSession should fail with an invalid session id
             try {
-                descrambler.setMediaCasSession(invalidSessionId);
+                descrambler.setMediaCasSession(invalidSession);
                 fail("setMediaCasSession shouldn't succeed with invalid session id");
             } catch (MediaCasStateException e) {
                 Log.d(TAG, "setMediaCasSession throws "
@@ -460,7 +464,7 @@
             }
 
             // Now set a valid session, should still fail because no valid ecm is processed
-            descrambler.setMediaCasSession(sessionId);
+            descrambler.setMediaCasSession(session);
             try {
                 ByteBuffer outputBuf = descrambleTestInputBuffer(descrambler);
                 fail("descramble should fail without valid ecm");
@@ -469,10 +473,10 @@
             }
         } finally {
             if (mediaCas != null) {
-                mediaCas.release();
+                mediaCas.close();
             }
             if (descrambler != null) {
-                descrambler.release();
+                descrambler.close();
             }
         }
     }
@@ -537,7 +541,7 @@
         ByteBuffer inputBuf = ByteBuffer.wrap(
                 loadByteArrayFromString(sInputBufferStr));
         ByteBuffer outputBuf = ByteBuffer.allocate(inputBuf.capacity());
-        descrambler.descramble(inputBuf, 0, outputBuf, 0, cryptoInfo);
+        descrambler.descramble(inputBuf, outputBuf, cryptoInfo);
 
         return outputBuf;
     }
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 253a5ab..99f2790 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -230,8 +230,6 @@
     private void prepareVideo() throws IOException {
         boolean hasVideo = false;
 
-        android.media.DrmInitData drmInitData = mVideoExtractor.getDrmInitData();
-
         for (int i = mVideoExtractor.getTrackCount(); i-- > 0;) {
             MediaFormat format = mVideoExtractor.getTrackFormat(i);
             String mime = format.getString(MediaFormat.KEY_MIME);
@@ -244,11 +242,10 @@
             Log.d(TAG, "video track #" + i + " " + format + " " + mime +
                   " Width:" + mMediaFormatWidth + ", Height:" + mMediaFormatHeight);
 
-            if (mScrambled && drmInitData != null && mime.startsWith("video/")) {
-                android.media.DrmInitData.SchemeInitData schemeInitData =
-                        drmInitData.get(new UUID(0, i));
-                if (schemeInitData != null) {
-                    mDescrambler.setMediaCasSession(schemeInitData.data);
+            if (mScrambled && mime.startsWith("video/")) {
+                MediaExtractor.CasInfo casInfo = mVideoExtractor.getCasInfo(i);
+                if (casInfo != null && casInfo.getSession() != null) {
+                    mDescrambler.setMediaCasSession(casInfo.getSession());
                 }
             }
 
@@ -291,23 +288,18 @@
 
     private void initCasAndDescrambler(MediaExtractor extractor) throws MediaCasException {
         int trackCount = extractor.getTrackCount();
-        android.media.DrmInitData drmInitData = extractor.getDrmInitData();
         for (int trackId = 0; trackId < trackCount; trackId++) {
             android.media.MediaFormat format = extractor.getTrackFormat(trackId);
             String mime = format.getString(android.media.MediaFormat.KEY_MIME);
             Log.d(TAG, "track "+ trackId + ": " + mime);
             if ("video/scrambled".equals(mime) || "audio/scrambled".equals(mime)) {
-                if (drmInitData == null) {
-                    throw new IllegalArgumentException("found scrambled track without drmInitData!");
+                MediaExtractor.CasInfo casInfo = extractor.getCasInfo(trackId);
+                if (casInfo != null) {
+                    mMediaCas = new MediaCas(casInfo.getSystemId());
+                    mDescrambler = new MediaDescrambler(casInfo.getSystemId());
+                    mMediaCas.provision(sProvisionStr);
+                    extractor.setMediaCas(mMediaCas);
                 }
-                android.media.DrmInitData.SchemeInitData schemeInitData =
-                        drmInitData.get(new UUID(0, trackId));
-                int CA_system_id = (schemeInitData.data[0] & 0xff)
-                                | ((schemeInitData.data[1] & 0xff) << 8);
-                mMediaCas = new MediaCas(CA_system_id);
-                mDescrambler = new MediaDescrambler(CA_system_id);
-                mMediaCas.provision(sProvisionStr);
-                extractor.setMediaCas(mMediaCas);
             }
         }
     }
@@ -550,12 +542,12 @@
         }
 
         if (mMediaCas != null) {
-            mMediaCas.release();
+            mMediaCas.close();
             mMediaCas = null;
         }
 
         if (mDescrambler != null) {
-            mDescrambler.release();
+            mDescrambler.close();
             mDescrambler = null;
         }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 9b941a2..56cbc93 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -32,10 +32,10 @@
 import android.media.MediaFormat;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaCodecInfo.CodecProfileLevel;
-import android.media.MediaMetricsSet;
 import android.opengl.GLES20;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.PersistableBundle;
 import android.support.test.filters.SmallTest;
 import android.platform.test.annotations.RequiresDevice;
 import android.test.AndroidTestCase;
@@ -919,17 +919,17 @@
                 // good
             }
 
-            MediaMetricsSet metricsSet = encoder.getMetrics();
-            if (metricsSet == null) {
+            PersistableBundle metrics = encoder.getMetrics();
+            if (metrics == null) {
                 fail("getMetrics() returns null");
-            } else if (metricsSet.isEmpty()) {
+            } else if (metrics.isEmpty()) {
                 fail("getMetrics() returns empty results");
             }
-            int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+            int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
             if (encoding != 1) {
                 fail("getMetrics() returns bad encoder value " + encoding);
             }
-            String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+            String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
             if (theCodec == null) {
                 fail("getMetrics() returns null codec value ");
             }
@@ -989,17 +989,17 @@
                 // good
             }
 
-            MediaMetricsSet metricsSet = encoder.getMetrics();
-            if (metricsSet == null) {
+            PersistableBundle metrics = encoder.getMetrics();
+            if (metrics == null) {
                 fail("getMetrics() returns null");
-            } else if (metricsSet.isEmpty()) {
+            } else if (metrics.isEmpty()) {
                 fail("getMetrics() returns empty results");
             }
-            int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+            int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
             if (encoding != 1) {
                 fail("getMetrics() returns bad encoder value " + encoding);
             }
-            String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+            String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
             if (theCodec == null) {
                 fail("getMetrics() returns null codec value ");
             }
@@ -1050,17 +1050,17 @@
                         throw new RuntimeException("decoder does not generate non-empty output.");
                     }
 
-                    MediaMetricsSet metricsSet = mediaCodec.getMetrics();
-                    if (metricsSet == null) {
+                    PersistableBundle metrics = mediaCodec.getMetrics();
+                    if (metrics == null) {
                         fail("getMetrics() returns null");
-                    } else if (metricsSet.isEmpty()) {
+                    } else if (metrics.isEmpty()) {
                         fail("getMetrics() returns empty results");
                     }
-                    int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+                    int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
                     if (encoder != 0) {
                         fail("getMetrics() returns bad encoder value " + encoder);
                     }
-                    String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+                    String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
                     if (theCodec == null) {
                         fail("getMetrics() returns null codec value ");
                     }
@@ -1071,17 +1071,17 @@
                     mediaCodec.flush();
 
                     completed.set(runDecodeTillFirstOutput(mediaCodec, mediaExtractor));
-                    metricsSet = mediaCodec.getMetrics();
-                    if (metricsSet == null) {
+                    metrics = mediaCodec.getMetrics();
+                    if (metrics == null) {
                         fail("getMetrics() returns null");
-                    } else if (metricsSet.isEmpty()) {
+                    } else if (metrics.isEmpty()) {
                         fail("getMetrics() returns empty results");
                     }
-                    int encoding = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+                    int encoding = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
                     if (encoding != 0) {
                         fail("getMetrics() returns bad encoder value " + encoding);
                     }
-                    String theCodec2 = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+                    String theCodec2 = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
                     if (theCodec2 == null) {
                         fail("getMetrics() returns null codec value ");
                     }
@@ -1092,17 +1092,17 @@
                     if (mediaCodec != null) {
                         mediaCodec.stop();
 
-                        MediaMetricsSet metricsSet = mediaCodec.getMetrics();
-                        if (metricsSet == null) {
+                        PersistableBundle metrics = mediaCodec.getMetrics();
+                        if (metrics == null) {
                             fail("getMetrics() returns null");
-                        } else if (metricsSet.isEmpty()) {
+                        } else if (metrics.isEmpty()) {
                             fail("getMetrics() returns empty results");
                         }
-                        int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+                        int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
                         if (encoder != 0) {
                             fail("getMetrics() returns bad encoder value " + encoder);
                         }
-                        String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+                        String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
                         if (theCodec == null) {
                             fail("getMetrics() returns null codec value ");
                         }
@@ -1166,14 +1166,14 @@
             }
             assertTrue("Wrong output buffer index", outputBufferIndex >= 0);
 
-            MediaMetricsSet metricsSet = mediaCodec.getMetrics();
-            Log.d(TAG, "getMetrics after first buffer metricsSet says: " + metricsSet);
+            PersistableBundle metrics = mediaCodec.getMetrics();
+            Log.d(TAG, "getMetrics after first buffer metrics says: " + metrics);
 
-            int encoder = metricsSet.getInt(MediaMetricsSet.MediaCodec.KEY_ENCODER, -1);
+            int encoder = metrics.getInt(MediaCodec.MetricsConstants.ENCODER, -1);
             if (encoder != 0) {
                 fail("getMetrics() returns bad encoder value " + encoder);
             }
-            String theCodec = metricsSet.getString(MediaMetricsSet.MediaCodec.KEY_CODEC, null);
+            String theCodec = metrics.getString(MediaCodec.MetricsConstants.CODEC, null);
             if (theCodec == null) {
                 fail("getMetrics() returns null codec value ");
             }
diff --git a/tests/tests/media/src/android/media/cts/MediaControllerTest.java b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
index 9aaf1aa..17588ee 100644
--- a/tests/tests/media/src/android/media/cts/MediaControllerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaControllerTest.java
@@ -19,11 +19,8 @@
 import android.media.AudioManager;
 import android.media.Rating;
 import android.media.VolumeProvider;
-import android.media.MediaDescription;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
-import android.media.session.MediaSession.QueueItem;
-import android.media.session.PlaybackState;
 import android.media.session.PlaybackState.CustomAction;
 import android.net.Uri;
 import android.os.Bundle;
@@ -53,7 +50,6 @@
         super.setUp();
         mSession = new MediaSession(getContext(), SESSION_TAG);
         mSession.setCallback(mCallback, mHandler);
-        mSession.setFlags(MediaSession.FLAG_HANDLES_QUEUE_COMMANDS);
         mController = mSession.getController();
     }
 
@@ -88,53 +84,6 @@
         }
     }
 
-    public void testAddRemoveQueueItems() throws Exception {
-        final String mediaId = "media_id";
-        final String mediaTitle = "media_title";
-        MediaDescription itemDescription = new MediaDescription.Builder()
-                .setMediaId(mediaId).setTitle(mediaTitle).build();
-        final MediaSession.Callback callback = (MediaSession.Callback) mCallback;
-
-        synchronized (mWaitLock) {
-            mCallback.reset();
-            mController.addQueueItem(itemDescription);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnAddQueueItemCalled);
-            assertEquals(-1, mCallback.mQueueIndex);
-            assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
-            assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
-            // just call the callback once directly so it's marked as tested
-            callback.onAddQueueItem(mCallback.mQueueDescription);
-
-            mCallback.reset();
-            mController.addQueueItem(itemDescription, 0);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnAddQueueItemAtCalled);
-            assertEquals(0, mCallback.mQueueIndex);
-            assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
-            assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
-            // just call the callback once directly so it's marked as tested
-            callback.onAddQueueItem(mCallback.mQueueDescription, mCallback.mQueueIndex);
-
-            mCallback.reset();
-            mController.removeQueueItemAt(0);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnRemoveQueueItemAtCalled);
-            assertEquals(0, mCallback.mQueueIndex);
-            // just call the callback once directly so it's marked as tested
-            callback.onRemoveQueueItemAt(mCallback.mQueueIndex);
-
-            mCallback.reset();
-            mController.removeQueueItem(itemDescription);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnRemoveQueueItemCalled);
-            assertEquals(mediaId, mCallback.mQueueDescription.getMediaId());
-            assertEquals(mediaTitle, mCallback.mQueueDescription.getTitle());
-            // just call the callback once directly so it's marked as tested
-            callback.onRemoveQueueItem(mCallback.mQueueDescription);
-        }
-    }
-
     public void testVolumeControl() throws Exception {
         VolumeProvider vp = new VolumeProvider(VolumeProvider.VOLUME_CONTROL_ABSOLUTE, 11, 5) {
             @Override
@@ -346,26 +295,6 @@
             assertTrue(mCallback.mOnPrepareFromUriCalled);
             assertEquals(uri, mCallback.mUri);
             assertEquals(EXTRAS_VALUE, mCallback.mExtras.getString(EXTRAS_KEY));
-            // just call the callback once directly so it's marked as tested
-            callback.onPrepareFromUri(mCallback.mUri, mCallback.mExtras);
-
-            mCallback.reset();
-            final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
-            controls.setRepeatMode(repeatMode);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnSetRepeatModeCalled);
-            assertEquals(repeatMode, mCallback.mRepeatMode);
-            // just call the callback once directly so it's marked as tested
-            callback.onSetRepeatMode(mCallback.mRepeatMode);
-
-            mCallback.reset();
-            final boolean shuffleModeEnabled = true;
-            controls.setShuffleModeEnabled(shuffleModeEnabled);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnSetShuffleModeEnabledCalled);
-            assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
-            // just call the callback once directly so it's marked as tested
-            callback.onSetShuffleModeEnabled(mCallback.mShuffleModeEnabled);
         }
     }
 
@@ -389,8 +318,6 @@
     private class MediaSessionCallback extends MediaSession.Callback {
         private long mSeekPosition;
         private long mQueueItemId;
-        private int mQueueIndex;
-        private MediaDescription mQueueDescription;
         private Rating mRating;
         private String mMediaId;
         private String mQuery;
@@ -399,8 +326,6 @@
         private String mCommand;
         private Bundle mExtras;
         private ResultReceiver mCommandCallback;
-        private int mRepeatMode;
-        private boolean mShuffleModeEnabled;
 
         private boolean mOnPlayCalled;
         private boolean mOnPauseCalled;
@@ -421,18 +346,10 @@
         private boolean mOnPrepareFromMediaIdCalled;
         private boolean mOnPrepareFromSearchCalled;
         private boolean mOnPrepareFromUriCalled;
-        private boolean mOnSetRepeatModeCalled;
-        private boolean mOnSetShuffleModeEnabledCalled;
-        private boolean mOnAddQueueItemCalled;
-        private boolean mOnAddQueueItemAtCalled;
-        private boolean mOnRemoveQueueItemCalled;
-        private boolean mOnRemoveQueueItemAtCalled;
 
         public void reset() {
             mSeekPosition = -1;
             mQueueItemId = -1;
-            mQueueIndex = -1;
-            mQueueDescription = null;
             mRating = null;
             mMediaId = null;
             mQuery = null;
@@ -441,8 +358,6 @@
             mExtras = null;
             mCommand = null;
             mCommandCallback = null;
-            mShuffleModeEnabled = false;
-            mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
 
             mOnPlayCalled = false;
             mOnPauseCalled = false;
@@ -463,12 +378,6 @@
             mOnPrepareFromMediaIdCalled = false;
             mOnPrepareFromSearchCalled = false;
             mOnPrepareFromUriCalled = false;
-            mOnSetRepeatModeCalled = false;
-            mOnSetShuffleModeEnabledCalled = false;
-            mOnAddQueueItemCalled = false;
-            mOnAddQueueItemAtCalled = false;
-            mOnRemoveQueueItemCalled = false;
-            mOnRemoveQueueItemAtCalled = false;
         }
 
         @Override
@@ -642,60 +551,5 @@
                 mWaitLock.notify();
             }
         }
-
-        @Override
-        public void onSetRepeatMode(int repeatMode) {
-            synchronized (mWaitLock) {
-                mOnSetRepeatModeCalled = true;
-                mRepeatMode = repeatMode;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onSetShuffleModeEnabled(boolean enabled) {
-            synchronized (mWaitLock) {
-                mOnSetShuffleModeEnabledCalled = true;
-                mShuffleModeEnabled = enabled;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onAddQueueItem(MediaDescription description) {
-            synchronized (mWaitLock) {
-                mOnAddQueueItemCalled = true;
-                mQueueDescription = description;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onAddQueueItem(MediaDescription description, int index) {
-            synchronized (mWaitLock) {
-                mOnAddQueueItemAtCalled = true;
-                mQueueIndex = index;
-                mQueueDescription = description;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onRemoveQueueItem(MediaDescription description) {
-            synchronized (mWaitLock) {
-                mOnRemoveQueueItemCalled = true;
-                mQueueDescription = description;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onRemoveQueueItemAt(int index) {
-            synchronized (mWaitLock) {
-                mOnRemoveQueueItemAtCalled = true;
-                mQueueIndex = index;
-                mWaitLock.notify();
-            }
-        }
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
index 7248c7d..b6f34f4 100644
--- a/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaExtractorTest.java
@@ -17,12 +17,12 @@
 package android.media.cts;
 
 import android.media.cts.R;
-import android.media.MediaMetricsSet;
 
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.media.MediaDataSource;
 import android.media.MediaExtractor;
+import android.os.PersistableBundle;
 import android.test.AndroidTestCase;
 
 import java.io.IOException;
@@ -110,12 +110,12 @@
         }
 
         // verify some getMetrics() behaviors while we're here.
-        MediaMetricsSet metricsSet = mExtractor.getMetrics();
-        if (metricsSet == null) {
+        PersistableBundle metrics = mExtractor.getMetrics();
+        if (metrics == null) {
             fail("getMetrics() returns no data");
         } else {
             // ensure existence of some known fields
-            int tracks = metricsSet.getInt(MediaMetricsSet.MediaExtractor.KEY_TRACKS, -1);
+            int tracks = metrics.getInt(MediaExtractor.MetricsConstants.TRACKS, -1);
             if (tracks != trackCount) {
                 fail("getMetrics() trackCount expect " + trackCount + " got " + tracks);
             }
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
index 2431bf2..82b992d 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTestBase.java
@@ -20,8 +20,8 @@
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Resources;
 import android.media.MediaPlayer;
-import android.media.MediaMetricsSet;
 import android.net.Uri;
+import android.os.PersistableBundle;
 import android.test.ActivityInstrumentationTestCase2;
 
 import com.android.compatibility.common.util.MediaUtils;
@@ -324,15 +324,15 @@
         }
 
         // validate a few MediaMetrics.
-        MediaMetricsSet metricsSet = mMediaPlayer.getMetrics();
-        if (metricsSet == null) {
+        PersistableBundle metrics = mMediaPlayer.getMetrics();
+        if (metrics == null) {
             fail("MediaPlayer.getMetrics() returned null metrics");
-        } else if (metricsSet.isEmpty()) {
+        } else if (metrics.isEmpty()) {
             fail("MediaPlayer.getMetrics() returned empty metrics");
         } else {
 
-            int size = metricsSet.size();
-            Set<String> keys = metricsSet.keySet();
+            int size = metrics.size();
+            Set<String> keys = metrics.keySet();
 
             if (keys == null) {
                 fail("MediaMetricsSet returned no keys");
@@ -341,22 +341,22 @@
             }
 
             // we played something; so one of these should be non-null
-            String vmime = metricsSet.getString(MediaMetricsSet.MediaPlayer.KEY_MIME_VIDEO, null);
-            String amime = metricsSet.getString(MediaMetricsSet.MediaPlayer.KEY_MIME_AUDIO, null);
+            String vmime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_VIDEO, null);
+            String amime = metrics.getString(MediaPlayer.MetricsConstants.MIME_TYPE_AUDIO, null);
             if (vmime == null && amime == null) {
                 fail("getMetrics() returned neither video nor audio mime value");
             }
 
-            long duration = metricsSet.getLong(MediaMetricsSet.MediaPlayer.KEY_DURATION, -2);
+            long duration = metrics.getLong(MediaPlayer.MetricsConstants.DURATION, -2);
             if (duration == -2) {
                 fail("getMetrics() didn't return a duration");
             }
-            long playing = metricsSet.getLong(MediaMetricsSet.MediaPlayer.KEY_PLAYING, -2);
+            long playing = metrics.getLong(MediaPlayer.MetricsConstants.PLAYING, -2);
             if (playing == -2) {
                 fail("getMetrics() didn't return a playing time");
             }
-            if (!keys.contains(MediaMetricsSet.MediaPlayer.KEY_PLAYING)) {
-                fail("MediaMetricsSet.keys() missing: " + MediaMetricsSet.MediaPlayer.KEY_PLAYING);
+            if (!keys.contains(MediaPlayer.MetricsConstants.PLAYING)) {
+                fail("MediaMetricsSet.keys() missing: " + MediaPlayer.MetricsConstants.PLAYING);
             }
         }
 
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index fbf51ca..d3c392c 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -30,10 +30,10 @@
 import android.media.MediaRecorder.OnErrorListener;
 import android.media.MediaRecorder.OnInfoListener;
 import android.media.MediaMetadataRetriever;
-import android.media.MediaMetricsSet;
 import android.os.ConditionVariable;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
 import android.support.test.filters.SmallTest;
 import android.platform.test.annotations.RequiresDevice;
 import android.test.ActivityInstrumentationTestCase2;
@@ -230,14 +230,14 @@
 
 
         // verify some getMetrics() behaviors while we're here.
-        MediaMetricsSet metricsSet = mMediaRecorder.getMetrics();
-        if (metricsSet == null) {
+        PersistableBundle metrics = mMediaRecorder.getMetrics();
+        if (metrics == null) {
             fail("MediaRecorder.getMetrics() returned null metrics");
-        } else if (metricsSet.isEmpty()) {
+        } else if (metrics.isEmpty()) {
             fail("MediaRecorder.getMetrics() returned empty metrics");
         } else {
-            int size = metricsSet.size();
-            Set<String> keys = metricsSet.keySet();
+            int size = metrics.size();
+            Set<String> keys = metrics.keySet();
 
             if (size == 0) {
                 fail("MediaRecorder.getMetrics().size() reports empty record");
@@ -250,14 +250,14 @@
             }
 
             // ensure existence of some known fields
-            int videoBitRate = metricsSet.getInt(MediaMetricsSet.MediaRecorder.KEY_VIDEO_BITRATE, -1);
+            int videoBitRate = metrics.getInt(MediaRecorder.MetricsConstants.VIDEO_BITRATE, -1);
             if (videoBitRate != VIDEO_BIT_RATE_IN_BPS) {
                 fail("getMetrics() videoEncodeBitrate set " +
                      VIDEO_BIT_RATE_IN_BPS + " got " + videoBitRate);
             }
 
             // careful when comparing floating point numbers
-            double captureFrameRate = metricsSet.getDouble(MediaMetricsSet.MediaRecorder.KEY_CAPTURE_FPS, -1);
+            double captureFrameRate = metrics.getDouble(MediaRecorder.MetricsConstants.CAPTURE_FPS, -1);
             if (captureFrameRate < 0) {
                 fail("getMetrics() capture framerate reports " + captureFrameRate);
             }
@@ -304,14 +304,14 @@
         Thread.sleep(RECORD_TIME_MS);
 
         // verify some getMetrics() behaviors while we're here.
-        MediaMetricsSet metricsSet = mMediaRecorder.getMetrics();
-        if (metricsSet == null) {
+        PersistableBundle metrics = mMediaRecorder.getMetrics();
+        if (metrics == null) {
             fail("MediaRecorder.getMetrics() returned null metrics");
-        } else if (metricsSet.isEmpty()) {
+        } else if (metrics.isEmpty()) {
             fail("MediaRecorder.getMetrics() returned empty metrics");
         } else {
-            int size = metricsSet.size();
-            Set<String> keys = metricsSet.keySet();
+            int size = metrics.size();
+            Set<String> keys = metrics.keySet();
 
             if (size == 0) {
                 fail("MediaRecorder.getMetrics().size() reports empty record");
@@ -324,14 +324,14 @@
             }
 
             // ensure existence of some known fields
-            int videoBitRate = metricsSet.getInt(MediaMetricsSet.MediaRecorder.KEY_VIDEO_BITRATE, -1);
+            int videoBitRate = metrics.getInt(MediaRecorder.MetricsConstants.VIDEO_BITRATE, -1);
             if (videoBitRate != VIDEO_BIT_RATE_IN_BPS) {
                 fail("getMetrics() videoEncodeBitrate set " +
                      VIDEO_BIT_RATE_IN_BPS + " got " + videoBitRate);
             }
 
             // careful when comparing floating point numbers
-            double captureFrameRate = metricsSet.getDouble(MediaMetricsSet.MediaRecorder.KEY_CAPTURE_FPS, -1);
+            double captureFrameRate = metrics.getDouble(MediaRecorder.MetricsConstants.CAPTURE_FPS, -1);
             if (captureFrameRate < 0) {
                 fail("getMetrics() capture framerate reports " + captureFrameRate);
             }
@@ -520,6 +520,19 @@
         fos.close();
     }
 
+    public void testSetOutputFile() throws Exception {
+        if (!hasCamera()) {
+            return;
+        }
+        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
+        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
+        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
+        mMediaRecorder.setPreviewDisplay(mActivity.getSurfaceHolder().getSurface());
+        mMediaRecorder.setOutputFile(mOutFile);
+        long maxFileSize = MAX_FILE_SIZE * 10;
+        recordMedia(maxFileSize, mOutFile);
+    }
+
     public void testRecordingAudioInRawFormats() throws Exception {
         int testsRun = 0;
         if (hasAmrNb()) {
@@ -771,7 +784,8 @@
                     } else if (mFileIndex < 6) {
                         try {
                             String path = OUTPUT_PATH + mFileIndex;
-                            mMediaRecorder.setNextOutputFile(path);
+                            File nextFile = new File(path);
+                            mMediaRecorder.setNextOutputFile(nextFile);
                             recordFileList.add(path);
                             mFileIndex++;
                         } catch (IOException e) {
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index 50b3033..2bf24b6 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -19,6 +19,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
@@ -102,6 +103,13 @@
     }
 
     public void testSetOnVolumeKeyLongPressListener() throws Exception {
+        Context context = getInstrumentation().getTargetContext();
+        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+            // Skip this test on TV platform because the PhoneWindowManager dispatches volume key
+            // events directly to the audio service to change the system volume.
+            return;
+        }
+
         HandlerThread handlerThread = new HandlerThread(TAG);
         handlerThread.start();
         Handler handler = new Handler(handlerThread.getLooper());
@@ -149,6 +157,9 @@
         session.setPlaybackState(state);
         session.setActive(true);
 
+        // A media playback is also needed to receive media key events.
+        Utils.assertMediaPlaybackStarted(getInstrumentation().getTargetContext());
+
         // Ensure that the listener is called for media key event,
         // and any other media sessions don't get the key.
         MediaKeyListener listener = new MediaKeyListener(2, true, handler);
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTest.java b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
index b84bf1c..58a643d 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTest.java
@@ -222,28 +222,6 @@
             mSession.setSessionActivity(pi);
             assertEquals(pi, controller.getSessionActivity());
 
-            // test setRepeatMode
-            mCallback.resetLocked();
-            final int repeatMode = PlaybackState.REPEAT_MODE_ALL;
-            mSession.setRepeatMode(repeatMode);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnRepeatModeChangedCalled);
-            assertEquals(repeatMode, mCallback.mRepeatMode);
-            assertEquals(repeatMode, controller.getRepeatMode());
-            // just call the callback once directly so it's marked as tested
-            callback.onRepeatModeChanged(mCallback.mRepeatMode);
-
-            // test setShuffleModeEnabled
-            mCallback.resetLocked();
-            final boolean shuffleModeEnabled = true;
-            mSession.setShuffleModeEnabled(shuffleModeEnabled);
-            mWaitLock.wait(TIME_OUT_MS);
-            assertTrue(mCallback.mOnShuffleModeChangedCalled);
-            assertEquals(shuffleModeEnabled, mCallback.mShuffleModeEnabled);
-            assertEquals(shuffleModeEnabled, controller.isShuffleModeEnabled());
-            // just call the callback once directly so it's marked as tested
-            callback.onShuffleModeChanged(mCallback.mShuffleModeEnabled);
-
             // test setActivity
             mSession.setActive(true);
             assertTrue(mSession.isActive());
@@ -354,6 +332,9 @@
                 .setState(PlaybackState.STATE_PLAYING, 0L, 0.0f).build();
         mSession.setPlaybackState(defaultState);
 
+        // A media playback is also needed to receive media key events.
+        Utils.assertMediaPlaybackStarted(getContext());
+
         synchronized (mWaitLock) {
             sessionCallback.reset();
             simulateMediaKeyInput(KeyEvent.KEYCODE_MEDIA_PLAY);
@@ -409,6 +390,26 @@
         }
     }
 
+    /**
+     * Test {@link MediaSession#release} doesn't crash when multiple media sessions are in the app
+     * which receives the media key events.
+     * See: b/36669550
+     */
+    public void testReleaseNoCrashWithMultipleSessions() throws Exception {
+        // Start a media playback for this app to receive media key events.
+        Utils.assertMediaPlaybackStarted(getContext());
+
+        MediaSession anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+        mSession.release();
+        anotherSession.release();
+
+        // Try release with the different order.
+        mSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+        anotherSession = new MediaSession(getContext(), TEST_SESSION_TAG);
+        anotherSession.release();
+        mSession.release();
+    }
+
     private void simulateMediaKeyInput(int keyCode) {
         mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
         mAudioManager.dispatchMediaKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
@@ -474,8 +475,6 @@
         private volatile boolean mOnAudioInfoChangedCalled;
         private volatile boolean mOnSessionDestroyedCalled;
         private volatile boolean mOnSessionEventCalled;
-        private volatile boolean mOnRepeatModeChangedCalled;
-        private volatile boolean mOnShuffleModeChangedCalled;
 
         private volatile PlaybackState mPlaybackState;
         private volatile MediaMetadata mMediaMetadata;
@@ -484,8 +483,6 @@
         private volatile String mEvent;
         private volatile Bundle mExtras;
         private volatile MediaController.PlaybackInfo mPlaybackInfo;
-        private volatile int mRepeatMode;
-        private volatile boolean mShuffleModeEnabled;
 
         public void resetLocked() {
             mOnPlaybackStateChangedCalled = false;
@@ -496,8 +493,6 @@
             mOnAudioInfoChangedCalled = false;
             mOnSessionDestroyedCalled = false;
             mOnSessionEventCalled = false;
-            mOnRepeatModeChangedCalled = false;
-            mOnShuffleModeChangedCalled = false;
 
             mPlaybackState = null;
             mMediaMetadata = null;
@@ -505,8 +500,6 @@
             mTitle = null;
             mExtras = null;
             mPlaybackInfo = null;
-            mRepeatMode = PlaybackState.REPEAT_MODE_NONE;
-            mShuffleModeEnabled = false;
         }
 
         @Override
@@ -580,24 +573,6 @@
                 mWaitLock.notify();
             }
         }
-
-        @Override
-        public void onRepeatModeChanged(int repeatMode) {
-            synchronized (mWaitLock) {
-                mOnRepeatModeChangedCalled = true;
-                mRepeatMode = repeatMode;
-                mWaitLock.notify();
-            }
-        }
-
-        @Override
-        public void onShuffleModeChanged(boolean enabled) {
-            synchronized (mWaitLock) {
-                mOnShuffleModeChangedCalled = true;
-                mShuffleModeEnabled = enabled;
-                mWaitLock.notify();
-            }
-        }
     }
 
     private class MediaSessionCallback extends MediaSession.Callback {
diff --git a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
index 96b33da..3dff5bf 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneManagerTest.java
@@ -99,12 +99,19 @@
         return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
     }
 
+    private boolean isTV() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
+    }
+
     public void testConstructors() {
         new RingtoneManager(mActivity);
         new RingtoneManager(mContext);
     }
 
     public void testAccessMethods() {
+        if (isTV()) {
+            return;
+        }
         if (!hasAudioOutput()) {
             Log.i(TAG, "Skipping testAccessMethods(): device doesn't have audio output.");
             return;
@@ -145,6 +152,9 @@
     }
 
     public void testStopPreviousRingtone() {
+        if (isTV()) {
+            return;
+        }
         if (!hasAudioOutput()) {
             Log.i(TAG, "Skipping testStopPreviousRingtone(): device doesn't have audio output.");
             return;
diff --git a/tests/tests/media/src/android/media/cts/RingtoneTest.java b/tests/tests/media/src/android/media/cts/RingtoneTest.java
index 1477f3f..31ae5bb 100644
--- a/tests/tests/media/src/android/media/cts/RingtoneTest.java
+++ b/tests/tests/media/src/android/media/cts/RingtoneTest.java
@@ -107,10 +107,18 @@
 
     private boolean hasAudioOutput() {
         return getInstrumentation().getContext().getPackageManager()
-            .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+                .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+    }
+
+    private boolean isTV() {
+        return getInstrumentation().getContext().getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY);
     }
 
     public void testRingtone() {
+        if (isTV()) {
+            return;
+        }
         if (!hasAudioOutput()) {
             Log.i(TAG, "Skipping testRingtone(): device doesn't have audio output.");
             return;
diff --git a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
index 628a50b..e22d8a7 100644
--- a/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/StreamingMediaPlayerTest.java
@@ -333,7 +333,7 @@
     }
 
     // TODO: unhide this test when we sort out how to expose buffering control API.
-    private void testBuffering() throws Throwable {
+    private void doTestBuffering() throws Throwable {
         final String name = "ringer.mp3";
         mServer = new CtsTestServer(mContext);
         try {
diff --git a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
index 888b3d4..9f90a75 100644
--- a/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
+++ b/tests/tests/media/src/android/media/cts/StubMediaBrowserService.java
@@ -45,10 +45,6 @@
         MEDIA_ID_CHILDREN_DELAYED
     };
 
-    static final String SEARCH_QUERY = "test_media_children";
-    static final String SEARCH_QUERY_FOR_NO_RESULT = "query no result";
-    static final String SEARCH_QUERY_FOR_ERROR = "query for error";
-
     static StubMediaBrowserService sInstance;
 
     /* package private */ static MediaSession sSession;
@@ -76,8 +72,10 @@
     public void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) {
         List<MediaItem> mediaItems = new ArrayList<>();
         if (MEDIA_ID_ROOT.equals(parentMediaId)) {
+            Bundle rootHints = getBrowserRootHints();
             for (String id : MEDIA_ID_CHILDREN) {
-                mediaItems.add(createMediaItem(id));
+                mediaItems.add(new MediaItem(new MediaDescription.Builder()
+                        .setMediaId(id).setExtras(rootHints).build(), MediaItem.FLAG_BROWSABLE));
             }
             result.sendResult(mediaItems);
         } else if (MEDIA_ID_CHILDREN_DELAYED.equals(parentMediaId)) {
@@ -101,7 +99,9 @@
 
         for (String id : MEDIA_ID_CHILDREN) {
             if (id.equals(itemId)) {
-                result.sendResult(createMediaItem(id));
+                result.sendResult(new MediaItem(new MediaDescription.Builder()
+                        .setMediaId(id).setExtras(getBrowserRootHints()).build(),
+                                MediaItem.FLAG_BROWSABLE));
                 return;
             }
         }
@@ -109,27 +109,6 @@
         super.onLoadItem(itemId, result);
     }
 
-    @Override
-    public void onSearch(String query, Bundle extras, Result<List<MediaItem>> result) {
-        if (result == null) {
-            // called the callback to mark as tested
-            return;
-        }
-        if (SEARCH_QUERY_FOR_NO_RESULT.equals(query)) {
-            result.sendResult(Collections.<MediaItem>emptyList());
-        } else if (SEARCH_QUERY_FOR_ERROR.equals(query)) {
-            result.sendResult(null);
-        } else if (SEARCH_QUERY.equals(query)) {
-            List<MediaItem> items = new ArrayList<>();
-            for (String id : MEDIA_ID_CHILDREN) {
-                if (id.contains(query)) {
-                    items.add(createMediaItem(id));
-                }
-            }
-            result.sendResult(items);
-        }
-    }
-
     public void sendDelayedNotifyChildrenChanged() {
         if (mPendingLoadChildrenResult != null) {
             mPendingLoadChildrenResult.sendResult(Collections.<MediaItem>emptyList());
@@ -147,10 +126,4 @@
             mPendingLoadItemResult = null;
         }
     }
-
-    private MediaItem createMediaItem(String id) {
-        return new MediaItem(new MediaDescription.Builder()
-                .setMediaId(id).setExtras(getBrowserRootHints()).build(),
-                MediaItem.FLAG_BROWSABLE);
-    }
 }
diff --git a/tests/tests/media/src/android/media/cts/Utils.java b/tests/tests/media/src/android/media/cts/Utils.java
index e8ceeae..fb461fe 100644
--- a/tests/tests/media/src/android/media/cts/Utils.java
+++ b/tests/tests/media/src/android/media/cts/Utils.java
@@ -20,15 +20,28 @@
 import android.app.UiAutomation;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioPlaybackConfiguration;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.provider.Settings;
 
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.util.Scanner;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Assert;
 
 public class Utils {
+    private static final String TAG = "CtsMediaTestUtil";
+    private static final int TEST_TIMING_TOLERANCE_MS = 50;
+
     public static void enableAppOps(String packageName, String operation,
             Instrumentation instrumentation) {
         setAppOps(packageName, operation, instrumentation, true);
@@ -113,4 +126,53 @@
         }
         uiAutomation.destroy();
     }
+
+    /**
+     * Assert that a media playback is started and an active {@link AudioPlaybackConfiguration}
+     * is created once. The playback will be stopped immediately after that.
+     * <p>For a media session to receive media button events, an actual playback is needed.
+     */
+    static void assertMediaPlaybackStarted(Context context) {
+        final AudioManager am = new AudioManager(context);
+        final HandlerThread handlerThread = new HandlerThread(TAG);
+        handlerThread.start();
+        final TestAudioPlaybackCallback callback = new TestAudioPlaybackCallback();
+        MediaPlayer mediaPlayer = null;
+
+        try {
+            final int activeConfigSizeBeforeStart = am.getActivePlaybackConfigurations().size();
+            final Handler handler = new Handler(handlerThread.getLooper());
+
+            am.registerAudioPlaybackCallback(callback, handler);
+            mediaPlayer = MediaPlayer.create(context, R.raw.sine1khzs40dblong);
+            mediaPlayer.start();
+            if (!callback.mCountDownLatch.await(TEST_TIMING_TOLERANCE_MS, TimeUnit.MILLISECONDS)
+                    || callback.mActiveConfigSize != activeConfigSizeBeforeStart + 1) {
+                Assert.fail("Failed to create an active AudioPlaybackConfiguration");
+            }
+        } catch (InterruptedException e) {
+            Assert.fail("Failed to create an active AudioPlaybackConfiguration");
+        } finally {
+            am.unregisterAudioPlaybackCallback(callback);
+            if (mediaPlayer != null) {
+                mediaPlayer.stop();
+                mediaPlayer.release();
+                mediaPlayer = null;
+            }
+            handlerThread.quitSafely();
+        }
+    }
+
+    private static class TestAudioPlaybackCallback extends AudioManager.AudioPlaybackCallback {
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+        private int mActiveConfigSize;
+
+        @Override
+        public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+            // For non-framework apps, only anonymized active AudioPlaybackCallbacks will be
+            // notified.
+            mActiveConfigSize = configs.size();
+            mCountDownLatch.countDown();
+        }
+    }
 }
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/nativemedia/aaudio/Android.mk b/tests/tests/nativemedia/aaudio/Android.mk
index af46aee..e37df49 100644
--- a/tests/tests/nativemedia/aaudio/Android.mk
+++ b/tests/tests/nativemedia/aaudio/Android.mk
@@ -27,7 +27,9 @@
     frameworks/av/media/libaaudio/include
 
 LOCAL_SRC_FILES := \
-    src/test_aaudio.cpp
+    src/test_aaudio.cpp \
+    src/test_aaudio_misc.cpp \
+    src/test_aaudio_callback.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libaaudio \
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
index 77c91e4..37b434e 100644
--- a/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.cpp
@@ -21,17 +21,9 @@
 #include <utils/Log.h>
 
 #include <aaudio/AAudio.h>
-#include <aaudio/AAudioDefinitions.h>
+#include "test_aaudio.h"
 
-
-#define NANOS_PER_MICROSECOND ((int64_t)1000)
-#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
-#define MILLIS_PER_SECOND     1000
-#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
-
-#define DEFAULT_STATE_TIMEOUT  (500 * NANOS_PER_MILLISECOND)
-
-static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
+int64_t getNanoseconds(clockid_t clockId) {
     struct timespec time;
     int result = clock_gettime(clockId, &time);
     if (result < 0) {
@@ -136,10 +128,12 @@
 
     // Check to see what kind of stream we actually got.
     actualSampleRate = AAudioStream_getSampleRate(aaudioStream);
-    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+    ASSERT_GE(actualSampleRate, 44100);
+    ASSERT_LE(actualSampleRate, 96000); // TODO what is min/max?
 
     actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
-    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+    ASSERT_GE(actualSamplesPerFrame, 1);
+    ASSERT_LE(actualSamplesPerFrame, 16); // TODO what is min/max?
 
     actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
@@ -151,7 +145,8 @@
     // ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(aaudioStream));
 
     framesPerBurst = AAudioStream_getFramesPerBurst(aaudioStream);
-    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+    ASSERT_GE(framesPerBurst, 16);
+    ASSERT_LE(framesPerBurst, 10000); // TODO what is min/max?
 
     // Allocate a buffer for the audio data.
     // TODO handle possibility of other data formats
@@ -270,10 +265,13 @@
     aaudioFramesRead = AAudioStream_getFramesRead(aaudioStream);
     EXPECT_EQ(aaudioFramesRead, aaudioFramesWritten);
 
+    sleep(1); // FIXME - The write returns 0 if we remove this sleep! Why?
+
     // The buffer should be empty after a flush so we should be able to write.
     framesWritten = AAudioStream_write(aaudioStream, data, framesPerBurst, timeoutNanos);
     // There should be some room for priming the buffer.
-    ASSERT_TRUE(framesWritten > 0 && framesWritten <= framesPerBurst);
+    ASSERT_GT(framesWritten, 0);
+    ASSERT_LE(framesWritten, framesPerBurst);
 
     EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
     free(data);
@@ -291,60 +289,6 @@
 }
 */
 
-#define AAUDIO_THREAD_ANSWER          1826375
-#define AAUDIO_THREAD_DURATION_MSEC       500
-
-static void *TestAAudioStreamThreadProc(void *arg) {
-    AAudioStream* aaudioStream = (AAudioStream*) reinterpret_cast<size_t>(arg);
-    aaudio_stream_state_t state;
-
-    // Use this to sleep by waiting for something that won't happen.
-    state = AAudioStream_getState(aaudioStream);
-    AAudioStream_waitForStateChange(aaudioStream, AAUDIO_STREAM_STATE_PAUSED, &state,
-            AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND);
-    return reinterpret_cast<void *>(AAUDIO_THREAD_ANSWER);
-}
-
-// Test creating a stream related thread.
-TEST(test_aaudio, aaudio_stream_thread_basic) {
-    AAudioStreamBuilder *aaudioBuilder = nullptr;
-    AAudioStream *aaudioStream = nullptr;
-    aaudio_result_t result = AAUDIO_OK;
-    void *threadResult;
-
-    // Use an AAudioStreamBuilder to define the stream.
-    result = AAudio_createStreamBuilder(&aaudioBuilder);
-    ASSERT_EQ(AAUDIO_OK, result);
-
-    // Create an AAudioStream using the Builder.
-    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream));
-
-    // Start a thread.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_createThread(aaudioStream,
-            10 * NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-    // Thread already started.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_createThread(aaudioStream,   // should fail!
-            10 * NANOS_PER_MILLISECOND,
-            TestAAudioStreamThreadProc,
-            reinterpret_cast<void *>(aaudioStream)));
-
-    // Wait for the thread to finish.
-    ASSERT_EQ(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
-    // The thread returns a special answer.
-    ASSERT_EQ(AAUDIO_THREAD_ANSWER, (int)reinterpret_cast<size_t>(threadResult));
-
-    // Thread should already be joined.
-    ASSERT_NE(AAUDIO_OK, AAudioStream_joinThread(aaudioStream,  // should fail!
-            &threadResult, 2 * AAUDIO_THREAD_DURATION_MSEC * NANOS_PER_MILLISECOND));
-
-    // Cleanup
-    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(aaudioBuilder));
-    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
-}
-
 int main(int argc, char **argv) {
     testing::InitGoogleTest(&argc, argv);
 
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio.h b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
new file mode 100644
index 0000000..dbb111d
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef CTS_MEDIA_TEST_AAUDIO_H
+#define CTS_MEDIA_TEST_AAUDIO_H
+
+#define NANOS_PER_MICROSECOND ((int64_t)1000)
+#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
+#define MILLIS_PER_SECOND     1000
+#define NANOS_PER_SECOND      (NANOS_PER_MILLISECOND * MILLIS_PER_SECOND)
+
+#define DEFAULT_STATE_TIMEOUT  (500 * NANOS_PER_MILLISECOND)
+
+int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC);
+
+#endif //CTS_MEDIA_TEST_AAUDIO_H
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
new file mode 100644
index 0000000..2ec1e1c
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_callback.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AAudioTest"
+
+#include <gtest/gtest.h>
+#include <utils/Log.h>
+
+#include <aaudio/AAudio.h>
+#include "test_aaudio.h"
+
+typedef struct AAudioCallbackTestData {
+    int32_t callbackCount;
+    int32_t expectedFramesPerCallback;
+    int32_t actualFramesPerCallback;
+} AAudioCallbackTestData;
+
+// Callback function that fills the audio output buffer.
+static aaudio_data_callback_result_t MyDataCallbackProc(
+        AAudioStream *stream,
+        void *userData,
+        void *audioData,
+        int32_t numFrames
+) {
+    AAudioCallbackTestData *myData = (AAudioCallbackTestData *) userData;
+
+    if (numFrames != myData->expectedFramesPerCallback) {
+        // record unexpected framecounts
+        myData->actualFramesPerCallback = numFrames;
+    } else if (myData->actualFramesPerCallback == 0) {
+        // record at least one frame count
+        myData->actualFramesPerCallback = numFrames;
+    }
+    int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+    int32_t numSamples = samplesPerFrame * numFrames;
+    if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_I16) {
+        int16_t *shortData = (int16_t *) audioData;
+        for (int i = 0; i < numSamples; i++) *shortData++ = 0;
+    } else if (AAudioStream_getFormat(stream) == AAUDIO_FORMAT_PCM_FLOAT) {
+        float *floatData = (float *) audioData;
+        for (int i = 0; i < numSamples; i++) *floatData++ = 0.0f;
+    }
+    myData->callbackCount++;
+    return AAUDIO_CALLBACK_RESULT_CONTINUE;
+}
+
+// Test Writing to an AAudioStream using a Callback
+void runtest_aaudio_callback(aaudio_sharing_mode_t requestedSharingMode,
+                             int32_t framesPerDataCallback) {
+    AAudioCallbackTestData myTestData = { 0, 0, 0 };
+    const int32_t requestedSampleRate = 48000;
+    const int32_t requestedSamplesPerFrame = 2;
+    const aaudio_audio_format_t requestedDataFormat = AAUDIO_FORMAT_PCM_I16;
+
+    int32_t actualSampleRate = -1;
+    int32_t actualSamplesPerFrame = -1;
+    aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_INVALID;
+    aaudio_sharing_mode_t actualSharingMode;
+    int32_t framesPerBurst = -1;
+    int32_t actualBufferSize = 0;
+    int32_t actualFramesPerDataCallback = 0;
+
+    aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNINITIALIZED;
+    AAudioStreamBuilder *builder = nullptr;
+    AAudioStream *stream = nullptr;
+
+    aaudio_result_t result = AAUDIO_OK;
+
+    // Use an AAudioStreamBuilder to define the stream.
+    result = AAudio_createStreamBuilder(&builder);
+    ASSERT_EQ(AAUDIO_OK, result);
+
+    // Request stream properties.
+    AAudioStreamBuilder_setDeviceId(builder, AAUDIO_DEVICE_UNSPECIFIED);
+    AAudioStreamBuilder_setDirection(builder, AAUDIO_DIRECTION_OUTPUT);
+    AAudioStreamBuilder_setSampleRate(builder, requestedSampleRate);
+    AAudioStreamBuilder_setSamplesPerFrame(builder, requestedSamplesPerFrame);
+    AAudioStreamBuilder_setFormat(builder, requestedDataFormat);
+    AAudioStreamBuilder_setSharingMode(builder, requestedSharingMode);
+    AAudioStreamBuilder_setBufferCapacityInFrames(builder, 2000);
+
+    AAudioStreamBuilder_setDataCallback(builder, MyDataCallbackProc, &myTestData);
+    if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+        AAudioStreamBuilder_setFramesPerDataCallback(builder, framesPerDataCallback);
+    }
+
+    // Create an AAudioStream using the Builder.
+    ASSERT_EQ(AAUDIO_OK, AAudioStreamBuilder_openStream(builder, &stream));
+    EXPECT_EQ(AAUDIO_OK, AAudioStreamBuilder_delete(builder));
+
+    EXPECT_EQ(AAUDIO_STREAM_STATE_OPEN, AAudioStream_getState(stream));
+    EXPECT_EQ(AAUDIO_DIRECTION_OUTPUT, AAudioStream_getDirection(stream));
+
+    // Check to see what kind of stream we actually got.
+    actualSampleRate = AAudioStream_getSampleRate(stream);
+    ASSERT_TRUE(actualSampleRate >= 44100 && actualSampleRate <= 96000);  // TODO what is range?
+
+    actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+    ASSERT_TRUE(actualSamplesPerFrame >= 1 && actualSamplesPerFrame <= 16); // TODO what is max?
+
+    actualSharingMode = AAudioStream_getSharingMode(stream);
+    ASSERT_TRUE(actualSharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE
+                || actualSharingMode == AAUDIO_SHARING_MODE_SHARED);
+
+    actualDataFormat = AAudioStream_getFormat(stream);
+
+    // TODO test this on full build
+    // ASSERT_NE(AAUDIO_DEVICE_UNSPECIFIED, AAudioStream_getDeviceId(stream));
+
+    framesPerBurst = AAudioStream_getFramesPerBurst(stream);
+    ASSERT_TRUE(framesPerBurst >= 16 && framesPerBurst <= 1024); // TODO what is min/max?
+
+    actualFramesPerDataCallback = AAudioStream_getFramesPerDataCallback(stream);
+    if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+        ASSERT_EQ(framesPerDataCallback, actualFramesPerDataCallback);
+    }
+
+    actualBufferSize = AAudioStream_getBufferSizeInFrames(stream);
+    actualBufferSize = AAudioStream_setBufferSizeInFrames(stream, actualBufferSize);
+    ASSERT_TRUE(actualBufferSize > 0);
+
+    // Start/stop more than once to see if it fails after the first time.
+    // Write some data and measure the rate to see if the timing is OK.
+    for (int loopIndex = 0; loopIndex < 2; loopIndex++) {
+        myTestData.callbackCount = 0;
+        myTestData.expectedFramesPerCallback = actualFramesPerDataCallback;
+
+        // Start and wait for server to respond.
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(stream));
+        ASSERT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                             AAUDIO_STREAM_STATE_STARTING,
+                                                             &state,
+                                                             DEFAULT_STATE_TIMEOUT));
+        EXPECT_EQ(AAUDIO_STREAM_STATE_STARTED, state);
+
+        sleep(2);
+
+        // For more coverage, alternate pausing and stopping.
+        if ((loopIndex & 1) == 0) {
+            // Request async pause and wait for server to say that it has completed the request.
+            ASSERT_EQ(AAUDIO_OK, AAudioStream_requestPause(stream));
+            EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                                 AAUDIO_STREAM_STATE_PAUSING,
+                                                                 &state,
+                                                                 DEFAULT_STATE_TIMEOUT));
+            EXPECT_EQ(AAUDIO_STREAM_STATE_PAUSED, state);
+        } else {
+            // Request async stop and wait for server to say that it has completed the request.
+            ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStop(stream));
+            EXPECT_EQ(AAUDIO_OK, AAudioStream_waitForStateChange(stream,
+                                                                 AAUDIO_STREAM_STATE_STOPPING,
+                                                                 &state,
+                                                                 DEFAULT_STATE_TIMEOUT));
+            EXPECT_EQ(AAUDIO_STREAM_STATE_STOPPED, state);
+        }
+
+        int32_t oldCallbackCount = myTestData.callbackCount;
+        EXPECT_GT(oldCallbackCount, 10);
+        sleep(1);
+        EXPECT_EQ(oldCallbackCount, myTestData.callbackCount); // expect not advancing
+
+        if (framesPerDataCallback != AAUDIO_UNSPECIFIED) {
+            ASSERT_EQ(framesPerDataCallback, myTestData.actualFramesPerCallback);
+        }
+    }
+
+    EXPECT_EQ(AAUDIO_OK, AAudioStream_close(stream));
+}
+
+// Test Using an AAudioStream callback in SHARED mode.
+
+TEST(test_aaudio, aaudio_callback_shared_unspecified) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, AAUDIO_UNSPECIFIED);
+}
+
+TEST(test_aaudio, aaudio_callback_shared_109) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 109); // arbitrary prime number < 192
+}
+
+TEST(test_aaudio, aaudio_callback_shared_223) {
+runtest_aaudio_callback(AAUDIO_SHARING_MODE_SHARED, 223); // arbitrary prime number > 192
+}
diff --git a/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
new file mode 100644
index 0000000..8599d48
--- /dev/null
+++ b/tests/tests/nativemedia/aaudio/src/test_aaudio_misc.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AAudioTest"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <aaudio/AAudio.h>
+
+// Make sure enums do not change value.
+TEST(test_aaudio_misc, aaudio_freeze_enums) {
+
+    ASSERT_EQ(0, AAUDIO_DIRECTION_OUTPUT);
+    ASSERT_EQ(1, AAUDIO_DIRECTION_INPUT);
+
+    ASSERT_EQ(-1, AAUDIO_FORMAT_INVALID);
+    ASSERT_EQ(0, AAUDIO_FORMAT_UNSPECIFIED);
+    ASSERT_EQ(1, AAUDIO_FORMAT_PCM_I16);
+    ASSERT_EQ(2, AAUDIO_FORMAT_PCM_FLOAT);
+
+    ASSERT_EQ(0, AAUDIO_OK);
+    ASSERT_EQ(-900, AAUDIO_ERROR_BASE);
+    ASSERT_EQ(-899, AAUDIO_ERROR_DISCONNECTED);
+    ASSERT_EQ(-898, AAUDIO_ERROR_ILLEGAL_ARGUMENT);
+    ASSERT_EQ(-897, AAUDIO_ERROR_INCOMPATIBLE);
+    ASSERT_EQ(-896, AAUDIO_ERROR_INTERNAL);
+    ASSERT_EQ(-895, AAUDIO_ERROR_INVALID_STATE);
+    ASSERT_EQ(-894, AAUDIO_ERROR_UNEXPECTED_STATE);
+    ASSERT_EQ(-893, AAUDIO_ERROR_UNEXPECTED_VALUE);
+    ASSERT_EQ(-892, AAUDIO_ERROR_INVALID_HANDLE);
+    ASSERT_EQ(-891, AAUDIO_ERROR_INVALID_QUERY);
+    ASSERT_EQ(-890, AAUDIO_ERROR_UNIMPLEMENTED);
+    ASSERT_EQ(-889, AAUDIO_ERROR_UNAVAILABLE);
+    ASSERT_EQ(-888, AAUDIO_ERROR_NO_FREE_HANDLES);
+    ASSERT_EQ(-887, AAUDIO_ERROR_NO_MEMORY);
+    ASSERT_EQ(-886, AAUDIO_ERROR_NULL);
+    ASSERT_EQ(-885, AAUDIO_ERROR_TIMEOUT);
+    ASSERT_EQ(-884, AAUDIO_ERROR_WOULD_BLOCK);
+    ASSERT_EQ(-883, AAUDIO_ERROR_INVALID_FORMAT);
+    ASSERT_EQ(-882, AAUDIO_ERROR_OUT_OF_RANGE);
+    ASSERT_EQ(-881, AAUDIO_ERROR_NO_SERVICE);
+
+    ASSERT_EQ(0, AAUDIO_STREAM_STATE_UNINITIALIZED);
+    ASSERT_EQ(1, AAUDIO_STREAM_STATE_UNKNOWN);
+    ASSERT_EQ(2, AAUDIO_STREAM_STATE_OPEN);
+    ASSERT_EQ(3, AAUDIO_STREAM_STATE_STARTING);
+    ASSERT_EQ(4, AAUDIO_STREAM_STATE_STARTED);
+    ASSERT_EQ(5, AAUDIO_STREAM_STATE_PAUSING);
+    ASSERT_EQ(6, AAUDIO_STREAM_STATE_PAUSED);
+    ASSERT_EQ(7, AAUDIO_STREAM_STATE_FLUSHING);
+    ASSERT_EQ(8, AAUDIO_STREAM_STATE_FLUSHED);
+    ASSERT_EQ(9, AAUDIO_STREAM_STATE_STOPPING);
+    ASSERT_EQ(10, AAUDIO_STREAM_STATE_STOPPED);
+    ASSERT_EQ(11, AAUDIO_STREAM_STATE_CLOSING);
+    ASSERT_EQ(12, AAUDIO_STREAM_STATE_CLOSED);
+
+    ASSERT_EQ(0, AAUDIO_SHARING_MODE_EXCLUSIVE);
+    ASSERT_EQ(1, AAUDIO_SHARING_MODE_SHARED);
+
+    ASSERT_EQ(0, AAUDIO_CALLBACK_RESULT_CONTINUE);
+    ASSERT_EQ(1, AAUDIO_CALLBACK_RESULT_STOP);
+}
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
index 24871ca..83f087b 100644
--- a/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -45,12 +45,15 @@
 
 import com.android.internal.telephony.PhoneConstants;
 
+import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.net.Socket;
 import java.net.InetSocketAddress;
 import java.util.HashMap;
+import java.util.Scanner;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -74,6 +77,17 @@
             "Host: " + TEST_HOST + "\r\n" +
             "Connection: keep-alive\r\n\r\n";
 
+    // Base path for IPv6 sysctls
+    private static final String IPV6_SYSCTL_DIR = "/proc/sys/net/ipv6/conf";
+
+    // Expected values for MIN|MAX_PLEN.
+    private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN = 48;
+    private static final int IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN = 64;
+
+    // Expected values for RFC 7559 router soliciations.
+    // Maximum number of router solicitations to send. -1 means no limit.
+    private static final int IPV6_WIFI_ROUTER_SOLICITATIONS = -1;
+
     // Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
     private static final String NETWORK_CALLBACK_ACTION =
             "ConnectivityManagerTest.NetworkCallbackAction";
@@ -91,6 +105,7 @@
     private PackageManager mPackageManager;
     private final HashMap<Integer, NetworkConfig> mNetworks =
             new HashMap<Integer, NetworkConfig>();
+    boolean mWifiConnectAttempted;
 
     @Override
     protected void setUp() throws Exception {
@@ -99,6 +114,7 @@
         mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
         mPackageManager = mContext.getPackageManager();
+        mWifiConnectAttempted = false;
 
         // Get com.android.internal.R.array.networkAttributes
         int resId = mContext.getResources().getIdentifier("networkAttributes", "array", "android");
@@ -116,6 +132,27 @@
         }
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        // Return WiFi to its original disabled state after tests that explicitly connect.
+        if (mWifiConnectAttempted) {
+            disconnectFromWifi(null);
+        }
+    }
+
+    /**
+     * Make sure WiFi is connected to an access point if it is not already. If
+     * WiFi is enabled as a result of this function, it will be disabled
+     * automatically in tearDown().
+     */
+    private Network ensureWifiConnected() {
+        if (mWifiManager.isWifiEnabled()) {
+            return getWifiNetwork();
+        }
+        mWifiConnectAttempted = true;
+        return connectToWifi();
+    }
+
     public void testIsNetworkTypeValid() {
         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_MOBILE));
         assertTrue(ConnectivityManager.isNetworkTypeValid(ConnectivityManager.TYPE_WIFI));
@@ -298,14 +335,10 @@
         final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
         mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
 
-        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
         Network wifiNetwork = null;
 
         try {
-            // Make sure WiFi is connected to an access point to start with.
-            if (!previousWifiEnabledState) {
-                connectToWifi();
-            }
+            ensureWifiConnected();
 
             // Now we should expect to get a network callback about availability of the wifi
             // network even if it was already connected as a state-based action when the callback
@@ -321,11 +354,6 @@
         } finally {
             mCm.unregisterNetworkCallback(callback);
             mCm.unregisterNetworkCallback(defaultTrackingCallback);
-
-            // Return WiFi to its original enabled/disabled state.
-            if (!previousWifiEnabledState) {
-                disconnectFromWifi(wifiNetwork);
-            }
         }
     }
 
@@ -357,13 +385,8 @@
         // We will register for a WIFI network being available or lost.
         mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
 
-        final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
-
         try {
-            // Make sure WiFi is connected to an access point to start with.
-            if (!previousWifiEnabledState) {
-                connectToWifi();
-            }
+            ensureWifiConnected();
 
             // Now we expect to get the Intent delivered notifying of the availability of the wifi
             // network even if it was already connected as a state-based action when the callback
@@ -376,11 +399,6 @@
             mCm.unregisterNetworkCallback(pendingIntent);
             pendingIntent.cancel();
             mContext.unregisterReceiver(receiver);
-
-            // Return WiFi to its original enabled/disabled state.
-            if (!previousWifiEnabledState) {
-                disconnectFromWifi(null);
-            }
         }
     }
 
@@ -761,4 +779,42 @@
             fail("No exception thrown when restricted network requested.");
         } catch (SecurityException expected) {}
     }
+
+    private Scanner makeWifiSysctlScanner(String key) throws FileNotFoundException {
+        Network network = ensureWifiConnected();
+        String iface = mCm.getLinkProperties(network).getInterfaceName();
+        String path = IPV6_SYSCTL_DIR + "/" + iface + "/" + key;
+        return new Scanner(new File(path));
+    }
+
+    /** Verify that accept_ra_rt_info_min_plen exists and is set to the expected value */
+    public void testAcceptRaRtInfoMinPlen() throws Exception {
+        Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_min_plen");
+        assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MIN_PLEN, s.nextInt());
+    }
+
+    /** Verify that accept_ra_rt_info_max_plen exists and is set to the expected value */
+    public void testAcceptRaRtInfoMaxPlen() throws Exception {
+        Scanner s = makeWifiSysctlScanner("accept_ra_rt_info_max_plen");
+        assertEquals(IPV6_WIFI_ACCEPT_RA_RT_INFO_MAX_PLEN, s.nextInt());
+    }
+
+    /** Verify that router_solicitations exists and is set to the expected value */
+    public void testRouterSolicitations() throws Exception {
+        Scanner s = makeWifiSysctlScanner("router_solicitations");
+        assertEquals(IPV6_WIFI_ROUTER_SOLICITATIONS, s.nextInt());
+    }
+
+    /** Verify that router_solicitation_max_interval exists and is in an acceptable interval */
+    public void testRouterSolicitationMaxInterval() throws Exception {
+        Scanner s = makeWifiSysctlScanner("router_solicitation_max_interval");
+        int interval = s.nextInt();
+        // Verify we're in the interval [15 minutes, 60 minutes]. Lower values may adversely
+        // impact battery life and higher values can decrease the probability of detecting
+        // network changes.
+        final int lowerBoundSec = 15 * 60;
+        final int upperBoundSec = 60 * 60;
+        assertTrue(lowerBoundSec <= interval);
+        assertTrue(interval <= upperBoundSec);
+    }
 }
diff --git a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
index 93b5c44..bcecee1 100644
--- a/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
+++ b/tests/tests/net/src/android/net/cts/IpSecManagerTest.java
@@ -21,11 +21,13 @@
 import android.net.IpSecAlgorithm;
 import android.net.IpSecManager;
 import android.net.IpSecTransform;
+import android.os.ParcelFileDescriptor;
+import android.system.Os;
+import android.system.OsConstants;
 import android.test.AndroidTestCase;
-import android.util.Log;
-import java.io.IOException;
-import java.net.DatagramPacket;
+import java.io.ByteArrayOutputStream;
 import java.net.DatagramSocket;
+import java.io.FileDescriptor;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -82,17 +84,17 @@
     public void testAllocSpi() throws Exception {
         for (InetAddress addr : GOOGLE_DNS_LIST) {
             IpSecManager.SecurityParameterIndex randomSpi = null, droidSpi = null;
-            randomSpi =
-                    mISM.reserveSecurityParameterIndex(
-                            IpSecTransform.DIRECTION_OUT,
-                            addr,
-                            IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
-            assertTrue(randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+            randomSpi = mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, addr);
+            assertTrue(
+                    "Failed to receive a valid SPI",
+                    randomSpi.getSpi() != IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
 
             droidSpi =
                     mISM.reserveSecurityParameterIndex(
                             IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
-            assertTrue(droidSpi.getSpi() == DROID_SPI);
+            assertTrue(
+                    "Failed to allocate specified SPI, " + DROID_SPI,
+                    droidSpi.getSpi() == DROID_SPI);
 
             try {
                 mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_IN, addr, DROID_SPI);
@@ -119,10 +121,7 @@
     public void testCreateTransform() throws Exception {
         InetAddress local = InetAddress.getLoopbackAddress();
         IpSecManager.SecurityParameterIndex outSpi =
-                mISM.reserveSecurityParameterIndex(
-                        IpSecTransform.DIRECTION_OUT,
-                        local,
-                        IpSecManager.INVALID_SECURITY_PARAMETER_INDEX);
+                mISM.reserveSecurityParameterIndex(IpSecTransform.DIRECTION_OUT, local);
 
         IpSecManager.SecurityParameterIndex inSpi =
                 mISM.reserveSecurityParameterIndex(
@@ -133,46 +132,40 @@
                         .setSpi(IpSecTransform.DIRECTION_OUT, outSpi)
                         .setEncryption(
                                 IpSecTransform.DIRECTION_OUT,
-                                new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY))
+                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
                         .setAuthentication(
                                 IpSecTransform.DIRECTION_OUT,
                                 new IpSecAlgorithm(
-                                        IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256,
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
                                         AUTH_KEY,
                                         AUTH_KEY.length * 8))
                         .setSpi(IpSecTransform.DIRECTION_IN, inSpi)
                         .setEncryption(
                                 IpSecTransform.DIRECTION_IN,
-                                new IpSecAlgorithm(IpSecAlgorithm.ALGO_CRYPT_AES_CBC, CRYPT_KEY))
+                                new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY))
                         .setAuthentication(
                                 IpSecTransform.DIRECTION_IN,
                                 new IpSecAlgorithm(
-                                        IpSecAlgorithm.ALGO_AUTH_HMAC_SHA256,
+                                        IpSecAlgorithm.AUTH_HMAC_SHA256,
                                         AUTH_KEY,
                                         CRYPT_KEY.length * 8))
                         .buildTransportModeTransform(local);
 
-        DatagramSocket localSocket;
-        localSocket = new DatagramSocket(8888);
-
+        // Hack to ensure the socket doesn't block indefinitely on failure
+        DatagramSocket localSocket = new DatagramSocket(8888);
         localSocket.setSoTimeout(500);
-        mISM.applyTransportModeTransform(localSocket, transform);
+        ParcelFileDescriptor pin = ParcelFileDescriptor.fromDatagramSocket(localSocket);
+        FileDescriptor udpSocket = pin.getFileDescriptor();
+
+        mISM.applyTransportModeTransform(udpSocket, transform);
         byte[] data = new String("Best test data ever!").getBytes("UTF-8");
 
-        DatagramPacket out = new DatagramPacket(data, data.length, local, 8888);
-        localSocket.send(out);
-        DatagramPacket in = new DatagramPacket(new byte[data.length], data.length);
-
-        localSocket.receive(in);
-        Log.d(TAG, Arrays.toString(data));
-        Log.d(TAG, Arrays.toString(in.getData()));
-        assertTrue(Arrays.equals(data, in.getData()));
+        byte[] in = new byte[data.length];
+        Os.sendto(udpSocket, data, 0, data.length, 0, local, 8888);
+        Os.read(udpSocket, in, 0, in.length);
+        assertTrue("Encapsulated data did not match.", Arrays.equals(data, in));
+        mISM.removeTransportModeTransform(udpSocket, transform);
+        Os.close(udpSocket);
         transform.close();
-        try {
-            localSocket.send(out);
-        } catch (IOException e) {
-        }
-
-        mISM.removeTransportModeTransform(localSocket, transform);
     }
 }
diff --git a/tests/tests/os/src/android/os/cts/AbiTest.java b/tests/tests/os/src/android/os/cts/AbiTest.java
index 49ff8aa..1765ae7 100644
--- a/tests/tests/os/src/android/os/cts/AbiTest.java
+++ b/tests/tests/os/src/android/os/cts/AbiTest.java
@@ -16,11 +16,14 @@
 
 package android.os.cts;
 
+import android.system.OsConstants;
+import android.system.ErrnoException;
 import android.util.ArraySet;
 
 import com.android.compatibility.common.util.ReadElf;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.Arrays;
 
 import junit.framework.TestCase;
@@ -74,6 +77,14 @@
                     elf = ReadElf.read(f);
                 } catch (IllegalArgumentException ignored) {
                     // If it's not actually an ELF file, we don't care.
+                } catch (IOException ex) {
+                    Throwable cause = ex.getCause();
+                    if (cause instanceof ErrnoException) {
+                        // if we are denied access to the file, ignore.
+                        if (((ErrnoException) cause).errno != OsConstants.EACCES) {
+                            throw ex;
+                        }
+                    }
                 } finally {
                     if (elf != null) {
                         elf.close();
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 1db2d72..736e0f3 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageManagerTest.java
@@ -53,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.UUID;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.SynchronousQueue;
 import junit.framework.AssertionFailedError;
@@ -256,6 +257,32 @@
         assertStorageVolumesEquals(primary, childVolume);
     }
 
+    private void assertNoUuid(File file) {
+        try {
+            final UUID uuid = mStorageManager.getUuidForPath(file);
+            fail("Unexpected UUID " + uuid + " for " + file);
+        } catch (IOException expected) {
+        }
+    }
+
+    public void testGetUuidForPath() throws Exception {
+        assertEquals(StorageManager.UUID_DEFAULT,
+                mStorageManager.getUuidForPath(Environment.getDataDirectory()));
+        assertEquals(StorageManager.UUID_DEFAULT,
+                mStorageManager.getUuidForPath(mContext.getDataDir()));
+
+        final UUID extUuid = mStorageManager
+                .getUuidForPath(Environment.getExternalStorageDirectory());
+        if (Environment.isExternalStorageEmulated()) {
+            assertEquals(StorageManager.UUID_DEFAULT, extUuid);
+        }
+
+        assertEquals(extUuid, mStorageManager.getUuidForPath(mContext.getExternalCacheDir()));
+
+        assertNoUuid(new File("/"));
+        assertNoUuid(new File("/proc/"));
+    }
+
     private static class TestProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
         final byte[] bytes;
         int fsyncCount;
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 4e6b9ea..8f0de7f 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -37,6 +37,7 @@
     <protected-broadcast android:name="android.intent.action.BOOT_COMPLETED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_INSTALL" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_ADDED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_ADDED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_REPLACED" />
     <protected-broadcast android:name="android.intent.action.MY_PACKAGE_REPLACED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_REMOVED" />
@@ -284,6 +285,7 @@
     <protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
     <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
     <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
+    <protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
 
     <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
     <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
@@ -491,7 +493,9 @@
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
+    <protected-broadcast android:name="android.accounts.action.ACCOUNT_REMOVED" />
     <protected-broadcast android:name="android.accounts.action.VISIBLE_ACCOUNTS_CHANGED" />
+
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
 
     <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" />
@@ -528,9 +532,14 @@
     <protected-broadcast android:name="com.android.internal.autofill.action.REQUEST_AUTOFILL" />
     <protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
     <protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+    <protected-broadcast android:name="android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED" />
 
     <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
     <protected-broadcast android:name="android.os.action.USER_RESTRICTIONS_CHANGED" />
+    <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT" />
+    <protected-broadcast android:name="android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED" />
+    <protected-broadcast android:name="android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED" />
+    <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
 
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
@@ -803,7 +812,7 @@
          <p>Protection level: dangerous-->
     <permission android:name="android.permission.READ_PHONE_NUMBERS"
         android:permissionGroup="android.permission-group.PHONE"
-        android:label="@string/permlab_readPhoneNumber"
+        android:label="@string/permlab_readPhoneNumbers"
         android:description="@string/permdesc_readPhoneNumbers"
         android:protectionLevel="dangerous|ephemeral" />
 
@@ -1299,6 +1308,13 @@
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
         android:protectionLevel="signature|setup" />
 
+    <!-- Allows network stack services (Connectivity and Wifi) to coordinate
+         <p>Not for use by third-party or privileged applications.
+         @hide This should only be used by Connectivity and Wifi Services.
+    -->
+    <permission android:name="android.permission.NETWORK_STACK"
+                android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -1511,6 +1527,16 @@
     <permission android:name="android.permission.DVB_DEVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by carrier state
+         @hide <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_CARRIER_OEM_UNLOCK_STATE"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi Allows reading and enabling/disabling the OEM unlock allowed by user state
+         @hide <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_USER_OEM_UNLOCK_STATE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows reading the OEM unlock state
          @hide <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_OEM_UNLOCK_STATE"
@@ -1644,6 +1670,21 @@
     <permission android:name="android.permission.BIND_IMS_SERVICE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to manage embedded subscriptions (those on a eUICC) through
+         EuiccManager APIs.
+         <p>Protection level: signature|privileged|development
+         TODO(b/35851809): Mark this as a SystemApi.
+         @hide -->
+    <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
+                android:protectionLevel="signature|privileged|development" />
+
+    <!-- Must be required by an EuiccService to ensure that only the system can bind to it.
+         <p>Protection level: signature
+         TODO(b/35851809): Mark this as a SystemApi.
+         @hide -->
+    <permission android:name="android.permission.BIND_EUICC_SERVICE"
+                android:protectionLevel="signature" />
+
 
     <!-- ================================== -->
     <!-- Permissions for sdcard interaction -->
@@ -1851,6 +1892,11 @@
         android:description="@string/permdesc_useDataInBackground"
         android:protectionLevel="signature" />
 
+    <!-- @hide Allows an application to set display offsets for the screen.
+         This permission is not available to third party applications. -->
+    <permission android:name="android.permission.SET_DISPLAY_OFFSET"
+                android:protectionLevel="signature|privileged" />
+
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
     <!-- ================================== -->
@@ -2511,6 +2557,13 @@
     <permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+         <p>Protection level: signature|privileged
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.NOTIFY_TV_INPUTS"
+                android:protectionLevel="signature|privileged" />
+
     <!-- Must be required by a {@link android.media.routing.MediaRouteService}
          to ensure that only the system can interact with it.
          @hide -->
@@ -3129,6 +3182,15 @@
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
 
+    <!-- @SystemApi Must be required by services that extend
+         {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
+         bind to them.
+         <p>Protection level: signature
+         @hide
+    -->
+    <permission android:name="android.permission.BIND_RESOLVER_RANKER_SERVICE"
+                android:protectionLevel="signature" />
+
     <!-- Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
@@ -3346,7 +3408,8 @@
                 android:documentLaunchMode="never"
                 android:relinquishTaskIdentity="true"
                 android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -3354,15 +3417,17 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity"
+                  android:exported="false"
                   android:theme="@style/Theme.DeviceDefault.Resolver"
                   android:finishOnCloseSystemDialogs="true"
                   android:excludeFromRecents="true"
                   android:documentLaunchMode="never"
                   android:relinquishTaskIdentity="true"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-                  android:process=":ui">
+                  android:process=":ui"
+                  android:visibleToInstantApps="true">
             <intent-filter>
-                <action android:name="android.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
+                <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
@@ -3421,7 +3486,8 @@
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
@@ -3429,14 +3495,16 @@
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
                 android:excludeFromRecents="true"
                 android:theme="@style/Theme.DeviceDefault.Light.Dialog"
                 android:label="@string/choose_account_label"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.CantAddAccountActivity"
@@ -3450,7 +3518,8 @@
                 android:excludeFromRecents="true"
                 android:exported="true"
                 android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
-                android:process=":ui">
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
@@ -3508,6 +3577,11 @@
                 android:process=":ui">
         </activity>
 
+        <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
+                  android:theme="@android:style/Theme.DeviceDefault.Light.Dialog.Alert"
+                  android:excludeFromRecents="true">
+        </activity>
+
         <receiver android:name="com.android.server.BootReceiver"
                 android:systemUserOnly="true">
             <intent-filter android:priority="1000">
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/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 9a79c64..284841b 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -89,6 +89,10 @@
                 android:name="android.support.FILE_PROVIDER_PATHS"
                 android:resource="@xml/file_paths" />
         </provider>
+        <provider android:name="android.provider.cts.MockFontProvider"
+                  android:authorities="android.provider.fonts.cts.font"
+                  android:exported="false"
+                  android:multiprocess="true" />
 
     </application>
 
diff --git a/tests/tests/provider/assets/samplefont1.ttf b/tests/tests/provider/assets/samplefont1.ttf
new file mode 100644
index 0000000..020436a
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont1.ttx b/tests/tests/provider/assets/samplefont1.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont1.ttx
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="a"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="a" width="500" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="a" />
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/provider/assets/samplefont2.ttf b/tests/tests/provider/assets/samplefont2.ttf
new file mode 100644
index 0000000..491540f
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttf
Binary files differ
diff --git a/tests/tests/provider/assets/samplefont2.ttx b/tests/tests/provider/assets/samplefont2.ttx
new file mode 100644
index 0000000..40fa268
--- /dev/null
+++ b/tests/tests/provider/assets/samplefont2.ttx
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+  <GlyphOrder>
+    <GlyphID id="0" name=".notdef"/>
+    <GlyphID id="1" name="a"/>
+  </GlyphOrder>
+
+  <head>
+    <tableVersion value="1.0"/>
+    <fontRevision value="1.0"/>
+    <checkSumAdjustment value="0x640cdb2f"/>
+    <magicNumber value="0x5f0f3cf5"/>
+    <flags value="00000000 00000011"/>
+    <unitsPerEm value="1000"/>
+    <created value="Fri Mar 17 07:26:00 2017"/>
+    <macStyle value="00000000 00000000"/>
+    <lowestRecPPEM value="7"/>
+    <fontDirectionHint value="2"/>
+    <glyphDataFormat value="0"/>
+  </head>
+
+  <hhea>
+    <tableVersion value="1.0"/>
+    <ascent value="1000"/>
+    <descent value="-200"/>
+    <lineGap value="0"/>
+    <caretSlopeRise value="1"/>
+    <caretSlopeRun value="0"/>
+    <caretOffset value="0"/>
+    <reserved0 value="0"/>
+    <reserved1 value="0"/>
+    <reserved2 value="0"/>
+    <reserved3 value="0"/>
+    <metricDataFormat value="0"/>
+  </hhea>
+
+  <maxp>
+    <tableVersion value="0x10000"/>
+    <maxZones value="0"/>
+    <maxTwilightPoints value="0"/>
+    <maxStorage value="0"/>
+    <maxFunctionDefs value="0"/>
+    <maxInstructionDefs value="0"/>
+    <maxStackElements value="0"/>
+    <maxSizeOfInstructions value="0"/>
+    <maxComponentElements value="0"/>
+  </maxp>
+
+  <OS_2>
+    <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+         will be recalculated by the compiler -->
+    <version value="3"/>
+    <xAvgCharWidth value="594"/>
+    <usWeightClass value="400"/>
+    <usWidthClass value="5"/>
+    <fsType value="00000000 00001000"/>
+    <ySubscriptXSize value="650"/>
+    <ySubscriptYSize value="600"/>
+    <ySubscriptXOffset value="0"/>
+    <ySubscriptYOffset value="75"/>
+    <ySuperscriptXSize value="650"/>
+    <ySuperscriptYSize value="600"/>
+    <ySuperscriptXOffset value="0"/>
+    <ySuperscriptYOffset value="350"/>
+    <yStrikeoutSize value="50"/>
+    <yStrikeoutPosition value="300"/>
+    <sFamilyClass value="0"/>
+    <panose>
+      <bFamilyType value="0"/>
+      <bSerifStyle value="0"/>
+      <bWeight value="5"/>
+      <bProportion value="0"/>
+      <bContrast value="0"/>
+      <bStrokeVariation value="0"/>
+      <bArmStyle value="0"/>
+      <bLetterForm value="0"/>
+      <bMidline value="0"/>
+      <bXHeight value="0"/>
+    </panose>
+    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+    <achVendID value="UKWN"/>
+    <fsSelection value="00000000 01000000"/>
+    <usFirstCharIndex value="32"/>
+    <usLastCharIndex value="122"/>
+    <sTypoAscender value="800"/>
+    <sTypoDescender value="-200"/>
+    <sTypoLineGap value="200"/>
+    <usWinAscent value="1000"/>
+    <usWinDescent value="200"/>
+    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+    <sxHeight value="500"/>
+    <sCapHeight value="700"/>
+    <usDefaultChar value="0"/>
+    <usBreakChar value="32"/>
+    <usMaxContext value="0"/>
+  </OS_2>
+
+  <hmtx>
+    <mtx name=".notdef" width="500" lsb="93"/>
+    <mtx name="a" width="500" lsb="93"/>
+  </hmtx>
+
+  <cmap>
+    <tableVersion version="0"/>
+    <cmap_format_4 platformID="3" platEncID="10" language="0">
+      <map code="0x0061" name="a" />
+    </cmap_format_4>
+  </cmap>
+
+  <loca>
+    <!-- The 'loca' table will be calculated by the compiler -->
+  </loca>
+
+  <glyf>
+    <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+    <TTGlyph name="a" xMin="0" yMin="0" xMax="0" yMax="0" />
+  </glyf>
+
+  <name>
+    <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+      SampleFont-Regular
+    </namerecord>
+    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+      Regular
+    </namerecord>
+    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+      Sample Font
+    </namerecord>
+    <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+      SampleFont-Regular
+    </namerecord>
+  </name>
+
+  <post>
+    <formatType value="3.0"/>
+    <italicAngle value="0.0"/>
+    <underlinePosition value="-75"/>
+    <underlineThickness value="50"/>
+    <isFixedPitch value="0"/>
+    <minMemType42 value="0"/>
+    <maxMemType42 value="0"/>
+    <minMemType1 value="0"/>
+    <maxMemType1 value="0"/>
+  </post>
+
+</ttFont>
diff --git a/tests/tests/provider/src/android/provider/cts/FontsContractTest.java b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
new file mode 100644
index 0000000..d95f74a
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/FontsContractTest.java
@@ -0,0 +1,139 @@
+/*
+ * 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 android.provider.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.app.Instrumentation;
+import android.content.pm.Signature;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.graphics.fonts.FontRequest;
+import android.graphics.fonts.FontResult;
+import android.graphics.fonts.FontVariationAxis;
+import android.provider.FontsContract;
+import android.provider.FontsContract.FontFamilyResult;
+import android.provider.FontsContract.FontInfo;
+import android.provider.FontsContract.Columns;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FontsContractTest {
+    private static final String AUTHORITY = "android.provider.fonts.cts.font";
+    private static final String PACKAGE = "android.provider.cts";
+
+    private static long TIMEOUT_MILLIS = 1000;
+
+    // Signature to be used for authentication to access content provider.
+    // In this test case, the content provider and consumer live in the same package, self package's
+    // signature works.
+    private static List<List<byte[]>> SIGNATURE;
+    static {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        try {
+            PackageManager manager = context.getPackageManager();
+            PackageInfo info = manager.getPackageInfo(
+                    context.getPackageName(), PackageManager.GET_SIGNATURES);
+            ArrayList<byte[]> out = new ArrayList<>();
+            for (Signature sig : info.signatures) {
+                out.add(sig.toByteArray());
+            }
+            SIGNATURE = new ArrayList<>();
+            SIGNATURE.add(out);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Test
+    public void querySingleFont() throws NameNotFoundException {
+        Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+        FontFamilyResult result = FontsContract.fetchFonts(
+                ctx, null /* cancellation signal */, request);
+        assertNotNull(result);
+        assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+        FontInfo[] fonts = result.getFonts();
+        assertEquals(1, fonts.length);
+        FontInfo font = fonts[0];
+        assertNotNull(font.getUri());
+        assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+        // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+        // configurable.
+        assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+    }
+
+    @Test
+    public void queryMultipleFont() throws NameNotFoundException {
+        Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "multipleFontFamily", SIGNATURE);
+        FontFamilyResult result = FontsContract.fetchFonts(
+                ctx, null /* cancellation signal */, request);
+        assertNotNull(result);
+        assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+
+        FontInfo[] fonts = result.getFonts();
+        assertEquals(4, fonts.length);
+        for (FontInfo font: fonts) {
+            assertNotNull(font.getUri());
+            assertEquals(Columns.RESULT_CODE_OK, font.getResultCode());
+        }
+        // TODO: add more test cases for FontInfo members once the MockFontProvider becomes
+        // configuarable.
+        assertNotNull(FontsContract.buildTypeface(ctx, null /* cancellation signal */, fonts));
+    }
+
+    @Test
+    public void restrictContextRejection() throws NameNotFoundException {
+        Context ctx = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        Context restrictedContext = ctx.createPackageContext(PACKAGE, Context.CONTEXT_RESTRICTED);
+
+        FontRequest request = new FontRequest(AUTHORITY, PACKAGE, "singleFontFamily", SIGNATURE);
+
+        // Rejected if restricted context is used.
+        FontFamilyResult result = FontsContract.fetchFonts(
+                restrictedContext, null /* cancellation signal */, request);
+        assertEquals(FontFamilyResult.STATUS_REJECTED, result.getStatusCode());
+
+        // Even if you have a result, buildTypeface should fail with restricted context.
+        result = FontsContract.fetchFonts(ctx, null /* cancellation signal */, request);
+        assertEquals(FontFamilyResult.STATUS_OK, result.getStatusCode());
+        assertNull(FontsContract.buildTypeface(
+                restrictedContext, null /* cancellation signal */, result.getFonts()));
+    }
+
+    // TODO: Add more test case.
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
index e40f2ed..d8a80d2 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
@@ -131,6 +131,14 @@
         }
     }
 
+    private void maybeClick(UiSelector sel) {
+        try { mDevice.findObject(sel).click(); } catch (Throwable ignored) { }
+    }
+
+    private void maybeClick(BySelector sel) {
+        try { mDevice.findObject(sel).click(); } catch (Throwable ignored) { }
+    }
+
     /**
      * Verify that whoever handles {@link MediaStore#ACTION_IMAGE_CAPTURE} can
      * correctly write the contents into a passed {@code content://} Uri.
@@ -164,7 +172,7 @@
                 + pkg + " " + android.Manifest.permission.ACCESS_COARSE_LOCATION);
         getInstrumentation().getUiAutomation().executeShellCommand("pm grant "
                 + pkg + " " + android.Manifest.permission.ACCESS_FINE_LOCATION);
-        Thread.sleep(1000);
+        SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
 
         mActivity.startActivityForResult(intent, REQUEST_CODE);
         mDevice.waitForIdle();
@@ -184,15 +192,27 @@
         // Hrm, that didn't work; let's try an alternative approach of digging
         // around for a shutter button
         if (result == null) {
-            mDevice.findObject(new UiSelector().resourceId(pkg + ":id/shutter_button")).click();
+            maybeClick(new UiSelector().resourceId(pkg + ":id/shutter_button"));
             mDevice.waitForIdle();
             SystemClock.sleep(5 * DateUtils.SECOND_IN_MILLIS);
-            mDevice.findObject(new UiSelector().resourceId(pkg + ":id/shutter_button")).click();
+            maybeClick(new UiSelector().resourceId(pkg + ":id/shutter_button"));
             mDevice.waitForIdle();
+
+            result = mActivity.getResult(15, TimeUnit.SECONDS);
+            Log.d(TAG, "Second pass result was " + result);
         }
 
-        result = mActivity.getResult(15, TimeUnit.SECONDS);
-        Log.d(TAG, "Second pass result was " + result);
+        // Grr, let's try hunting around even more
+        if (result == null) {
+            maybeClick(By.pkg(pkg).descContains("Capture"));
+            mDevice.waitForIdle();
+            SystemClock.sleep(5 * DateUtils.SECOND_IN_MILLIS);
+            maybeClick(By.pkg(pkg).descContains("Done"));
+            mDevice.waitForIdle();
+
+            result = mActivity.getResult(15, TimeUnit.SECONDS);
+            Log.d(TAG, "Third pass result was " + result);
+        }
 
         assertNotNull("Expected to get a IMAGE_CAPTURE result; your camera app should "
                 + "respond to the CAMERA and DPAD_CENTER keycodes", result);
diff --git a/tests/tests/provider/src/android/provider/cts/MockFontProvider.java b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
new file mode 100644
index 0000000..a348de2
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MockFontProvider.java
@@ -0,0 +1,195 @@
+/*
+ * 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 android.provider.cts;
+
+import static android.provider.FontsContract.Columns;
+
+import android.content.ContentProvider;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.graphics.fonts.FontVariationAxis;
+import android.net.Uri;
+import android.os.CancellationSignal;
+import android.os.ParcelFileDescriptor;
+import android.util.SparseArray;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.io.File;
+import java.nio.file.Files;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.nio.file.StandardCopyOption;
+
+public class MockFontProvider extends ContentProvider {
+    final static String AUTHORITY = "android.provider.fonts.cts.font";
+
+    final static String[] FONT_FILES = {
+        "samplefont1.ttf", "samplefont2.ttf",
+    };
+    private static final int SAMPLE_FONT_FILE_0_ID = 0;
+    private static final int SAMPLE_FONT_FILE_1_ID = 1;
+
+    static class Font {
+        public Font(int id, int fileId, int ttcIndex, String varSettings, int weight, int italic,
+                int resultCode) {
+            mId = id;
+            mFileId = fileId;
+            mTtcIndex = ttcIndex;
+            mVarSettings = varSettings;
+            mWeight = weight;
+            mItalic = italic;
+            mResultCode = resultCode;
+        }
+
+        public int getId() {
+            return mId;
+        }
+
+        public int getTtcIndex() {
+            return mTtcIndex;
+        }
+
+        public String getVarSettings() {
+            return mVarSettings;
+        }
+
+        public int getWeight() {
+            return mWeight;
+        }
+
+        public int getItalic() {
+            return mItalic;
+        }
+
+        public int getResultCode() {
+            return mResultCode;
+        }
+
+        public int getFileId() {
+            return mFileId;
+        }
+
+        private int mId;
+        private int mFileId;
+        private int mTtcIndex;
+        private String mVarSettings;
+        private int mWeight;
+        private int mItalic;
+        private int mResultCode;
+    };
+
+    private static Map<String, Font[]> QUERY_MAP;
+    static {
+        HashMap<String, Font[]> map = new HashMap<>();
+        int id = 0;
+
+        map.put("singleFontFamily", new Font[] {
+            new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+        });
+
+        map.put("multipleFontFamily", new Font[] {
+            new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+            new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 400, 0, Columns.RESULT_CODE_OK),
+            new Font(id++, SAMPLE_FONT_FILE_0_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+            new Font(id++, SAMPLE_FONT_FILE_1_ID, 0, null, 700, 1, Columns.RESULT_CODE_OK),
+        });
+
+        QUERY_MAP = Collections.unmodifiableMap(map);
+    }
+
+    private static Cursor buildCursor(Font[] in) {
+        MatrixCursor cursor = new MatrixCursor(new String[] {
+                Columns._ID, Columns.TTC_INDEX, Columns.VARIATION_SETTINGS, Columns.WEIGHT,
+                Columns.ITALIC, Columns.RESULT_CODE, Columns.FILE_ID});
+        for (Font font : in) {
+            MatrixCursor.RowBuilder builder = cursor.newRow();
+            builder.add(Columns._ID, font.getId());
+            builder.add(Columns.FILE_ID, font.getFileId());
+            builder.add(Columns.TTC_INDEX, font.getTtcIndex());
+            builder.add(Columns.VARIATION_SETTINGS, font.getVarSettings());
+            builder.add(Columns.WEIGHT, font.getWeight());
+            builder.add(Columns.ITALIC, font.getItalic());
+            builder.add(Columns.RESULT_CODE, font.getResultCode());
+        }
+        return cursor;
+    }
+
+    public MockFontProvider() {
+    }
+
+    @Override
+    public ParcelFileDescriptor openFile(Uri uri, String mode) {
+        final int id = (int)ContentUris.parseId(uri);
+        final File targetFile = getCopiedFile(FONT_FILES[id]);
+        try {
+            return ParcelFileDescriptor.open(targetFile, ParcelFileDescriptor.MODE_READ_ONLY);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public File getCopiedFile(String path) {
+        return new File(getContext().getFilesDir(), path);
+    }
+
+    @Override
+    public boolean onCreate() {
+        final AssetManager mgr = getContext().getAssets();
+        for (String path : FONT_FILES) {
+            try (InputStream is = mgr.open(path)) {
+                Files.copy(is, getCopiedFile(path).toPath(), StandardCopyOption.REPLACE_EXISTING);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        // TODO: do we have good time to remove above files from files directory?
+        return true;
+    }
+
+    @Override
+    public String getType(Uri uri) {
+        return "vnd.android.cursor.dir/vnd.android.provider.cts.font";
+    }
+
+    @Override
+    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+            String sortOrder) {
+        return buildCursor(QUERY_MAP.get(selectionArgs[0]));
+    }
+
+    @Override
+    public Uri insert(Uri uri, ContentValues values) {
+        throw new UnsupportedOperationException("insert is not supported.");
+    }
+
+    @Override
+    public int delete(Uri uri, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("delete is not supported.");
+    }
+
+    @Override
+    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+        throw new UnsupportedOperationException("update is not supported.");
+    }
+}
diff --git a/tests/tests/security/res/raw/cve_2015_3836.xmf b/tests/tests/security/res/raw/cve_2015_3836.xmf
new file mode 100644
index 0000000..b897c09
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3836.xmf
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4 b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
new file mode 100644
index 0000000..3d1b223
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2015_3864_b23034759.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/SeccompTest.java b/tests/tests/security/src/android/security/cts/SeccompTest.java
index 44185bd..745aa87 100644
--- a/tests/tests/security/src/android/security/cts/SeccompTest.java
+++ b/tests/tests/security/src/android/security/cts/SeccompTest.java
@@ -67,6 +67,30 @@
         }
     }
 
+    public void testCTSSwapOnOffBlocked() {
+        if (CpuFeatures.isArm64Cpu()) {
+            testBlocked(224); // __NR_swapon
+            testBlocked(225); // __NR_swapoff
+        } else if (CpuFeatures.isArmCpu()) {
+            testBlocked(87);  // __NR_swapon
+            testBlocked(115); // __NR_swapoff
+        } else if (CpuFeatures.isX86_64Cpu()) {
+            testBlocked(167); // __NR_swapon
+            testBlocked(168); // __NR_swapoff
+        } else if (CpuFeatures.isX86Cpu()) {
+            testBlocked(87);  // __NR_swapon
+            testBlocked(115); // __NR_swapoff
+        } else if (CpuFeatures.isMips64Cpu()) {
+            testBlocked(5162); // __NR_swapon
+            testBlocked(5163); // __NR_swapoff
+        } else if (CpuFeatures.isMipsCpu()) {
+            testBlocked(4087); // __NR_swapon
+            testBlocked(4115); // __NR_swapoff
+        } else {
+            fail("Unsupported OS");
+        }
+    }
+
     private void testBlocked(int nr) {
         assertTrue("Syscall " + nr + " allowed", testSyscallBlocked(nr));
     }
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 199c63b..1ad199d 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -148,11 +148,21 @@
     }
 
     @SecurityTest
+    public void testStagefright_cve_2015_3836() throws Exception {
+        doStagefrightTest(R.raw.cve_2015_3836);
+    }
+
+    @SecurityTest
     public void testStagefright_cve_2015_3864() throws Exception {
         doStagefrightTest(R.raw.cve_2015_3864);
     }
 
     @SecurityTest
+    public void testStagefright_cve_2015_3864_b23034759() throws Exception {
+        doStagefrightTest(R.raw.cve_2015_3864_b23034759);
+    }
+
+    @SecurityTest
     public void testStagefright_cve_2015_6598() throws Exception {
         doStagefrightTest(R.raw.cve_2015_6598);
     }
@@ -525,7 +535,11 @@
                 closeQuietly(fd);
             }
         } else {
-            ex.setDataSource(url);
+            try {
+                ex.setDataSource(url);
+            } catch (Exception e) {
+                // indicative of problems with our tame CTS test web server
+            }
         }
         int numtracks = ex.getTrackCount();
         String rname = url != null ? url: resources.getResourceEntryName(rid);
@@ -617,6 +631,7 @@
                     codec.release();
                 }
             }
+            ex.unselectTrack(t);
         }
         ex.release();
         String cve = rname.replace("_", "-").toUpperCase();
@@ -680,13 +695,17 @@
             AssetFileDescriptor fd = resources.openRawResourceFd(rid);
             try {
                 retriever.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
-            } catch (IllegalArgumentException e) {
+            } catch (RuntimeException e) {
                 // ignore
             } finally {
                 closeQuietly(fd);
             }
         } else {
-            retriever.setDataSource(url, new HashMap<String, String>());
+            try {
+                retriever.setDataSource(url, new HashMap<String, String>());
+            } catch (Exception e) {
+                // indicative of problems with our tame CTS test web server
+            }
         }
         retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
         retriever.getEmbeddedPicture();
diff --git a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
index 543831c..ee1f901 100644
--- a/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/SelfManagedConnectionServiceTest.java
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.telecom.CallAudioState;
 import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 
 import java.util.ArrayList;
@@ -68,6 +69,23 @@
     }
 
     /**
+     * Tests {@link TelecomManager#getSelfManagedPhoneAccounts()} API to ensure it returns a list of
+     * the registered self-managed {@link android.telecom.PhoneAccount}s.
+     */
+    public void testTelecomManagerGetSelfManagedPhoneAccounts() {
+        if (!mShouldTestTelecom) {
+            return;
+        }
+
+        List<PhoneAccountHandle> phoneAccountHandles =
+                mTelecomManager.getSelfManagedPhoneAccounts();
+
+        assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_1));
+        assertTrue(phoneAccountHandles.contains(TestUtils.TEST_SELF_MANAGED_HANDLE_2));
+        assertFalse(phoneAccountHandles.contains(TestUtils.TEST_PHONE_ACCOUNT_HANDLE));
+    }
+
+    /**
      * Tests the ability to successfully register a self-managed
      * {@link android.telecom.PhoneAccount}.
      */
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index 420bba1..a6404e0 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -183,10 +183,10 @@
         mTelephonyManager.getNeighboringCellInfo();
         mTelephonyManager.isNetworkRoaming();
         mTelephonyManager.getDeviceId();
-        mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
+        mTelephonyManager.getDeviceId(mTelephonyManager.getSlotIndex());
         mTelephonyManager.getDeviceSoftwareVersion();
         mTelephonyManager.getImei();
-        mTelephonyManager.getImei(mTelephonyManager.getDefaultSim());
+        mTelephonyManager.getImei(mTelephonyManager.getSlotIndex());
         mTelephonyManager.getPhoneCount();
         mTelephonyManager.getDataEnabled();
         mTelephonyManager.getNetworkSpecifier();
@@ -254,7 +254,7 @@
      */
     @Test
     public void testGetDeviceIdForSlot() {
-        String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
+        String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getSlotIndex());
         verifyDeviceId(deviceId);
         // Also verify that no exception is thrown for any slot index (including invalid ones)
         for (int i = -1; i <= mTelephonyManager.getPhoneCount(); i++) {
@@ -555,7 +555,47 @@
             fail("Expected SecurityException. App does not have carrier privileges or is not the "
                     + "default dialer app");
         } catch (SecurityException expected) {
+        }
+    }
 
+    /**
+     * Tests that the device properly reports the contents of EF_FPLMN or null
+     */
+    @Test
+    public void testGetForbiddenPlmns() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        String[] plmns = mTelephonyManager.getForbiddenPlmns();
+
+        int phoneType = mTelephonyManager.getPhoneType();
+        switch (phoneType) {
+            case TelephonyManager.PHONE_TYPE_GSM:
+                assertNotNull("Forbidden PLMNs must be valid or an empty list!", plmns);
+            case TelephonyManager.PHONE_TYPE_CDMA:
+            case TelephonyManager.PHONE_TYPE_NONE:
+                if (plmns == null) {
+                    return;
+                }
+        }
+
+        for(String plmn : plmns) {
+            if (plmn.length() > 6 || plmn.length() < 5) {
+                fail("Invalid Length for PLMN-ID, must be 5 or 6: " + plmn);
+            }
+
+            // A record which is written in the SIM but empty will
+            // be all f's
+            if(android.text.TextUtils.isDigitsOnly(plmn)) {
+                assertTrue(
+                        "PLMNs must be strings of digits 0-9,F! " + plmn,
+                        android.text.TextUtils.isDigitsOnly(plmn));
+            } else {
+                for (char c : plmn.toUpperCase().toCharArray()) {
+                    assertTrue("PLMNs must be strings of digits 0-9,F! " + plmn,
+                            Character.toUpperCase(c) == 'F');
+                }
+            }
         }
     }
 
diff --git a/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
index ae8ab8d..1e766ba 100644
--- a/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/VisualVoicemailServiceTest.java
@@ -348,6 +348,10 @@
     }
 
     public void testFilter_originatingNumber_match_filtered() {
+        if (!hasTelephony(mContext)) {
+            Log.d(TAG, "skipping test that requires telephony feature");
+            return;
+        }
         VisualVoicemailSmsFilterSettings settings = new VisualVoicemailSmsFilterSettings.Builder()
                 .setClientPrefix("//CTSVVM")
                 .setOriginatingNumbers(Arrays.asList(mPhoneNumber))
@@ -357,6 +361,10 @@
     }
 
     public void testFilter_originatingNumber_mismatch_notFiltered() {
+        if (!hasTelephony(mContext)) {
+            Log.d(TAG, "skipping test that requires telephony feature");
+            return;
+        }
         VisualVoicemailSmsFilterSettings settings = new VisualVoicemailSmsFilterSettings.Builder()
                 .setClientPrefix("//CTSVVM")
                 .setOriginatingNumbers(Arrays.asList("1"))
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
index 8ca7598..dfabe71 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringBuilderSpanTest.java
@@ -23,11 +23,15 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.Html;
+import android.text.Layout;
 import android.text.SpanWatcher;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.SpannableStringBuilder;
 import android.text.Spanned;
+import android.text.method.SingleLineTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.text.style.AlignmentSpan;
 import android.text.style.ParagraphStyle;
 import android.text.style.QuoteSpan;
 
@@ -583,4 +587,27 @@
                 ParagraphStyle.class);
         assertEquals(0, paragraphSpans.length);
     }
+
+    @Test
+    public void testCopyConstructorDoesNotEnforceParagraphStyleConstraint() {
+        final SpannableStringBuilder original = new SpannableStringBuilder("\ntest data\nb");
+        final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+                Layout.Alignment.ALIGN_NORMAL);
+        original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+        // test that paragraph style is in the copied when it is valid
+        SpannableStringBuilder copied = new SpannableStringBuilder(original);
+        AlignmentSpan.Standard[] copiedSpans = copied.getSpans(0, copied.length(),
+                AlignmentSpan.Standard.class);
+
+        assertEquals(1, copiedSpans.length);
+
+        // test that paragraph style is in not in the copied when it is invalid
+        final TransformationMethod transformation = SingleLineTransformationMethod.getInstance();
+        final CharSequence transformed = transformation.getTransformation(original, null);
+        copied = new SpannableStringBuilder(transformed);
+        copiedSpans = copied.getSpans(0, copied.length(), AlignmentSpan.Standard.class);
+
+        assertEquals(0, copiedSpans.length);
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/SpannableStringTest.java b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
index 81dbf9b..3771613 100644
--- a/tests/tests/text/src/android/text/cts/SpannableStringTest.java
+++ b/tests/tests/text/src/android/text/cts/SpannableStringTest.java
@@ -16,19 +16,34 @@
 
 package android.text.cts;
 
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.Assert.fail;
+
 import android.support.test.filters.SmallTest;
-import android.test.AndroidTestCase;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
 import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
 import android.text.Spanned;
+import android.text.method.SingleLineTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.text.style.AlignmentSpan;
 import android.text.style.LocaleSpan;
 import android.text.style.QuoteSpan;
 import android.text.style.UnderlineSpan;
 
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.Locale;
 
-public class SpannableStringTest extends AndroidTestCase {
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SpannableStringTest {
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         new SpannableString("test");
 
@@ -39,7 +54,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testValueOf() {
         String text = "test valueOf";
         SpannableString spannable = SpannableString.valueOf(text);
@@ -56,7 +71,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testSetSpan() {
         String text = "hello, world";
         SpannableString spannable = new SpannableString(text);
@@ -87,7 +102,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testRemoveSpan() {
         SpannableString spannable = new SpannableString("hello, world");
 
@@ -111,7 +126,7 @@
         assertEquals(0, spannable.getSpanFlags(underlineSpan));
     }
 
-    @SmallTest
+    @Test
     public void testSubSequence() {
         String text = "hello, world";
         SpannableString spannable = new SpannableString(text);
@@ -135,7 +150,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testSubsequence_copiesSpans() {
         SpannableString first = new SpannableString("t\nest data");
         QuoteSpan quoteSpan = new QuoteSpan();
@@ -165,8 +180,7 @@
         }
     }
 
-
-    @SmallTest
+    @Test
     public void testCopyConstructor_copiesAllSpans() {
         SpannableString first = new SpannableString("t\nest data");
         first.setSpan(new QuoteSpan(), 0, 2, Spanned.SPAN_PARAGRAPH);
@@ -189,7 +203,7 @@
         }
     }
 
-    @SmallTest
+    @Test
     public void testCopyGrowable() {
         SpannableString first = new SpannableString("t\nest data");
         final int N_SPANS = 127;
@@ -201,4 +215,27 @@
         Object[] secondSpans = second.getSpans(0, second.length(), Object.class);
         assertEquals(secondSpans.length, N_SPANS + 1);
     }
+
+    @Test
+    public void testCopyConstructorDoesNotEnforceParagraphStyleConstraint() {
+        final SpannableStringBuilder original = new SpannableStringBuilder("\ntest data\nb");
+        final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+                Layout.Alignment.ALIGN_NORMAL);
+        original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+        // test that paragraph style is in the copied when it is valid
+        SpannableString copied = new SpannableString(original);
+        AlignmentSpan.Standard[] copiedSpans = copied.getSpans(0, copied.length(),
+                AlignmentSpan.Standard.class);
+
+        assertEquals(1, copiedSpans.length);
+
+        // test that paragraph style is in not in the copied when it is invalid
+        final TransformationMethod transformation = SingleLineTransformationMethod.getInstance();
+        final CharSequence transformed = transformation.getTransformation(original, null);
+        copied = new SpannableString(transformed);
+        copiedSpans = copied.getSpans(0, copied.length(), AlignmentSpan.Standard.class);
+
+        assertEquals(0, copiedSpans.length);
+    }
 }
diff --git a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
index 9dca58f..308e750 100644
--- a/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
+++ b/tests/tests/text/src/android/text/cts/StaticLayoutTest.java
@@ -1196,8 +1196,8 @@
         assertEquals(0, layout.getLineForOffset(lineBreakOffset - 1));
 
         assertEquals(0, layout.getOffsetForHorizontal(0, 0.0f));
-        assertEquals(lineBreakOffset, layout.getOffsetForHorizontal(0, width));
-        assertEquals(lineBreakOffset, layout.getOffsetForHorizontal(0, width * 2));
+        assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width));
+        assertEquals(lineBreakOffset - 2, layout.getOffsetForHorizontal(0, width * 2));
 
         final int lineCount = layout.getLineCount();
         assertEquals(testString.length(), layout.getOffsetForHorizontal(lineCount - 1, width));
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/SingleLineTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
index 5db4a6f..ad622d0 100644
--- a/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/SingleLineTransformationMethodTest.java
@@ -25,7 +25,11 @@
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.text.Layout;
+import android.text.SpannableString;
+import android.text.Spanned;
 import android.text.method.SingleLineTransformationMethod;
+import android.text.style.AlignmentSpan;
 import android.util.TypedValue;
 import android.widget.EditText;
 
@@ -72,6 +76,21 @@
         // TODO cannot get transformed text from the view
     }
 
+    @Test
+    public void testSubsequence_doesNotThrowExceptionWithParagraphSpans() {
+        final SingleLineTransformationMethod method = SingleLineTransformationMethod.getInstance();
+        final SpannableString original = new SpannableString("\ntest data\nb");
+        final AlignmentSpan.Standard span = new AlignmentSpan.Standard(
+                Layout.Alignment.ALIGN_NORMAL);
+        original.setSpan(span, 1, original.length() - 1, Spanned.SPAN_PARAGRAPH);
+
+        final CharSequence transformed = method.getTransformation(original, null);
+        // expectation: should not throw an exception
+        transformed.subSequence(0, transformed.length());
+    }
+
+
+
     private static class MySingleLineTranformationMethod extends SingleLineTransformationMethod {
         @Override
         protected char[] getOriginal() {
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/ActivityTransitionTest.java b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
index 54a567a..872820a 100644
--- a/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
@@ -95,6 +95,29 @@
         TargetActivity.sLastCreated = null;
     }
 
+    // When using ActivityOptions.makeBasic(), no transitions should run
+    @Test
+    public void testMakeBasic() {
+        assertFalse(mActivity.isActivityTransitionRunning());
+        mInstrumentation.runOnMainSync(() -> {
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            ActivityOptions activityOptions =
+                    ActivityOptions.makeBasic();
+            mActivity.startActivity(intent, activityOptions.toBundle());
+        });
+
+        assertFalse(mActivity.isActivityTransitionRunning());
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        assertFalse(targetActivity.isActivityTransitionRunning());
+        mInstrumentation.runOnMainSync(() -> {
+            targetActivity.finish();
+        });
+
+        assertFalse(targetActivity.isActivityTransitionRunning());
+        assertFalse(mActivity.isActivityTransitionRunning());
+    }
+
     // Views that are outside the visible area only during the shared element start
     // should not be stripped from the transition.
     @Test
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..578591c 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;
     }
@@ -420,7 +426,6 @@
         ContentValues baseValues = createDummyChannelValues(mInputId, false);
         Uri channelUri = mContentResolver.insert(mChannelsUri, baseValues);
 
-        final String COLUMN_SYSTEM_APPROVED = "system_approved";
 
         // Test: insert
         ContentValues values = new ContentValues(baseValues);
@@ -432,14 +437,6 @@
             // Expected.
         }
         values = new ContentValues(baseValues);
-        values.put(COLUMN_SYSTEM_APPROVED, 1);
-        try {
-            mContentResolver.insert(mChannelsUri, values);
-            fail("'" + COLUMN_SYSTEM_APPROVED + "' should be read-only.");
-        } catch (Exception e) {
-            // Expected.
-        }
-        values = new ContentValues(baseValues);
         values.put(Channels.COLUMN_LOCKED, 1);
         try {
             mContentResolver.insert(mChannelsUri, values);
@@ -458,14 +455,6 @@
             // Expected.
         }
         values = new ContentValues(baseValues);
-        values.put(COLUMN_SYSTEM_APPROVED, 1);
-        try {
-            mContentResolver.update(channelUri, values, null, null);
-            fail("'" + COLUMN_SYSTEM_APPROVED + "' should be read-only.");
-        } catch (Exception e) {
-            // Expected.
-        }
-        values = new ContentValues(baseValues);
         values.put(Channels.COLUMN_LOCKED, 1);
         try {
             mContentResolver.update(channelUri, values, null, null);
@@ -547,6 +536,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);
         }
     }
 
@@ -708,6 +699,14 @@
         Uri programUri = TvContract.buildPreviewProgramUri(programId);
         verifyPreviewProgram(programUri, values, programId);
 
+        values.remove(PreviewPrograms.COLUMN_TYPE);
+        try {
+            mContentResolver.insert(previewProgramsUri, values);
+            fail("Type should be a required column.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
         // Test: update
         values.put(PreviewPrograms.COLUMN_EPISODE_TITLE, "Sample title");
         values.put(PreviewPrograms.COLUMN_SHORT_DESCRIPTION, "Short description");
@@ -735,6 +734,14 @@
         Uri programUri = TvContract.buildWatchNextProgramUri(programId);
         verifyWatchNextProgram(programUri, values, programId);
 
+        values.remove(WatchNextPrograms.COLUMN_TYPE);
+        try {
+            mContentResolver.insert(watchNextProgramsUri, values);
+            fail("Type should be a required column.");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+
         // Test: update
         values.put(WatchNextPrograms.COLUMN_EPISODE_TITLE, "Sample title");
         values.put(WatchNextPrograms.COLUMN_SHORT_DESCRIPTION, "Short description");
@@ -991,6 +998,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/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
deleted file mode 100644
index 3f9a9f6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BaseRenderScriptComparer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package android.uirendering.cts.bitmapcomparers;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.RenderScript;
-
-/**
- * Base class for calculators that want to implement renderscript
- */
-public abstract class BaseRenderScriptComparer extends BitmapComparer {
-    private Allocation mRowInputs;
-    private Allocation mRowOutputs;
-    private int mHeight;
-
-    public abstract boolean verifySame(int[] ideal, int[] given, int offset, int stride, int width,
-            int height);
-
-    /**
-     * The subclasses must implement this method, which will say that the rows follow their specific
-     * algorithm
-     */
-    public abstract boolean verifySameRowsRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation);
-
-    public boolean verifySameRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript) {
-        if (mRowInputs == null) {
-            mHeight = height;
-            mRowInputs = createInputRowIndexAllocation(renderScript);
-            mRowOutputs = createOutputRowAllocation(renderScript);
-        }
-        return verifySameRowsRS(resources, ideal, given, offset, stride, width, height,
-                renderScript, mRowInputs, mRowOutputs);
-    }
-
-    public boolean supportsRenderScript() {
-        return true;
-    }
-
-    /**
-     * Sums the values in the output Allocation
-     */
-    public float sum1DFloatAllocation(Allocation rowOutputs) {
-        //Get the values returned from the function
-        float[] returnValue = new float[mHeight];
-        rowOutputs.copyTo(returnValue);
-        float sum = 0;
-        //If any row had any different pixels, then it fails
-        for (int i = 0; i < mHeight; i++) {
-            sum += returnValue[i];
-        }
-        return sum;
-    }
-
-    /**
-     * Creates an allocation where the values in it are the indices of each row
-     */
-    private Allocation createInputRowIndexAllocation(RenderScript renderScript) {
-        //Create an array with the index of each row
-        int[] inputIndices = new int[mHeight];
-        for (int i = 0; i < mHeight; i++) {
-            inputIndices[i] = i;
-        }
-        //Create the allocation from that given array
-        Allocation inputAllocation = Allocation.createSized(renderScript, Element.I32(renderScript),
-                inputIndices.length, Allocation.USAGE_SCRIPT);
-        inputAllocation.copyFrom(inputIndices);
-        return inputAllocation;
-    }
-
-    private Allocation createOutputRowAllocation(RenderScript renderScript) {
-        return Allocation.createSized(renderScript, Element.F32(renderScript), mHeight,
-                Allocation.USAGE_SCRIPT);
-    }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
index 8d74aa5..c995e43 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/BitmapComparer.java
@@ -15,10 +15,6 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-
 /**
  * This abstract class can be used by the tester to implement their own comparison methods
  */
@@ -35,28 +31,9 @@
             int height);
 
     /**
-     * Compare the two bitmaps using RenderScript, if the comparer
-     * {@link supportsRenderScript() supports it}. If it does not, this method will throw an
-     * UnsupportedOperationException
-     */
-    public boolean verifySameRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript) {
-        throw new UnsupportedOperationException("Renderscript not supported for this calculator");
-    }
-
-    /**
      * This calculates the position in an array that would represent a bitmap given the parameters.
      */
     protected static int indexFromXAndY(int x, int y, int stride, int offset) {
         return x + (y * stride) + offset;
     }
-
-    /**
-     * Returns whether the verifySameRS() is implemented, and may be used on a RenderScript enabled
-     * system
-     */
-    public boolean supportsRenderScript() {
-        return false;
-    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 562b730..99d1f71 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -15,20 +15,13 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ExactComparer;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
 import android.util.Log;
 
 /**
  * This class does an exact comparison of the pixels in a bitmap.
  */
-public class ExactComparer extends BaseRenderScriptComparer {
+public class ExactComparer extends BitmapComparer {
     private static final String TAG = "ExactComparer";
-    private ScriptC_ExactComparer mScript;
 
     /**
      * This method does an exact 1 to 1 comparison of the two bitmaps
@@ -54,27 +47,4 @@
 
         return (count == 0);
     }
-
-    @Override
-    public boolean verifySameRowsRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
-        if (mScript == null) {
-            mScript = new ScriptC_ExactComparer(renderScript);
-        }
-        mScript.set_WIDTH(width);
-        mScript.set_OFFSET(offset);
-
-        //Set the bitmap allocations
-        mScript.set_ideal(ideal);
-        mScript.set_given(given);
-
-        //Call the renderscript function on each row
-        mScript.forEach_exactCompare(inputAllocation, outputAllocation);
-
-        float val = sum1DFloatAllocation(outputAllocation);
-        Log.d(TAG, "Number of different pixels RS : " + val);
-
-        return val == 0;
-    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
deleted file mode 100644
index 6425c17..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int OFFSET;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a simple comparison of all the values in the given and ideal allocations.
-// If any of the pixels are off, then the test will fail.
-void exactCompare(const int32_t *v_in, float *v_out){
-    int y = v_in[0];
-    v_out[0] = 0;
-
-    for(int i = 0 ; i < WIDTH ; i ++){
-        uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i + OFFSET, y);
-        uchar4 givenPixel = rsGetElementAt_uchar4(given, i + OFFSET, y);
-        uchar4 diff = idealPixel - givenPixel;
-        int totalDiff = diff.x + diff.y + diff.z;
-        if(totalDiff != 0){
-            v_out[0] ++;
-        }
-    }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
index 4a25695..e65ff2d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.java
@@ -15,12 +15,7 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import android.uirendering.cts.ScriptC_MSSIMComparer;
-
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
 import android.util.Log;
 
 /**
@@ -29,7 +24,7 @@
  *
  * https://ece.uwaterloo.ca/~z70wang/publications/ssim.pdf
  */
-public class MSSIMComparer extends BaseRenderScriptComparer {
+public class MSSIMComparer extends BitmapComparer {
     // These values were taken from the publication
     public static final String TAG_NAME = "MSSIM";
     public static final double CONSTANT_L = 254;
@@ -40,7 +35,6 @@
     public static final int WINDOW_SIZE = 10;
 
     private double mThreshold;
-    private ScriptC_MSSIMComparer mScript;
 
     public MSSIMComparer(double threshold) {
         mThreshold = threshold;
@@ -82,31 +76,6 @@
         return (SSIMTotal >= mThreshold);
     }
 
-    @Override
-    public boolean verifySameRowsRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
-        if (mScript == null) {
-            mScript = new ScriptC_MSSIMComparer(renderScript);
-        }
-        mScript.set_WIDTH(width);
-        mScript.set_HEIGHT(height);
-
-        //Set the bitmap allocations
-        mScript.set_ideal(ideal);
-        mScript.set_given(given);
-
-        //Call the renderscript function on each row
-        mScript.forEach_calcSSIM(inputAllocation, outputAllocation);
-
-        float MSSIM = sum1DFloatAllocation(outputAllocation);
-        MSSIM /= height;
-
-        Log.d(TAG_NAME, "MSSIM RS : " + MSSIM);
-
-        return (MSSIM >= mThreshold);
-    }
-
     private boolean isWindowWhite(int[] colors, int start, int stride) {
         for (int y = 0 ; y < WINDOW_SIZE ; y++) {
             for (int x = 0 ; x < WINDOW_SIZE ; x++) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
deleted file mode 100644
index b0e86b8..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MSSIMComparer.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int HEIGHT;
-
-rs_allocation ideal;
-rs_allocation given;
-
-static float getPixelWeight(uchar4 pixel) {
-    const float MAX_VALUE_COLOR = 255;
-    const float RED_WEIGHT = 0.21f / MAX_VALUE_COLOR;
-    const float GREEN_WEIGHT = 0.72f / MAX_VALUE_COLOR;
-    const float BLUE_WEIGHT = 0.07f / MAX_VALUE_COLOR;
-    return (pixel.r * RED_WEIGHT) + (pixel.g * GREEN_WEIGHT) + (pixel.b * BLUE_WEIGHT);
-}
-
-// Calculates SSIM of a row of pixels
-void calcSSIM(const int32_t *v_in, float *v_out) {
-    // TODO Test values for these constants
-    const float C1 = 0.0000064516;
-    const float C2 = 0.0000580644;
-
-    int y = v_in[0];
-    v_out[0] = 0;
-
-    float meanIdeal = 0;
-    float meanGiven = 0;
-
-    for (int i = 0 ; i < WIDTH ; i++) {
-        uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
-        uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
-        meanIdeal += getPixelWeight(idealPixel);
-        meanGiven += getPixelWeight(givenPixel);
-    }
-
-    meanIdeal /= WIDTH;
-    meanGiven /= WIDTH;
-
-    float varIdeal = 0;
-    float varGiven = 0;
-    float varBoth = 0;
-
-    for (int i = 0 ; i < WIDTH ; i++) {
-        uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
-        uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
-        float idealWeight = getPixelWeight(idealPixel);
-        float givenWeight = getPixelWeight(givenPixel);
-        idealWeight -= meanIdeal;
-        givenWeight -= meanGiven;
-        varIdeal +=  idealWeight * idealWeight;
-        varGiven += givenWeight * givenWeight;
-        varBoth += idealWeight * givenWeight;
-    }
-
-    varIdeal /= WIDTH - 1;
-    varGiven /= WIDTH - 1;
-    varBoth /= WIDTH - 1;
-
-    float SSIM = ((2 * meanIdeal * meanGiven) + C1) * ((2 * varBoth) + C2);
-    float denom = ((meanIdeal * meanIdeal) + (meanGiven * meanGiven) + C1)
-                    * (varIdeal + varGiven + C2);
-    SSIM /= denom;
-
-    v_out[0] = SSIM;
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
index 5cc896b..2b6ba0c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.java
@@ -15,21 +15,14 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_MeanSquaredComparer;
-
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
 import android.util.Log;
 
 /**
  * Finds the MSE using two images.
  */
-public class MeanSquaredComparer extends BaseRenderScriptComparer {
+public class MeanSquaredComparer extends BitmapComparer {
     private static final String TAG = "MeanSquared";
-    private ScriptC_MeanSquaredComparer mScript;
     private float mErrorPerPixel;
 
     /**
@@ -48,30 +41,6 @@
         return (totalError < (mErrorPerPixel));
     }
 
-    @Override
-    public boolean verifySameRowsRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
-        if (mScript == null) {
-            mScript = new ScriptC_MeanSquaredComparer(renderScript);
-        }
-        mScript.set_WIDTH(width);
-
-        //Set the bitmap allocations
-        mScript.set_ideal(ideal);
-        mScript.set_given(given);
-
-        //Call the renderscript function on each row
-        mScript.forEach_calcMSE(inputAllocation, outputAllocation);
-
-        float error = sum1DFloatAllocation(outputAllocation);
-        error /= (height * width);
-
-        Log.d(TAG, "Error RS : " + error);
-
-        return (error < mErrorPerPixel);
-    }
-
     /**
      * Gets the Mean Squared Error between two data sets.
      */
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
deleted file mode 100644
index 3b37609..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/MeanSquaredComparer.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int REGION_SIZE;
-int WIDTH;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void calcMSE(const int32_t *v_in, float *v_out){
-    int y = v_in[0];
-    v_out[0] = 0.0f;
-    for (int x = 0 ; x < WIDTH ; x++) {
-        float4 idealFloats = rsUnpackColor8888(rsGetElementAt_uchar4(ideal, x, y));
-        float4 givenFloats = rsUnpackColor8888(rsGetElementAt_uchar4(given, x, y));
-        float difference = (idealFloats.r - givenFloats.r) + (idealFloats.g - givenFloats.g) +
-              (idealFloats.b - givenFloats.b);
-        v_out[0] += (difference * difference);
-    }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
index 6a78f11..b7a608a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.java
@@ -15,22 +15,14 @@
  */
 package android.uirendering.cts.bitmapcomparers;
 
-import android.uirendering.cts.R;
-import android.uirendering.cts.ScriptC_ThresholdDifferenceComparer;
-
-import android.content.res.Resources;
 import android.graphics.Color;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
-import android.uirendering.cts.bitmapcomparers.BaseRenderScriptComparer;
 import android.util.Log;
 
 /**
  * Compares two images to see if each pixel is the same, within a certain threshold value
  */
-public class ThresholdDifferenceComparer extends BaseRenderScriptComparer {
+public class ThresholdDifferenceComparer extends BitmapComparer {
     private static final String TAG = "ThresholdDifference";
-    private ScriptC_ThresholdDifferenceComparer mScript;
     private int mThreshold;
 
     /**
@@ -63,27 +55,4 @@
         Log.d(TAG, "Number of different pixels : " + differentPixels);
         return (differentPixels == 0);
     }
-
-    @Override
-    public boolean verifySameRowsRS(Resources resources, Allocation ideal,
-            Allocation given, int offset, int stride, int width, int height,
-            RenderScript renderScript, Allocation inputAllocation, Allocation outputAllocation) {
-        if (mScript == null) {
-            mScript = new ScriptC_ThresholdDifferenceComparer(renderScript);
-        }
-
-        mScript.set_THRESHOLD(mThreshold);
-        mScript.set_WIDTH(width);
-
-        //Set the bitmap allocations
-        mScript.set_ideal(ideal);
-        mScript.set_given(given);
-
-        //Call the renderscript function on each row
-        mScript.forEach_thresholdCompare(inputAllocation, outputAllocation);
-
-        float differentPixels = sum1DFloatAllocation(outputAllocation);
-        Log.d(TAG, "Number of different pixels RS : " + differentPixels);
-        return (differentPixels == 0);
-    }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
deleted file mode 100644
index 8a40ad6..0000000
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ThresholdDifferenceComparer.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#pragma version(1)
-#pragma rs java_package_name(android.uirendering.cts)
-
-int WIDTH;
-int THRESHOLD;
-
-rs_allocation ideal;
-rs_allocation given;
-
-// This method does a threshold comparison of the values
-void thresholdCompare(const int32_t *v_in, float *v_out){
-    int y = v_in[0];
-    v_out[0] = 0;
-
-    for(int i = 0 ; i < WIDTH ; i ++){
-        uchar4 idealPixel = rsGetElementAt_uchar4(ideal, i, y);
-        uchar4 givenPixel = rsGetElementAt_uchar4(given, i, y);
-        float l1 = (idealPixel.x * 0.21f) + (idealPixel.y * 0.72f) + (idealPixel.z * 0.07f);
-        float l2 = (givenPixel.x * 0.21f) + (givenPixel.y * 0.72f) + (givenPixel.z * 0.07f);
-        float diff = l1 - l2;
-        if (fabs(diff) >= THRESHOLD) {
-            v_out[0]++;
-        }
-    }
-}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
index e3d56ba..95c222c3 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/AutofillHighlightTests.java
@@ -20,14 +20,17 @@
 import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class AutofillHighlightTests extends ActivityTestBase {
     @Test
     public void testHighlightedFrameLayout() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
index 77ff8f2..d705c7e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapFilterTests.java
@@ -20,6 +20,7 @@
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.PerPixelBitmapVerifier;
@@ -27,8 +28,10 @@
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class BitmapFilterTests extends ActivityTestBase {
     private static final int WHITE_WEIGHT = 255 * 3;
     private enum FilterEnum {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
index d9b8d7f..f0afd53 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/BitmapTests.java
@@ -24,9 +24,11 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.os.Handler;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
+import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.ColorCountVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -41,7 +43,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-@MediumTest
+import java.util.Arrays;
+
+@LargeTest
 @RunWith(AndroidJUnit4.class)
 public class BitmapTests extends ActivityTestBase {
     class BitmapView extends View {
@@ -146,21 +150,17 @@
     */
     @Test
     public void testChangeDuringUiAnimation() {
-        class PureBlueOrRedVerifier extends BitmapVerifier {
+        class BlueOrRedVerifier extends BitmapVerifier {
             @Override
             public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
-                int blueCount = 0;
-                int redCount = 0;
-                for (int x = 0; x < width; x++) {
-                    for (int y = 0; y < height; y++) {
-                        if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.BLUE) {
-                            blueCount++;
-                        } else if (bitmap[indexFromXAndY(x, y, stride, offset)] == Color.RED) {
-                            redCount++;
-                        }
-                    }
-                }
-                return blueCount == width * height || redCount == width * height;
+                MSSIMComparer comparer = new MSSIMComparer(0.99);
+                int[] red  = new int[offset + height * stride];
+                Arrays.fill(red, Color.RED);
+                int[] blue  = new int[offset + height * stride];
+                Arrays.fill(blue, Color.BLUE);
+                boolean isRed = comparer.verifySame(red, bitmap, offset, stride, width, height);
+                boolean isBlue = comparer.verifySame(blue, bitmap, offset, stride, width, height);
+                return isRed || isBlue;
             }
         }
 
@@ -210,6 +210,6 @@
 
         createTest()
                 .addLayout(R.layout.frame_layout, initializer, true)
-                .runWithAnimationVerifier(new PureBlueOrRedVerifier());
+                .runWithAnimationVerifier(new BlueOrRedVerifier());
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
index d9eec30..16f98f6 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/CanvasStateTests.java
@@ -26,11 +26,13 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.util.DisplayMetrics;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests of state query-able from canvas at draw time.
@@ -39,6 +41,7 @@
  * capability to test the hardware accelerated Canvas in the way that it is used by Views.
  */
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class CanvasStateTests extends ActivityTestBase {
     @Test
     public void testClipRectReturnValues() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
index bbc50df..5d875ab 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorFilterAlphaTest.java
@@ -22,17 +22,19 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.List;
 
-@LargeTest // large while non-parameterized
-//@RunWith(Parameterized.class) // TODO: Reenable when CTS supports parameterized tests
+@MediumTest
+@RunWith(Parameterized.class)
 public class ColorFilterAlphaTest extends ActivityTestBase {
     // We care about one point in each of the four rectangles of different alpha values, as well as
     // the area outside the rectangles
@@ -85,12 +87,16 @@
                 0xFFC21A1A, 0xFFC93333, 0xFFD04D4D, 0xFFD66666, 0xFFBB0000 } },
     };
 
-    //@Parameterized.Parameters(name = "{0}")
+    @Parameterized.Parameters(name = "{0}")
     public static List<XfermodeTest.Config> configs() {
         return XfermodeTest.configs(MODES_AND_EXPECTED_COLORS);
     }
 
-    private XfermodeTest.Config mConfig;
+    private final XfermodeTest.Config mConfig;
+
+    public ColorFilterAlphaTest(XfermodeTest.Config config) {
+        mConfig = config;
+    }
 
     private static final int[] BLOCK_COLORS = new int[] {
             0x33808080,
@@ -127,12 +133,9 @@
 
     @Test
     public void test() {
-        for (XfermodeTest.Config config : configs()) {
-            mConfig = config;
-            createTest()
-                    .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
-                    .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
-        }
+        createTest()
+                .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+                .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
     }
 }
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
index c5aa1b3..13c8e91 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ColorSpaceTests.java
@@ -31,16 +31,19 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.io.InputStream;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ColorSpaceTests extends ActivityTestBase {
     private Bitmap mMask;
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
index 444af9f..304303a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ExactCanvasTests.java
@@ -25,6 +25,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.NinePatchDrawable;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.ExactComparer;
@@ -35,8 +36,10 @@
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ExactCanvasTests extends ActivityTestBase {
     private final BitmapComparer mExactComparer = new ExactComparer();
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
index 2a2ec51..ea7403b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/FontRenderingTests.java
@@ -22,6 +22,7 @@
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
@@ -29,8 +30,10 @@
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class FontRenderingTests extends ActivityTestBase {
     // Thresholds are barely loose enough for differences between sw and hw renderers.
     private static final double REGULAR_THRESHOLD = 0.92;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
index e808296..4b8b6b2 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/GradientTests.java
@@ -22,11 +22,14 @@
 import android.graphics.Point;
 import android.graphics.Shader;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class GradientTests extends ActivityTestBase {
     @Test
     public void testAlphaPreMultiplication() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
index 00b61e9..c62e134 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/HardwareBitmapTests.java
@@ -28,6 +28,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.NinePatchDrawable;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 
 import android.graphics.Bitmap;
@@ -41,11 +42,13 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.io.InputStream;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class HardwareBitmapTests extends ActivityTestBase {
 
     private Resources mRes;
@@ -82,7 +85,7 @@
                     HARDWARE_OPTIONS);
             canvas.drawBitmap(hardwareBitmap, 0, 0, new Paint());
         }, true).runWithVerifier(new GoldenImageVerifier(getActivity(),
-                R.drawable.golden_headless_robot, new ExactComparer()));
+                R.drawable.golden_headless_robot, new MSSIMComparer(0.95)));
     }
 
     @Test
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
index f952bc23..ee46601 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/InfrastructureTests.java
@@ -18,7 +18,9 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
@@ -28,8 +30,10 @@
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class InfrastructureTests extends ActivityTestBase {
 
     @Test
@@ -45,6 +49,7 @@
      * by verifying that two paths that should render differently *do* render
      * differently.
      */
+    @LargeTest
     @Test
     public void testRenderSpecIsolation() {
         CanvasClient canvasClient = (canvas, width, height) -> {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index f7661a5..ed0110a 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -32,6 +32,7 @@
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.support.annotation.ColorInt;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
@@ -140,6 +141,7 @@
                 .runWithVerifier(new ColorVerifier(expectedColor));
     }
 
+    @LargeTest
     @Test
     public void testLayerClear() {
         ViewInitializer initializer = new ViewInitializer() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index c0323b6..3d1c10e 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -18,14 +18,17 @@
 import android.graphics.Color;
 import android.graphics.Rect;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class LayoutTests extends ActivityTestBase {
     @Test
     public void testSimpleRedLayout() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
index 6eaba8f..ae4fee1 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathClippingTests.java
@@ -24,7 +24,9 @@
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.Typeface;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
@@ -38,10 +40,12 @@
 import android.webkit.WebView;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class PathClippingTests extends ActivityTestBase {
     // draw circle with hole in it, with stroked circle
     static final CanvasClient sTorusDrawCanvasClient = (canvas, width, height) -> {
@@ -173,6 +177,7 @@
         };
     }
 
+    @LargeTest
     @Test
     public void testWebViewClipWithCircle() {
         if (!getActivity().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
index 5abe831..2d5acaa 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PathTests.java
@@ -5,14 +5,17 @@
 import android.graphics.Path;
 import android.graphics.Typeface;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class PathTests extends ActivityTestBase {
 
     private static final double REGULAR_THRESHOLD = 0.92;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
index c1e10d3..454eb2c0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/PictureTest.java
@@ -22,13 +22,16 @@
 import android.graphics.Picture;
 import android.graphics.Rect;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class PictureTest extends ActivityTestBase {
 
     private static final Rect sRect = new Rect(0, 0, 40, 40);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
index 44831bf..d9ec2b5 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/Rgba16fTests.java
@@ -25,16 +25,19 @@
 import android.graphics.Point;
 import android.graphics.Shader;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.io.IOException;
 import java.io.InputStream;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class Rgba16fTests extends ActivityTestBase {
     @Test
     public void testTransferFunctions() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
index 2c9df73..252874d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShaderTests.java
@@ -27,14 +27,17 @@
 import android.graphics.RadialGradient;
 import android.graphics.Shader;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ShaderTests extends ActivityTestBase {
     @Test
     public void testSinglePixelBitmapShader() {
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 e9b9bd4..e4f9809 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShadowTests.java
@@ -18,14 +18,17 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.util.CompareUtils;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ShadowTests extends ActivityTestBase {
 
     private class GrayScaleVerifier extends SamplePointVerifier {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
index 9aad23d..0b708d4 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ShapeTests.java
@@ -17,14 +17,17 @@
 package android.uirendering.cts.testclasses;
 
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ShapeTests extends ActivityTestBase {
     @Test
     public void testDashedOval() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 52b87cc..741c35c 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -24,7 +24,9 @@
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -40,10 +42,12 @@
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 
-@MediumTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
 public class SurfaceViewTests extends ActivityTestBase {
 
     static final CanvasCallback sGreenCanvasCallback =
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
index c374dd7e..ff0e9a7 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SweepTests.java
@@ -22,7 +22,9 @@
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.Shader;
+import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -31,11 +33,13 @@
 import android.uirendering.cts.testinfrastructure.ResourceModifier;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test cases of all combination of resource modifications.
  */
-@MediumTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
 public class SweepTests extends ActivityTestBase {
     private final static DisplayModifier COLOR_FILTER_GRADIENT_MODIFIER = new DisplayModifier() {
         private final Rect mBounds = new Rect(30, 30, 150, 150);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
index f220bfb..abbec36 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/TextureViewTests.java
@@ -27,6 +27,7 @@
 import android.graphics.SurfaceTexture;
 import android.support.annotation.ColorInt;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
@@ -42,10 +43,12 @@
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class TextureViewTests extends ActivityTestBase {
 
     private static SurfaceTexture sRedTexture;
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
index 2a64ac4..ffb263d 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/VectorDrawableTests.java
@@ -26,8 +26,10 @@
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class VectorDrawableTests extends ActivityTestBase {
     @Test
     public void testScaleDown() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
index d74dcb7..88aa265 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewAnimationUtilsTests.java
@@ -17,6 +17,7 @@
 package android.uirendering.cts.testclasses;
 
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapcomparers.MSSIMComparer;
 import android.uirendering.cts.bitmapverifiers.GoldenImageVerifier;
@@ -25,8 +26,10 @@
 import android.view.ViewAnimationUtils;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ViewAnimationUtilsTests extends ActivityTestBase {
     @Test
     public void testCreateCircularReveal() {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index 47f9f4d..d1f0ee5 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -7,6 +7,7 @@
 import android.graphics.Path;
 import android.graphics.Rect;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.bitmapverifiers.RectVerifier;
@@ -18,6 +19,7 @@
 import android.view.ViewOutlineProvider;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * This tests view clipping by modifying properties of blue_padded_layout, and validating
@@ -26,6 +28,7 @@
  * Since the layout is blue on a white background, this is always done with a RectVerifier.
  */
 @MediumTest
+@RunWith(AndroidJUnit4.class)
 public class ViewClippingTests extends ActivityTestBase {
     static final Rect FULL_RECT = new Rect(0, 0, 90, 90);
     static final Rect BOUNDS_RECT = new Rect(0, 0, 80, 80);
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
index 04e1dfd..38a4d40 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/XfermodeTest.java
@@ -22,18 +22,20 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.RectF;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
 import android.uirendering.cts.bitmapverifiers.SamplePointVerifier;
 import android.uirendering.cts.testinfrastructure.ActivityTestBase;
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@LargeTest // large while non-parameterized
-//@RunWith(Parameterized.class) // TODO: Reenable when CTS supports parameterized tests
+@MediumTest
+@RunWith(Parameterized.class)
 public class XfermodeTest extends ActivityTestBase {
     /**
      * There are 4 locations we care about in testing each filter:
@@ -124,12 +126,16 @@
                 BG_COLOR, DST_COLOR, SCREEN_COLOR, SRC_COLOR } },
     };
 
-    //@Parameterized.Parameters(name = "{0}")
+    @Parameterized.Parameters(name = "{0}")
     public static List<Config> configs() {
         return configs(MODES_AND_EXPECTED_COLORS);
     }
 
-    private Config mConfig;
+    private final Config mConfig;
+
+    public XfermodeTest(Config config) {
+        mConfig = config;
+    }
 
     private CanvasClient mCanvasClient = new CanvasClient() {
         final Paint mPaint = new Paint();
@@ -170,11 +176,8 @@
 
     @Test
     public void test() {
-        for (XfermodeTest.Config config : configs()) {
-            mConfig = config;
-            createTest()
-                    .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
-                    .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
-        }
+        createTest()
+                .addCanvasClient(mCanvasClient, mConfig.hardwareAccelerated)
+                .runWithVerifier(new SamplePointVerifier(TEST_POINTS, mConfig.expectedColors));
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
index 5a3331c..d5f9324 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapAsserter.java
@@ -20,17 +20,13 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.renderscript.Allocation;
-import android.renderscript.RenderScript;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.differencevisualizers.DifferenceVisualizer;
 import android.uirendering.cts.differencevisualizers.PassFailVisualizer;
 
 public class BitmapAsserter {
-    public static final boolean USE_RS = false;
     private DifferenceVisualizer mDifferenceVisualizer;
-    private RenderScript mRenderScript;
     private Context mContext;
     private String mClassName;
 
@@ -50,9 +46,6 @@
     public void setUp(Context context) {
         mDifferenceVisualizer = new PassFailVisualizer();
         mContext = context;
-        if (USE_RS) {
-            mRenderScript = RenderScript.create(context.getApplicationContext());
-        }
     }
 
     /**
@@ -69,20 +62,11 @@
             fail("Can't compare bitmaps of different sizes");
         }
 
-        if (USE_RS && comparer.supportsRenderScript()) {
-            Allocation idealAllocation = Allocation.createFromBitmap(mRenderScript, bitmap1,
-                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-            Allocation givenAllocation = Allocation.createFromBitmap(mRenderScript, bitmap2,
-                    Allocation.MipmapControl.MIPMAP_NONE, Allocation.USAGE_SCRIPT);
-            success = comparer.verifySameRS(mContext.getResources(), idealAllocation,
-                    givenAllocation, 0, width, width, height, mRenderScript);
-        } else {
-            int[] pixels1 = new int[width * height];
-            int[] pixels2 = new int[width * height];
-            bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
-            bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
-            success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
-        }
+        int[] pixels1 = new int[width * height];
+        int[] pixels2 = new int[width * height];
+        bitmap1.getPixels(pixels1, 0, width, 0, 0, width, height);
+        bitmap2.getPixels(pixels2, 0, width, 0, 0, width, height);
+        success = comparer.verifySame(pixels1, pixels2, 0, width, width, height);
 
         if (!success) {
             BitmapDumper.dumpBitmaps(bitmap1, bitmap2, testName, mClassName, mDifferenceVisualizer);
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 8afec2c..5f50e9c 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -331,6 +331,13 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <activity android:name="android.view.cts.DefaultFocusHighlightCtsActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/view/res/drawable/scrollbar_no_size.xml b/tests/tests/view/res/drawable/scrollbar_no_size.xml
deleted file mode 100644
index 88a59f0..0000000
--- a/tests/tests/view/res/drawable/scrollbar_no_size.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/white" />
-</shape>
diff --git a/tests/tests/view/res/drawable/scrollbar_thumb.xml b/tests/tests/view/res/drawable/scrollbar_thumb.xml
deleted file mode 100644
index d7612ac..0000000
--- a/tests/tests/view/res/drawable/scrollbar_thumb.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/white" />
-    <size
-        android:width="@dimen/scrollbar_thumb_width"
-        android:height="@dimen/scrollbar_thumb_height"/>
-</shape>
diff --git a/tests/tests/view/res/drawable/scrollbar_track.xml b/tests/tests/view/res/drawable/scrollbar_track.xml
deleted file mode 100644
index a184569..0000000
--- a/tests/tests/view/res/drawable/scrollbar_track.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-       android:shape="rectangle">
-    <solid android:color="@android:color/white" />
-    <size
-        android:width="@dimen/scrollbar_track_width"
-        android:height="@dimen/scrollbar_track_height"/>
-</shape>
diff --git a/tests/tests/view/res/layout/default_focus_highlight_layout.xml b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
new file mode 100644
index 0000000..827de43
--- /dev/null
+++ b/tests/tests/view/res/layout/default_focus_highlight_layout.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <View
+        android:id="@+id/view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/id_ok"/>
+
+    <ListView
+        android:id="@+id/listview"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/id_ok"/>
+
+    <EditText
+        android:id="@+id/edittext"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/id_ok"
+        android:inputType="text"/>
+
+    <Button
+        android:id="@+id/button"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/id_ok"/>
+
+    <LinearLayout
+        android:id="@+id/linearlayout"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+    </LinearLayout>
+
+    <View
+        android:id="@+id/view_to_inflate"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:defaultFocusHighlightEnabled="false"
+        android:text="@string/id_ok"/>
+
+    <ListView
+        android:id="@+id/listview_to_inflate"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:defaultFocusHighlightEnabled="true"
+        android:text="@string/id_ok"/>
+
+    <EditText
+        android:id="@+id/edittext_to_inflate"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/id_ok"
+        android:defaultFocusHighlightEnabled="true"
+        android:inputType="text"/>
+
+    <Button
+        android:id="@+id/button_to_inflate"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:defaultFocusHighlightEnabled="false"
+        android:text="@string/id_ok"/>
+
+    <LinearLayout
+        android:id="@+id/linearlayout_to_inflate"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:defaultFocusHighlightEnabled="false"
+        android:orientation="vertical">
+    </LinearLayout>
+
+</LinearLayout>
+
diff --git a/tests/tests/view/res/layout/focus_finder_layout.xml b/tests/tests/view/res/layout/focus_finder_layout.xml
index 610ffc8..1dea684 100644
--- a/tests/tests/view/res/layout/focus_finder_layout.xml
+++ b/tests/tests/view/res/layout/focus_finder_layout.xml
@@ -19,7 +19,7 @@
     <TableLayout android:id="@+id/layout"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_centerInParent="true">
+            android:layout_alignParentTop="true">
         <TableRow>
             <android.view.cts.TestButton android:id="@+id/top_left_button"
                     android:layout_width="60dp"
@@ -41,5 +41,12 @@
                     android:text="BR" />
         </TableRow>  
     </TableLayout>
+    <LinearLayout android:id="@+id/inflate_layout"
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/layout">
+
+    </LinearLayout>
 </RelativeLayout>
 
diff --git a/tests/tests/view/res/layout/focus_finder_sublayout.xml b/tests/tests/view/res/layout/focus_finder_sublayout.xml
new file mode 100644
index 0000000..c9a4c3b
--- /dev/null
+++ b/tests/tests/view/res/layout/focus_finder_sublayout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content">
+    <FrameLayout
+        android:focusableInTouchMode="true"
+        android:id="@+id/itembox"
+        android:layout_width="200px"
+        android:layout_height="200px">
+        <Button
+            android:id="@+id/itembutton"
+            android:focusableInTouchMode="true"
+            android:nextFocusForward="@id/itembox"
+            android:layout_gravity="bottom|right"
+            android:layout_marginRight="10px"
+            android:layout_marginBottom="10px"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+    </FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/tests/view/res/layout/view_layout.xml b/tests/tests/view/res/layout/view_layout.xml
index 3cfaafa..920da83 100644
--- a/tests/tests/view/res/layout/view_layout.xml
+++ b/tests/tests/view/res/layout/view_layout.xml
@@ -46,42 +46,6 @@
         android:requiresFadingEdge="horizontal|vertical"
         android:fadingEdgeLength="20px"/>
 
-    <android.view.cts.MockView
-        android:id="@+id/scroll_view_3"
-        android:layout_width="100px"
-        android:layout_height="200px"
-        android:scrollbars="horizontal|vertical"
-        android:scrollbarThumbVertical="@drawable/scrollbar_no_size"
-        android:scrollbarThumbHorizontal="@drawable/scrollbar_no_size"/>
-
-    <android.view.cts.MockView
-        android:id="@+id/scroll_view_4"
-        android:layout_width="100px"
-        android:layout_height="200px"
-        android:scrollbars="horizontal|vertical"
-        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
-        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"/>
-
-    <android.view.cts.MockView
-        android:id="@+id/scroll_view_5"
-        android:layout_width="100px"
-        android:layout_height="200px"
-        android:scrollbars="horizontal|vertical"
-        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
-        android:scrollbarTrackVertical="@drawable/scrollbar_track"
-        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
-        android:scrollbarTrackHorizontal="@drawable/scrollbar_track"/>
-
-    <android.view.cts.MockView
-        android:id="@+id/scroll_view_6"
-        android:layout_width="100px"
-        android:layout_height="200px"
-        android:scrollbars="horizontal|vertical"
-        android:scrollbarThumbVertical="@drawable/scrollbar_thumb"
-        android:scrollbarTrackVertical="@drawable/scrollbar_no_size"
-        android:scrollbarThumbHorizontal="@drawable/scrollbar_thumb"
-        android:scrollbarTrackHorizontal="@drawable/scrollbar_no_size"/>
-
     <View
         android:id="@+id/fit_windows"
         android:fitsSystemWindows="true"
diff --git a/tests/tests/view/res/values/dimens.xml b/tests/tests/view/res/values/dimens.xml
index a1d66f9..59369a7 100644
--- a/tests/tests/view/res/values/dimens.xml
+++ b/tests/tests/view/res/values/dimens.xml
@@ -30,8 +30,4 @@
     <dimen name="hover_target_margin">4dp</dimen>
     <dimen name="hover_target_size">8dp</dimen>
     <dimen name="hover_target_size_double">16dp</dimen>
-    <dimen name="scrollbar_thumb_width">11dp</dimen>
-    <dimen name="scrollbar_thumb_height">12dp</dimen>
-    <dimen name="scrollbar_track_width">13dp</dimen>
-    <dimen name="scrollbar_track_height">14dp</dimen>
 </resources>
\ No newline at end of file
diff --git a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
index c54f183..72c89df 100644
--- a/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
+++ b/tests/tests/view/src/android/view/cts/ContentPaneFocusTest.java
@@ -71,22 +71,7 @@
             return;
         }
 
-        final View content = mActivity.findViewById(android.R.id.content);
-        assertNotNull(content);
-        final ViewParent viewParent = content.getParent();
-        assertNotNull(viewParent);
-        assertTrue(viewParent instanceof ViewGroup);
-        ViewGroup parent = (ViewGroup) viewParent;
-        View actionBarView = null;
-        for (int i = 0; i < parent.getChildCount(); i++) {
-            View child = parent.getChildAt(i);
-            if ("android:action_bar".equals(child.getTransitionName())) {
-                actionBarView = child;
-                break;
-            }
-        }
-        assertNotNull(actionBarView);
-        final View actionBar = actionBarView;
+        final View actionBar = getActionBarView();
         // Should jump to the action bar after meta+tab
         mActivityRule.runOnUiThread(() -> {
             assertFalse(v1.hasFocus());
@@ -118,6 +103,47 @@
         }
     }
 
+    @Test
+    public void testNoFocusablesInContent() throws Throwable {
+        ViewGroup top = mActivity.findViewById(R.id.linearlayout);
+        top.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        mActivityRule.runOnUiThread(top::clearFocus);
+        mInstrumentation.waitForIdleSync();
+        top.clearFocus();
+        final View content = mActivity.findViewById(android.R.id.content);
+        assertTrue(content.findFocus() == null);
+        sendMetaHotkey(KeyEvent.KEYCODE_TAB);
+        mInstrumentation.waitForIdleSync();
+
+        ActionBar action = mActivity.getActionBar();
+        if (action == null || !action.isShowing()) {
+            // No action bar, so we only needed to make sure that the shortcut didn't cause
+            // the framework to crash.
+            return;
+        }
+
+        assertTrue(getActionBarView().hasFocus());
+    }
+
+    private View getActionBarView() {
+        final View content = mActivity.findViewById(android.R.id.content);
+        assertNotNull(content);
+        final ViewParent viewParent = content.getParent();
+        assertNotNull(viewParent);
+        assertTrue(viewParent instanceof ViewGroup);
+        ViewGroup parent = (ViewGroup) viewParent;
+        View actionBarView = null;
+        for (int i = 0; i < parent.getChildCount(); i++) {
+            View child = parent.getChildAt(i);
+            if ("android:action_bar".equals(child.getTransitionName())) {
+                actionBarView = child;
+                break;
+            }
+        }
+        assertNotNull(actionBarView);
+        return actionBarView;
+    }
+
     private void sendMetaHotkey(int keyCode) throws Throwable {
         sendMetaKey(KeyEvent.ACTION_DOWN);
         long time = SystemClock.uptimeMillis();
diff --git a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java b/tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
similarity index 69%
rename from hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
rename to tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
index d599eba..5211938 100644
--- a/hostsidetests/webkit/renderprocesscrash/src/com/android/cts/webkit/renderprocesscrash/RenderProcessCrashActivity.java
+++ b/tests/tests/view/src/android/view/cts/DefaultFocusHighlightCtsActivity.java
@@ -14,19 +14,18 @@
  * limitations under the License.
  */
 
-package com.android.cts.webkit.renderprocesscrash;
+package android.view.cts;
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.webkit.WebView;
 
-public class RenderProcessCrashActivity extends Activity {
-
+/**
+ * A simple activity to test "Default Focus Highlight"
+ */
+public class DefaultFocusHighlightCtsActivity extends Activity {
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WebView webView = new WebView(this);
-        setContentView(webView);
-        webView.loadUrl("chrome://kill");
+        setContentView(R.layout.default_focus_highlight_layout);
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 22fb6e0..8d56087 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -21,13 +21,16 @@
 import static org.junit.Assert.assertTrue;
 
 import android.graphics.Rect;
+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.view.FocusFinder;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
+import android.widget.FrameLayout;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -340,4 +343,75 @@
                 View.FOCUS_BACKWARD);
         assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
     }
+
+    @Test
+    public void testDuplicateId() throws Throwable {
+        LayoutInflater inflater = mActivityRule.getActivity().getLayoutInflater();
+        mLayout = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.inflate_layout);
+        View[] buttons = new View[3];
+        View[] boxes = new View[3];
+        mActivityRule.runOnUiThread(() -> {
+            for (int i = 0; i < 3; ++i) {
+                View item = inflater.inflate(R.layout.focus_finder_sublayout, mLayout, false);
+                buttons[i] = item.findViewById(R.id.itembutton);
+                boxes[i] = item.findViewById(R.id.itembox);
+                mLayout.addView(item);
+            }
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verifyNextFocus(buttons[0], View.FOCUS_FORWARD, boxes[0]);
+        verifyNextFocus(boxes[0], View.FOCUS_FORWARD, buttons[1]);
+        verifyNextFocus(buttons[1], View.FOCUS_FORWARD, boxes[1]);
+        verifyNextFocus(boxes[1], View.FOCUS_FORWARD, buttons[2]);
+    }
+
+    @Test
+    public void testBasicFocusOrder() {
+        // Sanity check to make sure sorter is behaving
+        FrameLayout layout = new FrameLayout(mLayout.getContext());
+        Button button1 = new Button(mLayout.getContext());
+        Button button2 = new Button(mLayout.getContext());
+        button1.setLeftTopRightBottom(0, 0, 10, 10);
+        button2.setLeftTopRightBottom(0, 0, 10, 10);
+        layout.addView(button1);
+        layout.addView(button2);
+        View[] views = new View[]{button2, button1};
+        // empty shouldn't crash or anything
+        FocusFinder.sort(views, 0, 0, layout, false);
+        // one view should work
+        FocusFinder.sort(views, 0, 1, layout, false);
+        assertEquals(button2, views[0]);
+        // exactly overlapping views should remain in original order
+        FocusFinder.sort(views, 0, 2, layout, false);
+        assertEquals(button2, views[0]);
+        assertEquals(button1, views[1]);
+        // make sure it will actually mutate input array.
+        button2.setLeftTopRightBottom(20, 0, 30, 10);
+        FocusFinder.sort(views, 0, 2, layout, false);
+        assertEquals(button1, views[0]);
+        assertEquals(button2, views[1]);
+
+        // While we don't want to test details, we should at least verify basic correctness
+        // like "left-to-right" ordering in well-behaved layouts
+        assertEquals(mLayout.findFocus(), mTopLeft);
+        verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+
+        // Should still work intuitively even if some views are slightly shorter.
+        mBottomLeft.setBottom(mBottomLeft.getBottom() - 3);
+        mBottomLeft.offsetTopAndBottom(3);
+        verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+
+        // RTL layout should work right-to-left
+        mActivityRule.getActivity().runOnUiThread(
+                () -> mLayout.setLayoutDirection(View.LAYOUT_DIRECTION_RTL));
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        verifyNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+        verifyNextFocus(mTopRight, View.FOCUS_FORWARD, mBottomLeft);
+        verifyNextFocus(mBottomLeft, View.FOCUS_FORWARD, mBottomRight);
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/MenuItemTest.java b/tests/tests/view/src/android/view/cts/MenuItemTest.java
index fc0ae0b..c9d362c 100644
--- a/tests/tests/view/src/android/view/cts/MenuItemTest.java
+++ b/tests/tests/view/src/android/view/cts/MenuItemTest.java
@@ -60,7 +60,7 @@
     }
 
     @Test
-    public void testAccessThumbTint() {
+    public void testAccessIconTint() {
         // Note that this test is not marked as @UiThreadTest. Updating MenuItem does not
         // immediately update the displayed content, and even though the getters are expected
         // to immediately return the just-set value, using instrumentation to wait for the
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java b/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
index a6bc5fb..cb85712 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewCtsActivity.java
@@ -52,8 +52,9 @@
         private static final int RECT_RIGHT = 200;
         private static final int RECT_BOTTOM = 200;
 
+        private Canvas mCanvas;
+
         private SurfaceHolder mHolder;
-        private MockCanvas mCanvas;
 
         private boolean mIsDraw;
         private boolean mIsAttachedToWindow;
@@ -64,6 +65,7 @@
         private boolean mIsOnWindowVisibilityChanged;
         private boolean mIsDispatchDraw;
         private boolean mIsSurfaceChanged;
+        private boolean mSurfaceCreatedCalled;
 
         private int mWidthInOnMeasure;
         private int mHeightInOnMeasure;
@@ -170,10 +172,12 @@
         }
 
         public void surfaceCreated(SurfaceHolder holder) {
+            mSurfaceCreatedCalled = true;
+
             // Use mock canvas listening to the drawColor() calling.
-            mCanvas = new MockCanvas(Bitmap.createBitmap( BITMAP_WIDTH,
-                                                          BITMAP_HEIGHT,
-                                                          Bitmap.Config.ARGB_8888));
+            mCanvas = new Canvas(Bitmap.createBitmap( BITMAP_WIDTH,
+                            BITMAP_HEIGHT,
+                            Bitmap.Config.ARGB_8888));
             draw(mCanvas);
 
             // Lock the surface, this returns a Canvas that can be used to render into.
@@ -186,6 +190,10 @@
             mHolder.unlockCanvasAndPost(canvas);
         }
 
+        boolean isSurfaceCreatedCalled() {
+            return mSurfaceCreatedCalled;
+        }
+
         public void surfaceDestroyed(SurfaceHolder holder) {
         }
 
@@ -229,44 +237,8 @@
             return mIsDispatchDraw;
         }
 
-        public boolean isDrawColor() {
-            if (mCanvas != null) {
-                return mCanvas.isDrawColor();
-            } else {
-                return false;
-            }
-        }
-
         public boolean isSurfaceChanged() {
             return mIsSurfaceChanged;
         }
-
-        public void setDrawColor(boolean isDrawColor) {
-            if (mCanvas != null) {
-                mCanvas.setDrawColor(isDrawColor);
-            }
-        }
-    }
-
-    class MockCanvas extends Canvas {
-        private boolean mIsDrawColor;
-
-        public MockCanvas(Bitmap bitmap) {
-            super(bitmap);
-        }
-
-        @Override
-        public void drawColor(int color, Mode mode) {
-            super.drawColor(color, mode);
-            mIsDrawColor = true;
-        }
-
-        public boolean isDrawColor() {
-            return mIsDrawColor;
-        }
-
-        public void setDrawColor(boolean isDrawColor) {
-            this.mIsDrawColor = isDrawColor;
-        }
     }
 }
diff --git a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
index 277a094..5d90c73 100644
--- a/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
+++ b/tests/tests/view/src/android/view/cts/SurfaceViewTest.java
@@ -79,7 +79,7 @@
         assertTrue(mMockSurfaceView.isDraw());
         assertTrue(mMockSurfaceView.isOnAttachedToWindow());
         assertTrue(mMockSurfaceView.isDispatchDraw());
-        assertTrue(mMockSurfaceView.isDrawColor());
+        assertTrue(mMockSurfaceView.isSurfaceCreatedCalled());
         assertTrue(mMockSurfaceView.isSurfaceChanged());
 
         assertTrue(mMockSurfaceView.isOnWindowVisibilityChanged());
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 17c6843..95b8491 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -208,6 +208,19 @@
         mMockViewGroup.setVisibility(View.GONE);
         parent.addKeyboardNavigationClusters(list, 0);
         assertEquals(0, list.size());
+        list.clear();
+
+        // Nested clusters are ignored
+        TestClusterHier h = new TestClusterHier();
+        h.nestedGroup.setKeyboardNavigationCluster(true);
+        h.cluster2.setKeyboardNavigationCluster(false);
+        h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
+        assertTrue(list.contains(h.nestedGroup));
+        list.clear();
+        h.cluster2.setKeyboardNavigationCluster(true);
+        h.top.addKeyboardNavigationClusters(list, View.FOCUS_FORWARD);
+        assertFalse(list.contains(h.nestedGroup));
+        list.clear();
     }
 
     @UiThreadTest
@@ -1562,6 +1575,14 @@
         h.c2view1.setVisibility(View.INVISIBLE);
         h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
         assertSame(h.c2view2, h.top.findFocus());
+
+        // Nested clusters should be ignored.
+        h = new TestClusterHier();
+        h.c1view1.setFocusedInCluster();
+        h.nestedGroup.setKeyboardNavigationCluster(true);
+        h.c2view2.setFocusedInCluster();
+        h.cluster2.restoreFocusInCluster(View.FOCUS_DOWN);
+        assertSame(h.c2view2, h.top.findFocus());
     }
 
     @UiThreadTest
@@ -1781,6 +1802,7 @@
         // can normal-navigate around once inside
         h.top.addFocusables(views, View.FOCUS_DOWN);
         assertTrue(views.contains(h.c1view1));
+        views.clear();
         h.c1view1.requestFocus();
         assertSame(h.c1view1, h.top.findFocus());
         // focus loops within cluster (doesn't leave)
@@ -1791,6 +1813,17 @@
         h.c2view2.requestFocus();
         h.c1view1.requestFocus();
         assertSame(h.c2view2, h.top.findFocus());
+
+        h = new TestClusterHier(false);
+        h.c1view1.requestFocus();
+        h.nestedGroup.setKeyboardNavigationCluster(true);
+        h.nestedGroup.setTouchscreenBlocksFocus(true);
+        // since cluster is nested, it should ignore its touchscreenBlocksFocus behavior.
+        h.c2view2.requestFocus();
+        assertSame(h.c2view2, h.top.findFocus());
+        h.top.addFocusables(views, View.FOCUS_DOWN);
+        assertTrue(views.contains(h.c2view2));
+        views.clear();
     }
 
     @UiThreadTest
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index ca39aab..2550915 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -3661,67 +3661,6 @@
     }
 
     @Test
-    public void testScrollbarSize() {
-        final int configScrollbarSize = ViewConfiguration.get(mActivity).getScaledScrollBarSize();
-        final int customScrollbarSize = configScrollbarSize * 2;
-
-        // No explicit scrollbarSize or custom drawables, ViewConfiguration applies.
-        final MockView view = (MockView) mActivity.findViewById(R.id.scroll_view);
-        assertEquals(configScrollbarSize, view.getScrollBarSize());
-        assertEquals(configScrollbarSize, view.getVerticalScrollbarWidth());
-        assertEquals(configScrollbarSize, view.getHorizontalScrollbarHeight());
-
-        // No custom drawables, explicit scrollbarSize takes precedence.
-        final MockView view2 = (MockView) mActivity.findViewById(R.id.scroll_view_2);
-        view2.setScrollBarSize(customScrollbarSize);
-        assertEquals(customScrollbarSize, view2.getScrollBarSize());
-        assertEquals(customScrollbarSize, view2.getVerticalScrollbarWidth());
-        assertEquals(customScrollbarSize, view2.getHorizontalScrollbarHeight());
-
-        // Custom drawables with no intrinsic size, ViewConfiguration applies.
-        final MockView view3 = (MockView) mActivity.findViewById(R.id.scroll_view_3);
-        assertEquals(configScrollbarSize, view3.getVerticalScrollbarWidth());
-        assertEquals(configScrollbarSize, view3.getHorizontalScrollbarHeight());
-        // Explicit scrollbarSize takes precedence.
-        view3.setScrollBarSize(customScrollbarSize);
-        assertEquals(view3.getScrollBarSize(), view3.getVerticalScrollbarWidth());
-        assertEquals(view3.getScrollBarSize(), view3.getHorizontalScrollbarHeight());
-
-        // Custom thumb drawables with intrinsic sizes define the scrollbars' dimensions.
-        final MockView view4 = (MockView) mActivity.findViewById(R.id.scroll_view_4);
-        final Resources res = mActivity.getResources();
-        final int thumbWidth = res.getDimensionPixelOffset(R.dimen.scrollbar_thumb_width);
-        final int thumbHeight = res.getDimensionPixelOffset(R.dimen.scrollbar_thumb_height);
-        assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
-        assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
-        // Explicit scrollbarSize has no effect.
-        view4.setScrollBarSize(customScrollbarSize);
-        assertEquals(thumbWidth, view4.getVerticalScrollbarWidth());
-        assertEquals(thumbHeight, view4.getHorizontalScrollbarHeight());
-
-        // Custom thumb and track drawables with intrinsic sizes. Track size take precedence.
-        final MockView view5 = (MockView) mActivity.findViewById(R.id.scroll_view_5);
-        final int trackWidth = res.getDimensionPixelOffset(R.dimen.scrollbar_track_width);
-        final int trackHeight = res.getDimensionPixelOffset(R.dimen.scrollbar_track_height);
-        assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
-        assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
-        // Explicit scrollbarSize has no effect.
-        view5.setScrollBarSize(customScrollbarSize);
-        assertEquals(trackWidth, view5.getVerticalScrollbarWidth());
-        assertEquals(trackHeight, view5.getHorizontalScrollbarHeight());
-
-        // Custom thumb and track, track with no intrinsic size, ViewConfiguration applies
-        // regardless of the thumb drawable dimensions.
-        final MockView view6 = (MockView) mActivity.findViewById(R.id.scroll_view_6);
-        assertEquals(configScrollbarSize, view6.getVerticalScrollbarWidth());
-        assertEquals(configScrollbarSize, view6.getHorizontalScrollbarHeight());
-        // Explicit scrollbarSize takes precedence.
-        view6.setScrollBarSize(customScrollbarSize);
-        assertEquals(customScrollbarSize, view6.getVerticalScrollbarWidth());
-        assertEquals(customScrollbarSize, view6.getHorizontalScrollbarHeight());
-    }
-
-    @Test
     public void testOnStartAndFinishTemporaryDetach() throws Throwable {
         final AtomicBoolean exitedDispatchStartTemporaryDetach = new AtomicBoolean(false);
         final AtomicBoolean exitedDispatchFinishTemporaryDetach = new AtomicBoolean(false);
diff --git a/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
new file mode 100644
index 0000000..5e362cf
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/View_DefaultFocusHighlightTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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 android.view.cts;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class View_DefaultFocusHighlightTest {
+
+    @Rule
+    public ActivityTestRule<DefaultFocusHighlightCtsActivity> mActivityRule =
+            new ActivityTestRule<>(DefaultFocusHighlightCtsActivity.class);
+
+    @UiThreadTest
+    @Test
+    public void testSettersAndGetters() {
+        Activity activity = mActivityRule.getActivity();
+
+        View view = activity.findViewById(R.id.view);
+        ListView listView = (ListView) activity.findViewById(R.id.listview);
+        EditText editText = (EditText) activity.findViewById(R.id.edittext);
+        Button button = (Button) activity.findViewById(R.id.button);
+        LinearLayout linearLayout = (LinearLayout) activity.findViewById(R.id.linearlayout);
+
+        assertTrue(view.getDefaultFocusHighlightEnabled());
+        assertFalse(listView.getDefaultFocusHighlightEnabled());
+        assertFalse(editText.getDefaultFocusHighlightEnabled());
+        assertTrue(button.getDefaultFocusHighlightEnabled());
+        assertTrue(linearLayout.getDefaultFocusHighlightEnabled());
+
+        view.setDefaultFocusHighlightEnabled(false);
+        listView.setDefaultFocusHighlightEnabled(true);
+        editText.setDefaultFocusHighlightEnabled(true);
+        button.setDefaultFocusHighlightEnabled(false);
+        linearLayout.setDefaultFocusHighlightEnabled(false);
+
+        assertFalse(view.getDefaultFocusHighlightEnabled());
+        assertTrue(listView.getDefaultFocusHighlightEnabled());
+        assertTrue(editText.getDefaultFocusHighlightEnabled());
+        assertFalse(button.getDefaultFocusHighlightEnabled());
+        assertFalse(linearLayout.getDefaultFocusHighlightEnabled());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testInflating() {
+        Activity activity = mActivityRule.getActivity();
+
+        View view = activity.findViewById(R.id.view_to_inflate);
+        ListView listView = (ListView) activity.findViewById(R.id.listview_to_inflate);
+        EditText editText = (EditText) activity.findViewById(R.id.edittext_to_inflate);
+        Button button = (Button) activity.findViewById(R.id.button_to_inflate);
+        LinearLayout linearLayout = (LinearLayout) activity.findViewById(
+                R.id.linearlayout_to_inflate);
+
+        assertFalse(view.getDefaultFocusHighlightEnabled());
+        assertTrue(listView.getDefaultFocusHighlightEnabled());
+        assertTrue(editText.getDefaultFocusHighlightEnabled());
+        assertFalse(button.getDefaultFocusHighlightEnabled());
+        assertFalse(linearLayout.getDefaultFocusHighlightEnabled());
+    }
+}
diff --git a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
index 3d9f66b..60ef12e 100644
--- a/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
+++ b/tests/tests/view/src/android/view/cts/surfacevalidator/SurfacePixelValidator.java
@@ -36,7 +36,7 @@
      * Observed that first few frames have errors with SurfaceView placement, so we skip for now.
      * b/29603849 tracking that issue.
      */
-    private static final int NUM_FIRST_FRAMES_SKIPPED = 8;
+    private static final int NUM_FIRST_FRAMES_SKIPPED = 25;
 
     // If no channel is greater than this value, pixel will be considered 'blackish'.
     private static final short PIXEL_CHANNEL_THRESHOLD = 4;
@@ -78,6 +78,7 @@
             synchronized (mResultLock) {
                 if (numSkipped < NUM_FIRST_FRAMES_SKIPPED) {
                     numSkipped++;
+                    Log.d(TAG, "skipped fram nr " + numSkipped + ", success = " + success);
                 } else {
                     if (success) {
                         mResultSuccessFrames++;
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
index b16d473..a840116 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java
@@ -17,7 +17,6 @@
 package android.view.textclassifier.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertThat;
 import static org.mockito.Mockito.mock;
 
 import android.os.LocaleList;
@@ -25,21 +24,12 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.textclassifier.TextClassificationManager;
-import android.view.textclassifier.TextClassificationResult;
 import android.view.textclassifier.TextClassifier;
-import android.view.textclassifier.TextLanguage;
-import android.view.textclassifier.TextSelection;
 
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
-import java.util.Locale;
-
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class TextClassificationManagerTest {
@@ -53,78 +43,23 @@
     public void setup() {
         mTcm = InstrumentationRegistry.getTargetContext()
                 .getSystemService(TextClassificationManager.class);
-        mTcm.setTextClassifier(null);
+        mTcm.setTextClassifier(null); // Resets the classifier.
         mClassifier = mTcm.getTextClassifier();
     }
 
     @Test
-    public void testSmartSelection() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Contact me at droid@android.com";
-        String selected = "droid";
-        String suggested = "droid@android.com";
-        int startIndex = text.indexOf(selected);
-        int endIndex = startIndex + selected.length();
-        int smartStartIndex = text.indexOf(suggested);
-        int smartEndIndex = smartStartIndex + suggested.length();
-
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
-                isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_EMAIL));
+    public void testSmartSelectionDoesNotThrowException() {
+        mClassifier.suggestSelection("text", 2, 3, LOCALES);
     }
 
     @Test
-    public void testSmartSelection_url() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Visit http://www.android.com for more information";
-        String selected = "http";
-        String suggested = "http://www.android.com";
-        int startIndex = text.indexOf(selected);
-        int endIndex = startIndex + selected.length();
-        int smartStartIndex = text.indexOf(suggested);
-        int smartEndIndex = smartStartIndex + suggested.length();
-
-        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
-                isTextSelection(smartStartIndex, smartEndIndex, TextClassifier.TYPE_URL));
+    public void testTextClassificationResultDoesNotThrowException() {
+        mClassifier.getTextClassificationResult("text", 2, 3, LOCALES);
     }
 
     @Test
-    public void testTextClassificationResult() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Contact me at droid@android.com";
-        String classifiedText = "droid@android.com";
-        int startIndex = text.indexOf(classifiedText);
-        int endIndex = startIndex + classifiedText.length();
-        assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES),
-                isTextClassificationResult(classifiedText, TextClassifier.TYPE_EMAIL));
-    }
-
-    @Test
-    public void testTextClassificationResult_url() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "Visit http://www.android.com for more information";
-        String classifiedText = "http://www.android.com";
-        int startIndex = text.indexOf(classifiedText);
-        int endIndex = startIndex + classifiedText.length();
-        assertThat(mClassifier.getTextClassificationResult(text, startIndex, endIndex, LOCALES),
-                isTextClassificationResult(classifiedText, TextClassifier.TYPE_URL));
-    }
-
-    @Test
-    public void testLanguageDetection() {
-        if (isTextClassifierDisabled()) return;
-
-        String text = "This is english text";
-        assertThat(mTcm.detectLanguages(text), isDetectedLanguage("en"));
-
-        text = "Das ist deutscher text";
-        assertThat(mTcm.detectLanguages(text), isDetectedLanguage("de"));
-
-        text = "これは日本語テキストです";
-        assertThat(mTcm.detectLanguages(text), isDetectedLanguage("ja"));
+    public void testLanguageDetectionDoesNotThrowException() {
+        mTcm.detectLanguages("text");
     }
 
     @Test
@@ -133,80 +68,4 @@
         mTcm.setTextClassifier(classifier);
         assertEquals(classifier, mTcm.getTextClassifier());
     }
-
-    private boolean isTextClassifierDisabled() {
-        return mClassifier == TextClassifier.NO_OP;
-    }
-
-    private static Matcher<TextSelection> isTextSelection(
-            final int startIndex, final int endIndex, final String type) {
-        return new BaseMatcher<TextSelection>() {
-            @Override
-            public boolean matches(Object o) {
-                if (o instanceof TextSelection) {
-                    TextSelection selection = (TextSelection) o;
-                    return startIndex == selection.getSelectionStartIndex()
-                            && endIndex == selection.getSelectionEndIndex()
-                            && selection.getEntityCount() > 0
-                            && type.equals(selection.getEntity(0));
-                }
-                return false;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendValue(
-                        String.format("%d, %d, %s", startIndex, endIndex, type));
-            }
-        };
-    }
-
-    private static Matcher<TextClassificationResult> isTextClassificationResult(
-            final String text, final String type) {
-        return new BaseMatcher<TextClassificationResult>() {
-            @Override
-            public boolean matches(Object o) {
-                if (o instanceof TextClassificationResult) {
-                    TextClassificationResult result = (TextClassificationResult) o;
-                    return text.equals(result.getText())
-                            && result.getEntityCount() > 0
-                            && type.equals(result.getEntity(0));
-                    // TODO: Include other properties.
-                }
-                return false;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendText("text=").appendValue(text)
-                        .appendText(", type=").appendValue(type);
-            }
-        };
-    }
-
-    private static Matcher<List<TextLanguage>> isDetectedLanguage(final String language) {
-        return new BaseMatcher<List<TextLanguage>>() {
-            @Override
-            public boolean matches(Object o) {
-                if (o instanceof List) {
-                    List languages = (List) o;
-                    if (!languages.isEmpty()) {
-                        Object o1 = languages.get(0);
-                        if (o1 instanceof TextLanguage) {
-                            TextLanguage lang = (TextLanguage) o1;
-                            return lang.getLanguageCount() > 0
-                                    && new Locale(language).getLanguage()
-                                            .equals(lang.getLanguage(0).getLanguage());
-                        }
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public void describeTo(Description description) {
-                description.appendValue(String.format("%s", language));
-            }
-        };
-    }
 }
diff --git a/tests/tests/webkit/AndroidManifest.xml b/tests/tests/webkit/AndroidManifest.xml
index 44df7c4..83775df 100644
--- a/tests/tests/webkit/AndroidManifest.xml
+++ b/tests/tests/webkit/AndroidManifest.xml
@@ -56,6 +56,8 @@
             </intent-filter>
         </activity>
 
+        <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing" android:value="false" />
+
     </application>
 
     <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
index 472e371..8caf161 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebSettingsTest.java
@@ -1005,6 +1005,18 @@
         }
     }
 
+    public void testEnableSafeBrowsing() throws Throwable {
+        if (!NullWebViewUtils.isWebViewAvailable()) {
+            return;
+        }
+        assertFalse(mSettings.getSafeBrowsingEnabled());
+        mSettings.setSafeBrowsingEnabled(true);
+        assertTrue(mSettings.getSafeBrowsingEnabled());
+        mSettings.setSafeBrowsingEnabled(false);
+        assertFalse(mSettings.getSafeBrowsingEnabled());
+    }
+
+
     /**
      * Starts the internal web server. The server will be shut down automatically
      * during tearDown().
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 07ba11e..d77af03 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -582,14 +582,14 @@
         }
         final MockWebViewClient webViewClient = new MockWebViewClient();
         mOnUiThread.setWebViewClient(webViewClient);
-        mOnUiThread.loadUrl("chrome://crash");
+        mOnUiThread.loadUrl("chrome://kill");
         new PollingCheck(TEST_TIMEOUT * 5) {
             @Override
             protected boolean check() {
                 return webViewClient.hasRenderProcessGoneCalled();
             }
         }.run();
-        assertTrue(webViewClient.didRenderProcessCrash());
+        assertFalse(webViewClient.didRenderProcessCrash());
     }
 
     private void requireLoadedPage() throws Throwable {
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 2ef274a..4ff8eef 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -26,7 +26,6 @@
 import android.graphics.Color;
 import android.graphics.Picture;
 import android.graphics.Rect;
-import android.graphics.pdf.PdfRenderer;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -2551,8 +2550,7 @@
                     // Called on UI thread
                     @Override
                     public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
-                        PageRange[] pageRanges = new PageRange[] {PageRange.ALL_PAGES};
-                        savePrintedPage(adapter, descriptor, pageRanges, result);
+                        savePrintedPage(adapter, descriptor, result);
                     }
                 });
         try {
@@ -2570,57 +2568,6 @@
         }
     }
 
-    // Verify Print feature can create a PDF file with correct number of pages.
-    public void testPrintingPagesCount() throws Throwable {
-        if (!NullWebViewUtils.isWebViewAvailable()) {
-            return;
-        }
-        String content = "<html><head></head><body>";
-        for (int i = 0; i < 500; ++i) {
-            content += "<br />abcdefghijk<br />";
-        }
-        content += "</body></html>";
-        mOnUiThread.loadDataAndWaitForCompletion(content, "text/html", null);
-        final PrintDocumentAdapter adapter =  mOnUiThread.createPrintDocumentAdapter();
-        printDocumentStart(adapter);
-        PrintAttributes attributes = new PrintAttributes.Builder()
-                .setMediaSize(PrintAttributes.MediaSize.ISO_A4)
-                .setResolution(new PrintAttributes.Resolution("foo", "bar", 300, 300))
-                .setMinMargins(PrintAttributes.Margins.NO_MARGINS)
-                .build();
-        final WebViewCtsActivity activity = getActivity();
-        final File file = activity.getFileStreamPath(PRINTER_TEST_FILE);
-        final ParcelFileDescriptor descriptor = ParcelFileDescriptor.open(file,
-                ParcelFileDescriptor.parseMode("w"));
-        final FutureTask<Boolean> result =
-                new FutureTask<Boolean>(new Callable<Boolean>() {
-                            public Boolean call() {
-                                return true;
-                            }
-                        });
-        printDocumentLayout(adapter, null, attributes,
-                new LayoutResultCallback() {
-                    // Called on UI thread
-                    @Override
-                    public void onLayoutFinished(PrintDocumentInfo info, boolean changed) {
-                        PageRange[] pageRanges = new PageRange[] {
-                            new PageRange(1, 1), new PageRange(4, 7)
-                        };
-                        savePrintedPage(adapter, descriptor, pageRanges, result);
-                    }
-                });
-        try {
-            result.get(TEST_TIMEOUT, TimeUnit.MILLISECONDS);
-            assertTrue(file.length() > 0);
-            PdfRenderer renderer = new PdfRenderer(
-                ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY));
-            assertEquals(5, renderer.getPageCount());
-        } finally {
-            descriptor.close();
-            file.delete();
-        }
-    }
-
     public void testVisualStateCallbackCalled() throws Exception {
         // Check that the visual state callback is called correctly.
         if (!NullWebViewUtils.isWebViewAvailable()) {
@@ -2692,9 +2639,8 @@
     }
 
     private void savePrintedPage(final PrintDocumentAdapter adapter,
-            final ParcelFileDescriptor descriptor, final PageRange[] pageRanges,
-            final FutureTask<Boolean> result) {
-        adapter.onWrite(pageRanges, descriptor,
+            final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
+        adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
                 new CancellationSignal(),
                 new WriteResultCallback() {
                     @Override
diff --git a/tests/tests/widget/res/layout/textview_imeoptions.xml b/tests/tests/widget/res/layout/textview_imeoptions.xml
new file mode 100644
index 0000000..82b1d26
--- /dev/null
+++ b/tests/tests/widget/res/layout/textview_imeoptions.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+
+    <!-- Test EditorInfo.IME_NULL -->
+    <TextView
+        android:id="@+id/textview_imeoption_normal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="normal" />
+
+    <!-- Test EditorInfo.IME_ACTION_* -->
+    <TextView
+        android:id="@+id/textview_imeoption_action_unspecified"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionUnspecified" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_none"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionNone" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_go"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionGo" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_search"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionSearch" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_send"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionSend" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_next"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionNext" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_done"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionDone" />
+    <TextView
+        android:id="@+id/textview_imeoption_action_previous"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionPrevious" />
+
+    <!-- Test EditorInfo.IME_FLAG_* -->
+    <TextView
+        android:id="@+id/textview_imeoption_no_personalized_learning"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNoPersonalizedLearning" />
+    <TextView
+        android:id="@+id/textview_imeoption_no_fullscreen"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNoFullscreen" />
+    <TextView
+        android:id="@+id/textview_imeoption_navigation_previous"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNavigatePrevious" />
+    <TextView
+        android:id="@+id/textview_imeoption_navigation_next"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNavigateNext" />
+    <TextView
+        android:id="@+id/textview_imeoption_no_extract_ui"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNoExtractUi" />
+    <TextView
+        android:id="@+id/textview_imeoption_no_accessory_action"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNoAccessoryAction" />
+    <TextView
+        android:id="@+id/textview_imeoption_no_enter_action"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagNoEnterAction" />
+    <TextView
+        android:id="@+id/textview_imeoption_force_ascii"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="flagForceAscii" />
+
+    <!-- test an action with multiple flags -->
+    <TextView
+        android:id="@+id/textview_imeoption_action_go_nagivate_next_no_extract_ui_force_ascii"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:imeOptions="actionGo|flagNavigateNext|flagNoExtractUi|flagForceAscii" />
+
+</LinearLayout>
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/AdapterViewTest.java b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
index 4e33156..b2fd35c 100644
--- a/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/AdapterViewTest.java
@@ -362,6 +362,11 @@
         assertTrue(mAdapterView.isFocusable());
         assertTrue(mAdapterView.isFocusableInTouchMode());
 
+        // FOCUSABLE_AUTO should also work with children added (AbsListView is clickable)
+        mAdapterView.setFocusable(View.FOCUSABLE_AUTO);
+        assertTrue(mAdapterView.isFocusable());
+        assertTrue(mAdapterView.isFocusableInTouchMode());
+
         mAdapterView.setFocusable(false);
         assertFalse(mAdapterView.isFocusable());
         assertFalse(mAdapterView.isFocusableInTouchMode());
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 2b55ed5..5476b22 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -510,7 +510,6 @@
         Drawable backgroundDrawable = new ColorDrawable(0xFF0000FF);
         mockImageView.setBackgroundDrawable(backgroundDrawable);
 
-        assertFalse(mockImageView.verifyDrawable(null));
         assertFalse(mockImageView.verifyDrawable(new ColorDrawable(0xFF00FF00)));
         assertTrue(mockImageView.verifyDrawable(drawable));
         assertTrue(mockImageView.verifyDrawable(backgroundDrawable));
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index 209f689..de6df87 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -1445,6 +1445,12 @@
         mPopupWindow = createPopupWindow(
                 mActivity.getLayoutInflater().inflate(R.layout.popup_window, null));
 
+        // This ensures that mPopupWindow is flipped vertically when anchored to one of the views
+        // at the bottom of the window (R.id.anchor_lower_*).
+        // This way the bottom edge of subPopup's anchor is aligned with the bottom edge of the
+        // window as well, which makes it possible to predict whether subPopup is going to flipped.
+        mPopupWindow.setOverlapAnchor(true);
+
         final PopupWindow subPopup =
                 createPopupWindow(createPopupContent(CONTENT_SIZE_DP, CONTENT_SIZE_DP));
 
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 4ced4fb..5a68273 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -514,26 +514,22 @@
     public void testVerifyDrawable() {
         MockProgressBar mockProgressBar =
                 (MockProgressBar) mActivity.findViewById(R.id.progress_custom);
-        assertTrue(mockProgressBar.verifyDrawable(null));
 
         Drawable d1 = mActivity.getDrawable(R.drawable.blue);
         Drawable d2 = mActivity.getDrawable(R.drawable.red);
         Drawable d3 = mActivity.getDrawable(R.drawable.yellow);
 
         mockProgressBar.setBackgroundDrawable(d1);
-        assertTrue(mockProgressBar.verifyDrawable(null));
         assertTrue(mockProgressBar.verifyDrawable(d1));
         assertFalse(mockProgressBar.verifyDrawable(d2));
         assertFalse(mockProgressBar.verifyDrawable(d3));
 
         mockProgressBar.setIndeterminateDrawable(d2);
-        assertTrue(mockProgressBar.verifyDrawable(null));
         assertTrue(mockProgressBar.verifyDrawable(d1));
         assertTrue(mockProgressBar.verifyDrawable(d2));
         assertFalse(mockProgressBar.verifyDrawable(d3));
 
         mockProgressBar.setProgressDrawable(d3);
-        assertFalse(mockProgressBar.verifyDrawable(null));
         assertTrue(mockProgressBar.verifyDrawable(d1));
         assertTrue(mockProgressBar.verifyDrawable(d2));
         assertTrue(mockProgressBar.verifyDrawable(d3));
diff --git a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
index b1523c5..2cc8993 100644
--- a/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
+++ b/tests/tests/widget/src/android/widget/cts/SearchView_CursorTest.java
@@ -37,6 +37,9 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AutoCompleteTextView;
 import android.widget.CursorAdapter;
 import android.widget.SearchView;
 import android.widget.SimpleCursorAdapter;
@@ -64,6 +67,7 @@
 
     private CursorAdapter mSuggestionsAdapter;
 
+    // This should be protected to spy an object of this class.
     protected class MyQueryTextListener implements SearchView.OnQueryTextListener {
         @Override
         public boolean onQueryTextSubmit(String s) {
@@ -75,7 +79,9 @@
             if (mSuggestionsAdapter == null) {
                 return false;
             }
-
+            if (!enoughToFilter()) {
+                return false;
+            }
             final MatrixCursor c = new MatrixCursor(
                     new String[] { BaseColumns._ID, TEXT_COLUMN_NAME} );
             for (int i = 0; i < mTextContent.length; i++) {
@@ -86,8 +92,32 @@
             mSuggestionsAdapter.swapCursor(c);
             return false;
         }
+
+        private boolean enoughToFilter() {
+            final AutoCompleteTextView searchSrcText = findAutoCompleteTextView(mSearchView);
+            return searchSrcText != null && searchSrcText.enoughToFilter();
+        }
+
+        private AutoCompleteTextView findAutoCompleteTextView(final ViewGroup viewGroup) {
+            final int count = viewGroup.getChildCount();
+            for (int index = 0; index < count; index++) {
+                final View view = viewGroup.getChildAt(index);
+                if (view instanceof AutoCompleteTextView) {
+                    return (AutoCompleteTextView) view;
+                }
+                if (view instanceof ViewGroup) {
+                    final AutoCompleteTextView findView =
+                            findAutoCompleteTextView((ViewGroup) view);
+                    if (findView != null) {
+                        return findView;
+                    }
+                }
+            }
+            return null;
+        }
     }
 
+    // This should be protected to spy an object of this class.
     protected class MySuggestionListener implements SearchView.OnSuggestionListener {
         @Override
         public boolean onSuggestionSelect(int position) {
@@ -103,7 +133,7 @@
                     mSearchView.setQuery(cursor.getString(1), false);
                 }
             }
-            return false;
+            return true;
         }
     }
 
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 0b500f3..a7cde1a 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -42,6 +42,9 @@
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.Instrumentation.ActivityMonitor;
@@ -63,6 +66,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;
@@ -157,6 +161,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -410,6 +415,108 @@
         assertEquals(-1, mTextView.getGravity());
     }
 
+    @Retention(SOURCE)
+    @IntDef({EditorInfo.IME_ACTION_UNSPECIFIED, EditorInfo.IME_ACTION_NONE,
+            EditorInfo.IME_ACTION_GO, EditorInfo.IME_ACTION_SEARCH, EditorInfo.IME_ACTION_SEND,
+            EditorInfo.IME_ACTION_NEXT, EditorInfo.IME_ACTION_DONE, EditorInfo.IME_ACTION_PREVIOUS})
+    private @interface ImeOptionAction {}
+
+    @Retention(SOURCE)
+    @IntDef(flag = true,
+            value = {EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING,
+                    EditorInfo.IME_FLAG_NO_FULLSCREEN, EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS,
+                    EditorInfo.IME_FLAG_NAVIGATE_NEXT, EditorInfo.IME_FLAG_NO_EXTRACT_UI,
+                    EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION, EditorInfo.IME_FLAG_NO_ENTER_ACTION,
+                    EditorInfo.IME_FLAG_FORCE_ASCII})
+    private @interface ImeOptionFlags {}
+
+    private static void assertImeOptions(TextView textView,
+            @ImeOptionAction int expectedImeOptionAction,
+            @ImeOptionFlags int expectedImeOptionFlags) {
+        final int actualAction = textView.getImeOptions() & EditorInfo.IME_MASK_ACTION;
+        final int actualFlags = textView.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
+        assertEquals(expectedImeOptionAction, actualAction);
+        assertEquals(expectedImeOptionFlags, actualFlags);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testImeOptions() {
+        mActivity.setContentView(R.layout.textview_imeoptions);
+
+        // Test "normal" to be a synonym EditorInfo.IME_NULL
+        assertEquals(EditorInfo.IME_NULL,
+                mActivity.<TextView>findViewById(R.id.textview_imeoption_normal).getImeOptions());
+
+        // Test EditorInfo.IME_ACTION_*
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_unspecified),
+                EditorInfo.IME_ACTION_UNSPECIFIED, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_none),
+                EditorInfo.IME_ACTION_NONE, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_go),
+                EditorInfo.IME_ACTION_GO, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_search),
+                EditorInfo.IME_ACTION_SEARCH, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_send),
+                EditorInfo.IME_ACTION_SEND, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_next),
+                EditorInfo.IME_ACTION_NEXT, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_done),
+                EditorInfo.IME_ACTION_DONE, 0);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_action_previous),
+                EditorInfo.IME_ACTION_PREVIOUS, 0);
+
+        // Test EditorInfo.IME_FLAG_*
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_no_personalized_learning),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_no_fullscreen),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NO_FULLSCREEN);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_navigation_previous),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_navigation_next),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_no_extract_ui),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_no_accessory_action),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NO_ACCESSORY_ACTION);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_no_enter_action),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+        assertImeOptions(
+                mActivity.findViewById(R.id.textview_imeoption_force_ascii),
+                EditorInfo.IME_ACTION_UNSPECIFIED,
+                EditorInfo.IME_FLAG_FORCE_ASCII);
+
+        // test action + multiple flags
+        assertImeOptions(
+                mActivity.findViewById(
+                        R.id.textview_imeoption_action_go_nagivate_next_no_extract_ui_force_ascii),
+                EditorInfo.IME_ACTION_GO,
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI
+                        | EditorInfo.IME_FLAG_FORCE_ASCII);
+    }
+
     @Test
     public void testAccessAutoLinkMask() throws Throwable {
         mTextView = findTextView(R.id.textview_text);
@@ -3369,9 +3476,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)
@@ -4532,7 +4652,7 @@
                 | InputType.TYPE_NUMBER_FLAG_DECIMAL
                 | InputType.TYPE_NUMBER_FLAG_SIGNED, mTextView.getInputType());
         assertSame(mTextView.getKeyListener(),
-                DigitsKeyListener.getInstance(mTextView.getTextLocale(), true, true));
+                DigitsKeyListener.getInstance(null, true, true));
 
         mTextView.setInputType(InputType.TYPE_CLASS_PHONE);
         assertEquals(InputType.TYPE_CLASS_PHONE, mTextView.getInputType());
@@ -4748,6 +4868,59 @@
 
     @UiThreadTest
     @Test
+    public void testSetImeHintLocalesChangesInputType() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("", BufferType.EDITABLE);
+
+        textView.setInputType(InputType.TYPE_CLASS_NUMBER);
+        assertEquals(InputType.TYPE_CLASS_NUMBER, textView.getInputType());
+
+        final LocaleList localeList = LocaleList.forLanguageTags("fa-IR");
+        textView.setImeHintLocales(localeList);
+        final int textType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        // Setting IME hint locales to Persian must change the input type to a full text IME,
+        // since the typical number input IME may not have localized digits.
+        assertEquals(textType, textView.getInputType());
+
+        // Changing the input type to datetime should keep the full text IME, since the IME hint
+        // is still set to Persian, which needs advanced input.
+        final int dateType = InputType.TYPE_CLASS_DATETIME | InputType.TYPE_DATETIME_VARIATION_DATE;
+        textView.setInputType(dateType);
+        assertEquals(textType, textView.getInputType());
+
+        // Changing the input type to number password should keep the full text IME, since the IME
+        // hint is still set to Persian, which needs advanced input. But it also needs to set the
+        // text password flag.
+        final int numberPasswordType = InputType.TYPE_CLASS_NUMBER
+                | InputType.TYPE_NUMBER_VARIATION_PASSWORD;
+        final int textPasswordType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_VARIATION_PASSWORD;
+        textView.setInputType(numberPasswordType);
+        assertEquals(textPasswordType, textView.getInputType());
+
+        // Setting the IME hint locales to null should reset the type to number password, since we
+        // no longer need internationalized input.
+        textView.setImeHintLocales(null);
+        assertEquals(numberPasswordType, textView.getInputType());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testSetImeHintLocalesDoesntLoseInputType() {
+        final TextView textView = new TextView(mActivity);
+        textView.setText("", BufferType.EDITABLE);
+        final int inputType = InputType.TYPE_CLASS_TEXT
+                | InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT
+                | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
+                | InputType.TYPE_TEXT_FLAG_MULTI_LINE
+                | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS;
+        textView.setInputType(inputType);
+        textView.setImeHintLocales(new LocaleList(Locale.US));
+        assertEquals(inputType, textView.getInputType());
+    }
+
+    @UiThreadTest
+    @Test
     public void testSetExtractedText() {
         mTextView = findTextView(R.id.textview_text);
         assertEquals(mActivity.getResources().getString(R.string.text_view_hello),
@@ -5392,28 +5565,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 +6607,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 +6617,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.
@@ -6567,19 +6789,17 @@
     public void testAutoSizeCallers_setHorizontallyScrolling() throws Throwable {
         final TextView autoSizeTextView = prepareAndRetrieveAutoSizeTestData(
                 R.id.textview_autosize_uniform, false);
+        // Verify that we do not have horizontal scrolling turned on.
+        assertTrue(!autoSizeTextView.getHorizontallyScrolling());
+
         final float initialTextSize = autoSizeTextView.getTextSize();
-        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
-                !autoSizeTextView.getHorizontallyScrolling()));
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(true));
         mInstrumentation.waitForIdleSync();
-        final float changedTextSize = autoSizeTextView.getTextSize();
+        assertTrue(autoSizeTextView.getTextSize() > initialTextSize);
 
-        assertTrue(changedTextSize < initialTextSize);
-
-        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(
-                autoSizeTextView.getHorizontallyScrolling()));
+        mActivityRule.runOnUiThread(() -> autoSizeTextView.setHorizontallyScrolling(false));
         mInstrumentation.waitForIdleSync();
-
-        assertEquals(changedTextSize, autoSizeTextView.getTextSize(), 0f);
+        assertEquals(initialTextSize, autoSizeTextView.getTextSize(), 0f);
     }
 
     @Test
@@ -6713,6 +6933,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(
@@ -7270,8 +7503,8 @@
         }
 
         private void calculatePositions() {
-            int xStart = (int) mParent.getLayout().getPrimaryHorizontal(mStartCharPos, true, true);
-            int xEnd = (int) mParent.getLayout().getPrimaryHorizontal(mEndCharPos, true, true);
+            int xStart = (int) mParent.getLayout().getPrimaryHorizontal(mStartCharPos, true);
+            int xEnd = (int) mParent.getLayout().getPrimaryHorizontal(mEndCharPos, true);
             int line = mParent.getLayout().getLineForOffset(mEndCharPos);
             int yTop = mParent.getLayout().getLineTop(line);
             int yBottom = mParent.getLayout().getLineBottom(line);
@@ -7411,8 +7644,8 @@
      */
     private static Point getCenterPositionOfTextAt(
             TextView textView, int startIndex, int endIndex) {
-        int xStart = (int) textView.getLayout().getPrimaryHorizontal(startIndex, true, true);
-        int xEnd = (int) textView.getLayout().getPrimaryHorizontal(endIndex, true, true);
+        int xStart = (int) textView.getLayout().getPrimaryHorizontal(startIndex, true);
+        int xEnd = (int) textView.getLayout().getPrimaryHorizontal(endIndex, true);
         int line = textView.getLayout().getLineForOffset(endIndex);
         int yTop = textView.getLayout().getLineTop(line);
         int yBottom = textView.getLayout().getLineBottom(line);
diff --git a/tools/cts-tradefed/res/config/cts-dev.xml b/tools/cts-tradefed/res/config/cts-dev.xml
index 97c3cdd..4ebda1b 100644
--- a/tools/cts-tradefed/res/config/cts-dev.xml
+++ b/tools/cts-tradefed/res/config/cts-dev.xml
@@ -20,6 +20,7 @@
     <option name="log-level" value="verbose" />
     <option name="skip-preconditions" value="true" />
     <option name="skip-device-info" value="true" />
+    <option name="result-reporter:compress-logs" value="false" />
 
     <option name="plan" value="cts-dev" />
     <option name="compatibility:skip-all-system-status-check" value="true" />
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 4c0d1af..f694daa 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -175,15 +175,16 @@
     <!-- b/31803630 -->
     <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
 
-    <!-- b/36812770 -->
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferNormal" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferNormal" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferNormal" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferFast" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testGyroscopeHardwareBufferFast" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testMagneticFieldHardwareBufferFast" />
-    <option name="compatibility:exclude-filter" value="CtsSensorTestCases android.hardware.cts.SensorDirectReportTest#testAccelerometerHardwareBufferVeryFast" />
-    <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/36686383 -->
+    <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.ErrorsTest#testANR" />
+
+    <!-- b/33090965 -->
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0320x0180" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf0640x0360" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1280x0720" />
+    <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.VideoEncoderDecoderTest#testVp9Goog0Perf1920x1080" />
+
+    <!-- b/37105075 -->
+    <option name="compatibility:exclude-filter" value="CtsIncidentHostTestCases com.android.server.cts.BatteryStatsValidationTest#testWifiUpload" />
 
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-vendor-interface.xml b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
index 582cebf..6785dd8 100644
--- a/tools/cts-tradefed/res/config/cts-vendor-interface.xml
+++ b/tools/cts-tradefed/res/config/cts-vendor-interface.xml
@@ -44,6 +44,7 @@
     <option name="compatibility:include-filter" value="CtsMonkeyTestCases" />
     <option name="compatibility:include-filter" value="CtsNetTestCases" />
     <option name="compatibility:include-filter" value="CtsOsTestCases" />
+    <option name="compatibility:include-filter" value="CtsPdfTestCases" />
     <option name="compatibility:include-filter" value="CtsPreference2TestCases" />
     <option name="compatibility:include-filter" value="CtsPrintTestCases" />
     <option name="compatibility:include-filter" value="CtsProviderTestCases" />
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
index 28a5c27..0e31afb 100644
--- a/tools/cts-tradefed/res/config/cts.xml
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -24,6 +24,10 @@
     <option name="test-tag" value="cts" />
 
     <option name="enable-root" value="false" />
+    <!-- retain 200MB of host log -->
+    <option name="max-log-size" value="200" />
+    <!--  retain 200MB of logcat -->
+    <option name="max-tmp-logcat-file" value="209715200" />
 
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
         <option name="property-name" value="ro.build.type" />