Merge "Relax timeouts to deflake"
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 4ee6926..b20e8a6 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -1724,6 +1724,11 @@
     <string name="aware_status_lifecycle_failed">Discovery lifecycle FAILURE!</string>
     <string name="aware_status_lifecycle_ok">Discovery lifecycle validated!</string>
 
+    <string name="aware_status_socket_failure">Failure on socket connection setup!</string>
+    <string name="aware_status_socket_server_socket_started">ServerSocket started on port %1$d!</string>
+    <string name="aware_status_socket_server_info_rx">Peer server info: IPv6=%1$s @ port=%2$d!</string>
+    <string name="aware_status_socket_server_message_from_peer">Message from peer: \'%1$s\'</string>
+
     <string name="aware_data_path_open_unsolicited_publish">Data Path: Open: Unsolicited Publish</string>
     <string name="aware_data_path_open_unsolicited_publish_info">The publisher is now ready.\n\nOn the other device: start the \'Data Path: Open: Unsolicited/Passive\' / \'Subscribe\' test.</string>
     <string name="aware_data_path_open_passive_subscribe">Data Path: Open: Passive Subscribe</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
index b1bd228..68c741e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/CallbackUtils.java
@@ -124,6 +124,7 @@
      */
     public static class NetworkCb extends ConnectivityManager.NetworkCallback {
         private CountDownLatch mBlocker = new CountDownLatch(1);
+        private Network mNetwork = null;
         private NetworkCapabilities mNetworkCapabilities = null;
 
         @Override
@@ -135,18 +136,20 @@
         @Override
         public void onCapabilitiesChanged(Network network,
                 NetworkCapabilities networkCapabilities) {
+            mNetwork = network;
             mNetworkCapabilities = networkCapabilities;
             mBlocker.countDown();
         }
 
         /**
-         * Wait (blocks) for Available or Unavailable callbacks - or timesout.
+         * Wait (blocks) for Capabilities Changed callback - or timesout.
          *
-         * @return true if Available, false otherwise (Unavailable or timeout).
+         * @return Network + NetworkCapabilities (pair) if occurred, null otherwise.
          */
-        public NetworkCapabilities waitForNetwork() throws InterruptedException {
+        public Pair<Network, NetworkCapabilities> waitForNetworkCapabilities()
+                throws InterruptedException {
             if (mBlocker.await(CALLBACK_TIMEOUT_SEC, TimeUnit.SECONDS)) {
-                return mNetworkCapabilities;
+                return Pair.create(mNetwork, mNetworkCapabilities);
             }
             return null;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
index 2f9bf4c..c5175c4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathInBandTestCase.java
@@ -20,13 +20,23 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.net.wifi.aware.WifiAwareManager;
+import android.net.wifi.aware.WifiAwareNetworkInfo;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.cts.verifier.R;
 import com.android.cts.verifier.wifiaware.CallbackUtils;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Inet6Address;
+import java.net.ServerSocket;
+import java.net.Socket;
 import java.util.Arrays;
 
 /**
@@ -44,7 +54,9 @@
  * 5. Wait for rx message
  * 6. Request network
  *    Wait for network
- * 7. Destroy session
+ * 7. Create socket and bind to server
+ * 8. Send/receive data to validate connection
+ * 9. Destroy session
  *
  * Publish test sequence:
  * 1. Attach
@@ -52,11 +64,13 @@
  * 2. Publish
  *    wait for results (publish session)
  * 3. Wait for rx message
- * 4. Request network
- * 5. Send message
+ * 4. Start a ServerSocket
+ * 5. Request network
+ * 6. Send message
  *    Wait for success
- * 6. Wait for network
- * 7. Destroy session
+ * 7. Wait for network
+ * 8. Receive/Send data to validate connection
+ * 9. Destroy session
  */
 public class DataPathInBandTestCase extends DiscoveryBaseTestCase {
     private static final String TAG = "DataPathInBandTestCase";
@@ -65,8 +79,14 @@
     private static final byte[] MSG_PUB_TO_SUB = "Ready".getBytes();
     private static final String PASSPHRASE = "Some super secret password";
 
+    private static final byte[] MSG_CLIENT_TO_SERVER = "GET SOME BYTES".getBytes();
+    private static final byte[] MSG_SERVER_TO_CLIENT = "PUT SOME OTHER BYTES".getBytes();
+
     private boolean mIsSecurityOpen;
     private boolean mIsPublish;
+    private Thread mClientServerThread;
+    private ConnectivityManager mCm;
+    private CallbackUtils.NetworkCb mNetworkCb;
 
     public DataPathInBandTestCase(Context context, boolean isSecurityOpen, boolean isPublish,
             boolean isUnsolicited) {
@@ -84,6 +104,10 @@
                             + ", mIsUnsolicited=" + mIsUnsolicited);
         }
 
+        mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mClientServerThread = null;
+        mNetworkCb = null;
+
         boolean success;
         if (mIsPublish) {
             success = executeTestPublisher();
@@ -102,6 +126,18 @@
         return true;
     }
 
+    @Override
+    protected void tearDown() {
+        if (mClientServerThread != null) {
+            mClientServerThread.interrupt();
+        }
+        if (mNetworkCb != null) {
+            mCm.unregisterNetworkCallback(mNetworkCb);
+        }
+        super.tearDown();
+    }
+
+
     private boolean executeTestSubscriber() throws InterruptedException {
         if (DBG) Log.d(TAG, "executeTestSubscriber");
         if (!executeSubscribe()) {
@@ -129,33 +165,118 @@
         }
 
         // 6. request network
-        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
+        WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                        mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+        if (!mIsSecurityOpen) {
+            nsBuilder.setPskPassphrase(PASSPHRASE);
+        }
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
-                mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
-                        : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
-                                PASSPHRASE)).build();
-        CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
-        cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+                nsBuilder.build()).build();
+        mNetworkCb = new CallbackUtils.NetworkCb();
+        mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(
                 mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestSubscriber: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
-        cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+
+        // 7. wait for network
+        Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
-            Log.e(TAG, "executeTestSubscriber: network request rejected - ON_UNAVAILABLE");
+            Log.e(TAG, "executeTestSubscriber: network request rejected or timed-out");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.first == null || info.second == null) {
+            setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+            Log.e(TAG, "executeTestSubscriber: received a null Network or NetworkCapabilities!?");
+            return false;
+        }
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
         }
+
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
         if (DBG) Log.d(TAG, "executeTestSubscriber: network request granted - AVAILABLE");
 
+        if (!mIsSecurityOpen) {
+            if (!(info.second.getTransportInfo() instanceof WifiAwareNetworkInfo)) {
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: did not get WifiAwareNetworkInfo from peer!?");
+                return false;
+            }
+            WifiAwareNetworkInfo peerAwareInfo =
+                    (WifiAwareNetworkInfo) info.second.getTransportInfo();
+            Inet6Address peerIpv6 = peerAwareInfo.getPeerIpv6Addr();
+            int peerPort = peerAwareInfo.getPort();
+            int peerTransportProtocol = peerAwareInfo.getTransportProtocol();
+            mListener.onTestMsgReceived(
+                    mContext.getString(R.string.aware_status_socket_server_info_rx,
+                            peerIpv6.toString(),
+                            peerPort));
+            if (DBG) {
+                Log.d(TAG,
+                        "executeTestPublisher: rx peer info IPv6=" + peerIpv6 + ", port=" + peerPort
+                                + ", transportProtocol=" + peerTransportProtocol);
+            }
+            if (peerTransportProtocol != 6) { // 6 == TCP: hard coded at peer
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: Got incorrect transport protocol from peer");
+                return false;
+            }
+            if (peerPort <= 0) {
+                setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+                Log.e(TAG, "executeTestSubscriber: Got invalid port from peer (<=0)");
+                return false;
+            }
+
+            // 8. send/receive - can happen inline here - no need for another thread
+            String currentMethod = "";
+            try {
+                currentMethod = "createSocket";
+                Socket socket = info.first.getSocketFactory().createSocket(peerIpv6, peerPort);
+
+                // simple interaction: write X bytes, read Y bytes
+                currentMethod = "getOutputStream()";
+                OutputStream os = socket.getOutputStream();
+                currentMethod = "write()";
+                os.write(MSG_CLIENT_TO_SERVER, 0, MSG_CLIENT_TO_SERVER.length);
+
+                byte[] buffer = new byte[1024];
+                currentMethod = "getInputStream()";
+                InputStream is = socket.getInputStream();
+                currentMethod = "read()";
+                int numBytes = is.read(buffer, 0, MSG_SERVER_TO_CLIENT.length);
+
+                mListener.onTestMsgReceived(
+                        mContext.getString(R.string.aware_status_socket_server_message_from_peer,
+                                new String(buffer, 0, numBytes)));
+
+                if (numBytes != MSG_SERVER_TO_CLIENT.length) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG,
+                            "executeTestSubscriber: didn't read expected number of bytes - only "
+                                    + "got -- " + numBytes);
+                    return false;
+                }
+                if (!Arrays.equals(MSG_SERVER_TO_CLIENT,
+                        Arrays.copyOf(buffer, MSG_SERVER_TO_CLIENT.length))) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG, "executeTestSubscriber: did not get expected message from server.");
+                    return false;
+                }
+
+                currentMethod = "close()";
+                os.close();
+            } catch (IOException e) {
+                setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG, "executeTestSubscriber: failure while executing " + currentMethod);
+                return false;
+            }
+        }
+
         return true;
     }
 
@@ -165,21 +286,90 @@
             return false;
         }
 
-        // 4. Request network
-        ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
-                Context.CONNECTIVITY_SERVICE);
+        // 4. create a ServerSocket
+        int port = 0;
+        if (!mIsSecurityOpen) {
+            ServerSocket server;
+            try {
+                server = new ServerSocket(0);
+            } catch (IOException e) {
+                setFailureReason(
+                        mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG, "executeTestPublisher: failure creating a ServerSocket -- " + e);
+                return false;
+            }
+            port = server.getLocalPort();
+            mListener.onTestMsgReceived(
+                    mContext.getString(R.string.aware_status_socket_server_socket_started, port));
+            if (DBG) Log.d(TAG, "executeTestPublisher: server socket started on port=" + port);
+
+            // accept connections on the server socket - has to be done in a separate thread!
+            mClientServerThread = new Thread(() -> {
+                String currentMethod = "";
+
+                try {
+                    currentMethod = "accept()";
+                    Socket socket = server.accept();
+                    currentMethod = "getInputStream()";
+                    InputStream is = socket.getInputStream();
+
+                    // simple interaction: read X bytes, write Y bytes
+                    byte[] buffer = new byte[1024];
+                    currentMethod = "read()";
+                    int numBytes = is.read(buffer, 0, MSG_CLIENT_TO_SERVER.length);
+
+                    mListener.onTestMsgReceived(mContext.getString(
+                            R.string.aware_status_socket_server_message_from_peer,
+                            new String(buffer, 0, numBytes)));
+
+                    if (numBytes != MSG_CLIENT_TO_SERVER.length) {
+                        setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                        Log.e(TAG,
+                                "executeTestPublisher: didn't read expected number of bytes - only "
+                                        + "got -- " + numBytes);
+                        return;
+                    }
+                    if (!Arrays.equals(MSG_CLIENT_TO_SERVER,
+                            Arrays.copyOf(buffer, MSG_CLIENT_TO_SERVER.length))) {
+                        setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                        Log.e(TAG,
+                                "executeTestPublisher: did not get expected message from client.");
+                        return;
+                    }
+
+                    currentMethod = "getOutputStream()";
+                    OutputStream os = socket.getOutputStream();
+                    currentMethod = "write()";
+                    os.write(MSG_SERVER_TO_CLIENT, 0, MSG_SERVER_TO_CLIENT.length);
+                    currentMethod = "close()";
+                    os.close();
+                } catch (IOException e) {
+                    setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                    Log.e(TAG, "executeTestPublisher: failure while executing " + currentMethod);
+                    return;
+                }
+            });
+            mClientServerThread.start();
+        }
+
+        // 5. Request network
+        WifiAwareManager.NetworkSpecifierBuilder nsBuilder =
+                new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+                        mWifiAwareDiscoverySession).setPeerHandle(mPeerHandle);
+        if (!mIsSecurityOpen) {
+            nsBuilder.setPskPassphrase(PASSPHRASE).setPort(port).setTransportProtocol(
+                    6); // 6 == TCP
+        }
         NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
                 NetworkCapabilities.TRANSPORT_WIFI_AWARE).setNetworkSpecifier(
-                mIsSecurityOpen ? mWifiAwareDiscoverySession.createNetworkSpecifierOpen(mPeerHandle)
-                        : mWifiAwareDiscoverySession.createNetworkSpecifierPassphrase(mPeerHandle,
-                                PASSPHRASE)).build();
-        CallbackUtils.NetworkCb networkCb = new CallbackUtils.NetworkCb();
-        cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
+                nsBuilder.build()).build();
+        mNetworkCb = new CallbackUtils.NetworkCb();
+        mCm.requestNetwork(nr, mNetworkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(
                 mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestPublisher: requested network");
 
-        // 5. send message & wait for send status
+        // 6. send message & wait for send status
         mWifiAwareDiscoverySession.sendMessage(mPeerHandle, MESSAGE_ID, MSG_PUB_TO_SUB);
         CallbackUtils.DiscoveryCb.CallbackData callbackData = mDiscoveryCb.waitForCallbacks(
                 CallbackUtils.DiscoveryCb.ON_MESSAGE_SEND_SUCCEEDED
@@ -204,15 +394,19 @@
             return false;
         }
 
-        // 6. wait for network
-        NetworkCapabilities nc = networkCb.waitForNetwork();
-        cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        // 7. wait for network
+        Pair<Network, NetworkCapabilities> info = mNetworkCb.waitForNetworkCapabilities();
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestPublisher: request network rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.first == null || info.second == null) {
+            setFailureReason(mContext.getString(R.string.aware_status_network_failed));
+            Log.e(TAG, "executeTestPublisher: received a null Network or NetworkCapabilities!?");
+            return false;
+        }
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
@@ -220,6 +414,18 @@
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_success));
         if (DBG) Log.d(TAG, "executeTestPublisher: network request granted - AVAILABLE");
 
+        // 8. Send/Receive data to validate connection - happens on thread above
+        if (!mIsSecurityOpen) {
+            mClientServerThread.join(CALLBACK_TIMEOUT_SEC * 1000);
+            if (mClientServerThread.isAlive()) {
+                setFailureReason(mContext.getString(R.string.aware_status_socket_failure));
+                Log.e(TAG,
+                        "executeTestPublisher: failure while waiting for client-server thread to "
+                                + "finish");
+                return false;
+            }
+        }
+
         return true;
     }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
index be198e1..0d6ca8f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/wifiaware/testcase/DataPathOutOfBandTestCase.java
@@ -20,6 +20,7 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
+import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.wifi.aware.DiscoverySession;
@@ -284,14 +285,14 @@
         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestResponder: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
+        Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
         cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestResponder: network request rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
@@ -423,14 +424,14 @@
         cm.requestNetwork(nr, networkCb, CALLBACK_TIMEOUT_SEC * 1000);
         mListener.onTestMsgReceived(mContext.getString(R.string.aware_status_network_requested));
         if (DBG) Log.d(TAG, "executeTestInitiator: requested network");
-        NetworkCapabilities nc = networkCb.waitForNetwork();
+        Pair<Network, NetworkCapabilities> info = networkCb.waitForNetworkCapabilities();
         cm.unregisterNetworkCallback(networkCb);
-        if (nc == null) {
+        if (info == null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed));
             Log.e(TAG, "executeTestInitiator: network request rejected - ON_UNAVAILABLE");
             return false;
         }
-        if (nc.getNetworkSpecifier() != null) {
+        if (info.second.getNetworkSpecifier() != null) {
             setFailureReason(mContext.getString(R.string.aware_status_network_failed_leak));
             Log.e(TAG, "executeTestSubscriber: network request accepted - but leaks NS!");
             return false;
diff --git a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
index bf5dc39..7500050 100644
--- a/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
+++ b/common/device-side/util/src/com/android/compatibility/common/util/BroadcastTestBase.java
@@ -54,6 +54,8 @@
 
     @Override
     protected void tearDown() throws Exception {
+        Log.v(TAG, getClass().getSimpleName() + ".tearDown(): hasFeature=" + mHasFeature
+                + " receiver=" + mActivityDoneReceiver);
         if (mHasFeature && mActivityDoneReceiver != null) {
             try {
                 mContext.unregisterReceiver(mActivityDoneReceiver);
diff --git a/hostsidetests/appbinding/app/app1/AndroidManifest.xml b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
index b3b55e8..b2c49db 100644
--- a/hostsidetests/appbinding/app/app1/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app1/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name=".MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE">
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE">
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app2/AndroidManifest.xml b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
index 7890c6f..7be1599 100644
--- a/hostsidetests/appbinding/app/app2/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app2/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name=".MyService2"
             android:exported="false"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app3/AndroidManifest.xml b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
index ec7a4bf..52080ee 100644
--- a/hostsidetests/appbinding/app/app3/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app3/AndroidManifest.xml
@@ -32,7 +32,7 @@
             android:exported="false"
             android:process=":persistent">
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app4/AndroidManifest.xml b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
index 5df5fa8..560c4c1 100644
--- a/hostsidetests/appbinding/app/app4/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app4/AndroidManifest.xml
@@ -31,18 +31,18 @@
             android:name=".MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
         <service
             android:name=".MyService2"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/app6/AndroidManifest.xml b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
index abea148..cf704d7 100644
--- a/hostsidetests/appbinding/app/app6/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/app6/AndroidManifest.xml
@@ -30,9 +30,9 @@
         <service
             android:name=".MyService2"
             android:exported="false"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/appb/AndroidManifest.xml b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
index 3a1c5d3..e6336a6 100644
--- a/hostsidetests/appbinding/app/appb/AndroidManifest.xml
+++ b/hostsidetests/appbinding/app/appb/AndroidManifest.xml
@@ -31,9 +31,9 @@
             android:name="com.android.cts.appbinding.app.MyService"
             android:exported="true"
             android:process=":persistent"
-            android:permission="android.permission.BIND_SMS_APP_SERVICE" >
+            android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE" >
             <intent-filter>
-                <action android:name="android.telephony.action.SMS_APP_SERVICE" />
+                <action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" />
             </intent-filter>
         </service>
 
diff --git a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
index 5df2fa9..9a569f3 100644
--- a/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
+++ b/hostsidetests/appbinding/app/src/com/android/cts/appbinding/app/MyService.java
@@ -15,12 +15,12 @@
  */
 package com.android.cts.appbinding.app;
 
-import android.app.SmsAppService;
+import android.service.carrier.CarrierMessagingClientService;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-public class MyService extends SmsAppService {
+public class MyService extends CarrierMessagingClientService {
     @Override
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
 
@@ -31,6 +31,6 @@
             return;
         }
         writer.print("Package=[" + getPackageName() + "]");
-        writer.println("Class=[" + this.getClass().getName() + "]");
+        writer.println(" Class=[" + this.getClass().getName() + "]");
     }
 }
diff --git a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
index dd4c438..5c37e01 100644
--- a/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
+++ b/hostsidetests/appbinding/hostside/src/com/android/cts/appbinding/AppBindingHostTest.java
@@ -321,7 +321,7 @@
      */
     public void testSimpleNotBound3() throws Throwable {
         installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
     }
 
     /**
@@ -336,7 +336,7 @@
      */
     public void testSimpleNotBound5() throws Throwable {
         installAndCheckNotBound(APK_5, PACKAGE_A, USER_SYSTEM,
-                "Service with android.telephony.action.SMS_APP_SERVICE not found");
+                "Service with android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE not found");
     }
 
     /**
@@ -355,7 +355,7 @@
         installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
         installAndCheckBound(APK_2, PACKAGE_A, SERVICE_2, USER_SYSTEM);
         installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
         installAndCheckBound(APK_1, PACKAGE_A, SERVICE_1, USER_SYSTEM);
         installAndCheckNotBound(APK_4, PACKAGE_A, USER_SYSTEM, "More than one");
     }
@@ -398,7 +398,7 @@
 
             // Replace the app on the primary user with an invalid one.
             installAndCheckNotBound(APK_3, PACKAGE_A, USER_SYSTEM,
-                    "must be protected with android.permission.BIND_SMS_APP_SERVICE");
+                    "must be protected with android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE");
 
             // Secondary user should still have a valid connection.
             checkBound(PACKAGE_B, SERVICE_1, userId);
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
deleted file mode 100644
index 1adf0f8..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/Android.mk
+++ /dev/null
@@ -1,36 +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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitApp
-
-# Tag this module as a cts test artifact
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
deleted file mode 100644
index f37be44..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/Android.mk
+++ /dev/null
@@ -1,35 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_EXPORT_PACKAGE_RESOURCES := true
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureA
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS += --custom-package com.android.cts.classloadersplitapp.feature_a
-LOCAL_AAPT_FLAGS += --package-id 0x80
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk b/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
deleted file mode 100644
index 3262e15..0000000
--- a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/Android.mk
+++ /dev/null
@@ -1,34 +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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_USE_AAPT2 := true
-LOCAL_MODULE_TAGS := tests
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-LOCAL_PACKAGE_NAME := CtsClassloaderSplitAppFeatureB
-LOCAL_SDK_VERSION := current
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_APK_LIBRARIES := CtsClassloaderSplitApp CtsClassloaderSplitAppFeatureA
-LOCAL_RES_LIBRARIES := $(LOCAL_APK_LIBRARIES)
-
-LOCAL_AAPT_FLAGS := --custom-package com.android.cts.classloadersplitapp.feature_b
-LOCAL_AAPT_FLAGS += --package-id 0x81
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
deleted file mode 100644
index df12f82..0000000
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SDK_VERSION := current
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test compatibility-device-util ctstestrunner ub-uiautomator
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
-    ../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
-
-LOCAL_PACKAGE_NAME := CtsUsesLibraryApp
-
-# tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
-
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/classloaders/splits/Android.bp b/hostsidetests/classloaders/splits/Android.bp
new file mode 100644
index 0000000..17f02a7
--- /dev/null
+++ b/hostsidetests/classloaders/splits/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2019 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.
+
+java_test_host {
+    name: "CtsClassloaderSplitsHostTestCases",
+    defaults: [ "cts_defaults" ],
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    required: [
+        "CtsClassloaderSplitApp",
+        "CtsClassloaderSplitAppFeatureA",
+        "CtsClassloaderSplitAppFeatureB",
+    ],
+}
diff --git a/hostsidetests/classloaders/splits/AndroidTest.xml b/hostsidetests/classloaders/splits/AndroidTest.xml
new file mode 100644
index 0000000..77b5bce
--- /dev/null
+++ b/hostsidetests/classloaders/splits/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for the CTS Classloader Splits host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsClassloaderSplitsHostTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/classloaders/splits/TEST_MAPPING b/hostsidetests/classloaders/splits/TEST_MAPPING
new file mode 100644
index 0000000..18f00dd
--- /dev/null
+++ b/hostsidetests/classloaders/splits/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsClassloaderSplitsHostTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/classloaders/splits/apps/Android.bp b/hostsidetests/classloaders/splits/apps/Android.bp
new file mode 100644
index 0000000..ebd9318
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2019 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.
+
+android_test {
+    name: "CtsClassloaderSplitApp",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "android-support-test",
+        "ctstestrunner",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/AndroidManifest.xml
diff --git a/hostsidetests/classloaders/splits/apps/feature_a/Android.bp b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
new file mode 100644
index 0000000..0fd7091
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_a/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 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.
+
+android_test_helper_app {
+    name: "CtsClassloaderSplitAppFeatureA",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: [ "src/**/*.java" ],
+    libs: [ "CtsClassloaderSplitApp" ],
+    aaptflags: [
+        "--custom-package",
+        "com.android.cts.classloadersplitapp.feature_a",
+        "--package-id",
+        "0x80",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_a/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java b/hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_a/src/com/android/cts/classloadersplitapp/feature_a/FeatureAReceiver.java
diff --git a/hostsidetests/classloaders/splits/apps/feature_b/Android.bp b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
new file mode 100644
index 0000000..2643840
--- /dev/null
+++ b/hostsidetests/classloaders/splits/apps/feature_b/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2019 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.
+
+android_test_helper_app {
+    name: "CtsClassloaderSplitAppFeatureB",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "CtsClassloaderSplitApp",
+        "CtsClassloaderSplitAppFeatureA",
+    ],
+    aaptflags: [
+        "--custom-package",
+        "com.android.cts.classloadersplitapp.feature_a",
+        "--package-id",
+        "0x81",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml b/hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/AndroidManifest.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values-pl/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values-pl/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml b/hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/res/values/values.xml
rename to hostsidetests/classloaders/splits/apps/feature_b/res/values/values.xml
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java b/hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
rename to hostsidetests/classloaders/splits/apps/feature_b/src/com/android/cts/classloadersplitapp/feature_b/FeatureBReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseActivity.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseActivity.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/BaseReceiver.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/BaseReceiver.java
diff --git a/hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java b/hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/ClassLoaderSplitApp/src/com/android/cts/classloadersplitapp/SplitAppTest.java
rename to hostsidetests/classloaders/splits/apps/src/com/android/cts/classloadersplitapp/SplitAppTest.java
diff --git a/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ *     private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; {
+ *         public InstallMultiple() {
+ *             super(getDevice(), null, null);
+ *         }
+ *     }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+    private final ITestDevice mDevice;
+    private final IBuildInfo mBuild;
+    private final IAbi mAbi;
+
+    private final List<String> mArgs = new ArrayList<>();
+    private final List<File> mApks = new ArrayList<>();
+    private boolean mUseNaturalAbi;
+
+    public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+        mDevice = device;
+        mBuild = buildInfo;
+        mAbi = abi;
+        addArg("-g");
+    }
+
+    T addArg(String arg) {
+        mArgs.add(arg);
+        return (T) this;
+    }
+
+    T addApk(String apk) throws FileNotFoundException {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        mApks.add(buildHelper.getTestFile(apk));
+        return (T) this;
+    }
+
+    T inheritFrom(String packageName) {
+        addArg("-r");
+        addArg("-p " + packageName);
+        return (T) this;
+    }
+
+    T useNaturalAbi() {
+        mUseNaturalAbi = true;
+        return (T) this;
+    }
+
+    T allowTest() {
+        addArg("-t");
+        return (T) this;
+    }
+
+    T locationAuto() {
+        addArg("--install-location 0");
+        return (T) this;
+    }
+
+    T locationInternalOnly() {
+        addArg("--install-location 1");
+        return (T) this;
+    }
+
+    T locationPreferExternal() {
+        addArg("--install-location 2");
+        return (T) this;
+    }
+
+    T forceUuid(String uuid) {
+        addArg("--force-uuid " + uuid);
+        return (T) this;
+    }
+
+    T forUser(int userId) {
+        addArg("--user " + userId);
+        return (T) this;
+    }
+
+    void run() throws DeviceNotAvailableException {
+        run(true, null);
+    }
+
+    void runExpectingFailure() throws DeviceNotAvailableException {
+        run(false, null);
+    }
+
+    void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+        run(false, failure);
+    }
+
+    private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+        final ITestDevice device = mDevice;
+
+        // Create an install session
+        final StringBuilder cmd = new StringBuilder();
+        cmd.append("pm install-create");
+        for (String arg : mArgs) {
+            cmd.append(' ').append(arg);
+        }
+        if (!mUseNaturalAbi && mAbi != null) {
+            cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+        }
+
+        String result = device.executeShellCommand(cmd.toString());
+        TestCase.assertTrue(result, result.startsWith("Success"));
+
+        final int start = result.lastIndexOf("[");
+        final int end = result.lastIndexOf("]");
+        int sessionId = -1;
+        try {
+            if (start != -1 && end != -1 && start < end) {
+                sessionId = Integer.parseInt(result.substring(start + 1, end));
+            }
+        } catch (NumberFormatException e) {
+        }
+        if (sessionId == -1) {
+            throw new IllegalStateException("Failed to create install session: " + result);
+        }
+
+        // Push our files into session. Ideally we'd use stdin streaming,
+        // but ddmlib doesn't support it yet.
+        for (int i = 0; i < mApks.size(); i++) {
+            final File apk = mApks.get(i);
+            final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+            if (!device.pushFile(apk, remotePath)) {
+                throw new IllegalStateException("Failed to push " + apk);
+            }
+
+            cmd.setLength(0);
+            cmd.append("pm install-write");
+            cmd.append(' ').append(sessionId);
+            cmd.append(' ').append(i + "_" + apk.getName());
+            cmd.append(' ').append(remotePath);
+
+            result = device.executeShellCommand(cmd.toString());
+            TestCase.assertTrue(result, result.startsWith("Success"));
+        }
+
+        // Everything staged; let's pull trigger
+        cmd.setLength(0);
+        cmd.append("pm install-commit");
+        cmd.append(' ').append(sessionId);
+
+        result = device.executeShellCommand(cmd.toString()).trim();
+        if (failure == null) {
+            if (expectingSuccess) {
+                TestCase.assertTrue(result, result.startsWith("Success"));
+            } else {
+                TestCase.assertFalse(result, result.startsWith("Success"));
+            }
+        } else {
+            TestCase.assertTrue(result, result.contains(failure));
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
similarity index 89%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
rename to hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
index 4e54bc4..1460bfc 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ClassloaderSplitsTest.java
+++ b/hostsidetests/classloaders/splits/src/android/classloaders/cts/ClassloaderSplitsTest.java
@@ -13,11 +13,12 @@
  * License for the specific language governing permissions and limitations
  * under the License.
  */
-package android.appsecurity.cts;
+package android.classloaders.cts;
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import org.junit.After;
 import org.junit.Before;
@@ -25,7 +26,7 @@
 import org.junit.runner.RunWith;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class ClassloaderSplitsTest extends BaseAppSecurityTest {
+public class ClassloaderSplitsTest extends BaseHostJUnit4Test {
     private static final String PKG = "com.android.cts.classloadersplitapp";
     private static final String TEST_CLASS = PKG + ".SplitAppTest";
 
@@ -47,7 +48,6 @@
 
     @Before
     public void setUp() throws Exception {
-        Utils.prepareSingleUser(getDevice());
         getDevice().uninstallPackage(PKG);
     }
 
@@ -116,4 +116,14 @@
         runDeviceTests(getDevice(), PKG, TEST_CLASS, "testBaseClassLoader");
         runDeviceTests(getDevice(), PKG, TEST_CLASS, "testAllReceivers");
     }
+
+    protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            this(false);
+        }
+        public InstallMultiple(boolean instant) {
+            super(getDevice(), getBuild(), getAbi());
+            addArg(instant ? "--instant" : "");
+        }
+    }
 }
diff --git a/hostsidetests/classloaders/useslibrary/Android.bp b/hostsidetests/classloaders/useslibrary/Android.bp
new file mode 100644
index 0000000..603b2ec
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2019 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.
+
+java_test_host {
+    name: "CtsUsesLibraryHostTestCases",
+    defaults: [ "cts_defaults" ],
+    srcs: [ "src/**/*.java" ],
+    libs: [
+        "compatibility-host-util",
+        "cts-tradefed",
+        "tradefed",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    required: [ "CtsUsesLibraryApp" ],
+}
diff --git a/hostsidetests/classloaders/useslibrary/AndroidTest.xml b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
new file mode 100644
index 0000000..b7796d7
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/AndroidTest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Config for the CTS UsesLibrary host tests">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+        <option name="jar" value="CtsUsesLibraryHostTestCases.jar" />
+        <option name="runtime-hint" value="1m" />
+    </test>
+</configuration>
diff --git a/hostsidetests/classloaders/useslibrary/TEST_MAPPING b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
new file mode 100644
index 0000000..72ef61b
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsUsesLibraryHostTestCases"
+    }
+  ]
+}
diff --git a/hostsidetests/classloaders/useslibrary/app/Android.bp b/hostsidetests/classloaders/useslibrary/app/Android.bp
new file mode 100644
index 0000000..faf7a22
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/app/Android.bp
@@ -0,0 +1,32 @@
+// Copyright (C) 2019 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.
+
+android_test {
+    name: "CtsUsesLibraryApp",
+    defaults: [ "cts_support_defaults" ],
+    sdk_version: "current",
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.base.stubs",
+    ],
+    static_libs: [
+        "android-support-test",
+        "ctstestrunner",
+    ],
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml b/hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
similarity index 100%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/AndroidManifest.xml
rename to hostsidetests/classloaders/useslibrary/app/AndroidManifest.xml
diff --git a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
similarity index 95%
rename from hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
rename to hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
index 73b820d..7fa8b20 100644
--- a/hostsidetests/appsecurity/test-apps/UsesLibraryApp/src/com/android/cts/useslibrary/UsesLibraryTest.java
+++ b/hostsidetests/classloaders/useslibrary/app/src/com/android/cts/useslibrary/UsesLibraryTest.java
@@ -16,11 +16,6 @@
 
 package com.android.cts.useslibrary;
 
-import android.content.pm.PackageManager;
-import android.os.Environment;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 
 import dalvik.system.BaseDexClassLoader;
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
new file mode 100644
index 0000000..f5170e9
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/BaseInstallMultiple.java
@@ -0,0 +1,187 @@
+/*
+ * 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.classloaders.cts;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.util.AbiUtils;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base class for invoking the install-multiple command via ADB. Subclass this for less typing:
+ *
+ * <code>
+ *     private class InstallMultiple extends BaseInstallMultiple&lt;InstallMultiple&gt; {
+ *         public InstallMultiple() {
+ *             super(getDevice(), null, null);
+ *         }
+ *     }
+ * </code>
+ */
+public class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
+    private final ITestDevice mDevice;
+    private final IBuildInfo mBuild;
+    private final IAbi mAbi;
+
+    private final List<String> mArgs = new ArrayList<>();
+    private final List<File> mApks = new ArrayList<>();
+    private boolean mUseNaturalAbi;
+
+    public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
+        mDevice = device;
+        mBuild = buildInfo;
+        mAbi = abi;
+        addArg("-g");
+    }
+
+    T addArg(String arg) {
+        mArgs.add(arg);
+        return (T) this;
+    }
+
+    T addApk(String apk) throws FileNotFoundException {
+        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+        mApks.add(buildHelper.getTestFile(apk));
+        return (T) this;
+    }
+
+    T inheritFrom(String packageName) {
+        addArg("-r");
+        addArg("-p " + packageName);
+        return (T) this;
+    }
+
+    T useNaturalAbi() {
+        mUseNaturalAbi = true;
+        return (T) this;
+    }
+
+    T allowTest() {
+        addArg("-t");
+        return (T) this;
+    }
+
+    T locationAuto() {
+        addArg("--install-location 0");
+        return (T) this;
+    }
+
+    T locationInternalOnly() {
+        addArg("--install-location 1");
+        return (T) this;
+    }
+
+    T locationPreferExternal() {
+        addArg("--install-location 2");
+        return (T) this;
+    }
+
+    T forceUuid(String uuid) {
+        addArg("--force-uuid " + uuid);
+        return (T) this;
+    }
+
+    T forUser(int userId) {
+        addArg("--user " + userId);
+        return (T) this;
+    }
+
+    void run() throws DeviceNotAvailableException {
+        run(true, null);
+    }
+
+    void runExpectingFailure() throws DeviceNotAvailableException {
+        run(false, null);
+    }
+
+    void runExpectingFailure(String failure) throws DeviceNotAvailableException {
+        run(false, failure);
+    }
+
+    private void run(boolean expectingSuccess, String failure) throws DeviceNotAvailableException {
+        final ITestDevice device = mDevice;
+
+        // Create an install session
+        final StringBuilder cmd = new StringBuilder();
+        cmd.append("pm install-create");
+        for (String arg : mArgs) {
+            cmd.append(' ').append(arg);
+        }
+        if (!mUseNaturalAbi && mAbi != null) {
+            cmd.append(' ').append(AbiUtils.createAbiFlag(mAbi.getName()));
+        }
+
+        String result = device.executeShellCommand(cmd.toString());
+        TestCase.assertTrue(result, result.startsWith("Success"));
+
+        final int start = result.lastIndexOf("[");
+        final int end = result.lastIndexOf("]");
+        int sessionId = -1;
+        try {
+            if (start != -1 && end != -1 && start < end) {
+                sessionId = Integer.parseInt(result.substring(start + 1, end));
+            }
+        } catch (NumberFormatException e) {
+        }
+        if (sessionId == -1) {
+            throw new IllegalStateException("Failed to create install session: " + result);
+        }
+
+        // Push our files into session. Ideally we'd use stdin streaming,
+        // but ddmlib doesn't support it yet.
+        for (int i = 0; i < mApks.size(); i++) {
+            final File apk = mApks.get(i);
+            final String remotePath = "/data/local/tmp/" + i + "_" + apk.getName();
+            if (!device.pushFile(apk, remotePath)) {
+                throw new IllegalStateException("Failed to push " + apk);
+            }
+
+            cmd.setLength(0);
+            cmd.append("pm install-write");
+            cmd.append(' ').append(sessionId);
+            cmd.append(' ').append(i + "_" + apk.getName());
+            cmd.append(' ').append(remotePath);
+
+            result = device.executeShellCommand(cmd.toString());
+            TestCase.assertTrue(result, result.startsWith("Success"));
+        }
+
+        // Everything staged; let's pull trigger
+        cmd.setLength(0);
+        cmd.append("pm install-commit");
+        cmd.append(' ').append(sessionId);
+
+        result = device.executeShellCommand(cmd.toString()).trim();
+        if (failure == null) {
+            if (expectingSuccess) {
+                TestCase.assertTrue(result, result.startsWith("Success"));
+            } else {
+                TestCase.assertFalse(result, result.startsWith("Success"));
+            }
+        } else {
+            TestCase.assertTrue(result, result.contains(failure));
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
similarity index 84%
rename from hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
rename to hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
index 41ce7a1..aecd87b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/UsesLibraryHostTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.appsecurity.cts;
+package android.classloaders.cts;
 
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.AppModeInstant;
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
 import org.junit.After;
 import org.junit.Before;
@@ -32,7 +33,7 @@
  */
 @AppModeFull(reason = "TODO verify whether or not these should run in instant mode")
 @RunWith(DeviceJUnit4ClassRunner.class)
-public class UsesLibraryHostTest extends BaseAppSecurityTest {
+public class UsesLibraryHostTest extends BaseHostJUnit4Test {
     private static final String PKG = "com.android.cts.useslibrary";
 
     private static final String APK = "CtsUsesLibraryApp.apk";
@@ -79,4 +80,14 @@
         new InstallMultiple(instant).addApk(APK).run();
         Utils.runDeviceTests(getDevice(), PKG, ".UsesLibraryTest", "testDuplicateLibrary");
     }
+
+    protected class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
+        public InstallMultiple() {
+            this(false);
+        }
+        public InstallMultiple(boolean instant) {
+            super(getDevice(), getBuild(), getAbi());
+            addArg(instant ? "--instant" : "");
+        }
+    }
 }
diff --git a/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
new file mode 100644
index 0000000..48497d8
--- /dev/null
+++ b/hostsidetests/classloaders/useslibrary/src/android/classloaders/cts/Utils.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2014 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.classloaders.cts;
+
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
+import com.android.ddmlib.testrunner.TestResult.TestStatus;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class Utils {
+    public static final int USER_SYSTEM = 0;
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, null);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, Map<String, String> testArgs)
+                    throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM, testArgs);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId) throws DeviceNotAvailableException {
+        runDeviceTests(device, packageName, testClassName, testMethodName, userId, null);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId, Map<String, String> testArgs)
+                    throws DeviceNotAvailableException {
+        // 60 min timeout per test by default
+        runDeviceTests(device, packageName, testClassName, testMethodName, userId, testArgs,
+                60L, TimeUnit.MINUTES);
+    }
+
+    public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
+            String testMethodName, int userId, Map<String, String> testArgs, long timeout,
+            TimeUnit unit)
+                    throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = packageName + testClassName;
+        }
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(packageName,
+                "android.support.test.runner.AndroidJUnitRunner", device.getIDevice());
+        // timeout_msec is the timeout per test for instrumentation
+        testRunner.addInstrumentationArg("timeout_msec", Long.toString(unit.toMillis(timeout)));
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        if (testArgs != null && testArgs.size() > 0) {
+            for (String name : testArgs.keySet()) {
+                final String value = testArgs.get(name);
+                testRunner.addInstrumentationArg(name, value);
+            }
+        }
+        final CollectingTestListener listener = new CollectingTestListener();
+        device.runInstrumentationTestsAsUser(testRunner, userId, listener);
+
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new AssertionError("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+        if (result.getNumTests() == 0) {
+            throw new AssertionError("No tests were run on the device");
+        }
+        if (result.hasFailedTests()) {
+            // build a meaningful error message
+            StringBuilder errorBuilder = new StringBuilder("on-device tests failed:\n");
+            for (Map.Entry<TestDescription, TestResult> resultEntry :
+                result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
+    }
+
+    /**
+     * Prepare and return a single user relevant for testing.
+     */
+    public static int[] prepareSingleUser(ITestDevice device)
+            throws DeviceNotAvailableException {
+        return prepareMultipleUsers(device, 1);
+    }
+
+    /**
+     * Prepare and return two users relevant for testing.
+     */
+    public static int[] prepareMultipleUsers(ITestDevice device)
+            throws DeviceNotAvailableException {
+        return prepareMultipleUsers(device, 2);
+    }
+
+    /**
+     * Prepare and return multiple users relevant for testing.
+     */
+    public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers)
+            throws DeviceNotAvailableException {
+        final int[] userIds = getAllUsers(device);
+        for (int i = 1; i < userIds.length; i++) {
+            if (i < maxUsers) {
+                device.startUser(userIds[i]);
+            } else {
+                device.stopUser(userIds[i]);
+            }
+        }
+        if (userIds.length > maxUsers) {
+            return Arrays.copyOf(userIds, maxUsers);
+        } else {
+            return userIds;
+        }
+    }
+
+    public static int[] getAllUsers(ITestDevice device)
+            throws DeviceNotAvailableException {
+        Integer primary = device.getPrimaryUserId();
+        if (primary == null) {
+            primary = USER_SYSTEM;
+        }
+        int[] users = new int[] { primary };
+        for (Integer user : device.listUsers()) {
+            if ((user != USER_SYSTEM) && (user != primary)) {
+                users = Arrays.copyOf(users, users.length + 1);
+                users[users.length - 1] = user;
+            }
+        }
+        return users;
+    }
+}
diff --git a/hostsidetests/dexmetadata/host/Android.mk b/hostsidetests/dexmetadata/host/Android.mk
index a51ddd2..cae13cd 100644
--- a/hostsidetests/dexmetadata/host/Android.mk
+++ b/hostsidetests/dexmetadata/host/Android.mk
@@ -29,6 +29,6 @@
     tradefed
 
 # tag this module as test artifact for cts
-LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_COMPATIBILITY_SUITE := cts general-tests
 
 include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/dumpsys/AndroidTest.xml b/hostsidetests/dumpsys/AndroidTest.xml
index ead52be..11ab26f 100644
--- a/hostsidetests/dumpsys/AndroidTest.xml
+++ b/hostsidetests/dumpsys/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- This module tests system service dumps, which is irrelevant for Instant Apps. -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest">
         <option name="jar" value="CtsDumpsysHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/edi/AndroidTest.xml b/hostsidetests/edi/AndroidTest.xml
index b0d5d9f..fdbe2cb 100644
--- a/hostsidetests/edi/AndroidTest.xml
+++ b/hostsidetests/edi/AndroidTest.xml
@@ -16,8 +16,8 @@
 <configuration description="Config for CTS EDI host test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="deviceinfo" />
-    <!-- Included not for instant-app but to collect the required information for the run -->
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <!-- Do no need to run instant mode for collecting information -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsEdiHostTestCases.jar" />
     </test>
diff --git a/hostsidetests/shortcuts/hostside/AndroidTest.xml b/hostsidetests/shortcuts/hostside/AndroidTest.xml
index 2f1c7f0..bc6ca74 100644
--- a/hostsidetests/shortcuts/hostside/AndroidTest.xml
+++ b/hostsidetests/shortcuts/hostside/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- Instant apps can't access ShortcutManager -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="android.cts.backup.BackupPreparer">
         <option name="enable-backup-if-needed" value="true" />
         <option name="select-local-transport" value="true" />
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 9298ac2..349578f 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -861,6 +861,19 @@
         }
     }
 
+    public void testSetDefaultSmsApplication_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testSetDefaultSmsApplication_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.setDefaultSmsApplication(mComponent, "android.admin.cts");
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
     public void testCreateAdminSupportIntent_returnNullIfRestrictionIsNotSet() {
         if (!mDeviceAdmin) {
             Log.w(TAG, "Skipping testCreateAdminSupportIntent");
diff --git a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
index 38f0b52..fb0ccf2 100644
--- a/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
+++ b/tests/app/app/src/android/app/stubs/ActivityCallbacksTestActivity.java
@@ -55,10 +55,12 @@
     public enum Source {
         ACTIVITY,
         ACTIVITY_CALLBACK,
+        ACTIVITY_CALLBACK_CREATE_ONLY,
         APPLICATION_ACTIVITY_CALLBACK
     }
 
     private final Application.ActivityLifecycleCallbacks mActivityCallbacks;
+    private final Application.ActivityLifecycleCallbacks mActivityCallbacksCreateOnly;
 
     private ArrayList<Pair<Source, Event>> mCollectedEvents = new ArrayList<>();
 
@@ -161,6 +163,101 @@
             }
         };
         registerActivityLifecycleCallbacks(mActivityCallbacks);
+        mActivityCallbacksCreateOnly = new Application.ActivityLifecycleCallbacks() {
+
+            @Override
+            public void onActivityPreCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_CREATE);
+            }
+
+            @Override
+            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_CREATE);
+            }
+
+            @Override
+            public void onActivityPostCreated(Activity activity, Bundle savedInstanceState) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_CREATE);
+                // We shouldn't get any additional callbacks after this point
+                unregisterActivityLifecycleCallbacks(this);
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_START);
+            }
+
+            @Override
+            public void onActivityPostStarted(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_START);
+            }
+
+            @Override
+            public void onActivityPreResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_RESUME);
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_RESUME);
+            }
+
+            @Override
+            public void onActivityPostResumed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_RESUME);
+            }
+
+            @Override
+            public void onActivityPrePaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_PAUSE);
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PAUSE);
+            }
+
+            @Override
+            public void onActivityPostPaused(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_PAUSE);
+            }
+
+            @Override
+            public void onActivityPreStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_STOP);
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_STOP);
+            }
+
+            @Override
+            public void onActivityPostStopped(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_STOP);
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+
+            }
+
+            @Override
+            public void onActivityPreDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_PRE_DESTROY);
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_DESTROY);
+            }
+
+            @Override
+            public void onActivityPostDestroyed(Activity activity) {
+                collectEvent(Source.ACTIVITY_CALLBACK_CREATE_ONLY, Event.ON_POST_DESTROY);
+            }
+        };
+        registerActivityLifecycleCallbacks(mActivityCallbacksCreateOnly);
     }
 
     public void collectEvent(Source source, Event event) {
diff --git a/tests/app/src/android/app/cts/ActivityCallbacksTest.java b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
index ff9c401..909748f 100644
--- a/tests/app/src/android/app/cts/ActivityCallbacksTest.java
+++ b/tests/app/src/android/app/cts/ActivityCallbacksTest.java
@@ -229,11 +229,19 @@
             Event preEvent, Event event, Event postEvent) {
         expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, preEvent));
         expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, preEvent));
+        if (preEvent == ON_PRE_CREATE) {
+            // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+            expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, preEvent));
+        }
         expectedEvents.add(new Pair<>(Source.ACTIVITY, preEvent));
         if (event == ON_CREATE || event == ON_START || event == ON_RESUME) {
             // Application goes first on upward lifecycle events
             expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, event));
             expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
+            if (event == ON_CREATE) {
+                // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+                expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, event));
+            }
         } else {
             // Application goes last on downward lifecycle events
             expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, event));
@@ -241,6 +249,10 @@
         }
         expectedEvents.add(new Pair<>(Source.ACTIVITY, postEvent));
         expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK, postEvent));
+        if (postEvent == ON_POST_CREATE) {
+            // ACTIVITY_CALLBACK_CREATE_ONLY only gets create events
+            expectedEvents.add(new Pair<>(Source.ACTIVITY_CALLBACK_CREATE_ONLY, postEvent));
+        }
         expectedEvents.add(new Pair<>(Source.APPLICATION_ACTIVITY_CALLBACK, postEvent));
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index f2b5cd4..cff8dcb 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -159,15 +159,11 @@
         NotificationChannel channel =
                 new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
         channel.setAllowBubbles(true);
-        assertEquals("Only HIGH channels can have bubbles", false, channel.canBubble());
+        assertEquals(true, channel.canBubble());
 
-        channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
+        channel = new NotificationChannel("1", "one", IMPORTANCE_DEFAULT);
         channel.setAllowBubbles(false);
         assertEquals(false, channel.canBubble());
-
-        channel = new NotificationChannel("1", "one", IMPORTANCE_HIGH);
-        channel.setAllowBubbles(true);
-        assertEquals(true, channel.canBubble());
     }
 
     public void testIsImportanceLockedByOEM() {
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index f639d56..543e7e8 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -965,6 +965,57 @@
         mListener.resetData();
     }
 
+    public void testCanBubble_ranking() throws Exception {
+        if (mActivityManager.isLowRamDevice() && !mPackageManager.hasSystemFeature(FEATURE_WATCH)) {
+            return;
+        }
+
+        assertEquals(1, Settings.Secure.getInt(
+                mContext.getContentResolver(), Settings.Secure.NOTIFICATION_BUBBLES));
+
+        toggleListenerAccess(TestNotificationListener.getId(),
+                InstrumentationRegistry.getInstrumentation(), true);
+        Thread.sleep(500); // wait for listener to be allowed
+
+        mListener = TestNotificationListener.getInstance();
+        assertNotNull(mListener);
+        try {
+            sendNotification(1, R.drawable.black);
+            Thread.sleep(500); // wait for notification listener to receive notification
+            NotificationListenerService.RankingMap rankingMap = mListener.mRankingMap;
+            NotificationListenerService.Ranking outRanking =
+                    new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    rankingMap.getRanking(key, outRanking);
+                    // by default everything can bubble
+                    assertTrue(outRanking.canBubble());
+                }
+            }
+
+            // turn off bubbles globally
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BUBBLES, 0));
+
+            Thread.sleep(500); // wait for ranking update
+
+            rankingMap = mListener.mRankingMap;
+            outRanking = new NotificationListenerService.Ranking();
+            for (String key : rankingMap.getOrderedKeys()) {
+                if (key.contains(mListener.getPackageName())) {
+                    assertFalse(outRanking.canBubble());
+                }
+            }
+
+            mListener.resetData();
+        } finally {
+            SystemUtil.runWithShellPermissionIdentity(() ->
+                    Settings.Secure.putInt(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BUBBLES, 1));
+        }
+    }
+
     public void testNotify_blockedChannel() throws Exception {
         mNotificationManager.cancelAll();
 
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index 3109a0e..94af896 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -188,7 +188,20 @@
         assertFeature(manualPostProcessing,
                 PackageManager.FEATURE_CAMERA_CAPABILITY_MANUAL_POST_PROCESSING);
         assertFeature(raw, PackageManager.FEATURE_CAMERA_CAPABILITY_RAW);
-        assertFeature(motionTracking, PackageManager.FEATURE_CAMERA_AR);
+        if (!motionTracking) {
+          // FEATURE_CAMERA_AR requires the presence of
+          // CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MOTION_TRACKING but
+          // MOTION_TRACKING does not require the presence of FEATURE_CAMERA_AR
+          //
+          // Logic table:
+          //    AR= F   T
+          // MT=F   Y   N
+          //   =T   Y   Y
+          //
+          // So only check the one disallowed condition: No motion tracking and FEATURE_CAMERA_AR is
+          // available
+          assertNotAvailable(PackageManager.FEATURE_CAMERA_AR);
+        }
     }
 
     private void checkFrontCamera() {
diff --git a/tests/autofillservice/AndroidTest.xml b/tests/autofillservice/AndroidTest.xml
index 4fe406f..e7413b1 100644
--- a/tests/autofillservice/AndroidTest.xml
+++ b/tests/autofillservice/AndroidTest.xml
@@ -17,6 +17,7 @@
   <option name="test-suite-tag" value="cts" />
   <option name="config-descriptor:metadata" key="component" value="autofill" />
   <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+  <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
 
   <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
diff --git a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
index be2625e..6997453 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/AutoFillServiceTestCase.java
@@ -19,6 +19,7 @@
 import static android.autofillservice.cts.Helper.getContext;
 import static android.autofillservice.cts.InstrumentedAutoFillService.SERVICE_NAME;
 import static android.content.Context.CLIPBOARD_SERVICE;
+import static android.provider.Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS;
 
 import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
 
@@ -38,7 +39,9 @@
 import com.android.compatibility.common.util.RequiredFeatureRule;
 import com.android.compatibility.common.util.RetryRule;
 import com.android.compatibility.common.util.SafeCleanerRule;
+import com.android.compatibility.common.util.SettingsStateChangerRule;
 import com.android.compatibility.common.util.SettingsStateKeeperRule;
+import com.android.compatibility.common.util.SettingsUtils;
 import com.android.compatibility.common.util.TestNameUtils;
 
 import org.junit.Before;
@@ -202,6 +205,10 @@
                 // mRetryRule should be closest to the main test as possible
                 .around(mRetryRule)
                 //
+                // Augmented Autofill should be disabled by default
+                .around(new SettingsStateChangerRule(sContext, SettingsUtils.NAMESPACE_GLOBAL,
+                        AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
+                        Integer.toString(getSmartSuggestionMode())))
                 //
                 // Finally, let subclasses add their own rules (like ActivityTestRule)
                 .around(getMainTestRule());
@@ -217,6 +224,10 @@
             mUiBot.reset();
         }
 
+        protected int getSmartSuggestionMode() {
+            return 0;
+        }
+
         /**
          * Gets how many times a test should be retried.
          *
diff --git a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
index f1b262f..83a938d 100644
--- a/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
+++ b/tests/autofillservice/src/android/autofillservice/cts/augmented/AugmentedAutofillAutoActivityLaunchTestCase.java
@@ -17,31 +17,21 @@
 
 import static android.autofillservice.cts.Helper.allowOverlays;
 import static android.autofillservice.cts.Helper.disallowOverlays;
-import static android.provider.Settings.Global.AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS;
 
 import android.autofillservice.cts.AbstractAutoFillActivity;
 import android.autofillservice.cts.AutoFillServiceTestCase;
 import android.autofillservice.cts.augmented.CtsAugmentedAutofillService.AugmentedReplier;
 import android.view.autofill.AutofillManager;
 
-import com.android.compatibility.common.util.SettingsStateChangerRule;
-import com.android.compatibility.common.util.SettingsUtils;
-
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.ClassRule;
 
 // Must be public because of the @ClassRule
 public abstract class AugmentedAutofillAutoActivityLaunchTestCase
         <A extends AbstractAutoFillActivity> extends AutoFillServiceTestCase.AutoActivityLaunch<A> {
 
-    @ClassRule
-    public static final SettingsStateChangerRule sFeatureEnabler = new SettingsStateChangerRule(
-            sContext, SettingsUtils.NAMESPACE_GLOBAL, AUTOFILL_SMART_SUGGESTION_EMULATION_FLAGS,
-            Integer.toString(AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM));
-
     protected static AugmentedReplier sAugmentedReplier;
     protected AugmentedUiBot mAugmentedUiBot;
 
@@ -70,6 +60,11 @@
         AugmentedHelper.resetAugmentedService();
     }
 
+    @Override
+    protected int getSmartSuggestionMode() {
+        return AutofillManager.FLAG_SMART_SUGGESTION_SYSTEM;
+    }
+
     protected void enableAugmentedService() {
         AugmentedHelper.setAugmentedService(CtsAugmentedAutofillService.SERVICE_NAME);
     }
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
index ebbd555..32b5932 100644
--- a/tests/camera/Android.mk
+++ b/tests/camera/Android.mk
@@ -82,12 +82,6 @@
 LOCAL_JNI_SHARED_LIBRARIES := \
 	libctscamera2_jni \
 	libnativehelper_compat_libc++ \
-	libdynamic_depth \
-	libimage_io \
-	libxml2 \
-	libandroidicu \
-	libbase \
-	libc++ \
 
 LOCAL_NDK_STL_VARIANT := c++_shared
 
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
index 83cdd03..94f7ca3 100644
--- a/tests/camera/AndroidTest.xml
+++ b/tests/camera/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="camera" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsCameraTestCases.apk" />
@@ -24,7 +25,7 @@
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.camera.cts" />
         <option name="runtime-hint" value="12m7s" />
-        <!-- test-timeout unit is ms, value = 20 min -->
-        <option name="test-timeout" value="1200000" />
+        <!-- test-timeout unit is ms, value = 33 min -->
+        <option name="test-timeout" value="2000000" />
     </test>
 </configuration>
diff --git a/tests/camera/libctscamera2jni/Android.mk b/tests/camera/libctscamera2jni/Android.mk
index e9c301e..798674b 100644
--- a/tests/camera/libctscamera2jni/Android.mk
+++ b/tests/camera/libctscamera2jni/Android.mk
@@ -35,15 +35,18 @@
 # Flags to avoid warnings from DNG SDK
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-unused-value -Wno-unused-variable
+# Flags related to dynamic depth
+LOCAL_CFLAGS += -Wno-ignored-qualifiers -DSTATIC_LIBXML=1
 
 LOCAL_STATIC_LIBRARIES := libdng_sdk_validate libjpeg_static_ndk
+# Dynamic depth libraries
+LOCAL_STATIC_LIBRARIES += libdynamic_depth_ndk libimage_io_ndk libbase_ndk libxml2_ndk
 LOCAL_SHARED_LIBRARIES := libandroid \
     libnativehelper_compat_libc++ \
     liblog \
     libcamera2ndk \
     libmediandk \
     libz \
-    libdl \
 
 # NDK build, shared C++ runtime
 LOCAL_SDK_VERSION := current
diff --git a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
index a1d4b83..fbc63ef 100644
--- a/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
+++ b/tests/camera/libctscamera2jni/dynamic-depth-validate-jni.cpp
@@ -17,11 +17,9 @@
 #define LOG_TAG "DYNAMIC-DEPTH-JNI"
 #include <jni.h>
 #include <log/log.h>
-#include <dlfcn.h>
+#include <dynamic_depth/depth_jpeg.h>
 
-typedef int32_t (*validate_dynamic_depth_buffer) (const char *, size_t);
-static const char *kDynamicDepthLibraryName = "libdynamic_depth.so";
-static const char *kDynamicDepthValidateFunction = "ValidateAndroidDynamicDepthBuffer";
+using namespace dynamic_depth;
 
 extern "C" jboolean
 Java_android_hardware_camera2_cts_ImageReaderTest_validateDynamicDepthNative(
@@ -34,23 +32,8 @@
         return JNI_FALSE;
     }
 
-    void* depthLibHandle = dlopen(kDynamicDepthLibraryName, RTLD_NOW | RTLD_LOCAL);
-    if (depthLibHandle == nullptr) {
-        ALOGE("Failed to load dynamic depth library!");
-        return JNI_FALSE;
-    }
-
-    validate_dynamic_depth_buffer validate = reinterpret_cast<validate_dynamic_depth_buffer> (
-            dlsym(depthLibHandle, kDynamicDepthValidateFunction));
-    if (validate == nullptr) {
-        ALOGE("Failed to link to dynamic depth validate function!");
-        dlclose(depthLibHandle);
-        return JNI_FALSE;
-    }
-
-    auto ret = (validate(reinterpret_cast<const char *> (buffer), bufferLength) == 0) ?
-            JNI_TRUE : JNI_FALSE;
-    dlclose(depthLibHandle);
+    auto ret = (ValidateAndroidDynamicDepthBuffer(reinterpret_cast<const char *> (buffer),
+                bufferLength) == 0) ? JNI_TRUE : JNI_FALSE;
 
     return ret;
 }
diff --git a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index 3ed4fdb..e275aa4 100644
--- a/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -367,6 +367,32 @@
     }
 
     /**
+     * If the camera device advertises the SECURE_IAMGE_DATA capability, test
+     * ImageFormat.PRIVATE + PROTECTED usage capture by using ImageReader with the
+     * ImageReader factory method that has usage flag argument, and uses a custom usage flag.
+     */
+    public void testImageReaderPrivateWithProtectedUsageFlag() throws Exception {
+        for (String id : mCameraIds) {
+            try {
+                Log.v(TAG, "Private format and protected usage testing for camera " + id);
+                if (!mAllStaticInfo.get(id).isCapabilitySupported(
+                        CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA)) {
+                    Log.i(TAG, "Camera " + id +
+                            " does not support secure image data capability, skipping");
+
+                    continue;
+                }
+                openDevice(id);
+                bufferFormatTestByCamera(ImageFormat.PRIVATE, /*setUsageFlag*/ true,
+                        HardwareBuffer.USAGE_PROTECTED_CONTENT, /*repeating*/ true,
+                        /*checkSession*/ true, /*validateImageData*/ false);
+            } finally {
+                closeDevice(id);
+            }
+        }
+    }
+
+    /**
      * Test two image stream (YUV420_888 and RAW_SENSOR) capture by using ImageReader with the
      * ImageReader factory method that has usage flag argument.
      *
@@ -930,11 +956,23 @@
     }
 
     private void bufferFormatTestByCamera(int format, boolean repeating) throws Exception {
-        bufferFormatTestByCamera(format, repeating, /*checkSession*/ false);
+        bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+                HardwareBuffer.USAGE_CPU_READ_OFTEN, repeating,
+                /*checkSession*/ false, /*validateImageData*/ true);
     }
 
     private void bufferFormatTestByCamera(int format, boolean repeating, boolean checkSession)
             throws Exception {
+        bufferFormatTestByCamera(format, /*setUsageFlag*/ false,
+                HardwareBuffer.USAGE_CPU_READ_OFTEN,
+                repeating, checkSession, /*validateImageData*/true);
+    }
+
+    private void bufferFormatTestByCamera(int format, boolean setUsageFlag, long usageFlag,
+            // TODO: Consider having some sort of test configuration class passed to reduce the
+            //       proliferation of parameters ?
+            boolean repeating, boolean checkSession, boolean validateImageData)
+            throws Exception {
         Size[] availableSizes = mStaticInfo.getAvailableSizesForFormatChecked(format,
                 StaticMetadata.StreamDirection.Output);
 
@@ -948,7 +986,11 @@
 
                 // Create ImageReader.
                 mListener  = new SimpleImageListener();
-                createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+                if (setUsageFlag) {
+                    createDefaultImageReader(sz, format, MAX_NUM_IMAGES, usageFlag, mListener);
+                } else {
+                    createDefaultImageReader(sz, format, MAX_NUM_IMAGES, mListener);
+                }
 
                 if (checkSession) {
                     assertTrue("Camera capture session validation for format: " + format +
@@ -962,8 +1004,10 @@
 
                 int numFrameVerified = repeating ? NUM_FRAME_VERIFIED : 1;
 
-                // Validate images.
-                validateImage(sz, format, numFrameVerified, repeating);
+                if (validateImageData) {
+                    // Validate images.
+                    validateImage(sz, format, numFrameVerified, repeating);
+                }
 
                 // Validate capture result.
                 validateCaptureResult(format, sz, listener, numFrameVerified);
@@ -1191,7 +1235,6 @@
 
     /** Load dynamic depth validation jni on initialization */
     static {
-        System.loadLibrary("dynamic_depth");
         System.loadLibrary("ctscamera2_jni");
     }
     /**
diff --git a/tests/contentcaptureservice/AndroidTest.xml b/tests/contentcaptureservice/AndroidTest.xml
index 941df89..b3c8635 100644
--- a/tests/contentcaptureservice/AndroidTest.xml
+++ b/tests/contentcaptureservice/AndroidTest.xml
@@ -16,13 +16,18 @@
 <configuration description="Config for ContentCapture CTS tests.">
   <option name="test-suite-tag" value="cts" />
   <option name="config-descriptor:metadata" key="component" value="framework" />
+  <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+  <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
 
   <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
     <option name="cleanup-apks" value="true" />
     <option name="test-file-name" value="CtsContentCaptureServiceTestCases.apk" />
   </target_preparer>
 
-  <!--  TODO(b/122605818): add preparer for instant-apps tests  -->
+  <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+    <option name="run-command" value="cmd content_capture set bind-instant-service-allowed true" />
+    <option name="teardown-command" value="cmd content_capture set bind-instant-service-allowed false" />
+  </target_preparer>
 
   <test class="com.android.tradefed.testtype.AndroidJUnitTest">
     <option name="package" value="android.contentcaptureservice.cts" />
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
index 96f94b4..7e6f6f2 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/AbstractContentCaptureIntegrationTest.java
@@ -42,7 +42,9 @@
 import com.android.compatibility.common.util.SettingsUtils;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
@@ -54,6 +56,8 @@
 public abstract class AbstractContentCaptureIntegrationTest
         <A extends AbstractContentCaptureActivity> {
 
+    private static final String TAG = AbstractContentCaptureIntegrationTest.class.getSimpleName();
+
     private final String mTag = getClass().getSimpleName();
 
     protected static final Context sContext = InstrumentationRegistry.getTargetContext();
@@ -67,8 +71,24 @@
 
     private final ContentCaptureLoggingTestRule mLoggingRule = new ContentCaptureLoggingTestRule();
 
+
+    /**
+     * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
+     * finishes.
+     */
+    private ServiceWatcher mServiceWatcher;
+
     protected final SafeCleanerRule mSafeCleanerRule = new SafeCleanerRule()
             .setDumper(mLoggingRule)
+            .run(() -> {
+                Log.v(mTag, "@SafeCleaner: resetDefaultService()");
+                resetService();
+
+                if (mServiceWatcher != null) {
+                    mServiceWatcher.waitOnDestroy();
+                }
+
+            })
             .add(() -> {
                 return CtsContentCaptureService.getExceptions();
             });
@@ -93,16 +113,22 @@
             // Finally, let subclasses set their ActivityTestRule
             .around(getActivityTestRule());
 
-    /**
-     * Watcher set on {@link #enableService()} and used to wait until it's gone after the test
-     * finishes.
-     */
-    private ServiceWatcher mServiceWatcher;
-
     protected AbstractContentCaptureIntegrationTest(@NonNull Class<A> activityClass) {
         mActivityClass = activityClass;
     }
 
+    @BeforeClass
+    public static void disableDefaultService() {
+        Log.v(TAG, "@BeforeClass: disableDefaultService()");
+        Helper.setDefaultServiceEnabled(false);
+    }
+
+    @AfterClass
+    public static void enableDefaultService() {
+        Log.v(TAG, "@AfterClass: enableDefaultService()");
+        Helper.setDefaultServiceEnabled(true);
+    }
+
     @Before
     public void prepareDevice() throws Exception {
         Log.v(mTag, "@Before: prepareDevice()");
@@ -140,18 +166,6 @@
         }
     }
 
-    // TODO(b/123539404): this method should be called from the SafeCleaner, but we'll need to
-    // add a run() method that takes an object that can throw an exception
-    @After
-    public void restoreDefaultService() throws InterruptedException {
-        Log.v(mTag, "@After: restoreDefaultService()");
-        resetService();
-
-        if (mServiceWatcher != null) {
-            mServiceWatcher.waitOnDestroy();
-        }
-    }
-
     @Nullable
     public static void setFeatureEnabled(@Nullable String enabled) {
         if (enabled == null) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
index b74b22c..e3792ee 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Assertions.java
@@ -279,8 +279,18 @@
         assertThat(events).hasSize(minimumSize + 1);
         final ContentCaptureEvent batchDisappearEvent = events.get(minimumSize);
 
-        final List<AutofillId> actualIds = batchDisappearEvent.getIds();
-        assertThat(actualIds).containsExactly((Object[]) expectedIds);
+        if (expectedIds.length == 1) {
+            assertWithMessage("Should have just one deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getIds()).isNull();
+            assertWithMessage("wrong deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getId()).isEqualTo(expectedIds[0]);
+        } else {
+            assertWithMessage("Should not have individual deleted id on %s", batchDisappearEvent)
+                    .that(batchDisappearEvent.getId()).isNull();
+            final List<AutofillId> actualIds = batchDisappearEvent.getIds();
+            assertWithMessage("wrong deleteds id on %s", batchDisappearEvent)
+                    .that(actualIds).containsExactly((Object[]) expectedIds);
+        }
     }
 
     /**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
index 5a78cb6..abb0e7e 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankActivityTest.java
@@ -25,6 +25,7 @@
 import android.content.ComponentName;
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 
@@ -33,6 +34,7 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class BlankActivityTest extends AbstractContentCaptureIntegrationTest<BlankActivity> {
 
     private static final String TAG = BlankActivityTest.class.getSimpleName();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
index d99dfec..28dc2e7 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/BlankWithTitleActivityTest.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
 import android.contentcaptureservice.cts.common.ActivitiesWatcher.ActivityWatcher;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 
@@ -60,6 +61,7 @@
         activity.assertDefaultEvents(session);
     }
 
+    @AppModeFull(reason = "testSimpleSessionLifecycle() is enough")
     @Test
     public void testSimpleSessionLifecycle_noAnimation() throws Exception {
         final CtsContentCaptureService service = enableService();
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
index 3af2c65..8dbda23 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/ChildlessActivityTest.java
@@ -43,6 +43,7 @@
 import android.contentcaptureservice.cts.common.ActivityLauncher;
 import android.net.Uri;
 import android.os.SystemClock;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.View;
@@ -66,6 +67,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class ChildlessActivityTest
         extends AbstractContentCaptureIntegrationTest<ChildlessActivity> {
 
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
index e869fc1..04213ba 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
@@ -58,11 +58,6 @@
 
     private static ServiceWatcher sServiceWatcher;
 
-    // TODO(b/123421324): reuse with allSessions
-    /** Used by {@link #getOnlyFinishedSession()}. */
-    private static ContentCaptureSessionId sFirstSessionId;
-
-
     private final int mId = ++sIdCounter;
 
     private static final ArrayList<Throwable> sExceptions = new ArrayList<>();
@@ -118,7 +113,6 @@
 
 
     public static void resetStaticState() {
-        sFirstSessionId = null;
         sExceptions.clear();
         // TODO(b/123540602): should probably set sInstance to null as well, but first we would need
         // to make sure each test unbinds the service.
@@ -202,11 +196,8 @@
     public void onCreateContentCaptureSession(ContentCaptureContext context,
             ContentCaptureSessionId sessionId) {
         Log.i(TAG, "onCreateContentCaptureSession(id=" + mId + ", ctx=" + context
-                + ", session=" + sessionId + ", firstId=" + sFirstSessionId + ")");
+                + ", session=" + sessionId);
         mAllSessions.add(sessionId);
-        if (sFirstSessionId == null) {
-            sFirstSessionId = sessionId;
-        }
 
         safeRun(() -> {
             final Session session = mOpenSessions.get(sessionId);
@@ -289,9 +280,11 @@
      */
     @NonNull
     public Session getOnlyFinishedSession() throws InterruptedException {
-        // TODO(b/123421324): add some assertions to make sure There Can Be Only One!
-        assertWithMessage("No session yet").that(sFirstSessionId).isNotNull();
-        return getFinishedSession(sFirstSessionId);
+        final ArrayList<ContentCaptureSessionId> allSessions = mAllSessions;
+        assertWithMessage("Wrong number of sessions").that(allSessions).hasSize(1);
+        final ContentCaptureSessionId id = allSessions.get(0);
+        Log.d(TAG, "getOnlyFinishedSession(): id=" + id);
+        return getFinishedSession(id);
     }
 
     /**
@@ -319,7 +312,6 @@
         super.dump(fd, pw, args);
 
         pw.print("sServiceWatcher: "); pw.println(sServiceWatcher);
-        pw.print("sFirstSessionId: "); pw.println(sFirstSessionId);
         pw.print("sExceptions: "); pw.println(sExceptions);
         pw.print("sIdCounter: "); pw.println(sIdCounter);
         pw.print("mId: "); pw.println(mId);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
index 92b4f53..33cd31f 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivity.java
@@ -101,13 +101,16 @@
     @NonNull
     private List<ContentCaptureEvent> assertJustInitialViewsAppeared(@NonNull Session session,
             int additionalEvents) {
-        final List<ContentCaptureEvent> events = session.getEvents();
-        Log.v(TAG, "events(" + events.size() + "): " + events);
-        assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
-
         final View grandpa1 = (View) mCustomView.getParent();
         final View grandpa2 = (View) grandpa1.getParent();
         final View decorView = getDecorView();
+        Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+                + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+                + decorView.getAutofillId());
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        assertThat(events.size()).isAtLeast(MIN_EVENTS + additionalEvents);
 
         // Assert just the relevant events
         assertViewHierarchyStarted(events, 0);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
index 0218b4a..0ab1425 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CustomViewActivityTest.java
@@ -15,7 +15,11 @@
  */
 package android.contentcaptureservice.cts;
 
+import static android.contentcaptureservice.cts.Assertions.assertDecorViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertRightActivity;
+import static android.contentcaptureservice.cts.Assertions.assertViewAppeared;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyFinished;
+import static android.contentcaptureservice.cts.Assertions.assertViewHierarchyStarted;
 import static android.contentcaptureservice.cts.Assertions.assertViewWithUnknownParentAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewAppeared;
 import static android.contentcaptureservice.cts.Assertions.assertVirtualViewDisappeared;
@@ -31,8 +35,10 @@
 import android.contentcaptureservice.cts.common.DoubleVisitor;
 import android.os.Handler;
 import android.os.Looper;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
+import android.view.View;
 import android.view.ViewStructure;
 import android.view.autofill.AutofillId;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -40,13 +46,13 @@
 
 import androidx.annotation.NonNull;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class CustomViewActivityTest extends
         AbstractContentCaptureIntegrationTest<CustomViewActivity> {
 
@@ -89,7 +95,6 @@
      * the session notification methods instead - this is wrong because the main view will be
      * notified last, but we cannot prevent the apps from doing so...
      */
-    @Ignore("current broken, will be fixed by b/123777277")
     @Test
     public void testVirtualView_wrongWay() throws Exception {
         final CtsContentCaptureService service = enableService();
@@ -123,24 +128,36 @@
 
         assertRightActivity(session, session.id, activity);
 
-
-        final int additionalEvents = 3;
-        final List<ContentCaptureEvent> events = activity.assertInitialViewsAppeared(session,
-                additionalEvents);
-
+        final View grandpa1 = (View) activity.mCustomView.getParent();
+        final View grandpa2 = (View) grandpa1.getParent();
+        final View decorView = activity.getDecorView();
         final AutofillId customViewId = activity.mCustomView.getAutofillId();
+        Log.v(TAG, "assertJustInitialViewsAppeared(): grandpa1=" + grandpa1.getAutofillId()
+                + ", grandpa2=" + grandpa2.getAutofillId() + ", decor="
+                + decorView.getAutofillId() + "customView=" + customViewId);
+
+        final List<ContentCaptureEvent> events = session.getEvents();
+        Log.v(TAG, "events(" + events.size() + "): " + events);
+        final int additionalEvents = 2;
+
+        assertThat(events.size()).isAtLeast(CustomViewActivity.MIN_EVENTS + additionalEvents);
+
+        // Assert just the relevant events
+        assertViewHierarchyStarted(events, 0);
+        assertDecorViewAppeared(events, 1, decorView);
+        assertViewAppeared(events, 2, grandpa2, decorView.getAutofillId());
+        assertViewAppeared(events, 3, grandpa1, grandpa2.getAutofillId());
+
         final ContentCaptureSession mainSession = activity.mCustomView.getContentCaptureSession();
-
-        final int i = CustomViewActivity.MIN_EVENTS;
-
-        assertVirtualViewAppeared(events, i, mainSession, customViewId, 1, "child");
-        assertVirtualViewDisappeared(events, i + 1, customViewId, mainSession, 1);
+        assertVirtualViewAppeared(events, 4, mainSession, customViewId, 1, "child");
+        assertVirtualViewDisappeared(events, 5, customViewId, mainSession, 1);
 
         // This is the "wrong" part - the parent is notified last
-        assertViewWithUnknownParentAppeared(events, i + 2, session.id, activity.mCustomView);
+        assertViewWithUnknownParentAppeared(events, 6, session.id, activity.mCustomView);
+
+        assertViewHierarchyFinished(events, 7);
 
         activity.assertInitialViewsDisappeared(events, additionalEvents);
-        // TODO(b/122315042): assert views disappeared
     }
 
     /**
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
index 9784213..30ba124 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/Helper.java
@@ -74,6 +74,15 @@
     }
 
     /**
+     * Enables / disables the default service.
+     */
+    public static void setDefaultServiceEnabled(boolean enabled) {
+        Log.d(TAG, "setDefaultServiceEnabled(): " + enabled);
+        runShellCommand("cmd content_capture set default-service-enabled 0 %s",
+                Boolean.toString(enabled));
+    }
+
+    /**
      * Gets the component name for a given class.
      */
     public static ComponentName componentNameFor(@NonNull Class<?> clazz) {
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
index d78c329..926f63a 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/LoginActivityTest.java
@@ -38,6 +38,7 @@
 import android.contentcaptureservice.cts.common.DoubleVisitor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
 import android.support.test.rule.ActivityTestRule;
 import android.util.Log;
 import android.view.View;
@@ -59,6 +60,7 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
 
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
 public class LoginActivityTest extends AbstractContentCaptureIntegrationTest<LoginActivity> {
 
     private static final String TAG = LoginActivityTest.class.getSimpleName();
diff --git a/tests/framework/base/activitymanager/util/Android.bp b/tests/framework/base/activitymanager/util/Android.bp
index 2e2f030..f71603b 100644
--- a/tests/framework/base/activitymanager/util/Android.bp
+++ b/tests/framework/base/activitymanager/util/Android.bp
@@ -24,9 +24,7 @@
     static_libs: [
         "platformprotosnano",
         "compatibility-device-util",
-	"android-support-test",
-        "androidx.test.rules",
-        "androidx.test.runner",
+        "android-support-test",
     ],
 
     sdk_version: "test_current",
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
deleted file mode 100644
index 3307af1..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AmUtils.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 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.am.compat;
-
-import com.android.compatibility.common.util.TestUtils;
-
-/**
- * {@link com.android.compatibility.common.util.AmUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AmUtils {
-
-    public static void runKill(String packageName, boolean wait) throws Exception {
-        SystemUtil.runShellCommandForNoOutput("am kill --user cur " + packageName);
-
-        if (!wait) {
-            return;
-        }
-
-        TestUtils.waitUntil("package process was not killed:" + packageName,
-                () -> !isProcessRunning(packageName));
-    }
-
-    private static boolean isProcessRunning(String packageName) {
-        final String output = SystemUtil.runShellCommand("ps -A -o NAME");
-        String[] packages = output.split("\\n");
-        for (int i = packages.length - 1; i >= 0; --i) {
-            if (packages[i].equals(packageName)) {
-                return true;
-            }
-        }
-        return false;
-    }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
deleted file mode 100644
index f957d14..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/AppOpsUtils.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2019 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.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import android.app.AppOpsManager;
-
-import java.io.IOException;
-
-/**
- * {@link com.android.compatibility.common.util.AppOpsUtils} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class AppOpsUtils {
-    /**
-     * Resets a package's app ops configuration to the device default. See AppOpsManager for the
-     * default op settings.
-     *
-     * <p>
-     * It's recommended to call this in setUp() and tearDown() of your test so the test starts and
-     * ends with a reproducible default state, and so doesn't affect other tests.
-     *
-     * <p>
-     * Some app ops are configured to be non-resettable, which means that the state of these will
-     * not be reset even when calling this method.
-     */
-    public static String reset(String packageName) throws IOException {
-        return SystemUtil.runShellCommand(getInstrumentation(), "appops reset " + packageName);
-    }
-
-    /**
-     * Sets the app op mode (e.g. allowed, denied) for a single package and operation.
-     */
-    public static String setOpMode(String packageName, String opStr, int mode)
-            throws IOException {
-        String modeStr;
-        switch (mode) {
-            case AppOpsManager.MODE_ALLOWED:
-                modeStr = "allow";
-                break;
-            case AppOpsManager.MODE_ERRORED:
-                modeStr = "deny";
-                break;
-            case AppOpsManager.MODE_IGNORED:
-                modeStr = "ignore";
-                break;
-            case AppOpsManager.MODE_DEFAULT:
-                modeStr = "default";
-                break;
-            default:
-                throw new IllegalArgumentException("Unexpected app op type");
-        }
-        String command = "appops set " + packageName + " " + opStr + " " + modeStr;
-        return SystemUtil.runShellCommand(getInstrumentation(), command);
-    }
-
-    /**
-     * Get the app op mode (e.g. MODE_ALLOWED, MODE_DEFAULT) for a single package and operation.
-     */
-    public static int getOpMode(String packageName, String opStr)
-            throws IOException {
-        String opState = getOpState(packageName, opStr);
-        if (opState.contains(" allow")) {
-            return AppOpsManager.MODE_ALLOWED;
-        } else if (opState.contains(" deny")) {
-            return AppOpsManager.MODE_ERRORED;
-        } else if (opState.contains(" ignore")) {
-            return AppOpsManager.MODE_IGNORED;
-        } else if (opState.contains(" default")) {
-            return AppOpsManager.MODE_DEFAULT;
-        } else {
-            throw new IllegalStateException("Unexpected app op mode returned " + opState);
-        }
-    }
-
-    /**
-     * Returns whether an allowed operation has been logged by the AppOpsManager for a
-     * package. Operations are noted when the app attempts to perform them and calls e.g.
-     * {@link AppOpsManager#noteOp}.
-     *
-     * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
-     */
-    public static boolean allowedOperationLogged(String packageName, String opStr)
-            throws IOException {
-        return getOpState(packageName, opStr).contains(" time=");
-    }
-
-    /**
-     * Returns whether a rejected operation has been logged by the AppOpsManager for a
-     * package. Operations are noted when the app attempts to perform them and calls e.g.
-     * {@link AppOpsManager#noteOp}.
-     *
-     * @param opStr The public string constant of the operation (e.g. OPSTR_READ_SMS).
-     */
-    public static boolean rejectedOperationLogged(String packageName, String opStr)
-            throws IOException {
-        return getOpState(packageName, opStr).contains(" rejectTime=");
-    }
-
-    /**
-     * Returns the app op state for a package. Includes information on when the operation was
-     * last attempted to be performed by the package.
-     *
-     * Format: "SEND_SMS: allow; time=+23h12m54s980ms ago; rejectTime=+1h10m23s180ms"
-     */
-    private static String getOpState(String packageName, String opStr) throws IOException {
-        return SystemUtil.runShellCommand(
-                getInstrumentation(), "appops get " + packageName + " " + opStr);
-    }
-}
diff --git a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java b/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
deleted file mode 100644
index 23f8784..0000000
--- a/tests/framework/base/activitymanager/util/src/android/server/am/compat/SystemUtil.java
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright (C) 2019 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.am.compat;
-
-import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.concurrent.Callable;
-
-/**
- * {@link com.android.compatibility.common.util.SystemUtil} class compatible with
- * {@link androidx.test}.
- *
- * <p>TODO(b/123772361): Should be removed once the original class gets compatible with
- * {@link androidx.test}.
- */
-public class SystemUtil {
-
-    private static final String TAG = SystemUtil.class.getSimpleName();
-
-    /**
-     * Executes a shell command using shell user identity, and return the standard output in string
-     * <p>Note: calling this function requires API level 21 or above
-     * @param instrumentation {@link Instrumentation} instance, obtained from a test running in
-     * instrumentation framework
-     * @param cmd the command to run
-     * @return the standard output of the command
-     * @throws Exception
-     */
-    public static String runShellCommand(Instrumentation instrumentation, String cmd)
-            throws IOException {
-        Log.v(TAG, "Running command: " + cmd);
-        if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
-            throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
-                    + "or revokeRuntimePermission() directly, which are more robust.");
-        }
-        ParcelFileDescriptor pfd = instrumentation.getUiAutomation().executeShellCommand(cmd);
-        byte[] buf = new byte[512];
-        int bytesRead;
-        FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-        StringBuffer stdout = new StringBuffer();
-        while ((bytesRead = fis.read(buf)) != -1) {
-            stdout.append(new String(buf, 0, bytesRead));
-        }
-        fis.close();
-        return stdout.toString();
-    }
-
-    /**
-     * Simpler version of {@link #runShellCommand(Instrumentation, String)}.
-     */
-    public static String runShellCommand(String cmd) {
-        try {
-            return runShellCommand(getInstrumentation(), cmd);
-        } catch (IOException e) {
-            fail("Failed reading command output: " + e);
-            return "";
-        }
-    }
-
-    /**
-     * Same as {@link #runShellCommand(String)}, but fails if the output is not empty.
-     */
-    public static String runShellCommandForNoOutput(String cmd) {
-        final String result = runShellCommand(cmd);
-        assertTrue("Command failed. Command was: " + cmd + "\n"
-                        + "Didn't expect any output, but the output was:\n" + result,
-                result.length() == 0);
-        return result;
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting Shell's permissions.
-     */
-    public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable) {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        runWithShellPermissionIdentity(automan, runnable, (String[]) null /* permissions */);
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting a subset of Shell's permissions.
-     */
-    public static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable runnable,
-            String... permissions) {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        runWithShellPermissionIdentity(automan, runnable, permissions);
-    }
-
-    /**
-     * Runs a {@link ThrowingRunnable} adopting Shell's permissions, where you can specify the
-     * uiAutomation used.
-     * @param automan UIAutomation to use.
-     * @param runnable The code to run with Shell's identity.
-     * @param permissions A subset of Shell's permissions. Passing {@code null} will use all
-     *                    available permissions.
-     */
-    private static void runWithShellPermissionIdentity(@NonNull UiAutomation automan,
-            @NonNull ThrowingRunnable runnable, String... permissions) {
-        automan.adoptShellPermissionIdentity(permissions);
-        try {
-            runnable.run();
-        } catch (Exception e) {
-            throw new RuntimeException("Caught exception", e);
-        } finally {
-            automan.dropShellPermissionIdentity();
-        }
-    }
-
-    /**
-     * Calls a {@link Callable} adopting Shell's permissions.
-     */
-    public static <T> T callWithShellPermissionIdentity(@NonNull Callable<T> callable)
-            throws Exception {
-        final UiAutomation automan = getInstrumentation().getUiAutomation();
-        automan.adoptShellPermissionIdentity();
-        try {
-            return callable.call();
-        } finally {
-            automan.dropShellPermissionIdentity();
-        }
-    }
-}
diff --git a/tests/jdwp/AndroidTest.xml b/tests/jdwp/AndroidTest.xml
index 462ed34..9b42fb9 100644
--- a/tests/jdwp/AndroidTest.xml
+++ b/tests/jdwp/AndroidTest.xml
@@ -36,6 +36,7 @@
         <option name="dalvik-arg" value="-Djpda.settings.verbose=false" />
         <option name="dalvik-arg" value="-Djpda.settings.timeout=10000" />
         <option name="dalvik-arg" value="-Djpda.settings.waitingTime=10000" />
+        <option name="dalvik-arg" value="-Djpda.settings.dumpProcess='/system/xbin/su root /system/bin/logwrapper /system/bin/debuggerd'" />
         <option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeAgentArgument=-agentpath:" />
         <option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeAgentName=libjdwp.so" />
         <option name="dalvik-arg-adbconnection" value="-Djpda.settings.debuggeeJavaPath='dalvikvm|#ABI#| -XXlib:libart.so -Xplugin:libopenjdkjvmti.so -Xcompiler-option --debuggable -Xusejit:true'" />
diff --git a/tests/sample/AndroidTest.xml b/tests/sample/AndroidTest.xml
index c398ab05..e2a3139 100644
--- a/tests/sample/AndroidTest.xml
+++ b/tests/sample/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="misc" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsSampleDeviceTestCases.apk" />
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 99fbff7..23d555e 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -18,6 +18,7 @@
 
 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 static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
@@ -971,6 +972,8 @@
         final Context context = InstrumentationRegistry.getInstrumentation().getContext();
         context.startService(new Intent(context, TestService.class));
         mUiDevice.wait(Until.hasObject(By.clazz(TestService.class)), TIMEOUT);
+        final long sleepTime = 500;
+        SystemClock.sleep(sleepTime);
         context.stopService(new Intent(context, TestService.class));
         mUiDevice.wait(Until.gone(By.clazz(TestService.class)), TIMEOUT);
         final long endTime = System.currentTimeMillis();
@@ -1000,6 +1003,19 @@
         assertEquals(numStarts, 1);
         assertEquals(numStops, 1);
         assertLessThan(startIdx, stopIdx);
+
+        final Map<String, UsageStats> map = mUsageStatsManager.queryAndAggregateUsageStats(
+            startTime, endTime);
+        final UsageStats stats = map.get(mTargetPackage);
+        assertNotNull(stats);
+        final long lastTimeUsed = stats.getLastTimeForegroundServiceUsed();
+        // lastTimeUsed should be falling between startTime and endTime.
+        assertLessThan(startTime, lastTimeUsed);
+        assertLessThan(lastTimeUsed, endTime);
+        final long totalTimeUsed = stats.getTotalTimeForegroundServiceUsed();
+        // because we slept for 500 milliseconds earlier, we know the totalTimeUsed must be more
+        // more than 500 milliseconds.
+        assertLessThan(sleepTime, totalTimeUsed);
     }
 
     @AppModeFull // No usage events access in instant apps
@@ -1050,6 +1066,8 @@
             SystemClock.sleep(500);
         }
 
+        mUiDevice.pressHome();
+
         setUsageSourceSetting(Integer.toString(mUsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY));
         launchSubActivity(TaskRootActivity.class);
         // Usage should be attributed to the test app package
diff --git a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
index ec79572..ffbaaa5 100644
--- a/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarPackageManagerTest.java
@@ -37,7 +37,6 @@
 import java.util.List;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
diff --git a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
index 3b9d8eb..c7cce6d 100644
--- a/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
+++ b/tests/tests/car/src/android/car/cts/CarSensorManagerTest.java
@@ -33,7 +33,6 @@
 import java.util.stream.IntStream;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -55,7 +54,6 @@
 
     @CddTest(requirement="2.5.1")
     @Test
-    @Ignore // Enable when b/120125891 is fixed
     public void testRequiredSensorsForDrivingState() throws Exception {
         boolean foundSpeed = false;
         boolean foundGear = false;
diff --git a/tests/tests/contactsproviderwipe/AndroidTest.xml b/tests/tests/contactsproviderwipe/AndroidTest.xml
index 7bbb519..d73a717 100644
--- a/tests/tests/contactsproviderwipe/AndroidTest.xml
+++ b/tests/tests/contactsproviderwipe/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- This is a test for apps with READ/WRITE_CONTACTS, which instant apps don't have -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/dynamic_linker/AndroidTest.xml b/tests/tests/dynamic_linker/AndroidTest.xml
index e4fa4cb..58fe8a0 100644
--- a/tests/tests/dynamic_linker/AndroidTest.xml
+++ b/tests/tests/dynamic_linker/AndroidTest.xml
@@ -16,7 +16,7 @@
 <configuration description="Config for CTS dynamic linker test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="bionic" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
new file mode 100644
index 0000000..04d2d35
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/EGL15Test.java
@@ -0,0 +1,327 @@
+/*
+ * 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.
+ */
+
+package android.graphics.cts;
+
+import static org.junit.Assert.assertEquals;
+//import static android.opengl.EGL14.*;
+//import static android.opengl.EGL15.*;
+
+import android.opengl.EGL14;
+import android.opengl.EGL15;
+import android.opengl.EGLConfig;
+import android.opengl.EGLContext;
+import android.opengl.EGLDisplay;
+import android.opengl.EGLImage;
+import android.opengl.EGLSurface;
+import android.opengl.EGLSync;
+import android.opengl.GLES20;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.BlockJUnit4ClassRunner;
+
+
+@SmallTest
+@RunWith(BlockJUnit4ClassRunner.class)
+public class EGL15Test {
+
+    static {
+        System.loadLibrary("ctsgraphics_jni");
+    }
+
+    private static final String TAG = EGL15Test.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private EGLDisplay mEglDisplay = EGL15.EGL_NO_DISPLAY;
+    private EGLConfig mEglConfig = null;
+    private EGLSurface mEglPbuffer = EGL15.EGL_NO_SURFACE;
+    private EGLContext mEglContext = EGL15.EGL_NO_CONTEXT;
+    private int mEglVersion = 0;
+
+    @Before
+    public void setup() throws Throwable {
+        int error;
+
+        mEglDisplay = EGL15.eglGetPlatformDisplay(EGL15.EGL_PLATFORM_ANDROID_KHR,
+                EGL14.EGL_DEFAULT_DISPLAY,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (mEglDisplay == EGL15.EGL_NO_DISPLAY) {
+            throw new RuntimeException("no EGL display");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglGetPlatformDisplay failed");
+        }
+
+        int[] major = new int[1];
+        int[] minor = new int[1];
+        if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
+            throw new RuntimeException("error in eglInitialize");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglInitialize failed");
+        }
+        mEglVersion = major[0] * 10 + minor[0];
+
+        // If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
+        // wouldn't have to create a config or pbuffer at all.
+
+        int[] numConfigs = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        if (!EGL14.eglChooseConfig(mEglDisplay,
+                new int[] {
+                    EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
+                    EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT,
+                    EGL14.EGL_NONE},
+                0, configs, 0, 1, numConfigs, 0)) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglChooseConfig failed");
+        }
+
+        mEglConfig = configs[0];
+
+        mEglPbuffer = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig,
+                new int[] {EGL14.EGL_WIDTH, 1, EGL14.EGL_HEIGHT, 1, EGL14.EGL_NONE}, 0);
+        if (mEglPbuffer == EGL15.EGL_NO_SURFACE) {
+            throw new RuntimeException("eglCreatePbufferSurface failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreatePbufferSurface failed");
+        }
+
+
+        mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL14.EGL_NO_CONTEXT,
+                new int[] {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE}, 0);
+        if (mEglContext == EGL15.EGL_NO_CONTEXT) {
+            throw new RuntimeException("eglCreateContext failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateContext failed");
+        }
+
+
+        if (!EGL14.eglMakeCurrent(mEglDisplay, mEglPbuffer, mEglPbuffer, mEglContext)) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglMakeCurrent failed");
+        }
+    }
+
+    @After
+    public void teardown() throws Throwable {
+        EGL14.eglTerminate(mEglDisplay);
+    }
+
+    @Test
+    public void testEGL15SyncFence() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        GLES20.glFlush();
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glFlush failed");
+        }
+
+        int status = EGL15.eglClientWaitSync(mEglDisplay, sync, 0, EGL15.EGL_FOREVER);
+        if (status != EGL15.EGL_CONDITION_SATISFIED) {
+            throw new RuntimeException("eglClientWaitSync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglClientWaitSync failed");
+        }
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15GetSyncType() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        long[] type = new long[1];
+        boolean success = EGL15.eglGetSyncAttrib(mEglDisplay, sync, EGL15.EGL_SYNC_TYPE, type, 0);
+        if (!success) {
+            throw new RuntimeException("eglGetSyncAttrib failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglGetSyncAttrib failed");
+        }
+        assertEquals(type[0], EGL15.EGL_SYNC_FENCE);
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15WaitSync() {
+        if (mEglVersion < 15) {
+            return;
+        }
+        EGLSync sync = EGL15.eglCreateSync(mEglDisplay, EGL15.EGL_SYNC_FENCE,
+                new long[] {
+                    EGL14.EGL_NONE },
+                0);
+        if (sync == EGL15.EGL_NO_SYNC) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+        int error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateSync failed");
+        }
+
+        boolean success = EGL15.eglWaitSync(mEglDisplay, sync, 0);
+        if (!success) {
+            throw new RuntimeException("eglWaitSync failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglWaitSync failed");
+        }
+
+        if (!EGL15.eglDestroySync(mEglDisplay, sync)) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroySync failed");
+        }
+    }
+
+    @Test
+    public void testEGL15CreateImage() {
+        if (mEglVersion < 15) {
+            return;
+        }
+
+        int error;
+        int srcTex = 1;
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, srcTex);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glBindTexture failed");
+        }
+
+        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 64, 64, 0,
+                            GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glTexImage2D failed");
+        }
+
+        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
+                               GLES20.GL_LINEAR);
+        error = GLES20.glGetError();
+        if (error != GLES20.GL_NO_ERROR) {
+            throw new RuntimeException("glTexParameteri failed");
+        }
+
+        long[] attribs = new long[] {
+                EGL15.EGL_GL_TEXTURE_LEVEL, 0,
+                EGL14.EGL_NONE };
+        EGLImage image = EGL15.eglCreateImage(mEglDisplay, mEglContext,
+                EGL15.EGL_GL_TEXTURE_2D, srcTex, attribs, 0);
+        if (image == EGL15.EGL_NO_IMAGE) {
+            throw new RuntimeException("eglCreateImage failed, got EGL_NO_IMAGE");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglCreateImage failed");
+        }
+
+        boolean success = EGL15.eglDestroyImage(mEglDisplay, image);
+        if (!success) {
+            throw new RuntimeException("eglDestroyImage failed (returned false)");
+        }
+        error = EGL14.eglGetError();
+        if (error != EGL14.EGL_SUCCESS) {
+            throw new RuntimeException("eglDestroyImage failed");
+        }
+    }
+
+    @Test
+    public void testEGL15CreatePlatformPixmap() {
+        if (mEglVersion < 15) {
+            return;
+        }
+
+        long[] attribs = new long[] { EGL14.EGL_NONE };
+        boolean unsupported = false;
+        try {
+            EGLSurface surface = EGL15.eglCreatePlatformPixmapSurface(mEglDisplay,
+                    mEglConfig, null, attribs, 0);
+        } catch (UnsupportedOperationException e) {
+            unsupported = true;
+        }
+        if (!unsupported) {
+            throw new RuntimeException("eglCreatePlatformPixmapSurface is not supported on Android,"
+                    + " why did call not report that!");
+        }
+    }
+}
+
+// Note: Need to add tests for eglCreatePlatformWindowSurface
diff --git a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4 b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
index 8820340..157c222 100644
--- a/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
+++ b/tests/tests/media/res/raw/audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/lg_g4_iso_800.jpg b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
new file mode 100644
index 0000000..d264196
--- /dev/null
+++ b/tests/tests/media/res/raw/lg_g4_iso_800.jpg
Binary files differ
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index 3443f33..f4f648d 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -49,6 +49,9 @@
         <item>50</item>
         <item>6</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="exifbyteordermm_jpg">
         <item>false</item>
@@ -84,6 +87,9 @@
         <item>146</item>
         <item>0</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="lg_g4_iso_800_dng">
         <item>true</item>
@@ -119,14 +125,55 @@
         <item>800</item>
         <item>1</item>
         <item>0</item>
+        <item>true</item>
+        <item>826</item>
+        <item>10067</item>
+    </array>
+    <array name="lg_g4_iso_800_jpg">
+        <item>false</item>
+        <item />
+        <item />
+        <item />
+        <item />
+        <item />
+        <item>true</item>
+        <item>1662</item>
+        <item>24</item>
+        <item>53.834507</item>
+        <item>10.69585</item>
+        <item>0.0</item>
+        <item>LGE</item>
+        <item>LG-H815</item>
+        <item>1.800</item>
+        <item>2015:11:12 16:46:18</item>
+        <item>0.0040</item>
+        <item>0.0</item>
+        <item>442/100</item>
+        <item />
+        <item />
+        <item>1970:01:17</item>
+        <item>53/1,50/1,423/100</item>
+        <item>N</item>
+        <item>10/1,41/1,4506/100</item>
+        <item>E</item>
+        <item />
+        <item>18:08:10</item>
+        <item>337</item>
+        <item>600</item>
+        <item>800</item>
+        <item>1</item>
+        <item>0</item>
+        <item>true</item>
+        <item>1809</item>
+        <item>13197</item>
     </array>
     <array name="volantis_jpg">
         <item>false</item>
         <item />
         <item />
-        <item>0</item>
-        <item>0</item>
-        <item>false</item>
+        <item />
+        <item />
+        <item />
         <item>true</item>
         <item>3081</item>
         <item>24</item>
@@ -154,6 +201,9 @@
         <item>175</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="sony_rx_100_arw">
         <item>true</item>
@@ -189,6 +239,9 @@
         <item>125</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="canon_g7x_cr2">
         <item>true</item>
@@ -224,6 +277,9 @@
         <item>12800</item>
         <item>8</item>
         <item>1</item>
+        <item>true</item>
+        <item>14336</item>
+        <item>8192</item>
     </array>
     <array name="fuji_x20_raf">
         <item>true</item>
@@ -259,6 +315,9 @@
         <item>100</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="nikon_1aw1_nef">
         <item>true</item>
@@ -294,6 +353,9 @@
         <item>200</item>
         <item>8</item>
         <item>0</item>
+        <item>true</item>
+        <item>472</item>
+        <item>2048</item>
     </array>
     <array name="nikon_p330_nrw">
         <item>true</item>
@@ -329,6 +391,9 @@
         <item>3200</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="pentax_k5_pef">
         <item>true</item>
@@ -364,6 +429,9 @@
         <item>100</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="olympus_e_pl3_orf">
         <item>true</item>
@@ -399,6 +467,9 @@
         <item>200</item>
         <item>1</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="panasonic_gm5_rw2">
         <item>true</item>
@@ -434,6 +505,9 @@
         <item>200</item>
         <item>8</item>
         <item>1</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
     <array name="samsung_nx3000_srw">
         <item>true</item>
@@ -469,5 +543,8 @@
         <item>100</item>
         <item>8</item>
         <item>0</item>
+        <item>false</item>
+        <item />
+        <item />
     </array>
 </resources>
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 305a374..5bcfaa7 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -35,8 +35,11 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 
 @AppModeFull(reason = "Instant apps cannot access the SD card")
 public class ExifInterfaceTest extends AndroidTestCase {
@@ -53,6 +56,7 @@
     private static final String EXIF_BYTE_ORDER_II_JPEG = "image_exif_byte_order_ii.jpg";
     private static final String EXIF_BYTE_ORDER_MM_JPEG = "image_exif_byte_order_mm.jpg";
     private static final String LG_G4_ISO_800_DNG = "lg_g4_iso_800.dng";
+    private static final String LG_G4_ISO_800_JPG = "lg_g4_iso_800.jpg";
     private static final String SONY_RX_100_ARW = "sony_rx_100.arw";
     private static final String CANON_G7X_CR2 = "canon_g7x.cr2";
     private static final String FUJI_X20_RAF = "fuji_x20.raf";
@@ -128,6 +132,11 @@
         public final int orientation;
         public final int whiteBalance;
 
+        // XMP information.
+        public final boolean hasXmp;
+        public final int xmpOffset;
+        public final int xmpLength;
+
         private static String getString(TypedArray typedArray, int index) {
             String stringValue = typedArray.getString(index);
             if (stringValue == null || stringValue.equals("")) {
@@ -178,6 +187,11 @@
             orientation = typedArray.getInt(index++, 0);
             whiteBalance = typedArray.getInt(index++, 0);
 
+            // Reads XMP information.
+            hasXmp = typedArray.getBoolean(index++, false);
+            xmpOffset = typedArray.getInt(index++, 0);
+            xmpLength = typedArray.getInt(index++, 0);
+
             typedArray.recycle();
         }
     }
@@ -254,6 +268,7 @@
         // Checks a thumbnail image.
         assertEquals(expectedValue.hasThumbnail, exifInterface.hasThumbnail());
         if (expectedValue.hasThumbnail) {
+            assertNotNull(exifInterface.getThumbnailRange());
             if (assertRanges) {
                 final long[] thumbnailRange = exifInterface.getThumbnailRange();
                 assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
@@ -268,6 +283,7 @@
             assertEquals(expectedValue.isThumbnailCompressed,
                     exifInterface.isThumbnailCompressed());
         } else {
+            assertNull(exifInterface.getThumbnailRange());
             assertNull(exifInterface.getThumbnail());
         }
 
@@ -275,6 +291,7 @@
         float[] latLong = new float[2];
         assertEquals(expectedValue.hasLatLong, exifInterface.getLatLong(latLong));
         if (expectedValue.hasLatLong) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
             if (assertRanges) {
                 final long[] latitudeRange = exifInterface
                         .getAttributeRange(ExifInterface.TAG_GPS_LATITUDE);
@@ -286,6 +303,7 @@
             assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
             assertTrue(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
         } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_GPS_LATITUDE));
             assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LATITUDE));
             assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_GPS_LONGITUDE));
         }
@@ -318,6 +336,26 @@
         assertStringTag(exifInterface, ExifInterface.TAG_ISO_SPEED_RATINGS, expectedValue.iso);
         assertIntTag(exifInterface, ExifInterface.TAG_ORIENTATION, expectedValue.orientation);
         assertIntTag(exifInterface, ExifInterface.TAG_WHITE_BALANCE, expectedValue.whiteBalance);
+
+        if (expectedValue.hasXmp) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+            if (assertRanges) {
+                final long[] xmpRange = exifInterface.getAttributeRange(ExifInterface.TAG_XMP);
+                assertEquals(expectedValue.xmpOffset, xmpRange[0]);
+                assertEquals(expectedValue.xmpLength, xmpRange[1]);
+            }
+            final String xmp = new String(exifInterface.getAttributeBytes(ExifInterface.TAG_XMP),
+                    StandardCharsets.UTF_8);
+            // We're only interested in confirming that we were able to extract
+            // valid XMP data, which must always include this XML tag; a full
+            // XMP parser is beyond the scope of ExifInterface. See XMP
+            // Specification Part 1, Section C.2.2 for additional details.
+            if (!xmp.contains("<rdf:RDF")) {
+                fail("Invalid XMP: " + xmp);
+            }
+        } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_XMP));
+        }
     }
 
     private void testExifInterfaceCommon(String fileName, ExpectedValue expectedValue)
@@ -453,6 +491,12 @@
         testExifInterfaceForRaw(LG_G4_ISO_800_DNG, R.array.lg_g4_iso_800_dng);
     }
 
+    public void testReadExifDataFromLgG4Iso800Jpg() throws Throwable {
+        stageFile(R.raw.lg_g4_iso_800, new File(Environment.getExternalStorageDirectory(),
+                EXTERNAL_BASE_DIRECTORY + LG_G4_ISO_800_JPG));
+        testExifInterfaceForJpeg(LG_G4_ISO_800_JPG, R.array.lg_g4_iso_800_jpg);
+    }
+
     public void testDoNotFailOnCorruptedImage() throws Throwable {
         // To keep the compatibility with old versions of ExifInterface, even on a corrupted image,
         // it shouldn't raise any exceptions except an IOException when unable to open a file.
@@ -535,4 +579,11 @@
         assertEquals(dateTimeOriginalValue, exif.getAttribute(ExifInterface.TAG_DATETIME));
         imageFile.delete();
     }
+
+    private void stageFile(int resId, File file) throws IOException {
+        try (InputStream source = getContext().getResources().openRawResource(resId);
+                OutputStream target = new FileOutputStream(file)) {
+            FileUtils.copy(source, target);
+        }
+    }
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaFormatTest.java b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
new file mode 100644
index 0000000..c5b3ed4
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaFormatTest.java
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.media.MediaFormat;
+import android.test.AndroidTestCase;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+public class MediaFormatTest extends AndroidTestCase {
+    private static ByteBuffer defaultByteBuffer = ByteBuffer.allocateDirect(16);
+
+    private void assertGetByteBuffersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            ByteBuffer value = format.getByteBuffer(key);
+            throw new AssertionError("read " + type + " as ByteBuffer " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            ByteBuffer value = format.getByteBuffer(key, defaultByteBuffer);
+            throw new AssertionError("read " + type + " with default as ByteBuffer " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetFloatsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            float value = format.getFloat(key);
+            throw new AssertionError("read " + type + " as float " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            float value = format.getFloat(key, 321.f);
+            throw new AssertionError("read " + type + " with default as float " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetIntegersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            int value = format.getInteger(key);
+            throw new AssertionError("read " + type + " as int " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            int value = format.getInteger(key, 123);
+            throw new AssertionError("read " + type + " with default as int " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetLongsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            long value = format.getLong(key);
+            throw new AssertionError("read " + type + " as long " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            long value = format.getLong(key, 321L);
+            throw new AssertionError("read " + type + " with default as long " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetNumbersThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            Number value = format.getNumber(key);
+            throw new AssertionError("read " + type + " as Number " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            Number value = format.getNumber(key, 321.f);
+            throw new AssertionError("read " + type + " with default as Number " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    private void assertGetStringsThrowClassCastException(
+            MediaFormat format, String key, String type) {
+        try {
+            String value = format.getString(key);
+            throw new AssertionError("read " + type + " as string " + value);
+        } catch (ClassCastException e) {
+        }
+
+        try {
+            String value = format.getString(key, "321");
+            throw new AssertionError("read " + type + " with default as string " + value);
+        } catch (ClassCastException e) {
+        }
+    }
+
+    public void testIntegerValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+
+        assertEquals(123, format.getInteger("int"));
+
+        // We should be able to read int values as numbers.
+        assertEquals(123, format.getNumber("int").intValue());
+        assertEquals(123, format.getNumber("int", 321).intValue());
+
+        // We should not be able to get an integer value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "int", "int");
+        assertGetFloatsThrowClassCastException(format, "int", "int");
+        assertGetLongsThrowClassCastException(format, "int", "int");
+        assertGetStringsThrowClassCastException(format, "int", "int");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("int");
+            throw new AssertionError("read int as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "int", MediaFormat.TYPE_INTEGER);
+    }
+
+    public void testLongValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setLong("long", 9876543210L);
+
+        assertEquals(9876543210L, format.getLong("long"));
+
+        // We should be able to read long values as numbers.
+        assertEquals(9876543210L, format.getNumber("long").longValue());
+        assertEquals(9876543210L, format.getNumber("long", 9012345678L).longValue());
+
+        // We should not be able to get a long value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "long", "long");
+        assertGetFloatsThrowClassCastException(format, "long", "long");
+        assertGetIntegersThrowClassCastException(format, "long", "long");
+        assertGetStringsThrowClassCastException(format, "long", "long");
+
+        // We should not have a feature enabled for a long value
+        try {
+            boolean value = format.getFeatureEnabled("long");
+            throw new AssertionError("read long as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "long", MediaFormat.TYPE_LONG);
+    }
+
+    public void testFloatValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setFloat("float", 3.14f);
+
+        assertEquals(3.14f, format.getFloat("float"));
+
+        // We should be able to read float values as numbers.
+        assertEquals(3.14f, format.getNumber("float").floatValue());
+        assertEquals(3.14f, format.getNumber("float", 2.81f).floatValue());
+
+        // We should not be able to get a float value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "float", "float");
+        assertGetIntegersThrowClassCastException(format, "float", "float");
+        assertGetLongsThrowClassCastException(format, "float", "float");
+        assertGetStringsThrowClassCastException(format, "float", "float");
+
+        // We should not have a feature enabled for a float value
+        try {
+            boolean value = format.getFeatureEnabled("float");
+            throw new AssertionError("read float as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "float", MediaFormat.TYPE_FLOAT);
+    }
+
+    public void testStringValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setString("string", "value");
+
+        assertEquals("value", format.getString("string"));
+
+        // We should not be able to get a string value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetByteBuffersThrowClassCastException(format, "string", "string");
+        assertGetFloatsThrowClassCastException(format, "string", "string");
+        assertGetIntegersThrowClassCastException(format, "string", "string");
+        assertGetLongsThrowClassCastException(format, "string", "string");
+        assertGetNumbersThrowClassCastException(format, "string", "string");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("string");
+            throw new AssertionError("read string as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "string", MediaFormat.TYPE_STRING);
+    }
+
+    public void testByteBufferValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        ByteBuffer buffer = ByteBuffer.allocateDirect(123);
+        format.setByteBuffer("buffer", buffer);
+
+        assertEquals(buffer, format.getByteBuffer("buffer"));
+
+        // We should not be able to get a string value as any other type. Instead,
+        // we should receive a ClassCastException
+        assertGetFloatsThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetIntegersThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetLongsThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetNumbersThrowClassCastException(format, "buffer", "ByteBuffer");
+        assertGetStringsThrowClassCastException(format, "buffer", "ByteBuffer");
+
+        // We should not have a feature enabled for an integer value
+        try {
+            boolean value = format.getFeatureEnabled("buffer");
+            throw new AssertionError("read ByteBuffer as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+
+        testSingleKeyRemoval(format, "buffer", MediaFormat.TYPE_BYTE_BUFFER);
+    }
+
+    public void testNullStringValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setString("null", null);
+        testNullOrMissingValue(format, "null");
+        testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+    }
+
+    public void testNullByteBufferValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        format.setByteBuffer("null", null);
+        testNullOrMissingValue(format, "null");
+        testSingleKeyRemoval(format, "null", MediaFormat.TYPE_NULL);
+    }
+
+    public void testMissingValue() throws Exception {
+        MediaFormat format = new MediaFormat();
+        // null values should be handled the same as missing values
+        assertEquals(MediaFormat.TYPE_NULL, format.getValueTypeForKey("missing"));
+        testNullOrMissingValue(format, "missing");
+    }
+
+    private void testSingleKeyRemoval(
+            MediaFormat format, String key, @MediaFormat.Type int type) {
+        assertEquals(type, format.getValueTypeForKey(key));
+        assertTrue(format.containsKey(key));
+
+        Set<String> keySet = format.getKeys();
+        assertEquals(1, keySet.size());
+        assertTrue(keySet.contains(key));
+
+        format.removeKey(key);
+        assertFalse(format.containsKey(key));
+
+        // test that keySet is connected to the format
+        assertFalse(keySet.contains(key));
+        assertEquals(0, keySet.size());
+    }
+
+    private static Set<String> asSet(String ... values) {
+        return new HashSet<>(Arrays.asList(values));
+    }
+
+    private void assertStringSetEquals(Set<String> set, String ... expected_members) {
+        Set<String> expected = new HashSet<>(Arrays.asList(expected_members));
+        assertEquals(expected, set);
+    }
+
+    public void testKeySetContainsAndRemove() {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+        format.setLong("long", 9876543210L);
+        format.setFloat("float", 321.f);
+        format.setFeatureEnabled("int", true);
+        format.setFeatureEnabled("long", false);
+        format.setFeatureEnabled("float", true);
+        format.setFeatureEnabled("string", false);
+
+        Set<String> keySet = format.getKeys();
+        // test size and contains
+        assertEquals(3, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertTrue(keySet.contains("float"));
+        assertFalse(keySet.contains("string"));
+        assertStringSetEquals(keySet, "int", "long", "float");
+
+        // test adding an element
+        format.setString("string", "value");
+
+        // test that key set reflects format change in size and contains
+        assertEquals(4, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertTrue(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+
+        // test iterator
+        {
+            Set<String> toFind = asSet("int", "long", "float", "string");
+            Iterator<String> it = keySet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // remove via format
+        format.removeKey("float");
+
+        // test that key set reflects format change in size and contains
+        assertEquals(3, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertTrue(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+
+        // re-test iterator after removal
+        {
+            Set<String> toFind = asSet("int", "long", "string");
+            for (String k : keySet) {
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test remove
+        keySet.remove("long");
+        assertEquals(2, keySet.size());
+        assertTrue(keySet.contains("int"));
+        assertFalse(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+        assertTrue(format.containsKey("int"));
+        assertFalse(format.containsKey("long"));
+        assertFalse(format.containsKey("float"));
+        assertTrue(format.containsKey("string"));
+
+        // test iterator by its interface as well as its remove
+        {
+            Set<String> toFind = asSet("int", "string");
+            Iterator<String> it = keySet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+                if (k.equals("int")) {
+                    it.remove();
+                }
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that removing via iterator also removes from format
+        assertEquals(1, keySet.size());
+        assertFalse(keySet.contains("int"));
+        assertFalse(keySet.contains("long"));
+        assertFalse(keySet.contains("float"));
+        assertTrue(keySet.contains("string"));
+        assertFalse(format.containsKey("int"));
+        assertFalse(format.containsKey("long"));
+        assertFalse(format.containsKey("float"));
+        assertTrue(format.containsKey("string"));
+
+        // verify that features are still present
+        assertTrue(format.getFeatureEnabled("int"));
+        assertFalse(format.getFeatureEnabled("long"));
+        assertTrue(format.getFeatureEnabled("float"));
+        assertFalse(format.getFeatureEnabled("string"));
+    }
+
+    public void testFeatureKeySetContainsAndRemove() {
+        MediaFormat format = new MediaFormat();
+        format.setInteger("int", 123);
+        format.setLong("long", 9876543210L);
+        format.setFloat("float", 321.f);
+        format.setString("string", "value");
+        format.setFeatureEnabled("int", true);
+        format.setFeatureEnabled("long", false);
+        format.setFeatureEnabled("float", true);
+
+        Set<String> featureSet = format.getFeatures();
+        // test size and contains
+        assertEquals(3, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertTrue(featureSet.contains("float"));
+        assertFalse(featureSet.contains("string"));
+        assertStringSetEquals(featureSet, "int", "long", "float");
+
+        // test adding an element
+        format.setFeatureEnabled("string", false);
+
+        // test that key set reflects format change in size and contains
+        assertEquals(4, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertTrue(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        // test iterator
+        {
+            Set<String> toFind = asSet("int", "long", "float", "string");
+            Iterator<String> it = featureSet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that features cannot be removed via format as keys, even though for backward
+        // compatibility, they can be accessed as integers and can be found via containsKey
+        format.removeKey("feature-float");
+        assertEquals(4, featureSet.size());
+        assertTrue(featureSet.contains("float"));
+
+        format.removeFeature("float");
+
+        // TODO: deprecate this usage
+        assertEquals(1, format.getInteger("feature-int"));
+        assertEquals(0, format.getInteger("feature-long"));
+        assertTrue(format.containsKey("feature-int"));
+
+        // Along these lines also verify that this is not true for the getKeys() set
+        assertFalse(format.getKeys().contains("feature-int"));
+
+        // Also verify that getKeys() cannot be used to remove a feature
+        assertFalse(format.getKeys().remove("feature-int"));
+
+        // test that key set reflects format change in size and contains
+        assertEquals(3, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertTrue(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        // re-test iterator after removal
+        {
+            Set<String> toFind = asSet("int", "long", "string");
+            for (String k : featureSet) {
+                assertTrue(toFind.remove(k));
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test remove via set
+        featureSet.remove("long");
+        assertEquals(2, featureSet.size());
+        assertTrue(featureSet.contains("int"));
+        assertFalse(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        assertTrue(format.containsFeature("int"));
+        assertFalse(format.containsFeature("long"));
+        assertFalse(format.containsFeature("float"));
+        assertTrue(format.containsFeature("string"));
+
+        assertTrue(format.getFeatureEnabled("int"));
+        try {
+            format.getFeatureEnabled("long");
+            fail("should not contain feature long");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("float");
+            fail("should not contain feature float");
+        } catch (IllegalArgumentException e) {}
+        assertFalse(format.getFeatureEnabled("string"));
+
+        // test iterator by its interface as well as its remove
+        {
+            Set<String> toFind = asSet("int", "string");
+            Iterator<String> it = featureSet.iterator();
+            while (it.hasNext()) {
+                String k = it.next();
+                assertTrue(toFind.remove(k));
+                if (k.equals("int")) {
+                    it.remove();
+                }
+            }
+            assertEquals(0, toFind.size());
+        }
+
+        // test that removing via iterator also removes from format
+        assertEquals(1, featureSet.size());
+        assertFalse(featureSet.contains("int"));
+        assertFalse(featureSet.contains("long"));
+        assertFalse(featureSet.contains("float"));
+        assertTrue(featureSet.contains("string"));
+
+        assertFalse(format.containsFeature("int"));
+        assertFalse(format.containsFeature("long"));
+        assertFalse(format.containsFeature("float"));
+        assertTrue(format.containsFeature("string"));
+
+        try {
+            format.getFeatureEnabled("int");
+            fail("should not contain feature int");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("long");
+            fail("should not contain feature long");
+        } catch (IllegalArgumentException e) {}
+        try {
+            format.getFeatureEnabled("float");
+            fail("should not contain feature float");
+        } catch (IllegalArgumentException e) {}
+        assertFalse(format.getFeatureEnabled("string"));
+
+        // verify that keys are still present
+        assertEquals(123, format.getInteger("int"));
+        assertEquals(9876543210L, format.getLong("long"));
+        assertEquals(321.f, format.getFloat("float"));
+        assertEquals("value", format.getString("string"));
+    }
+
+    private void testNullOrMissingValue(MediaFormat format, String key) throws Exception {
+        // We should not be able to get a string value as any primitive type. Instead,
+        // we should receive a NullPointerException
+        try {
+            int value = format.getInteger(key);
+            throw new AssertionError("read " + key + " as int " + value);
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            long value = format.getLong(key);
+            throw new AssertionError("read " + key + " as long " + value);
+        } catch (NullPointerException e) {
+        }
+
+        try {
+            float value = format.getFloat(key);
+            throw new AssertionError("read " + key + " as float " + value);
+        } catch (NullPointerException e) {
+        }
+
+        // We should get null for all object types (ByteBuffer, Number, String)
+        assertNull(format.getNumber(key));
+        assertNull(format.getString(key));
+        assertNull(format.getByteBuffer(key));
+
+        // We should get the default value for all getters with default
+        assertEquals(123, format.getInteger(key, 123));
+        assertEquals(321L, format.getLong(key, 321L));
+        assertEquals(321.f, format.getFloat(key, 321.f));
+        assertEquals(321.f, format.getNumber(key, 321.f));
+        assertEquals("value", format.getString(key, "value"));
+        assertEquals(defaultByteBuffer, format.getByteBuffer(key, defaultByteBuffer));
+
+        // We should not have a feature enabled for a null value
+        try {
+            boolean value = format.getFeatureEnabled(key);
+            throw new AssertionError("read " + key + " as feature " + value);
+        } catch (IllegalArgumentException e) {
+        }
+    }
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
index 0d1796a..c19dba5 100644
--- a/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMuxerTest.java
@@ -464,9 +464,8 @@
                 verifyAttributesMatch(srcMedia, outputMediaFile, degrees);
                 verifyLocationInFile(outputMediaFile);
             }
-            // Check the sample on 1s and 0.5s.
-            verifySamplesMatch(srcMedia, outputMediaFile, 1000000);
-            verifySamplesMatch(srcMedia, outputMediaFile, 500000);
+            // Verify timestamp of all samples.
+            verifyTimestampsWithSamplesDropSet(srcMedia, outputMediaFile, null, null);
         } finally {
             new File(outputMediaFile).delete();
         }
@@ -1003,15 +1002,12 @@
                 }
                 extractorSrc.selectTrack(videoTrackIndex);
                 extractorTest.selectTrack(videoTrackIndex);
+                checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
+                    videoStartOffsetUs);
+                extractorSrc.unselectTrack(videoTrackIndex);
+                extractorTest.unselectTrack(videoTrackIndex);
             }
         }
-        if (videoTrackIndex != -1) {
-            checkVideoSamplesTimeStamps(extractorSrc, extractorTest, samplesDropSet,
-                videoStartOffsetUs);
-        }
-
-        extractorSrc.unselectTrack(videoTrackIndex);
-        extractorTest.unselectTrack(videoTrackIndex);
 
         int audioTrackIndex = -1;
         int audioSampleCount = 0;
@@ -1026,14 +1022,10 @@
                 }
                 extractorSrc.selectTrack(audioTrackIndex);
                 extractorTest.selectTrack(audioTrackIndex);
+                checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
             }
         }
 
-        if (audioTrackIndex != -1) {
-           // No audio track
-            checkAudioSamplesTimestamps(extractorSrc, extractorTest, audioStartOffsetUs);
-        }
-
         extractorSrc.release();
         extractorTest.release();
         srcFd.close();
@@ -1057,10 +1049,10 @@
             srcSampleTimeUs = extractorSrc.getSampleTime();
             testSampleTimeUs = extractorTest.getSampleTime();
             if (VERBOSE) {
-                Log.d(TAG, "videoSampleCount:" + videoSampleCount);
-                Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
+                Log.i(TAG, "videoSampleCount:" + videoSampleCount);
+                Log.i(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
                             "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
-                Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
+                Log.i(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
             }
             if (samplesDropSet == null || !samplesDropSet.contains(videoSampleCount)) {
                 if (srcSampleTimeUs == -1 || testSampleTimeUs == -1) {
@@ -1114,6 +1106,7 @@
             srcSampleTimeUs = extractorSrc.getSampleTime();
             testSampleTimeUs = extractorTest.getSampleTime();
             if(VERBOSE) {
+                Log.d(TAG, "audioSampleCount:" + audioSampleCount);
                 Log.v(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
                             "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
                 Log.v(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
@@ -1137,22 +1130,12 @@
             else if ((audioSampleCount > 1 &&
                 (srcSampleTimeUs + audioStartOffsetUs) != testSampleTimeUs) ||
                 (audioSampleCount == 1 && srcSampleTimeUs != testSampleTimeUs)) {
-                    if (VERBOSE) {
-                        Log.d(TAG, "Fail:audio timestamps didn't match");
-                        Log.d(TAG, "srcTrackIndex:" + extractorSrc.getSampleTrackIndex() +
-                            "  testTrackIndex:" + extractorTest.getSampleTrackIndex());
-                        Log.d(TAG, "srcTSus:" + srcSampleTimeUs + " testTSus:" + testSampleTimeUs);
-                        Log.d(TAG, "audioSampleCount:" + audioSampleCount);
-                    }
                     fail("audio timestamps didn't match");
                 }
             testAdvance = extractorTest.advance();
             srcAdvance = extractorSrc.advance();
         } while(srcAdvance && testAdvance);
         if (srcAdvance != testAdvance) {
-            if (VERBOSE) {
-                Log.d(TAG, "audioSampleCount:" + audioSampleCount);
-            }
             fail("either audio track has not reached its last sample");
         }
     }
diff --git a/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
new file mode 100644
index 0000000..aa9894f
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/SurfaceEncodeTimestampTest.java
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2019 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.graphics.Color;
+import android.graphics.Rect;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaCodec.CodecException;
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.media.MediaCodecInfo.CodecCapabilities;
+import android.opengl.GLES20;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.RequiresDevice;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+@AppModeFull(reason = "TODO: evaluate and port to instant")
+@SmallTest
+@RequiresDevice
+public class SurfaceEncodeTimestampTest extends AndroidTestCase {
+    private static final String TAG = SurfaceEncodeTimestampTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private static final Color COLOR_BLOCK =
+            Color.valueOf(1.0f, 1.0f, 1.0f);
+    private static final Color[] COLOR_BARS = {
+            Color.valueOf(0.0f, 0.0f, 0.0f),
+            Color.valueOf(0.0f, 0.0f, 0.64f),
+            Color.valueOf(0.0f, 0.64f, 0.0f),
+            Color.valueOf(0.0f, 0.64f, 0.64f),
+            Color.valueOf(0.64f, 0.0f, 0.0f),
+            Color.valueOf(0.64f, 0.0f, 0.64f),
+            Color.valueOf(0.64f, 0.64f, 0.0f),
+    };
+    private static final int BORDER_WIDTH = 16;
+
+    private Handler mHandler;
+    private HandlerThread mHandlerThread;
+    private MediaCodec mEncoder;
+    private InputSurface mInputEglSurface;
+    private int mInputCount;
+
+    @Override
+    public void setUp() throws Exception {
+        if (mHandlerThread == null) {
+            mHandlerThread = new HandlerThread(
+                    "EncoderThread", Process.THREAD_PRIORITY_FOREGROUND);
+            mHandlerThread.start();
+            mHandler = new Handler(mHandlerThread.getLooper());
+        }
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        mHandler = null;
+        if (mHandlerThread != null) {
+            mHandlerThread.quit();
+            mHandlerThread = null;
+        }
+    }
+
+    /*
+     * Test KEY_MAX_PTS_GAP_TO_ENCODER
+     *
+     * This key is supposed to cap the gap between any two frames fed to the encoder,
+     * and restore the output pts back to the original. Since the pts is not supposed
+     * to be modified, we can't really verify that the "capping" actually took place.
+     * However, we can at least verify that the pts is preserved.
+     */
+    public void testMaxPtsGap() throws Throwable {
+        long[] inputPts = {1000000, 2000000, 3000000, 4000000};
+        long[] expectedOutputPts = {1000000, 2000000, 3000000, 4000000};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, 33333);
+        });
+    }
+
+    /*
+     * Test that by default backward-going frames get dropped.
+     */
+    public void testBackwardFrameDroppedWithoutFixedPtsGap() throws Throwable {
+        long[] inputPts = {33333, 66667, 66000, 100000};
+        long[] expectedOutputPts = {33333, 66667, 100000};
+        doTest(inputPts, expectedOutputPts, null);
+    }
+
+    /*
+     * Test KEY_MAX_PTS_GAP_TO_ENCODER
+     *
+     * Test that when fixed pts gap is used, backward-going frames are accepted
+     * and the pts is preserved.
+     */
+    public void testBackwardFramePreservedWithFixedPtsGap() throws Throwable {
+        long[] inputPts = {33333, 66667, 66000, 100000};
+        long[] expectedOutputPts = {33333, 66667, 66000, 100000};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_MAX_PTS_GAP_TO_ENCODER, -33333);
+        });
+    }
+
+    /*
+     * Test KEY_MAX_FPS_TO_ENCODER
+     *
+     * Input frames are timestamped at 60fps, the key is supposed to drop
+     * one every other frame to maintain 30fps output.
+     */
+    public void testMaxFps() throws Throwable {
+        long[] inputPts = {16667, 33333, 50000, 66667, 83333};
+        long[] expectedOutputPts = {16667, 50000, 83333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setFloat(MediaFormat.KEY_MAX_FPS_TO_ENCODER, 30.0f);
+        });
+    }
+
+    /*
+     * Test KEY_REPEAT_PREVIOUS_FRAME_AFTER
+     *
+     * Test that the frame is repeated at least once if no new frame arrives after
+     * the specified amount of time.
+     */
+    public void testRepeatPreviousFrameAfter() throws Throwable {
+        long[] inputPts = {16667, 33333, -100000, 133333};
+        long[] expectedOutputPts = {16667, 33333, 103333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setLong(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 70000);
+        });
+    }
+
+    /*
+     * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED and PARAMETER_KEY_SUSPEND
+     *
+     * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then resume
+     * by PARAMETER_KEY_SUSPEND. Verify only frames after resume are captured.
+     */
+    public void testCreateInputSurfaceSuspendedResume() throws Throwable {
+        // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+        // PARAMETER_KEY_SUSPEND_TIME) to resume doesn't enforce a time
+        // for the action to take effect. Due to the asynchronous operation
+        // between the MediaCodec's parameters and the input surface, frames
+        // rendered before the resume call may reach encoder input side after
+        // the resume. Here we do a slight wait (100000us) to make sure that
+        // the resume only takes effect on the frame with timestamp 100000.
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+        long[] expectedOutputPts = {100000, 133333};
+        doTest(inputPts, expectedOutputPts, (format) -> {
+            format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            return params;
+        });
+    }
+
+    /*
+     * Test KEY_CREATE_INPUT_SURFACE_SUSPENDED,
+     * PARAMETER_KEY_SUSPEND and PARAMETER_KEY_SUSPEND_TIME
+     *
+     * Start the encoder with KEY_CREATE_INPUT_SURFACE_SUSPENDED set, then request resume
+     * at specific time using PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+     * Verify only frames after the specified time are captured.
+     */
+     public void testCreateInputSurfaceSuspendedResumeWithTime() throws Throwable {
+         // Unlike using PARAMETER_KEY_SUSPEND alone to resume, using PARAMETER_KEY_SUSPEND
+         // + PARAMETER_KEY_SUSPEND_TIME to resume can be scheduled any time before the
+         // frame with the specified time arrives. Here we do it immediately after start.
+         long[] inputPts = {-1, 33333, 66667, 100000, 133333};
+         long[] expectedOutputPts = {100000, 133333};
+         doTest(inputPts, expectedOutputPts, (format) -> {
+             format.setInteger(MediaFormat.KEY_CREATE_INPUT_SURFACE_SUSPENDED, 1);
+         }, () -> {
+             Bundle params = new Bundle();
+             params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+             params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+             return params;
+         });
+    }
+
+     /*
+      * Test PARAMETER_KEY_SUSPEND.
+      *
+      * Suspend/resume during capture, and verify that frames during the suspension
+      * period are dropped.
+      */
+    public void testSuspendedResume() throws Throwable {
+        // Using PARAMETER_KEY_SUSPEND (instead of PARAMETER_KEY_SUSPEND +
+        // PARAMETER_KEY_SUSPEND_TIME) to suspend/resume doesn't enforce a time
+        // for the action to take effect. Due to the asynchronous operation
+        // between the MediaCodec's parameters and the input surface, frames
+        // rendered before the request may reach encoder input side after
+        // the request. Here we do a slight wait (100000us) to make sure that
+        // the suspend/resume only takes effect on the next frame.
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333, -100000, 166667};
+        long[] expectedOutputPts = {33333, 66667, 166667};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+            return params;
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            return params;
+        });
+    }
+
+    /*
+     * Test PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME.
+     *
+     * Suspend/resume with specified time during capture, and verify that frames during
+     * the suspension period are dropped.
+     */
+    public void testSuspendedResumeWithTime() throws Throwable {
+        // Unlike using PARAMETER_KEY_SUSPEND alone to suspend/resume, requests using
+        // PARAMETER_KEY_SUSPEND + PARAMETER_KEY_SUSPEND_TIME can be scheduled any time
+        // before the frame with the specified time arrives. Queue both requests shortly
+        // after start and test that they take place at the proper frames.
+        long[] inputPts = {-1, 33333, -1, 66667, 100000, 133333, 166667};
+        long[] expectedOutputPts = {33333, 66667, 166667};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 1);
+            params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 100000);
+            return params;
+        }, () -> {
+            Bundle params = new Bundle();
+            params.putInt(MediaCodec.PARAMETER_KEY_SUSPEND, 0);
+            params.putLong(MediaCodec.PARAMETER_KEY_SUSPEND_TIME, 166667);
+            return params;
+        });
+    }
+
+    /*
+     * Test PARAMETER_KEY_OFFSET_TIME.
+     *
+     * Apply PARAMETER_KEY_OFFSET_TIME during capture, and verify that the pts
+     * of frames after the request are adjusted by the offset correctly.
+     */
+    public void testOffsetTime() throws Throwable {
+        long[] inputPts = {33333, 66667, -100000, 100000, 133333};
+        long[] expectedOutputPts = {33333, 66667, 83333, 116666};
+        doTest(inputPts, expectedOutputPts, null, () -> {
+            Bundle params = new Bundle();
+            params.putLong(MediaCodec.PARAMETER_KEY_OFFSET_TIME, -16667);
+            return params;
+        });
+    }
+
+    private void doTest(long[] inputPtsUs, long[] expectedOutputPtsUs,
+            Consumer<MediaFormat> configSetter, Supplier<Bundle>... paramGetter) throws Exception {
+
+        try {
+            if (DEBUG) Log.d(TAG, "started");
+
+            // setup surface encoder format
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC);
+            MediaFormat codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720);
+            codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
+            codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+                    CodecCapabilities.COLOR_FormatSurface);
+            codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30);
+            codecFormat.setInteger(MediaFormat.KEY_BITRATE_MODE,
+                    MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
+            codecFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000);
+
+            if (configSetter != null) {
+                configSetter.accept(codecFormat);
+            }
+
+            CountDownLatch latch = new CountDownLatch(1);
+
+            // configure and start encoder
+            long[] actualOutputPtsUs = new long[expectedOutputPtsUs.length];
+            mEncoder.setCallback(new EncoderCallback(latch, actualOutputPtsUs), mHandler);
+            mEncoder.configure(codecFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+            mInputEglSurface = new InputSurface(mEncoder.createInputSurface());
+
+            mEncoder.start();
+
+            mInputCount = 0;
+            int paramIndex = 0;
+            // perform input operations
+            for (int i = 0; i < inputPtsUs.length; i++) {
+                if (DEBUG) Log.d(TAG, "drawFrame: " + i + ", pts " + inputPtsUs[i]);
+
+                if (inputPtsUs[i] < 0) {
+                    if (inputPtsUs[i] < -1) {
+                        // larger negative number means that a sleep is required
+                        // before the parameter test.
+                        Thread.sleep(-inputPtsUs[i]/1000);
+                    }
+                    if (paramIndex < paramGetter.length && paramGetter[paramIndex] != null) {
+                        // this means a pause to apply parameter to be tested
+                        mEncoder.setParameters(paramGetter[paramIndex].get());
+                    }
+                    paramIndex++;
+                } else {
+                    drawFrame(1280, 720, inputPtsUs[i]);
+                }
+            }
+
+            // if it worked there is really no reason to take longer..
+            latch.await(1000, TimeUnit.MILLISECONDS);
+
+            // verify output timestamps
+            assertTrue("mismatch in output timestamp",
+                    Arrays.equals(expectedOutputPtsUs, actualOutputPtsUs));
+
+            if (DEBUG) Log.d(TAG, "stopped");
+        } finally {
+            if (mEncoder != null) {
+                mEncoder.stop();
+                mEncoder.release();
+                mEncoder = null;
+            }
+            if (mInputEglSurface != null) {
+                // This also releases the surface from encoder.
+                mInputEglSurface.release();
+                mInputEglSurface = null;
+            }
+        }
+    }
+
+    class EncoderCallback extends MediaCodec.Callback {
+        private boolean mOutputEOS;
+        private int mOutputCount;
+        private final CountDownLatch mLatch;
+        private final long[] mActualOutputPts;
+        private final int mMaxOutput;
+
+        EncoderCallback(CountDownLatch latch, long[] actualOutputPts) {
+            mLatch = latch;
+            mActualOutputPts = actualOutputPts;
+            mMaxOutput = actualOutputPts.length;
+        }
+
+        @Override
+        public void onOutputFormatChanged(MediaCodec codec, MediaFormat format) {
+            if (codec != mEncoder) return;
+            if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
+        }
+
+        @Override
+        public void onInputBufferAvailable(MediaCodec codec, int index) {
+            if (codec != mEncoder) return;
+            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index);
+        }
+
+        @Override
+        public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
+            if (codec != mEncoder || mOutputEOS) return;
+
+            if (DEBUG) {
+                Log.d(TAG, "onOutputBufferAvailable: " + index
+                        + ", time " + info.presentationTimeUs
+                        + ", size " + info.size
+                        + ", flags " + info.flags);
+            }
+
+            if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
+                mActualOutputPts[mOutputCount++] = info.presentationTimeUs;
+            }
+
+            mOutputEOS |= ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) ||
+                    (mOutputCount == mMaxOutput);
+
+            codec.releaseOutputBuffer(index, false);
+
+            if (mOutputEOS) {
+                stopAndNotify(null);
+            }
+        }
+
+        @Override
+        public void onError(MediaCodec codec, CodecException e) {
+            if (codec != mEncoder) return;
+
+            Log.e(TAG, "onError: " + e);
+            stopAndNotify(e);
+        }
+
+        private void stopAndNotify(CodecException e) {
+            mLatch.countDown();
+        }
+    }
+
+    private void drawFrame(int width, int height, long ptsUs) {
+        mInputEglSurface.makeCurrent();
+        generateSurfaceFrame(mInputCount, width, height);
+        mInputEglSurface.setPresentationTime(1000 * ptsUs);
+        mInputEglSurface.swapBuffers();
+        mInputCount++;
+    }
+
+    private static Rect getColorBarRect(int index, int width, int height) {
+        int barWidth = (width - BORDER_WIDTH * 2) / COLOR_BARS.length;
+        return new Rect(BORDER_WIDTH + barWidth * index, BORDER_WIDTH,
+                BORDER_WIDTH + barWidth * (index + 1), height - BORDER_WIDTH);
+    }
+
+    private static Rect getColorBlockRect(int index, int width, int height) {
+        int blockCenterX = (width / 5) * (index % 4 + 1);
+        return new Rect(blockCenterX - width / 10, height / 6,
+                        blockCenterX + width / 10, height / 3);
+    }
+
+    private void generateSurfaceFrame(int frameIndex, int width, int height) {
+        GLES20.glViewport(0, 0, width, height);
+        GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
+        GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
+
+        for (int i = 0; i < COLOR_BARS.length; i++) {
+            Rect r = getColorBarRect(i, width, height);
+
+            GLES20.glScissor(r.left, r.top, r.width(), r.height());
+            final Color color = COLOR_BARS[i];
+            GLES20.glClearColor(color.red(), color.green(), color.blue(), 1.0f);
+            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        }
+
+        Rect r = getColorBlockRect(frameIndex, width, height);
+        GLES20.glScissor(r.left, r.top, r.width(), r.height());
+        GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+        r.inset(BORDER_WIDTH, BORDER_WIDTH);
+        GLES20.glScissor(r.left, r.top, r.width(), r.height());
+        GLES20.glClearColor(COLOR_BLOCK.red(), COLOR_BLOCK.green(), COLOR_BLOCK.blue(), 1.0f);
+        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+    }
+}
diff --git a/tests/tests/multiuser/AndroidTest.xml b/tests/tests/multiuser/AndroidTest.xml
index 595fcd5..8edf9d6 100644
--- a/tests/tests/multiuser/AndroidTest.xml
+++ b/tests/tests/multiuser/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsMultiUserTestCases.apk" />
diff --git a/tests/tests/neuralnetworks/benchmark/Android.mk b/tests/tests/neuralnetworks/benchmark/Android.mk
index 9670236..067db34 100644
--- a/tests/tests/neuralnetworks/benchmark/Android.mk
+++ b/tests/tests/neuralnetworks/benchmark/Android.mk
@@ -29,7 +29,7 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test androidx.test.rules \
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test \
     compatibility-device-util ctstestrunner junit NeuralNetworksApiBenchmark_Lib
 LOCAL_JNI_SHARED_LIBRARIES := libnnbenchmark_jni
 
diff --git a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
index be6d40e..827b5dd 100644
--- a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
+++ b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
@@ -23,10 +23,9 @@
 import android.os.Bundle;
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
+import android.support.test.InstrumentationRegistry;
 import android.util.Pair;
 
-import androidx.test.InstrumentationRegistry;
-
 import com.android.nn.benchmark.core.BenchmarkException;
 import com.android.nn.benchmark.core.BenchmarkResult;
 import com.android.nn.benchmark.core.InferenceInOutSequence;
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 2292392..836214c 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -4410,9 +4410,9 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. -->
-    <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
-        android:protectionLevel="signature" />
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
+                android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
diff --git a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
index 9613c15..13caf39 100644
--- a/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
+++ b/tests/tests/role/src/android/app/role/cts/RoleManagerTest.java
@@ -206,7 +206,7 @@
         boolean[] successful = new boolean[1];
         CountDownLatch latch = new CountDownLatch(1);
         runWithShellPermissionIdentity(() -> sRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         successful[0] = true;
@@ -229,7 +229,7 @@
         boolean[] successful = new boolean[1];
         CountDownLatch latch = new CountDownLatch(1);
         runWithShellPermissionIdentity(() -> sRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         successful[0] = true;
diff --git a/tests/tests/shortcutmanager/AndroidTest.xml b/tests/tests/shortcutmanager/AndroidTest.xml
index f2f6a46..512330b 100644
--- a/tests/tests/shortcutmanager/AndroidTest.xml
+++ b/tests/tests/shortcutmanager/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="config-descriptor:metadata" key="component" value="framework" />
     <!-- Instant apps can't access ShortcutManager -->
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsShortcutManagerTestCases.apk" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
index d3e0958..ef7a9ec 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallRedirectionServiceTest.java
@@ -180,7 +180,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
@@ -209,7 +209,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
diff --git a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
index 27a7010..3abf52f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CtsRoleManagerAdapter.java
@@ -163,7 +163,7 @@
         Executor executor = mContext.getMainExecutor();
         LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
         runWithShellPermissionIdentity(() -> {
-            mRoleManager.addRoleHolderAsUser(roleName, packageName, user, executor,
+            mRoleManager.addRoleHolderAsUser(roleName, packageName, 0, user, executor,
                     new RoleManagerCallback() {
                         @Override
                         public void onSuccess() {
@@ -186,7 +186,7 @@
         Executor executor = mContext.getMainExecutor();
         LinkedBlockingQueue<String> q = new LinkedBlockingQueue<>(1);
         runWithShellPermissionIdentity(() -> {
-            mRoleManager.removeRoleHolderAsUser(roleName, packageName, user, executor,
+            mRoleManager.removeRoleHolderAsUser(roleName, packageName, 0, user, executor,
                     new RoleManagerCallback() {
                         @Override
                         public void onSuccess() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
index 7d1bae2..83f3995 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ThirdPartyCallScreeningServiceTest.java
@@ -454,7 +454,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.addRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
@@ -483,7 +483,7 @@
         LinkedBlockingQueue<Boolean> queue = new LinkedBlockingQueue(1);
 
         runWithShellPermissionIdentity(() -> mRoleManager.removeRoleHolderAsUser(roleName,
-                packageName, user, executor, new RoleManagerCallback() {
+                packageName, 0, user, executor, new RoleManagerCallback() {
                     @Override
                     public void onSuccess() {
                         try {
diff --git a/tests/tests/transition/AndroidTest.xml b/tests/tests/transition/AndroidTest.xml
index e75e8de..cac2338 100644
--- a/tests/tests/transition/AndroidTest.xml
+++ b/tests/tests/transition/AndroidTest.xml
@@ -16,6 +16,9 @@
 <configuration description="Config for CTS Transition test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="uitoolkit" />
+    <!-- There is no difference between instant apps and installed apps with
+         respect to transition tests, so don't run these in instant apps. -->
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsTransitionTestCases.apk" />
diff --git a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
index 71bb9f1..cabe7bf 100644
--- a/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ChangeBoundsTest.java
@@ -71,7 +71,7 @@
     private void resetChangeBoundsTransition() {
         mListener = mock(Transition.TransitionListener.class);
         mChangeBounds = new MyChangeBounds();
-        mChangeBounds.setDuration(500);
+        mChangeBounds.setDuration(1000);
         mChangeBounds.addListener(mListener);
         mChangeBounds.setInterpolator(new LinearInterpolator());
         mTransition = mChangeBounds;
diff --git a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
index c1248a5..70da07f 100644
--- a/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/ExplodeTest.java
@@ -51,7 +51,7 @@
 
     private void resetTransition() {
         mExplode = new Explode();
-        mExplode.setDuration(500);
+        mExplode.setDuration(1000);
         mTransition = mExplode;
         resetListener();
     }
diff --git a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
index 63db5ef..dc4be47 100644
--- a/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
+++ b/tests/tests/transition/src/android/transition/cts/SlideEdgeTest.java
@@ -72,7 +72,7 @@
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            slide.setDuration(500);
+            slide.setDuration(1000);
             final Transition.TransitionListener listener =
                     mock(Transition.TransitionListener.class);
             slide.addListener(listener);
@@ -107,7 +107,7 @@
                         });
             });
             verify(listener, within(1000)).onTransitionStart(any());
-            verify(listener, within(1000)).onTransitionEnd(any());
+            verify(listener, within(2000)).onTransitionEnd(any());
 
             verifyMovement(redPoints, slideEdge, false);
             verifyMovement(greenPoints, slideEdge, false);
@@ -128,7 +128,7 @@
         for (int i = 0; i < sSlideEdgeArray.length; i++) {
             final int slideEdge = (Integer) (sSlideEdgeArray[i][0]);
             final Slide slide = new Slide(slideEdge);
-            slide.setDuration(500);
+            slide.setDuration(1000);
             final Transition.TransitionListener listener =
                     mock(Transition.TransitionListener.class);
             slide.addListener(listener);
@@ -172,7 +172,7 @@
                         });
             });
             verify(listener, within(1000)).onTransitionStart(any());
-            verify(listener, within(1000)).onTransitionEnd(any());
+            verify(listener, within(2000)).onTransitionEnd(any());
 
             verifyMovement(redPoints, slideEdge, true);
             verifyMovement(greenPoints, slideEdge, true);
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
index e401e88..bf8c7f7 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionManagerTest.java
@@ -16,7 +16,6 @@
 package android.transition.cts;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
@@ -77,6 +76,8 @@
         enterScene(R.layout.scene1);
         final CountDownLatch startLatch = new CountDownLatch(1);
         final Scene scene6 = loadScene(R.layout.scene6);
+
+        final CountDownLatch moveLatch = watchForRedSquareMoving();
         mActivityRule.runOnUiThread(() -> {
             mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
                     new ViewTreeObserver.OnPreDrawListener() {
@@ -91,37 +92,56 @@
             scene6.enter();
         });
         assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
-        ensureRedSquareIsMoving();
+        assertTrue(moveLatch.await(1000, TimeUnit.MILLISECONDS));
         endTransition();
     }
 
-    private void ensureRedSquareIsMoving() throws InterruptedException {
-        final View view = mActivity.findViewById(R.id.redSquare);
-        assertNotNull(view);
-        // We should see a ChangeBounds on redSquare
-        final Rect position = new Rect(view.getLeft(), view.getTop(), view.getRight(),
-                view.getBottom());
-
+    private CountDownLatch watchForRedSquareMoving() throws Throwable {
         final CountDownLatch latch = new CountDownLatch(1);
-        final Rect[] nextArr = new Rect[1];
-        view.postOnAnimation(new Runnable() {
-            // Wait at most 10 frames for the position to change
-            int mFramesToChange = 10;
 
-            @Override
-            public void run() {
-                nextArr[0] = new Rect(view.getLeft(), view.getTop(), view.getRight(),
-                        view.getBottom());
-                mFramesToChange--;
-                if (nextArr[0].equals(position) && mFramesToChange > 0) {
-                    view.postOnAnimation(this);
-                } else {
-                    latch.countDown();
-                }
-            }
+        mActivityRule.runOnUiThread(() -> {
+            final View decor = mActivity.getWindow().getDecorView();
+            final View viewBeforeTransition = mActivity.findViewById(R.id.redSquare);
+            decor.getViewTreeObserver().addOnPreDrawListener(
+                    new ViewTreeObserver.OnPreDrawListener() {
+                        // Wait at most 20 frames for the position to change
+                        int mFramesToChange = 20;
+                        Rect mLastPosition = null;
+                        View mView = null;
+                        int mPositionChanges = 0;
+
+                        @Override
+                        public boolean onPreDraw() {
+                            final View view = mActivity.findViewById(R.id.redSquare);
+                            if (mView == null && view != viewBeforeTransition) {
+                                // Capture the new red square View. It will be in the end
+                                // position now, so don't capture its position.
+                                mView = view;
+                                return true;
+                            }
+                            Rect nextPosition = new Rect(view.getLeft(), view.getTop(),
+                                    view.getRight(), view.getBottom());
+                            if (mLastPosition == null) {
+                                // This is the start position
+                                mLastPosition = nextPosition;
+                                return true;
+                            }
+                            mFramesToChange--;
+                            if (!nextPosition.equals(mLastPosition)) {
+                                mPositionChanges++;
+                                mLastPosition = nextPosition;
+                                if (mPositionChanges > 2) {
+                                    latch.countDown();
+                                }
+                            }
+                            if (mFramesToChange <= 0 || mPositionChanges > 2) {
+                                decor.getViewTreeObserver().removeOnPreDrawListener(this);
+                            }
+                            return true;
+                        }
+                    });
         });
-        assertTrue(latch.await(500, TimeUnit.MILLISECONDS));
-        assertNotEquals(position, nextArr[0]);
+        return latch;
     }
 
     @Test
@@ -149,6 +169,7 @@
         enterScene(R.layout.scene1);
         final CountDownLatch startLatch = new CountDownLatch(1);
         final Scene scene6 = loadScene(R.layout.scene6);
+        final CountDownLatch moveLatch = watchForRedSquareMoving();
         mActivityRule.runOnUiThread(() -> {
             mSceneRoot.getViewTreeObserver().addOnPreDrawListener(
                     new ViewTreeObserver.OnPreDrawListener() {
@@ -162,7 +183,7 @@
             TransitionManager.go(scene6);
         });
         assertTrue(startLatch.await(500, TimeUnit.MILLISECONDS));
-        ensureRedSquareIsMoving();
+        assertTrue(moveLatch.await(1000, TimeUnit.MILLISECONDS));
         endTransition();
     }
 
diff --git a/tests/tests/transition/src/android/transition/cts/TransitionTest.java b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
index 2c2e951..d200299 100644
--- a/tests/tests/transition/src/android/transition/cts/TransitionTest.java
+++ b/tests/tests/transition/src/android/transition/cts/TransitionTest.java
@@ -70,6 +70,14 @@
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class TransitionTest extends BaseTransitionTest {
+    @Override
+    public void setup() {
+        super.setup();
+        // We want to be able to catch the transition in the middle of running, so
+        // it should be long enough that devices can catch it without trouble.
+        mTransition.setDuration(1000);
+    }
+
     @Test
     public void testAddListener() throws Throwable {
         startTransition(R.layout.scene1);
@@ -103,13 +111,14 @@
 
     @Test
     public void testRemoveListener() throws Throwable {
+        TransitionListener listener = mock(TransitionListener.class);
+        mTransition.addListener(listener);
         startTransition(R.layout.scene1);
         waitForStart();
 
-        mActivityRule.runOnUiThread(() -> mTransition.removeListener(mListener));
-
-        SystemClock.sleep(250);
-        verify(mListener, never()).onTransitionEnd(any());
+        mActivityRule.runOnUiThread(() -> mTransition.removeListener(listener));
+        waitForEnd(2000);
+        mActivityRule.runOnUiThread(() -> verify(listener, never()).onTransitionEnd(any()));
     }
 
     @Test
@@ -360,7 +369,7 @@
         View redSquare1 = layout1.findViewById(R.id.redSquare);
         mTransition.excludeTarget(redSquare1, true);
         startTransition(R.layout.scene7);
-        waitForEnd(600);
+        waitForEnd(2000);
 
         mTransition.excludeTarget(redSquare1, false); // remove it
         resetListener();
@@ -422,21 +431,22 @@
 
     @Test
     public void testDuration() throws Throwable {
-        assertEquals(-1, mTransition.getDuration());
+        Transition transition = new AutoTransition();
+        assertEquals(-1, transition.getDuration());
         enterScene(R.layout.scene1);
-        mTransition.setDuration(500);
-        assertEquals(500, mTransition.getDuration());
+        mTransition.setDuration(1000);
+        assertEquals(1000, mTransition.getDuration());
         DurationListener durationListener = new DurationListener();
         mTransition.addListener(durationListener);
         startTransition(R.layout.scene3);
         waitForEnd(5000);
         // We can't be certain that the onTransitionStart() and onTransitionEnd()
-        // are going to be called exactly 500ms apart. There could be more of a
+        // are going to be called exactly 1000ms apart. There could be more of a
         // delay at the beginning than the end. So, we give it some room at the
         // minimum. It can also take a lot longer on the larger side because of
         // slow devices.
         assertThat(durationListener.getDuration(),
-                allOf(greaterThanOrEqualTo(400L), lessThan(900L)));
+                allOf(greaterThanOrEqualTo(500L), lessThan(2000L)));
     }
 
     @Test
@@ -468,7 +478,7 @@
         assertFalse(transition.animators.isEmpty());
         Animator animator = transition.animators.get(redSquare);
         Animator.AnimatorListener listener = transition.listeners.get(redSquare);
-        verify(listener, within(100)).onAnimationStart(any(), eq(false));
+        verify(listener, within(1000)).onAnimationStart(any(), eq(false));
         assertSame(interpolator, animator.getInterpolator());
         endTransition();
     }
@@ -525,7 +535,7 @@
         Animator redSquareAnimator = transition.animators.get(redSquare);
         Animator greenSquareAnimator = transition.animators.get(greenSquare);
         Animator.AnimatorListener listener = transition.listeners.get(redSquare);
-        verify(listener, within(100)).onAnimationStart(any(), eq(false));
+        verify(listener, within(1000)).onAnimationStart(any(), eq(false));
         assertEquals(0, redSquareAnimator.getStartDelay());
         assertEquals(diffTop, greenSquareAnimator.getStartDelay());
         endTransition();
@@ -569,8 +579,8 @@
         mTransition.setDuration(10);
         resetListener();
         startTransition(R.layout.scene2);
-        assertTrue(transition.onDisappearCalled.await(500, TimeUnit.MILLISECONDS));
-        assertTrue(transition.onAppearCalled.await(500, TimeUnit.MILLISECONDS));
+        assertTrue(transition.onDisappearCalled.await(2000, TimeUnit.MILLISECONDS));
+        assertTrue(transition.onAppearCalled.await(2000, TimeUnit.MILLISECONDS));
         // The transition has all the asserts in it, so we can just end it now.
         endTransition();
     }
@@ -583,7 +593,7 @@
         startTransition(R.layout.scene8);
 
         // scene 8 swaps the ids, but not the names. No transition should happen.
-        waitForEnd(1000);
+        waitForEnd(2000);
 
         // now change the match order to prefer the id
         mTransition.setMatchOrder(new int[] {Transition.MATCH_ID, Transition.MATCH_NAME});
@@ -591,7 +601,7 @@
         resetListener();
         startTransition(R.layout.scene1);
         verify(mListener, never()).onTransitionEnd(any()); // it is running as expected
-        waitForEnd(1000);
+        waitForEnd(2000);
     }
 
     @Test
@@ -602,7 +612,7 @@
         mTransition = transition;
         resetListener();
         startTransition(R.layout.scene2);
-        assertTrue(transition.latch.await(500, TimeUnit.MILLISECONDS));
+        assertTrue(transition.latch.await(2000, TimeUnit.MILLISECONDS));
         endTransition();
 
         // Now make the transition only make changes to unimportant properties.
@@ -610,7 +620,7 @@
         mTransition = transition;
         resetListener();
         startTransition(R.layout.scene1);
-        verify(mListener, within(500)).onTransitionEnd(any());
+        verify(mListener, within(2000)).onTransitionEnd(any());
         // createAnimator shouldn't have been called.
         assertEquals(1, transition.latch.getCount());
 
diff --git a/tests/tests/view/src/android/view/cts/ChoreographerTest.java b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
index a232b51..2adbc13 100644
--- a/tests/tests/view/src/android/view/cts/ChoreographerTest.java
+++ b/tests/tests/view/src/android/view/cts/ChoreographerTest.java
@@ -81,15 +81,15 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, null);
 
             // We expect the remaining callbacks to have been invoked once.
-            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(1)).run();
-            verify(addedCallback2, timeout(NOMINAL_VSYNC_PERIOD * 10).times(1)).run();
+            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(1)).run();
+            verify(addedCallback2, timeout(NOMINAL_VSYNC_PERIOD * 30).times(1)).run();
             verifyZeroInteractions(removedCallback);
 
             // If we post a callback again, then it should be invoked again.
             mChoreographer.postCallback(
                     Choreographer.CALLBACK_ANIMATION, addedCallback1, null);
 
-            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(2)).run();
+            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(2)).run();
             verify(addedCallback2, times(1)).run();
             verifyZeroInteractions(removedCallback);
 
@@ -100,7 +100,7 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, null, TOKEN);
-            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(3)).run();
+            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(3)).run();
             verifyZeroInteractions(removedCallback);
 
             // If the action and token matches, then the callback should be removed.
@@ -111,7 +111,7 @@
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
             mChoreographer.removeCallbacks(
                     Choreographer.CALLBACK_ANIMATION, removedCallback, TOKEN);
-            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 10).times(4)).run();
+            verify(addedCallback1, timeout(NOMINAL_VSYNC_PERIOD * 30).times(4)).run();
             verifyZeroInteractions(removedCallback);
         } finally {
             mChoreographer.removeCallbacks(
diff --git a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
index 8e34571..484644f 100644
--- a/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
+++ b/tests/tests/view/src/android/view/textclassifier/cts/ConversationActionsTest.java
@@ -313,7 +313,7 @@
         assertThat(request.getConversation().get(0).getText().toString()).isEqualTo(TEXT);
         assertThat(request.getConversation().get(0).getAuthor()).isEqualTo(PERSON);
         assertThat(request.getHints()).isEmpty();
-        assertThat(request.getMaxSuggestions()).isEqualTo(0);
+        assertThat(request.getMaxSuggestions()).isEqualTo(-1);
         assertThat(request.getTypeConfig()).isNotNull();
         assertThat(request.getConversationId()).isNull();
     }
diff --git a/tests/tests/voicesettings/AndroidTest.xml b/tests/tests/voicesettings/AndroidTest.xml
index 5b97823..7bdb094 100644
--- a/tests/tests/voicesettings/AndroidTest.xml
+++ b/tests/tests/voicesettings/AndroidTest.xml
@@ -16,6 +16,8 @@
 <configuration description="Config for CTS Voice Settings test cases">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
@@ -27,7 +29,9 @@
 
         <!-- Close the "turn on battery saver?" dialog, and wait for the broadcast queue to drain. -->
         <option name="teardown-command" value="am broadcast --receiver-foreground -a android.intent.action.CLOSE_SYSTEM_DIALOGS" />
+        <!-- TODO(b/123958025): disabled because it hangs most of the time
         <option name="teardown-command" value="am wait-for-broadcast-idle" />
+        -->
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.voicesettings.cts" />
diff --git a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
index db6bbb9..2ef1999 100644
--- a/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
+++ b/tests/tests/voicesettings/src/android/voicesettings/cts/AirplaneModeTest.java
@@ -40,6 +40,7 @@
         super.setUp();
         mContext = getInstrumentation().getTargetContext();
         mHasFeature = mContext.getPackageManager().hasSystemFeature(FEATURE_VOICE_RECOGNIZERS);
+        Log.v(TAG, "setUp(): mHasFeature=" + mHasFeature);
     }
 
     public AirplaneModeTest() {
@@ -84,6 +85,7 @@
             }
             runTest(BroadcastUtils.TestcaseType.AIRPLANE_MODE_ON, AIRPLANE_MODE_IS_ON);
         }
+        Log.i(TAG, "All done!");
     }
 
     private boolean runTest(BroadcastUtils.TestcaseType test, int expectedMode) throws Exception {
diff --git a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
index 5a68273..1904710 100644
--- a/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ProgressBarTest.java
@@ -559,6 +559,38 @@
         assertEquals(oldSecondaryProgress, mProgressBarHorizontal.getSecondaryProgress());
     }
 
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMinWidth() {
+        final int minWidth = 20;
+        mProgressBar.setMinWidth(minWidth);
+        assertEquals(minWidth, mProgressBar.getMinWidth());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMaxWidth() {
+        final int maxWidth = 20;
+        mProgressBar.setMaxWidth(maxWidth);
+        assertEquals(maxWidth, mProgressBar.getMaxWidth());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMinHeight() {
+        final int minHeight = 20;
+        mProgressBar.setMinHeight(minHeight);
+        assertEquals(minHeight, mProgressBar.getMinHeight());
+    }
+
+    @UiThreadTest
+    @Test
+    public void testGetAndSetMaxHeight() {
+        final int maxHeight = 20;
+        mProgressBar.setMaxHeight(maxHeight);
+        assertEquals(maxHeight, mProgressBar.getMaxHeight());
+    }
+
     /*
      * Mock class for ProgressBar to test protected methods
      */
diff --git a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
index 3abb023..bae62ed 100644
--- a/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ScrollViewTest.java
@@ -800,6 +800,22 @@
         assertTrue(myScrollView.getBottomFadingEdgeStrength() >= 0.0f);
     }
 
+    @Test
+    public void testScrollDescendant() throws Throwable {
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(0, mScrollViewCustom.getScrollY());
+
+        View lastChild = mScrollViewCustom.findViewById(R.id.last_child);
+        int lastChildTop = (ITEM_COUNT - 1) * mItemHeight;
+
+        mActivityRule.runOnUiThread(() -> mScrollViewCustom.scrollToDescendant(lastChild));
+        // smoothScrollBy doesn't scroll in X
+        pollingCheckSmoothScrolling(0, 0, 0, lastChildTop);
+
+        assertEquals(0, mScrollViewCustom.getScrollX());
+        assertEquals(lastChildTop, mScrollViewCustom.getScrollY());
+    }
+
     private boolean isInRange(int current, int from, int to) {
         if (from < to) {
             return current >= from && current <= to;