Merge "Add CTS for FD support in StrictJarFile."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..77f70e7
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,5 @@
+[Hook Scripts]
+checkstyle_hook = ../development/tools/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
+                  -fw apps/CtsVerifier/src/com/android/cts/verifier/usb/
+                      apps/CtsVerifierUSBCompanion/
+                      tests/tests/print/
diff --git a/apps/CameraITS/pymodules/its/image.py b/apps/CameraITS/pymodules/its/image.py
index 4d98f9c..60a2173f 100644
--- a/apps/CameraITS/pymodules/its/image.py
+++ b/apps/CameraITS/pymodules/its/image.py
@@ -408,8 +408,9 @@
     Returns:
         The black level value for the specified channel.
     """
-    if cap_res.has_key("android.sensor.dynamicBlackLevel"):
-        black_levels = cap_res["android.sensor.dynamicBlackLevel"]
+    if (cap_res.has_key('android.sensor.dynamicBlackLevel') and
+            cap_res['android.sensor.dynamicBlackLevel'] is not None):
+        black_levels = cap_res['android.sensor.dynamicBlackLevel']
     else:
         black_levels = props['android.sensor.blackLevelPattern']
     idxs = its.image.get_canonical_cfa_order(props)
diff --git a/apps/CameraITS/tests/scene0/test_metadata.py b/apps/CameraITS/tests/scene0/test_metadata.py
index e5fbba5..69ed19d 100644
--- a/apps/CameraITS/tests/scene0/test_metadata.py
+++ b/apps/CameraITS/tests/scene0/test_metadata.py
@@ -49,7 +49,6 @@
     check('props.has_key("android.info.supportedHardwareLevel")')
     check('props["android.info.supportedHardwareLevel"] is not None')
     check('props["android.info.supportedHardwareLevel"] in [0,1,2,3]')
-    full = getval('props["android.info.supportedHardwareLevel"]') == 1
     manual_sensor = its.caps.manual_sensor(props)
 
     # Test: rollingShutterSkew, and frameDuration tags must all be present,
@@ -75,7 +74,12 @@
     check('props["android.scaler.croppingType"] is not None')
     check('props["android.scaler.croppingType"] in [0,1]')
 
-    assert(not failed)
+    # Test: android.sensor.blackLevelPattern exists for RAW and is not None
+    if its.caps.raw(props):
+        check('props.has_key("android.sensor.blackLevelPattern")')
+        check('props["android.sensor.blackLevelPattern"] is not None')
+
+    assert not failed
 
     if not its.caps.legacy(props):
         # Test: pixel_pitch, FOV, and hyperfocal distance are reasonable
diff --git a/apps/CameraITS/tools/run_all_tests.py b/apps/CameraITS/tools/run_all_tests.py
index ff05850..03bf268 100644
--- a/apps/CameraITS/tools/run_all_tests.py
+++ b/apps/CameraITS/tools/run_all_tests.py
@@ -287,6 +287,12 @@
                                       'turn_off_screen.py'), screen_id_arg]
         retcode = subprocess.call(cmd)
         assert retcode == 0
+        print 'Shutting down DUT screen: ', device_id
+        screen_id_arg = ('screen=%s' % device_id)
+        cmd = ['python', os.path.join(os.environ['CAMERA_ITS_TOP'], 'tools',
+                                      'turn_off_screen.py'), screen_id_arg]
+        retcode = subprocess.call(cmd)
+        assert retcode == 0
 
     print "ITS tests finished. Please go back to CtsVerifier and proceed"
 
diff --git a/apps/CameraITS/tools/turn_off_screen.py b/apps/CameraITS/tools/turn_off_screen.py
index 4163ab4..207042b 100644
--- a/apps/CameraITS/tools/turn_off_screen.py
+++ b/apps/CameraITS/tools/turn_off_screen.py
@@ -33,10 +33,10 @@
     process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
     cmd_ret = process.stdout.read()
     screen_state = re.split(r'[s|=]', cmd_ret)[-1]
-    if screen_state == 'OFF\n':
-        print 'Screen OFF. Turning ON.'
+    if 'OFF' in screen_state:
+        print 'Screen already OFF.'
     else:
-        wakeup = ('adb -s %s shell input keyevent POWER' % screen_id)
-        subprocess.Popen(wakeup.split())
+        pwrdn = ('adb -s %s shell input keyevent POWER' % screen_id)
+        subprocess.Popen(pwrdn.split())
 if __name__ == '__main__':
     main()
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b776ecc..d49f279 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1055,6 +1055,17 @@
             <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
         </activity>
 
+        <activity android:name=".location.GnssStatusTestsActivity"
+            android:label="@string/location_gnss_status_test"
+            android:screenOrientation="locked">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.cts.intent.category.MANUAL_TEST"/>
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_hardware"/>
+            <meta-data android:name="test_required_features" android:value="android.hardware.location.gps" />
+        </activity>
+
         <activity android:name=".location.LocationListenerActivity"
                 android:label="@string/location_listener_activity"
                 android:configChanges="keyboardHidden|orientation|screenSize">
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 668776f..6311fa3 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -568,6 +568,7 @@
     <string name="location_gnss_reg_test">GNSS Measurement Registration Test</string>
     <string name="location_gnss_value_test">GNSS Measurement Values Test</string>
     <string name="location_gnss_nav_msg_test">GNSS Navigation Message Test</string>
+    <string name="location_gnss_status_test">GNSS Status Test</string>
     <string name="location_gnss_test_info">This test verifies basic GNSS behavior.
         Make sure the device has line of sight to GNSS satellites
         (for example, stationary on a windowsill.  If needed, try again, outside, also with the
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
index 193c94c0..2a6c146 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsSerializer.java
@@ -371,7 +371,7 @@
         try {
             Object keyValue = getKeyValue(md, keyObj);
             if (keyValue == null) {
-                return new MetadataEntry(keyName, JSONObject.NULL);
+                return null;
             }
             int arrayLen = Array.getLength(keyValue);
             Type elmtType = ((GenericArrayType)keyType).getGenericComponentType();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java
new file mode 100644
index 0000000..a64c5d3
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/location/GnssStatusTestsActivity.java
@@ -0,0 +1,15 @@
+package com.android.cts.verifier.location;
+
+import com.android.cts.verifier.location.base.GnssCtsTestActivity;
+import android.location.cts.GnssStatusTest;
+
+/**
+ * Activity to execute CTS GnssStatusTest.
+ * It is a wrapper for {@link GnssStatusTest} running with AndroidJUnitRunner.
+ */
+
+public class GnssStatusTestsActivity extends GnssCtsTestActivity {
+  public GnssStatusTestsActivity() {
+    super(GnssStatusTest.class);
+  }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
index b8d8c30..017ae42 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/PlayVideoActivity.java
@@ -51,7 +51,7 @@
     static final String EXTRA_STREAM = "com.android.cts.verifier.streamquality.EXTRA_STREAM";
 
     private static final String TAG = PlayVideoActivity.class.getName();
-    private static final long ENABLE_PASS_DELAY = 60 * 1000;
+    private static final long ENABLE_PASS_DELAY = 5 * 1000;
 
     private static final int FAIL_DIALOG_ID = 1;
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
index 00a52ae..8354fae 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
@@ -109,7 +109,7 @@
             "618FBB112E1B2FBB66DA9F203AE8CC7DF93C7400" +
             ".20498AA006E999F42BE69D66E3596F2C7CA18114";
     private static final String RTSP_LOOKUP_URI_TEMPLATE =
-            "http://redirector.c.youtube.com/videoplayback?id=271de9756065677e" +
+            "http://redirector.gvt1.com/videoplayback?id=271de9756065677e" +
             "&source=youtube&protocol=rtsp&sparams=ip,ipbits,expire,id,itag,source" +
             "&ip=0.0.0.0&ipbits=0&expire=19000000000&key=ik0&alr=yes" +
             "&itag=%d" +
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index d7c575b..d762096 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -16,6 +16,16 @@
 
 package com.android.cts.verifier.usb.device;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeNotNull;
+import static org.junit.Assume.assumeTrue;
+
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -36,32 +46,24 @@
 import android.util.Log;
 import android.util.Pair;
 import android.widget.Toast;
+
 import com.android.cts.verifier.PassFailButtons;
 import com.android.cts.verifier.R;
+
 import org.junit.AssumptionViolatedException;
 
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
 import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Random;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeNotNull;
-import static org.junit.Assume.assumeTrue;
-
 public class UsbDeviceTestActivity extends PassFailButtons.Activity {
     private static final String ACTION_USB_PERMISSION =
             "com.android.cts.verifier.usb.device.USB_PERMISSION";
@@ -73,6 +75,10 @@
     private final BroadcastReceiver mUsbDeviceConnectionReceiver;
     private Thread mTestThread;
 
+    private static long now() {
+        return System.nanoTime() / 1000000;
+    }
+
     /**
      * Run a {@link Invokable} and expect a {@link Throwable} of a certain type.
      *
@@ -356,14 +362,14 @@
      */
     private void receiveWithEmptyBuffer(@NonNull UsbDeviceConnection connection,
             @NonNull UsbEndpoint in, @Nullable byte[] buffer, int offset, int length) {
-        long startTime = System.currentTimeMillis();
+        long startTime = now();
         int numReceived;
         if (offset == 0) {
             numReceived = connection.bulkTransfer(in, buffer, length, 0);
         } else {
             numReceived = connection.bulkTransfer(in, buffer, offset, length, 0);
         }
-        long endTime = System.currentTimeMillis();
+        long endTime = now();
         assertEquals(-1, numReceived);
 
         // The transfer should block
@@ -424,7 +430,7 @@
     }
 
     /**
-     * Send a USB request and receive it back.
+     * Send a USB request using the {@link UsbRequest#queue legacy path} and receive it back.
      *
      * @param connection      The connection to use
      * @param in              The endpoint to receive requests from
@@ -437,9 +443,10 @@
      * @param limitInSlice    The limited parameter in the final buffer
      * @param useDirectBuffer If the buffer to be used should be a direct buffer
      */
-    private void echoUsbRequest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
-            @NonNull UsbEndpoint out, int size, int originalSize, int sliceStart, int sliceEnd,
-            int positionInSlice, int limitInSlice, boolean useDirectBuffer) {
+    private void echoUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int size, int originalSize,
+            int sliceStart, int sliceEnd, int positionInSlice, int limitInSlice,
+            boolean useDirectBuffer) {
         Random random = new Random();
 
         UsbRequest sent = new UsbRequest();
@@ -542,12 +549,127 @@
      * @param connection      The connection to use
      * @param in              The endpoint to receive requests from
      * @param out             The endpoint to send requests to
+     * @param originalSize    The size of the original buffer
+     * @param sliceStart      The start of the final buffer in the original buffer
+     * @param sliceEnd        The end of the final buffer in the original buffer
+     * @param positionInSlice The position parameter in the final buffer
+     * @param limitInSlice    The limited parameter in the final buffer
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
+            @NonNull UsbEndpoint out, int originalSize, int sliceStart, int sliceEnd,
+            int positionInSlice, int limitInSlice, boolean useDirectBuffer,
+            boolean makeSendBufferReadOnly) {
+        Random random = new Random();
+
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+        Object sentClientData = new Object();
+        sent.setClientData(sentClientData);
+
+        UsbRequest receive = new UsbRequest();
+        isInited = receive.initialize(connection, in);
+        assertTrue(isInited);
+        Object receiveClientData = new Object();
+        receive.setClientData(receiveClientData);
+
+        ByteBuffer bufferSent;
+        if (useDirectBuffer) {
+            bufferSent = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferSent = ByteBuffer.allocate(originalSize);
+        }
+        for (int i = 0; i < originalSize; i++) {
+            bufferSent.put((byte) random.nextInt());
+        }
+        if (makeSendBufferReadOnly) {
+            bufferSent = bufferSent.asReadOnlyBuffer();
+        }
+        bufferSent.position(sliceStart);
+        bufferSent.limit(sliceEnd);
+        ByteBuffer bufferSentSliced = bufferSent.slice();
+        bufferSentSliced.position(positionInSlice);
+        bufferSentSliced.limit(limitInSlice);
+
+        bufferSent.position(0);
+        bufferSent.limit(originalSize);
+
+        ByteBuffer bufferReceived;
+        if (useDirectBuffer) {
+            bufferReceived = ByteBuffer.allocateDirect(originalSize);
+        } else {
+            bufferReceived = ByteBuffer.allocate(originalSize);
+        }
+        bufferReceived.position(sliceStart);
+        bufferReceived.limit(sliceEnd);
+        ByteBuffer bufferReceivedSliced = bufferReceived.slice();
+        bufferReceivedSliced.position(positionInSlice);
+        bufferReceivedSliced.limit(limitInSlice);
+
+        bufferReceived.position(0);
+        bufferReceived.limit(originalSize);
+
+        boolean wasQueued = receive.enqueue(bufferReceivedSliced);
+        assertTrue(wasQueued);
+        wasQueued = sent.enqueue(bufferSentSliced);
+        assertTrue(wasQueued);
+
+        for (int reqRun = 0; reqRun < 2; reqRun++) {
+            UsbRequest finished = connection.requestWait();
+
+            if (finished == receive) {
+                assertEquals(limitInSlice, bufferReceivedSliced.limit());
+                assertEquals(limitInSlice, bufferReceivedSliced.position());
+
+                for (int i = 0; i < originalSize; i++) {
+                    if (i >= sliceStart + positionInSlice && i < sliceStart + limitInSlice) {
+                        assertEquals(bufferSent.get(i), bufferReceived.get(i));
+                    } else {
+                        assertEquals(0, bufferReceived.get(i));
+                    }
+                }
+
+                assertSame(receiveClientData, finished.getClientData());
+                assertSame(in, finished.getEndpoint());
+            } else {
+                assertEquals(limitInSlice, bufferSentSliced.limit());
+                assertEquals(limitInSlice, bufferSentSliced.position());
+
+                assertSame(sent, finished);
+                assertSame(sentClientData, finished.getClientData());
+                assertSame(out, finished.getEndpoint());
+            }
+            finished.close();
+        }
+    }
+
+    /**
+     * Send a USB request using the {@link UsbRequest#queue legacy path} and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
+     * @param size            The size of the request to send
+     * @param useDirectBuffer If the buffer to be used should be a direct buffer
+     */
+    private void echoUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, int size, boolean useDirectBuffer) {
+        echoUsbRequestLegacy(connection, in, out, size, size, 0, size, 0, size, useDirectBuffer);
+    }
+
+    /**
+     * Send a USB request and receive it back.
+     *
+     * @param connection      The connection to use
+     * @param in              The endpoint to receive requests from
+     * @param out             The endpoint to send requests to
      * @param size            The size of the request to send
      * @param useDirectBuffer If the buffer to be used should be a direct buffer
      */
     private void echoUsbRequest(@NonNull UsbDeviceConnection connection, @NonNull UsbEndpoint in,
             @NonNull UsbEndpoint out, int size, boolean useDirectBuffer) {
-        echoUsbRequest(connection, in, out, size, size, 0, size, 0, size, useDirectBuffer);
+        echoUsbRequest(connection, in, out, size, 0, size, 0, size, useDirectBuffer, false);
     }
 
     /**
@@ -557,7 +679,7 @@
      * @param in              The endpoint to receive requests from
      * @param out             The endpoint to send requests to
      */
-    private void echoOversizedUsbRequest(@NonNull UsbDeviceConnection connection,
+    private void echoOversizedUsbRequestLegacy(@NonNull UsbDeviceConnection connection,
             @NonNull UsbEndpoint in, @NonNull UsbEndpoint out) {
         Random random = new Random();
         int totalSize = MAX_BUFFER_SIZE * 3 / 2;
@@ -601,12 +723,58 @@
     }
 
     /**
-     * Send a USB request with size 0.
+     * Time out while waiting for USB requests.
+     *
+     * @param connection The connection to use
+     */
+    private void timeoutWhileWaitingForUsbRequest(@NonNull UsbDeviceConnection connection)
+            throws Throwable {
+        assertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
+
+        long startTime = now();
+        UsbRequest req = connection.requestWait(100);
+        assertNull(req);
+        assertTrue(now() - startTime >= 100);
+        assertTrue(now() - startTime < 400);
+
+        startTime = now();
+        req = connection.requestWait(0);
+        assertNull(req);
+        assertTrue(now() - startTime < 400);
+    }
+
+    /**
+     * Receive a USB request before a timeout triggers
+     *
+     * @param connection The connection to use
+     * @param in         The endpoint to receive requests from
+     */
+    private void receiveAfterTimeout(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint in, int timeout) throws InterruptedException {
+        UsbRequest reqQueued = new UsbRequest();
+        ByteBuffer buffer = ByteBuffer.allocate(1);
+
+        reqQueued.initialize(connection, in);
+        reqQueued.enqueue(buffer);
+
+        // Let the kernel receive and process the request
+        Thread.sleep(50);
+
+        long startTime = now();
+        UsbRequest reqFinished = connection.requestWait(timeout);
+        assertTrue(now() - startTime < timeout + 50);
+        assertSame(reqQueued, reqFinished);
+        reqFinished.close();
+    }
+
+    /**
+     * Send a USB request with size 0 using the {@link UsbRequest#queue legacy path}.
      *
      * @param connection      The connection to use
      * @param out             The endpoint to send requests to
+     * @param useDirectBuffer Send data from a direct buffer
      */
-    private void sendZeroLengthRequest(@NonNull UsbDeviceConnection connection,
+    private void sendZeroLengthRequestLegacy(@NonNull UsbDeviceConnection connection,
             @NonNull UsbEndpoint out, boolean useDirectBuffer) {
         UsbRequest sent = new UsbRequest();
         boolean isInited = sent.initialize(connection, out);
@@ -627,12 +795,58 @@
     }
 
     /**
+     * Send a USB request with size 0.
+     *
+     * @param connection      The connection to use
+     * @param out             The endpoint to send requests to
+     * @param useDirectBuffer Send data from a direct buffer
+     */
+    private void sendZeroLengthRequest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint out, boolean useDirectBuffer) {
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        ByteBuffer buffer;
+        if (useDirectBuffer) {
+            buffer = ByteBuffer.allocateDirect(0);
+        } else {
+            buffer = ByteBuffer.allocate(0);
+        }
+
+        boolean isQueued = sent.enqueue(buffer);
+        assumeTrue(isQueued);
+        UsbRequest finished = connection.requestWait();
+        assertSame(finished, sent);
+        finished.close();
+    }
+
+    /**
+     * Send a USB request with a null buffer.
+     *
+     * @param connection      The connection to use
+     * @param out             The endpoint to send requests to
+     */
+    private void sendNullRequest(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbEndpoint out) {
+        UsbRequest sent = new UsbRequest();
+        boolean isInited = sent.initialize(connection, out);
+        assertTrue(isInited);
+
+        boolean isQueued = sent.enqueue(null);
+        assumeTrue(isQueued);
+        UsbRequest finished = connection.requestWait();
+        assertSame(finished, sent);
+        finished.close();
+    }
+
+    /**
      * Receive a USB request with size 0.
      *
      * @param connection      The connection to use
      * @param in             The endpoint to recevie requests from
      */
-    private void receiveZeroLengthRequest(@NonNull UsbDeviceConnection connection,
+    private void receiveZeroLengthRequestLegacy(@NonNull UsbDeviceConnection connection,
             @NonNull UsbEndpoint in, boolean useDirectBuffer) {
         UsbRequest zeroReceived = new UsbRequest();
         boolean isInited = zeroReceived.initialize(connection, in);
@@ -656,20 +870,20 @@
             buffer1 = ByteBuffer.allocate(1);
         }
 
-        boolean isQueued = zeroReceived.queue(buffer, 0);
+        boolean isQueued = zeroReceived.enqueue(buffer);
         assumeTrue(isQueued);
-        isQueued = oneReceived.queue(buffer1, 0);
+        isQueued = oneReceived.enqueue(buffer1);
         assumeTrue(isQueued);
 
         // We expect both to be returned after some time
         ArrayList<UsbRequest> finished = new ArrayList<>(2);
 
         // We expect both request to come back after the delay, but then quickly
-        long startTime = System.currentTimeMillis();
+        long startTime = now();
         finished.add(connection.requestWait());
-        long firstReturned = System.currentTimeMillis();
+        long firstReturned = now();
         finished.add(connection.requestWait());
-        long secondReturned = System.currentTimeMillis();
+        long secondReturned = now();
 
         assumeTrue(firstReturned - startTime > 100);
         assumeTrue(secondReturned - firstReturned < 100);
@@ -679,6 +893,130 @@
     }
 
     /**
+     * Tests the {@link UsbRequest#queue legacy implementaion} of {@link UsbRequest} and
+     * {@link UsbDeviceConnection#requestWait()}.
+     *
+     * @param connection The connection to use for testing
+     * @param iface      The interface of the android accessory interface of the device
+     * @throws Throwable
+     */
+    private void usbRequestLegacyTests(@NonNull UsbDeviceConnection connection,
+            @NonNull UsbInterface iface) throws Throwable {
+        // Find bulk in and out endpoints
+        assumeTrue(iface.getEndpointCount() == 2);
+        final UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+        final UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+        assertNotNull(in);
+        assertNotNull(out);
+
+        // Single threaded send and receive
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequestLegacy(connection, in, out, 1, true);
+
+        nextTest(connection, in, out, "Echo 1 byte");
+        echoUsbRequestLegacy(connection, in, out, 1, false);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequestLegacy(connection, in, out, MAX_BUFFER_SIZE, true);
+
+        nextTest(connection, in, out, "Echo max bytes");
+        echoUsbRequestLegacy(connection, in, out, MAX_BUFFER_SIZE, false);
+
+        nextTest(connection, in, out, "Echo oversized buffer");
+        echoOversizedUsbRequestLegacy(connection, in, out);
+
+        // Send empty requests
+        sendZeroLengthRequestLegacy(connection, out, true);
+        sendZeroLengthRequestLegacy(connection, out, false);
+
+        // waitRequest with timeout
+        timeoutWhileWaitingForUsbRequest(connection);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveAfterTimeout(connection, in, 400);
+
+        nextTest(connection, in, out, "Receive byte immediately");
+        // Make sure the data is received before we queue the request for it
+        Thread.sleep(50);
+        receiveAfterTimeout(connection, in, 0);
+
+        /* TODO: Unreliable
+
+        // Zero length means waiting for the next data and then return
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequestLegacy(connection, in, true);
+
+        nextTest(connection, in, out, "Receive byte after some time");
+        receiveZeroLengthRequestLegacy(connection, in, true);
+
+        */
+
+        // UsbRequest.queue ignores position, limit, arrayOffset, and capacity
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 42, 5, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 42, 0, 36, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 5, 42, 0, 36, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 42, 0, 36, 0, 31, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 47, 0, 47, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 5, 47, 0, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 42, 0, 42, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 0, 47, 5, 47, false);
+
+        nextTest(connection, in, out, "Echo 42 bytes");
+        echoUsbRequestLegacy(connection, in, out, 42, 47, 5, 47, 5, 36, false);
+
+        // Illegal arguments
+        final UsbRequest req1 = new UsbRequest();
+        assertException(() -> req1.initialize(null, in), NullPointerException.class);
+        assertException(() -> req1.initialize(connection, null), NullPointerException.class);
+        boolean isInited = req1.initialize(connection, in);
+        assertTrue(isInited);
+        assertException(() -> req1.queue(null, 0), NullPointerException.class);
+        assertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
+                IllegalArgumentException.class);
+        req1.close();
+
+        // Cannot queue closed request
+        assertException(() -> req1.queue(ByteBuffer.allocate(1), 1), NullPointerException.class);
+        assertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
+                NullPointerException.class);
+    }
+
+    /**
+     * Repeat c n times
+     *
+     * @param c The character to repeat
+     * @param n The number of times to repeat
+     *
+     * @return c repeated n times
+     */
+    public static String repeat(char c, int n) {
+        final StringBuilder result = new StringBuilder();
+        for (int i = 0; i < n; i++) {
+            if (c != ' ' && i % 10 == 0) {
+                result.append(i / 10);
+            } else {
+                result.append(c);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
      * Tests {@link UsbRequest} and {@link UsbDeviceConnection#requestWait()}.
      *
      * @param connection The connection to use for testing
@@ -707,12 +1045,10 @@
         nextTest(connection, in, out, "Echo max bytes");
         echoUsbRequest(connection, in, out, MAX_BUFFER_SIZE, false);
 
-        nextTest(connection, in, out, "Echo oversized buffer");
-        echoOversizedUsbRequest(connection, in, out);
-
         // Send empty requests
         sendZeroLengthRequest(connection, out, true);
         sendZeroLengthRequest(connection, out, false);
+        sendNullRequest(connection, out);
 
         /* TODO: Unreliable
 
@@ -725,33 +1061,38 @@
 
         */
 
-        // UsbRequest.queue ignores position, limit, arrayOffset, and capacity
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 42, 0, 42, 5, 42, false);
+        for (int startOfSlice : new int[]{0, 1}) {
+            for (int endOffsetOfSlice : new int[]{0, 2}) {
+                for (int positionInSlice : new int[]{0, 5}) {
+                    for (int limitOffsetInSlice : new int[]{0, 11}) {
+                        for (boolean useDirectBuffer : new boolean[]{true, false}) {
+                            for (boolean makeSendBufferReadOnly : new boolean[]{true, false}) {
+                                int sliceSize = 42 + positionInSlice + limitOffsetInSlice;
+                                int originalSize = sliceSize + startOfSlice + endOffsetOfSlice;
 
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 42, 0, 42, 0, 36, false);
+                                nextTest(connection, in, out, "Echo 42 bytes");
 
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 42, 5, 42, 0, 36, false);
+                                // Log buffer, slice, and data offsets
+                                Log.i(LOG_TAG,
+                                        "buffer" + (makeSendBufferReadOnly ? "(ro): [" : ":     [")
+                                                + repeat('.', originalSize) + "]");
+                                Log.i(LOG_TAG,
+                                        "slice:     " + repeat(' ', startOfSlice) + " [" + repeat(
+                                                '.', sliceSize) + "]");
+                                Log.i(LOG_TAG,
+                                        "data:      " + repeat(' ', startOfSlice + positionInSlice)
+                                                + " [" + repeat('.', 42) + "]");
 
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 42, 0, 36, 0, 31, false);
-
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 47, 0, 47, 0, 47, false);
-
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 47, 5, 47, 0, 42, false);
-
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 47, 0, 42, 0, 42, false);
-
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 47, 0, 47, 5, 47, false);
-
-        nextTest(connection, in, out, "Echo 42 bytes");
-        echoUsbRequest(connection, in, out, 42, 47, 5, 47, 5, 36, false);
+                                echoUsbRequest(connection, in, out, originalSize, startOfSlice,
+                                        originalSize - endOffsetOfSlice, positionInSlice,
+                                        sliceSize - limitOffsetInSlice, useDirectBuffer,
+                                        makeSendBufferReadOnly);
+                            }
+                        }
+                    }
+                }
+            }
+        }
 
         // Illegal arguments
         final UsbRequest req1 = new UsbRequest();
@@ -759,15 +1100,16 @@
         assertException(() -> req1.initialize(connection, null), NullPointerException.class);
         boolean isInited = req1.initialize(connection, in);
         assertTrue(isInited);
-        assertException(() -> req1.queue(null, 0), NullPointerException.class);
-        assertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
+        assertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
+                IllegalArgumentException.class);
+        assertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
                 IllegalArgumentException.class);
         req1.close();
 
         // Cannot queue closed request
-        assertException(() -> req1.queue(ByteBuffer.allocate(1), 1), NullPointerException.class);
-        assertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
-                NullPointerException.class);
+        assertException(() -> req1.enqueue(ByteBuffer.allocate(1)), IllegalStateException.class);
+        assertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
+                IllegalStateException.class);
 
         // Initialize
         UsbRequest req2 = new UsbRequest();
@@ -907,6 +1249,7 @@
      */
     private class QueuerThread extends TestThread {
         private static final int MAX_IN_FLIGHT = 64;
+        private static final long RUN_TIME = 10 * 1000;
 
         private final AtomicInteger mCounter;
 
@@ -940,7 +1283,9 @@
         public void run() {
             Random random = new Random();
 
-            while (!mShouldStop) {
+            long endTime = now() + RUN_TIME;
+
+            while (now() < endTime && !mShouldStop) {
                 try {
                     int counter = mCounter.getAndIncrement();
 
@@ -953,6 +1298,7 @@
                     ByteBuffer writeBuffer = mBufferRecycler.get();
                     int data = random.nextInt();
                     writeBuffer.put((byte)1).putInt(counter).putInt(data);
+                    writeBuffer.flip();
 
                     // Send read that will receive the data back from the write as the other side
                     // will echo all requests.
@@ -988,7 +1334,7 @@
 
                     // Send both requests to the system. Once they finish the ReceiverThread will
                     // be notified
-                    boolean isQueued = writeRequest.queue(writeBuffer, 9);
+                    boolean isQueued = writeRequest.enqueue(writeBuffer);
                     assertTrue(isQueued);
 
                     isQueued = readRequest.queue(readBuffer, 9);
@@ -998,6 +1344,7 @@
                         mErrors.add(t);
                         mErrors.notify();
                     }
+                    break;
                 }
             }
         }
@@ -1104,6 +1451,7 @@
                         mErrors.add(t);
                         mErrors.notify();
                     }
+                    break;
                 }
             }
         }
@@ -1165,7 +1513,7 @@
 
             @Override
             protected @NonNull ByteBuffer create() {
-                return ByteBuffer.allocate(9);
+                return ByteBuffer.allocateDirect(9);
             }
         };
 
@@ -1194,30 +1542,7 @@
         queuer2.start();
         receiver.start();
 
-        // Run for 10 seconds or until we have an error
-        final long RUN_TIME = 10 * 1000;
-
-        long startTime = System.currentTimeMillis();
-        while (true) {
-            long timeLeft = RUN_TIME - (System.currentTimeMillis() - startTime);
-
-            synchronized (errors) {
-                if (!errors.isEmpty() || timeLeft < 0) {
-                    break;
-                } else {
-                    try {
-                        errors.wait(timeLeft);
-                    } catch (InterruptedException e) {
-                        errors.add(e);
-                        break;
-                    }
-                }
-            }
-        }
-
-        Log.i(LOG_TAG, "Stopping sending new requests");
-        queuer1.abort();
-        queuer2.abort();
+        Log.i(LOG_TAG, "Waiting for queuers to stop");
 
         try {
             queuer1.join();
@@ -1632,6 +1957,7 @@
             boolean claimed = connection.claimInterface(iface, false);
             assertTrue(claimed);
 
+            usbRequestLegacyTests(connection, iface);
             usbRequestTests(connection, iface);
             parallelUsbRequestsTests(connection, iface);
             ctrlTransferTests(connection);
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java
index 9899167..15ea2f4 100644
--- a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/DeviceTestCompanion.java
@@ -16,6 +16,9 @@
 
 package com.android.cts.verifierusbcompanion;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
 import android.content.Context;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbManager;
@@ -26,12 +29,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.ByteBuffer;
-import java.nio.IntBuffer;
 import java.nio.charset.Charset;
-import java.util.Arrays;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 
 /**
  * Companion code for com.android.cts.verifier.usb.device.UsbDeviceTestActivity
@@ -199,12 +197,15 @@
                             isSuccess = true;
                         }
                         break;
-                        case "Receive byte after some time": {
+                        case "Receive byte after some time":
                             Thread.sleep(200);
                             os.write(new byte[1]);
                             isSuccess = true;
-                        }
-                        break;
+                            break;
+                        case "Receive byte immediately":
+                            os.write(new byte[1]);
+                            isSuccess = true;
+                            break;
                         case "Echo until stop signal":
                             isSuccess = echoUntilStopSignal(is, os);
                             break;
diff --git a/apps/cts-usb-accessory/cts-usb-accessory.c b/apps/cts-usb-accessory/cts-usb-accessory.c
index c5da3ef..0fbfce7 100644
--- a/apps/cts-usb-accessory/cts-usb-accessory.c
+++ b/apps/cts-usb-accessory/cts-usb-accessory.c
@@ -29,6 +29,8 @@
 #include <usbhost/usbhost.h>
 #include <linux/usb/f_accessory.h>
 
+#define USB_CONTROL_READ_TIMEOUT_MS 200
+
 static struct usb_device *sDevice = NULL;
 static int sAfterUnplug = 0;
 static char* sDeviceSerial = NULL;
@@ -91,7 +93,7 @@
         return 0;
     }
 
-    char* serial = usb_device_get_serial(device);
+    char* serial = usb_device_get_serial(device, USB_CONTROL_READ_TIMEOUT_MS);
     if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) {
         free(serial);
         return 0;
@@ -111,7 +113,7 @@
         printf("Found Android device in accessory mode (%x:%x)...\n",
                vendorId, productId);
         sDevice = device;
-        sDeviceSerial = usb_device_get_serial(sDevice);
+        sDeviceSerial = usb_device_get_serial(sDevice, USB_CONTROL_READ_TIMEOUT_MS);
 
         usb_descriptor_iter_init(device, &iter);
         while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
diff --git a/common/host-side/tradefed/res/report/compatibility_result.xsl b/common/host-side/tradefed/res/report/compatibility_result.xsl
index 007f494..156f3c6 100644
--- a/common/host-side/tradefed/res/report/compatibility_result.xsl
+++ b/common/host-side/tradefed/res/report/compatibility_result.xsl
@@ -88,6 +88,18 @@
                             </td>
                         </tr>
                         <tr>
+                            <td class="rowtitle">Modules Done</td>
+                            <td>
+                                <xsl:value-of select="Result/Summary/@modules_done"/>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td class="rowtitle">Modules Total</td>
+                            <td>
+                                <xsl:value-of select="Result/Summary/@modules_total"/>
+                            </td>
+                        </tr>
+                        <tr>
                             <td class="rowtitle">Fingerprint</td>
                             <td>
                                 <xsl:value-of select="Result/Build/@build_fingerprint"/>
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index 83d4141..0887d07 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -208,6 +208,13 @@
     }
 
     /**
+     * @return a {@link File} in the resultDir for logging invocation failures
+     */
+    public File getInvocationFailureFile() throws FileNotFoundException {
+        return new File(getResultDir(), "invocation_failure.txt");
+    }
+
+    /**
      * @return a {@link String} to use for directory suffixes created from the given time.
      */
     public static String getDirSuffix(long millis) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java
new file mode 100644
index 0000000..e588fbb
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/InvocationFailureHandler.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.util.FileUtil;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+
+/**
+ * A helper class for setting and checking whether an invocation has failed.
+ */
+public class InvocationFailureHandler {
+
+    /**
+     * Determine whether the invocation for this session has previously failed.
+     *
+     * @param buildHelper the {@link CompatibilityBuildHelper} from which to retrieve invocation
+     * failure file
+     * @return if invocation has previously failed
+     */
+    public static boolean hasFailed(final CompatibilityBuildHelper buildHelper) {
+        try {
+            File f = buildHelper.getInvocationFailureFile();
+            return (f.exists() && f.length() != 0);
+        } catch (FileNotFoundException e) {
+            CLog.e("Could not find invocation failure file for session %s",
+                buildHelper.getDirSuffix(buildHelper.getStartTime()));
+            CLog.e(e);
+            return false;
+        }
+    }
+
+    /**
+     * Write the cause of invocation failure to the result's invocation failure file.
+     *
+     * @param buildHelper the {@link CompatibilityBuildHelper} from which to retrieve the
+     * invocation failure file
+     * @param cause the throwable responsible for invocation failure
+     */
+    public static void setFailed(final CompatibilityBuildHelper buildHelper, Throwable cause) {
+        try {
+            File f = buildHelper.getInvocationFailureFile();
+            if (!f.exists()) {
+                f.createNewFile();
+                FileUtil.writeToFile(cause.toString(), f);
+            }
+        } catch (IOException e) {
+            CLog.e("Exception while writing invocation failure file.");
+            CLog.e(e);
+        }
+    }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index bbdc8d8..7310f56 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -16,6 +16,7 @@
 package com.android.compatibility.common.tradefed.result;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
 import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
 import com.android.compatibility.common.util.ICaseResult;
 import com.android.compatibility.common.util.IInvocationResult;
@@ -484,6 +485,7 @@
     @Override
     public void invocationFailed(Throwable cause) {
         warn("Invocation failed: %s", cause);
+        InvocationFailureHandler.setFailed(mBuildHelper, cause);
     }
 
     /**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 6dabac6..e68d913 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -18,6 +18,7 @@
 
 import com.android.compatibility.SuiteInfo;
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.compatibility.common.tradefed.result.InvocationFailureHandler;
 import com.android.compatibility.common.tradefed.result.SubPlanCreator;
 import com.android.compatibility.common.tradefed.targetprep.NetworkConnectivityChecker;
 import com.android.compatibility.common.tradefed.targetprep.SystemStatusChecker;
@@ -71,6 +72,7 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A Test for running Compatibility Suites
@@ -95,6 +97,9 @@
     public static final String DEVICE_TOKEN_OPTION = "device-token";
     public static final String LOGCAT_ON_FAILURE_SIZE_OPTION = "logcat-on-failure-size";
 
+    // Constants for checking invocation or preconditions preparation failure
+    private static final int NUM_PREP_ATTEMPTS = 10;
+    private static final int MINUTES_PER_PREP_ATTEMPT = 2;
 
     @Option(name = SUBPLAN_OPTION,
             description = "the subplan to run",
@@ -310,7 +315,7 @@
                     // throw a {@link FileNotFoundException}
                     mModuleRepo.initialize(mTotalShards, mBuildHelper.getTestsDir(), getAbis(),
                             mDeviceTokens, mTestArgs, mModuleArgs, mIncludeFilters,
-                            mExcludeFilters, mBuildHelper.getBuildInfo());
+                            mExcludeFilters);
 
                     // Add the entire list of modules to the CompatibilityBuildHelper for reporting
                     mBuildHelper.setModuleIds(mModuleRepo.getModuleIds());
@@ -358,11 +363,20 @@
             }
             mModuleRepo.setPrepared(isPrepared);
 
-            if (!mModuleRepo.isPrepared()) {
-                CLog.logAndDisplay(LogLevel.ERROR,
-                        "Incorrect preparation detected, exiting test run from %s",
-                        mDevice.getSerialNumber());
-                return;
+            int prepAttempt = 1;
+            while (!mModuleRepo.isPrepared(MINUTES_PER_PREP_ATTEMPT, TimeUnit.MINUTES)) {
+                if (prepAttempt >= NUM_PREP_ATTEMPTS
+                        || InvocationFailureHandler.hasFailed(mBuildHelper)) {
+                    CLog.logAndDisplay(LogLevel.ERROR,
+                            "Incorrect preparation detected, exiting test run from %s",
+                            mDevice.getSerialNumber());
+                    return;
+                } else {
+                    CLog.logAndDisplay(LogLevel.INFO,
+                            "Device %s on standby while all shards complete preparation",
+                            mDevice.getSerialNumber());
+                }
+                prepAttempt++;
             }
 
             // Run the tests
@@ -386,6 +400,9 @@
                     runPreModuleCheck(module.getName(), checkers, mDevice, listener);
                 }
                 try {
+                    if (module.getTest() instanceof IBuildReceiver) {
+                        ((IBuildReceiver)module.getTest()).setBuild(mBuildHelper.getBuildInfo());
+                    }
                     module.run(listener);
                 } catch (DeviceUnresponsiveException due) {
                     // being able to catch a DeviceUnresponsiveException here implies that recovery
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
index 540373b..cbefc7c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
@@ -15,13 +15,13 @@
  */
 package com.android.compatibility.common.tradefed.testtype;
 
-import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.testtype.IAbi;
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Interface for accessing tests from the Compatibility repository.
@@ -31,7 +31,7 @@
     /**
      * @return true after each shard has prepared successfully.
      */
-    boolean isPrepared();
+    boolean isPrepared(long timeout, TimeUnit unit);
 
     /**
      * Indicates to the repo whether a shard is prepared to run.
@@ -48,7 +48,7 @@
      */
     void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
             List<String> testArgs, List<String> moduleArgs, Set<String> mIncludeFilters,
-            Set<String> mExcludeFilters, IBuildInfo buildInfo);
+            Set<String> mExcludeFilters);
 
     /**
      * @return a {@link Map} of all modules to run on the device referenced by the given serial.
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 412f9747..57d5db3 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -17,14 +17,12 @@
 
 import com.android.compatibility.common.util.TestFilter;
 import com.android.ddmlib.Log.LogLevel;
-import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ConfigurationException;
 import com.android.tradefed.config.ConfigurationFactory;
 import com.android.tradefed.config.IConfiguration;
 import com.android.tradefed.config.IConfigurationFactory;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IBuildReceiver;
 import com.android.tradefed.testtype.IRemoteTest;
 import com.android.tradefed.testtype.IShardableTest;
 import com.android.tradefed.testtype.ITestFileFilterReceiver;
@@ -202,13 +200,13 @@
      * {@inheritDoc}
      */
     @Override
-    public boolean isPrepared() {
+    public boolean isPrepared(long timeout, TimeUnit unit) {
+        // returns true only if CountDownLatch reaches zero && no shards have setPrepared to false
         try {
-            mPreparedLatch.await();
+            return (mPreparedLatch.await(timeout, unit)) ? mPrepared : false;
         } catch (InterruptedException e) {
             return false;
         }
-        return mPrepared;
     }
 
     /**
@@ -234,7 +232,7 @@
     @Override
     public void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
             List<String> testArgs, List<String> moduleArgs, Set<String> includeFilters,
-            Set<String> excludeFilters, IBuildInfo buildInfo) {
+            Set<String> excludeFilters) {
         CLog.d("Initializing ModuleRepo\nShards:%d\nTests Dir:%s\nABIs:%s\nDevice Tokens:%s\n" +
                 "Test Args:%s\nModule Args:%s\nIncludes:%s\nExcludes:%s",
                 shards, testsDir.getAbsolutePath(), abis, deviceTokens, testArgs, moduleArgs,
@@ -316,12 +314,9 @@
                     }
                     List<IRemoteTest> shardedTests = tests;
                     if (mShards > 1) {
-                         shardedTests = splitShardableTests(tests, buildInfo);
+                         shardedTests = splitShardableTests(tests);
                     }
                     for (IRemoteTest test : shardedTests) {
-                        if (test instanceof IBuildReceiver) {
-                            ((IBuildReceiver)test).setBuild(buildInfo);
-                        }
                         addModuleDef(name, abi, test, pathArg);
                     }
                 }
@@ -339,14 +334,10 @@
         mLargeModulesPerShard = mLargeModules.size() / shards;
     }
 
-    private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests,
-            IBuildInfo buildInfo) {
+    private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests) {
         ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
         for (IRemoteTest test : tests) {
             if (test instanceof IShardableTest) {
-                if (test instanceof IBuildReceiver) {
-                    ((IBuildReceiver)test).setBuild(buildInfo);
-                }
                 shardedList.addAll(((IShardableTest)test).split());
             } else {
                 shardedList.add(test);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
index 23b2b05..600f6d1 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
@@ -21,12 +21,11 @@
 import com.android.compatibility.common.util.ICaseResult;
 import com.android.compatibility.common.util.IInvocationResult;
 import com.android.compatibility.common.util.IModuleResult;
-import com.android.compatibility.common.util.InvocationResult;
 import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.InvocationResult;
 import com.android.compatibility.common.util.ResultHandler;
 import com.android.compatibility.common.util.TestFilter;
 import com.android.compatibility.common.util.TestStatus;
-import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.tradefed.build.BuildInfo;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.config.ArgsOptionParser;
@@ -47,7 +46,6 @@
     private static final String SUITE_VERSION = "5.0";
     private static final String SUITE_PLAN = "cts";
     private static final String SUITE_BUILD = "12345";
-    private static final String REPORT_VERSION = "5.0";
     private static final String NAME_A = "ModuleA";
     private static final String NAME_B = "ModuleB";
     private static final String ABI = "mips64";
@@ -59,7 +57,6 @@
     private static final String EXAMPLE_BUILD_PRODUCT = "wolverine";
     private static final String DEVICE_A = "device123";
     private static final String DEVICE_B = "device456";
-    private static final String DEVICES = "device456,device123";
     private static final String CLASS_A = "android.test.Foor";
     private static final String CLASS_B = "android.test.Bar";
     private static final String METHOD_1 = "testBlah1";
@@ -68,8 +65,6 @@
     private static final String METHOD_4 = "testBlah4";
     private static final long START_MS = 1431586801000L;
     private static final long END_MS = 1431673199000L;
-    private static final String START_DISPLAY = "Fri Aug 20 15:13:03 PDT 2010";
-    private static final String END_DISPLAY = "Fri Aug 20 15:13:04 PDT 2010";
     private static final String REFERENCE_URL="http://android.com";
     private static final String LOG_URL ="file:///path/to/logs";
     private static final String COMMAND_LINE_ARGS = "cts -m CtsMyModuleTestCases";
@@ -169,6 +164,7 @@
             return mResultsDir;
         }
 
+        @Override
         public File getSubPlansDir() throws FileNotFoundException {
             return mSubPlansDir;
         }
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index 8851117..46958b8 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -16,10 +16,7 @@
 
 package com.android.compatibility.common.tradefed.testtype;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
 import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
-import com.android.compatibility.common.tradefed.testtype.IModuleDef;
-import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.testtype.Abi;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IRemoteTest;
@@ -37,6 +34,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 public class ModuleRepoTest extends TestCase {
 
@@ -87,11 +85,6 @@
         "armeabi-v7a FooModuleC",
         "armeabi-v7a FooModuleB"
     };
-    private static final String ROOT_DIR_NAME = "root";
-    private static final String BASE_DIR_NAME = "android-tests";
-    private static final String TESTCASES = "testcases";
-    private static final String ROOT_PROPERTY = "TESTS_ROOT";
-    private static final String SUITE_NAME = "TESTS";
 
     static {
         SERIALS.add(SERIAL1);
@@ -110,26 +103,12 @@
     }
     private IModuleRepo mRepo;
     private File mTestsDir;
-    private IBuildInfo mBuild;
     private File mRoot = null;
 
     @Override
     public void setUp() throws Exception {
         mTestsDir = setUpConfigs();
         mRepo = new ModuleRepo();
-        mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
-        File base = new File(mRoot, BASE_DIR_NAME);
-        base.mkdirs();
-        File tests = new File(base, TESTCASES);
-        tests.mkdirs();
-        System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
-        CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
-            @Override
-            protected String getSuiteInfoName() {
-                return SUITE_NAME;
-            }
-        };
-        mBuild = provider.getBuild();
     }
 
     private File setUpConfigs() throws IOException {
@@ -144,7 +123,8 @@
         createConfig(testsDir, name, token, TEST_STUB);
     }
 
-    private void createConfig(File testsDir, String name, String token, String moduleClass) throws IOException {
+    private void createConfig(File testsDir, String name, String token, String moduleClass)
+            throws IOException {
         File config = new File(testsDir, String.format(FILENAME, name));
         String preparer = "";
         if (token != null) {
@@ -165,7 +145,7 @@
 
     public void testInitialization() throws Exception {
         mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+                EXCLUDES);
         assertTrue("Should be initialized", mRepo.isInitialized());
         assertEquals("Wrong number of shards", 3, mRepo.getNumberOfShards());
         assertEquals("Wrong number of modules per shard", 2, mRepo.getModulesPerShard());
@@ -210,7 +190,7 @@
         excludeFilters.add(ID_A_32);
         excludeFilters.add(MODULE_NAME_B);
         mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, includeFilters,
-                excludeFilters, mBuild);
+                excludeFilters);
         List<IModuleDef> modules = mRepo.getModules(SERIAL1);
         assertEquals("Incorrect number of modules", 1, modules.size());
         IModuleDef module = modules.get(0);
@@ -220,7 +200,7 @@
 
     public void testParsing() throws Exception {
         mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+                EXCLUDES);
         List<IModuleDef> modules = mRepo.getModules(SERIAL3);
         Set<String> idSet = new HashSet<>();
         for (IModuleDef module : modules) {
@@ -255,7 +235,7 @@
         ArrayList<String> emptyList = new ArrayList<>();
 
         mRepo.initialize(3, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, INCLUDES,
-                         EXCLUDES, mBuild);
+                         EXCLUDES);
 
         List<IModuleDef> modules = new ArrayList<>();
         modules.addAll(mRepo.getLargeModules());
@@ -267,7 +247,6 @@
         for (IModuleDef def : modules) {
             IRemoteTest test = def.getTest();
             if (test instanceof IShardableTest) {
-                assertNotNull("Build not set", ((ShardableTestStub)test).mBuildInfo);
                 shardableCount++;
             }
         }
@@ -276,7 +255,7 @@
 
     public void testGetModuleIds() {
         mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+                EXCLUDES);
         assertTrue("Should be initialized", mRepo.isInitialized());
 
         assertArrayEquals(EXPECTED_MODULE_IDS, mRepo.getModuleIds());
@@ -284,22 +263,22 @@
 
     public void testIsPrepared() {
         mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+                EXCLUDES);
         assertTrue("Should be initialized", mRepo.isInitialized());
         mRepo.setPrepared(true);
         mRepo.setPrepared(true);
         mRepo.setPrepared(true); // each shard should call setPrepared() once
-        assertTrue(mRepo.isPrepared());
+        assertTrue(mRepo.isPrepared(0, TimeUnit.MINUTES));
     }
 
     public void testIsNotPrepared() {
         mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
-                EXCLUDES, mBuild);
+                EXCLUDES);
         assertTrue("Should be initialized", mRepo.isInitialized());
         mRepo.setPrepared(true);
         mRepo.setPrepared(false); // mRepo should return false for setPrepared() after third call
         mRepo.setPrepared(true);
-        assertFalse(mRepo.isPrepared());
+        assertFalse(mRepo.isPrepared(0, TimeUnit.MINUTES));
     }
 
     private void assertArrayEquals(Object[] expected, Object[] actual) {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
index 1b3f955..f4db091 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -28,8 +28,6 @@
 import com.android.tradefed.testtype.ITestCollector;
 import com.android.tradefed.testtype.ITestFilterReceiver;
 
-import junit.framework.Assert;
-
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Set;
@@ -69,8 +67,6 @@
      */
     @Override
     public Collection<IRemoteTest> split() {
-        Assert.assertNotNull(mBuildInfo);
-
         mShards = new ArrayList<>();
         for (int i = 0; i < 3; i++) {
             mShards.add(new ShardableTestStub());
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
index fa24b32..75b5df6 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/SubPlanTest.java
@@ -66,13 +66,15 @@
 
         // Serialize to file
         File subPlanFile = FileUtil.createTempFile("test-subPlan-serialization", ".txt");
-        OutputStream subPlanOutputStream = new FileOutputStream(subPlanFile);
-        subPlan.serialize(subPlanOutputStream);
-        subPlanOutputStream.close();
-
-        // Parse subPlan and assert correctness
-        checkSubPlan(subPlanFile);
-
+        try {
+            OutputStream subPlanOutputStream = new FileOutputStream(subPlanFile);
+            subPlan.serialize(subPlanOutputStream);
+            subPlanOutputStream.close();
+            // Parse subPlan and assert correctness
+            checkSubPlan(subPlanFile);
+        } finally {
+            FileUtil.deleteFile(subPlanFile);
+        }
     }
 
     public void testParsing() throws Exception {
@@ -97,6 +99,7 @@
             checkSubPlan(planFile);
         } finally {
             writer.close();
+            FileUtil.deleteFile(planFile);
         }
     }
 
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
index 4a78835..9bd3a4b 100644
--- a/common/host-side/util/tests/Android.mk
+++ b/common/host-side/util/tests/Android.mk
@@ -24,4 +24,4 @@
 
 LOCAL_MODULE_TAGS := optional
 
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
index 36c4970..a1d3d0a2 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/DynamicConfigHandlerTest.java
@@ -16,6 +16,9 @@
 
 package com.android.compatibility.common.util;
 
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.StreamUtil;
+
 import junit.framework.TestCase;
 
 import java.io.File;
@@ -92,29 +95,31 @@
     public void testDynamicConfigHandler() throws Exception {
         String module = "test1";
         File localConfigFile = createFileFromStr(localConfig, module);
+        try {
+            File mergedFile = DynamicConfigHandler
+                    .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
 
-        File mergedFile = DynamicConfigHandler
-                .getMergedDynamicConfigFile(localConfigFile, overrideJson, module);
+            Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
 
-        Map<String, List<String>> configMap = DynamicConfig.createConfigMap(mergedFile);
+            assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
+            assertTrue(configMap.get("override-config-list-1")
+                    .contains("override-config-list-val-1-1"));
+            assertTrue(configMap.get("override-config-list-1")
+                    .contains("override-config-list-val-1-2"));
+            assertTrue(configMap.get("override-config-list-3").size() == 0);
 
-        assertEquals("override-config-val-1", configMap.get("override-config-1").get(0));
-        assertTrue(configMap.get("override-config-list-1")
-                .contains("override-config-list-val-1-1"));
-        assertTrue(configMap.get("override-config-list-1")
-                .contains("override-config-list-val-1-2"));
-        assertTrue(configMap.get("override-config-list-3").size() == 0);
+            assertEquals("test config 1", configMap.get("test-config-1").get(0));
+            assertTrue(configMap.get("config-list").contains("config2"));
 
-        assertEquals("test config 1", configMap.get("test-config-1").get(0));
-        assertTrue(configMap.get("config-list").contains("config2"));
-
-        assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
-        assertEquals(1, configMap.get("override-config-list-2").size());
-        assertTrue(configMap.get("override-config-list-2")
-                .contains("override-config-list-val-2-1"));
+            assertEquals("override-config-val-2", configMap.get("override-config-2").get(0));
+            assertEquals(1, configMap.get("override-config-list-2").size());
+            assertTrue(configMap.get("override-config-list-2")
+                    .contains("override-config-list-val-2-1"));
+        } finally {
+            FileUtil.deleteFile(localConfigFile);
+        }
     }
 
-
     private File createFileFromStr(String configStr, String module) throws IOException {
         File file = File.createTempFile(module, "dynamic");
         FileOutputStream stream = null;
@@ -123,9 +128,7 @@
             stream.write(configStr.getBytes());
             stream.flush();
         } finally {
-            if (stream != null) {
-                stream.close();
-            }
+            StreamUtil.close(stream);
         }
         return file;
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index de9fdc2..68b19af 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -132,20 +132,4 @@
         // DISALLOW_UNMUTE_MICROPHONE and DISALLOW_ADJUST_VOLUME can only be set by device owners
         // and profile owners on the primary user.
     }
-
-    @Override
-    public void testDelegatedCertInstaller() throws Exception {
-        if (!mHasFeature) {
-            return;
-        }
-
-        try {
-            super.testDelegatedCertInstaller();
-        } finally {
-            // In managed profile, clearing password through dpm is not allowed. Recreate user to
-            // clear password instead.
-            removeUser(mUserId);
-            createManagedProfile();
-        }
-    }
 }
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index e08cacf..c34c97f3 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -199,6 +199,12 @@
                   android:exported="true"
                   android:theme="@style/TranslucentTheme"
         />
+        <activity android:name=".AnimationTestActivity"
+                  android:exported="true"
+        />
+        <activity android:name=".VirtualDisplayActivity"
+                  android:exported="true"
+        />
     </application>
 </manifest>
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml
new file mode 100644
index 0000000..877ecc4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/anim/animation_with_background.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<translate
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fromYDelta="100%" android:toYDelta="0"
+    android:interpolator="@android:interpolator/linear"
+    android:fillEnabled="true"
+    android:fillBefore="true" android:fillAfter="true"
+    android:duration="500"
+    android:background="#ff0000">
+</translate>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml
new file mode 100644
index 0000000..deac584
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/res/layout/virtual_display_layout.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent">
+
+    <SurfaceView
+        android:id="@+id/surfaceView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+</RelativeLayout>
\ No newline at end of file
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java
new file mode 100644
index 0000000..5ae923e
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AnimationTestActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+
+public class AnimationTestActivity extends Activity {
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        overridePendingTransition(R.anim.animation_with_background, -1);
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
new file mode 100644
index 0000000..05f7b91
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.cts;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.WindowManager;
+
+/**
+ * Activity that is able to create and destroy a virtual display.
+ */
+public class VirtualDisplayActivity extends Activity {
+    private static final String TAG = "VirtualDisplayActivity";
+
+    private static final int DEFAULT_DENSITY_DPI = 160;
+    private static final String KEY_DENSITY_DPI = "densityDpi";
+
+    private DisplayManager mDisplayManager;
+    private VirtualDisplay mVirtualDisplay;
+
+    private Surface mSurface;
+    private SurfaceView mSurfaceView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.virtual_display_layout);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
+        mSurface = mSurfaceView.getHolder().getSurface();
+
+        mDisplayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        final Bundle extras = intent.getExtras();
+        if (extras == null) {
+            return;
+        }
+
+        String command = extras.getString("command");
+        switch (command) {
+            case "create_display":
+                createVirtualDisplay(extras);
+                break;
+            case "destroy_display":
+                destroyVirtualDisplay();
+                break;
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        destroyVirtualDisplay();
+    }
+
+    private void createVirtualDisplay(Bundle extras) {
+        if (mVirtualDisplay == null) {
+            final int width = mSurfaceView.getWidth();
+            final int height = mSurfaceView.getHeight();
+            final int densityDpi = extras.getInt(KEY_DENSITY_DPI, DEFAULT_DENSITY_DPI);
+            Log.d(TAG, "createVirtualDisplay: " + width + "x" + height + ", dpi: "
+                    + densityDpi);
+            final int flags = 0;
+            mVirtualDisplay = mDisplayManager.createVirtualDisplay("VirtualDisplay", width, height,
+                    densityDpi, mSurface, flags);
+        }
+    }
+
+    private void destroyVirtualDisplay() {
+        if (mVirtualDisplay != null) {
+            Log.d(TAG, "destroyVirtualDisplay");
+            mVirtualDisplay.release();
+            mVirtualDisplay = null;
+        }
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
index 3179ac5..f5481b8 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerAppConfigurationTests.java
@@ -82,7 +82,13 @@
      */
     public void testConfigurationUpdatesWhenRotatingWhileDocked() throws Exception {
         setDeviceRotation(0);
-        launchActivityInStack(RESIZEABLE_ACTIVITY_NAME, DOCKED_STACK_ID);
+        launchActivityInDockStack(LAUNCHING_ACTIVITY);
+        // Launch our own activity to side in case Recents (or other activity to side) doesn't
+        // support rotation.
+        launchActivityToSide(false /* randomData */, false /* multipleTask */, TEST_ACTIVITY_NAME);
+        // Launch target activity in docked stack.
+        launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask */,
+                RESIZEABLE_ACTIVITY_NAME);
         final ReportedSizes initialSizes = getActivityDisplaySize(RESIZEABLE_ACTIVITY_NAME,
                 DOCKED_STACK_ID);
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
new file mode 100644
index 0000000..8b77ff4
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package android.server.cts;
+
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import static android.server.cts.StateLogger.log;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.ActivityManagerDisplayTests
+ */
+public class ActivityManagerDisplayTests extends ActivityManagerTestBase {
+    private static final String DUMPSYS_ACTIVITY_PROCESSES = "dumpsys activity processes";
+
+    private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
+
+    private static final int CUSTOM_DENSITY_DPI = 222;
+
+    /** Temp storage used for parsing. */
+    private final LinkedList<String> mDumpLines = new LinkedList<>();
+
+    /**
+     * Tests that the global configuration is equal to the default display's override configuration.
+     */
+    public void testDefaultDisplayOverrideConfiguration() throws Exception {
+        final DisplaysState ds = getDisplaysStates();
+        assertNotNull("Global configuration must not be empty.", ds.mGlobalConfig);
+        final String primaryDisplayOverrideConfig = ds.mDisplayConfigs.get(0);
+        assertEquals("Primary display's configuration should not be equal to global configuration.",
+                ds.mGlobalConfig, primaryDisplayOverrideConfig);
+    }
+
+    /**
+     * Tests that secondary display has override configuration set.
+     */
+    public void testCreateVirtualDisplayWithCustomConfig() throws Exception {
+        // Start an activity that is able to create virtual displays.
+        executeShellCommand(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+        mAmWmState.computeState(mDevice, new String[] { VIRTUAL_DISPLAY_ACTIVITY },
+                false /* compareTaskAndStackBounds */);
+        final DisplaysState originalDS = getDisplaysStates();
+        final int originalDisplayCount = originalDS.mDisplayConfigs.size();
+
+        // Create virtual display with custom density dpi.
+        executeShellCommand(getCreateVirtualDisplayCommand(CUSTOM_DENSITY_DPI));
+
+        // Wait for the virtual display to be created and get configurations.
+        DisplaysState ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
+        assertEquals("New virtual display should be created",
+                originalDisplayCount + 1, ds.mDisplayConfigs.size());
+
+        // Find the id of newly added display.
+        int newDisplayId = -1;
+        for (Integer displayId : ds.mDisplayConfigs.keySet()) {
+            if (!originalDS.mDisplayConfigs.containsKey(displayId)) {
+                newDisplayId = displayId;
+                break;
+            }
+        }
+        assertFalse(-1 == newDisplayId);
+
+        // Find the density of created display.
+        final String newDisplayConfig = ds.mDisplayConfigs.get(newDisplayId);
+        final String[] configParts = newDisplayConfig.split(" ");
+        int newDensityDpi = -1;
+        for (String part : configParts) {
+            if (part.endsWith("dpi")) {
+                final String densityDpiString = part.substring(0, part.length() - 3);
+                newDensityDpi = Integer.parseInt(densityDpiString);
+                break;
+            }
+        }
+        assertEquals(CUSTOM_DENSITY_DPI, newDensityDpi);
+
+        // Destroy the created display.
+        executeShellCommand(getDestroyVirtualDisplayCommand());
+    }
+
+    private DisplaysState getDisplaysStateAfterCreation(int expectedDisplayCount)
+            throws DeviceNotAvailableException {
+        DisplaysState ds = getDisplaysStates();
+
+        while (ds.mDisplayConfigs.size() != expectedDisplayCount) {
+            log("***Waiting for the correct number of displays...");
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                log(e.toString());
+            }
+            ds = getDisplaysStates();
+        }
+
+        return ds;
+    }
+
+    private DisplaysState getDisplaysStates() throws DeviceNotAvailableException {
+        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        mDevice.executeShellCommand(DUMPSYS_ACTIVITY_PROCESSES, outputReceiver);
+        String dump = outputReceiver.getOutput();
+        mDumpLines.clear();
+
+        Collections.addAll(mDumpLines, dump.split("\\n"));
+
+        return DisplaysState.create(mDumpLines);
+    }
+
+    /** Contains the configurations applied to attached displays. */
+    private static final class DisplaysState {
+        private static final Pattern sGlobalConfigurationPattern =
+                Pattern.compile("mGlobalConfiguration: (\\{.*\\})");
+        private static final Pattern sDisplayOverrideConfigurationsPattern =
+                Pattern.compile("Display override configurations:");
+        private static final Pattern sDisplayConfigPattern =
+                Pattern.compile("(\\d+): (\\{.*\\})");
+
+        private String mGlobalConfig;
+        private Map<Integer, String> mDisplayConfigs = new HashMap<>();
+
+        static DisplaysState create(LinkedList<String> dump) {
+            final DisplaysState result = new DisplaysState();
+
+            while (!dump.isEmpty()) {
+                final String line = dump.pop().trim();
+
+                Matcher matcher = sDisplayOverrideConfigurationsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    while (DisplaysState.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
+                        final String displayOverrideConfigLine = dump.pop().trim();
+                        log(displayOverrideConfigLine);
+                        matcher = sDisplayConfigPattern.matcher(displayOverrideConfigLine);
+                        matcher.matches();
+                        final Integer displayId = Integer.valueOf(matcher.group(1));
+                        result.mDisplayConfigs.put(displayId, matcher.group(2));
+                    }
+                    continue;
+                }
+
+                matcher = sGlobalConfigurationPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(line);
+                    result.mGlobalConfig = matcher.group(1);
+                }
+            }
+
+            return result;
+        }
+
+        /** Check if next line in dump matches the pattern and we should continue extracting. */
+        static boolean shouldContinueExtracting(LinkedList<String> dump, Pattern matchingPattern) {
+            if (dump.isEmpty()) {
+                return false;
+            }
+
+            final String line = dump.peek().trim();
+            return matchingPattern.matcher(line).matches();
+        }
+    }
+
+    private static String getCreateVirtualDisplayCommand(int densityDpi) {
+        StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+        commandBuilder.append(" -f 0x20000000");
+        commandBuilder.append(" --es command create_display");
+        if (densityDpi != -1) {
+            commandBuilder.append(" --ei densityDpi ").append(densityDpi);
+        }
+        return commandBuilder.toString();
+    }
+
+    private static String getDestroyVirtualDisplayCommand() {
+        return getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY) + " -f 0x20000000" +
+                " --es command destroy_display";
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
index f7716a5..d095398 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerPinnedStackTests.java
@@ -19,6 +19,8 @@
 import java.awt.Rectangle;
 import java.lang.Exception;
 import java.lang.String;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Build: mmma -j32 cts/hostsidetests/services
@@ -65,11 +67,117 @@
         executeShellCommand(String.format("input tap %d %d", tapX, tapY));
         mAmWmState.computeState(mDevice, new String[] {TAP_TO_FINISH_ACTIVITY},
                 false /* compareTaskAndStackBounds */);
-        mAmWmState.assertContainsStack("Must contain pinned stack.", PINNED_STACK_ID);
-        mAmWmState.assertFrontStack("Pinned stack must be the front stack.", PINNED_STACK_ID);
         mAmWmState.assertVisibility(TAP_TO_FINISH_ACTIVITY, true);
     }
 
+    public void testPinnedStackDefaultBounds() throws Exception {
+        setDeviceRotation(0 /* ROTATION_0 */);
+        ActivityManagerState amState = mAmWmState.getAmState();
+        WindowManagerState wmState = mAmWmState.getWmState();
+        amState.computeState(mDevice, ActivityManagerState.DUMP_MODE_PIP);
+        wmState.computeState(mDevice, WindowManagerState.DUMP_MODE_POLICY);
+        Rectangle defaultPipBounds = amState.getDefaultPinnedStackBounds();
+        Rectangle stableBounds = wmState.getStableBounds();
+        assertTrue(defaultPipBounds.width > 0 && defaultPipBounds.height > 0);
+        assertTrue(stableBounds.contains(defaultPipBounds));
+
+        setDeviceRotation(1 /* ROTATION_90 */);
+        amState = mAmWmState.getAmState();
+        wmState = mAmWmState.getWmState();
+        amState.computeState(mDevice, ActivityManagerState.DUMP_MODE_PIP);
+        wmState.computeState(mDevice, WindowManagerState.DUMP_MODE_POLICY);
+        defaultPipBounds = amState.getDefaultPinnedStackBounds();
+        stableBounds = wmState.getStableBounds();
+        assertTrue(defaultPipBounds.width > 0 && defaultPipBounds.height > 0);
+        assertTrue(stableBounds.contains(defaultPipBounds));
+    }
+
+    public void testPinnedStackMovementBounds() throws Exception {
+        setDeviceRotation(0 /* ROTATION_0 */);
+        ActivityManagerState amState = mAmWmState.getAmState();
+        WindowManagerState wmState = mAmWmState.getWmState();
+        amState.computeState(mDevice, ActivityManagerState.DUMP_MODE_PIP);
+        wmState.computeState(mDevice, WindowManagerState.DUMP_MODE_POLICY);
+        Rectangle pipMovementBounds = amState.getPinnedStackMomentBounds();
+        Rectangle stableBounds = wmState.getStableBounds();
+        assertTrue(pipMovementBounds.width > 0 && pipMovementBounds.height > 0);
+        assertTrue(stableBounds.contains(pipMovementBounds));
+
+        setDeviceRotation(1 /* ROTATION_90 */);
+        amState = mAmWmState.getAmState();
+        wmState = mAmWmState.getWmState();
+        amState.computeState(mDevice, ActivityManagerState.DUMP_MODE_PIP);
+        wmState.computeState(mDevice, WindowManagerState.DUMP_MODE_POLICY);
+        pipMovementBounds = amState.getPinnedStackMomentBounds();
+        stableBounds = wmState.getStableBounds();
+        assertTrue(pipMovementBounds.width > 0 && pipMovementBounds.height > 0);
+        assertTrue(stableBounds.contains(pipMovementBounds));
+    }
+
+    public void testPinnedStackOutOfBoundsInsetsNonNegative() throws Exception {
+        final WindowManagerState wmState = mAmWmState.getWmState();
+
+        // Launch an activity into the pinned stack
+        executeShellCommand(getAmStartCmd(LAUNCH_TAP_TO_FINISH_ACTIVITY));
+
+        // Get the display dimensions
+        WindowManagerState.WindowState windowState = getWindowState(TAP_TO_FINISH_ACTIVITY);
+        WindowManagerState.Display display = wmState.getDisplay(windowState.getDisplayId());
+        Rectangle displayRect = display.getDisplayRect();
+
+        // Move the pinned stack offscreen
+        String moveStackOffscreenCommand = String.format("am stack resize 4 %d %d %d %d",
+                displayRect.width - 200, 0, displayRect.width + 200, 500);
+        executeShellCommand(moveStackOffscreenCommand);
+
+        // Ensure that the surface insets are not negative
+        windowState = getWindowState(TAP_TO_FINISH_ACTIVITY);
+        Rectangle contentInsets = windowState.getContentInsets();
+        assertTrue(contentInsets.x >= 0 && contentInsets.y >= 0 && contentInsets.width >= 0 &&
+                contentInsets.height >= 0);
+    }
+
+    public void testPinnedStackInBoundsAfterRotation() throws Exception {
+        // Launch an activity into the pinned stack
+        executeShellCommand(getAmStartCmd(LAUNCH_TAP_TO_FINISH_ACTIVITY));
+
+        // Ensure that the PIP stack is fully visible in each orientation
+        setDeviceRotation(0 /* ROTATION_0 */);
+        assertPinnedStackActivityIsInDisplayBounds(TAP_TO_FINISH_ACTIVITY);
+        setDeviceRotation(1 /* ROTATION_90 */);
+        assertPinnedStackActivityIsInDisplayBounds(TAP_TO_FINISH_ACTIVITY);
+        setDeviceRotation(2 /* ROTATION_180 */);
+        assertPinnedStackActivityIsInDisplayBounds(TAP_TO_FINISH_ACTIVITY);
+        setDeviceRotation(3 /* ROTATION_270 */);
+        assertPinnedStackActivityIsInDisplayBounds(TAP_TO_FINISH_ACTIVITY);
+        setDeviceRotation(0 /* ROTATION_0 */);
+    }
+
+    /**
+     * Asserts that the pinned stack bounds is contained in the display bounds.
+     */
+    private void assertPinnedStackActivityIsInDisplayBounds(String activity) throws Exception {
+        final WindowManagerState.WindowState windowState = getWindowState(TAP_TO_FINISH_ACTIVITY);
+        final WindowManagerState.Display display = mAmWmState.getWmState().getDisplay(
+                windowState.getDisplayId());
+        final Rectangle displayRect = display.getDisplayRect();
+        final Rectangle pinnedStackBounds =
+                mAmWmState.getAmState().getStackById(PINNED_STACK_ID).getBounds();
+        assertTrue(displayRect.contains(pinnedStackBounds));
+    }
+
+    /**
+     * @return the window state for the given {@param activity}'s window.
+     */
+    private WindowManagerState.WindowState getWindowState(String activity) throws Exception {
+        String windowName = getWindowName(activity);
+        mAmWmState.computeState(mDevice, true /* visibleOnly */,
+                new String[] {activity});
+        final List<WindowManagerState.WindowState> tempWindowList = new ArrayList<>();
+        mAmWmState.getWmState().getMatchingWindowState(windowName, tempWindowList);
+        return tempWindowList.get(0);
+    }
+
     private void pinnedStackTester(String startActivity, String topActivityName,
             boolean moveTopToPinnedStack, boolean isFocusable) throws Exception {
 
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java
new file mode 100644
index 0000000..d34a5cf
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/AnimationBackgroundTests.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.cts;
+
+/**
+ * Build: mmma -j32 cts/hostsidetests/services
+ * Run: cts/hostsidetests/services/activityandwindowmanager/util/run-test android.server.cts.AnimationBackgroundTests
+ */
+public class AnimationBackgroundTests extends ActivityManagerTestBase {
+
+    public void testAnimationBackground_duringAnimation() throws Exception {
+        executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY));
+        launchActivity(false, false, false, "AnimationTestActivity");
+
+        // Make sure we are in the middle of the animation.
+        Thread.sleep(250);
+        mAmWmState.computeState(mDevice, null);
+        assertTrue("window animation background needs to be showing", mAmWmState.getWmState()
+                .getStack(FULLSCREEN_WORKSPACE_STACK_ID)
+                .isWindowAnimationBackgroundSurfaceShowing());
+    }
+
+    public void testAnimationBackground_gone() throws Exception {
+        executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY));
+        launchActivity(false, false, false, "AnimationTestActivity");
+        mAmWmState.computeState(mDevice, new String[] { "AnimationTestActivity "});
+        assertFalse("window animation background needs to be gone", mAmWmState.getWmState()
+                .getStack(FULLSCREEN_WORKSPACE_STACK_ID)
+                .isWindowAnimationBackgroundSurfaceShowing());
+    }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
index 33bf8cc..1c41c92 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -36,7 +36,11 @@
 import static android.server.cts.StateLogger.logE;
 
 class ActivityManagerState {
+    public static final int DUMP_MODE_ACTIVITIES = 0;
+    public static final int DUMP_MODE_PIP = 1;
+
     private static final String DUMPSYS_ACTIVITY_ACTIVITIES = "dumpsys activity activities";
+    private static final String DUMPSYS_ACTIVITY_PIP = "dumpsys activity pip";
 
     // Copied from ActivityRecord.java
     private static final int APPLICATION_ACTIVITY_TYPE = 0;
@@ -49,6 +53,10 @@
             Pattern.compile("ResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
     private final Pattern mFocusedStackPattern =
             Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)");
+    private final Pattern mDefaultPinnedStackBoundsPattern = Pattern.compile(
+            "defaultBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
+    private final Pattern mPinnedStackMovementBoundsPattern = Pattern.compile(
+            "movementBounds=\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]");
 
     private final Pattern[] mExtractStackExitPatterns =
             { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern};
@@ -59,8 +67,14 @@
     private String mResumedActivityRecord = null;
     private final List<String> mResumedActivities = new ArrayList();
     private final LinkedList<String> mSysDump = new LinkedList();
+    private final Rectangle mDefaultPinnedStackBounds = new Rectangle();
+    private final Rectangle mPinnedStackMovementBounds = new Rectangle();
 
     void computeState(ITestDevice device) throws DeviceNotAvailableException {
+        computeState(device, DUMP_MODE_ACTIVITIES);
+    }
+
+    void computeState(ITestDevice device, int dumpMode) throws DeviceNotAvailableException {
         // It is possible the system is in the middle of transition to the right state when we get
         // the dump. We try a few times to get the information we need before giving up.
         int retriesLeft = 3;
@@ -84,7 +98,14 @@
             }
 
             final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-            device.executeShellCommand(DUMPSYS_ACTIVITY_ACTIVITIES, outputReceiver);
+            String dumpsysCmd = "";
+            switch (dumpMode) {
+                case DUMP_MODE_ACTIVITIES:
+                    dumpsysCmd = DUMPSYS_ACTIVITY_ACTIVITIES; break;
+                case DUMP_MODE_PIP:
+                    dumpsysCmd = DUMPSYS_ACTIVITY_PIP; break;
+            }
+            device.executeShellCommand(dumpsysCmd, outputReceiver);
             dump = outputReceiver.getOutput();
             parseSysDump(dump);
 
@@ -154,6 +175,30 @@
                 log(displayId);
                 currentDisplayId = Integer.parseInt(displayId);
             }
+
+            matcher = mDefaultPinnedStackBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mDefaultPinnedStackBounds.setBounds(left, top, right - left, bottom - top);
+                log(mDefaultPinnedStackBounds.toString());
+                continue;
+            }
+
+            matcher = mPinnedStackMovementBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mPinnedStackMovementBounds.setBounds(left, top, right - left, bottom - top);
+                log(mPinnedStackMovementBounds.toString());
+                continue;
+            }
         }
     }
 
@@ -275,6 +320,14 @@
         return null;
     }
 
+    Rectangle getDefaultPinnedStackBounds() {
+        return mDefaultPinnedStackBounds;
+    }
+
+    Rectangle getPinnedStackMomentBounds() {
+        return mPinnedStackMovementBounds;
+    }
+
     static class ActivityStack extends ActivityContainer {
 
         private static final Pattern TASK_ID_PATTERN = Pattern.compile("Task id #(\\d+)");
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 25e1a41..53ea94d2 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -371,6 +371,10 @@
         runCommandAndPrintOutput("input keyevent 82");
     }
 
+    /**
+     * Sets the device rotation, value corresponds to one of {@link Surface.ROTATION_0},
+     * {@link Surface.ROTATION_90}, {@link Surface.ROTATION_180}, {@link Surface.ROTATION_270}.
+     */
     protected void setDeviceRotation(int rotation) throws DeviceNotAvailableException {
         setAccelerometerRotation(0);
         setUserRotation(rotation);
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index 2d89268..494e501 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -19,7 +19,6 @@
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 
 import java.awt.Rectangle;
 import java.lang.String;
@@ -38,10 +37,12 @@
     public static final int DUMP_MODE_APPS = 0;
     public static final int DUMP_MODE_VISIBLE = 1;
     public static final int DUMP_MODE_VISIBLE_APPS = 2;
+    public static final int DUMP_MODE_POLICY = 3;
 
     private static final String DUMPSYS_WINDOWS_APPS = "dumpsys window -a apps";
     private static final String DUMPSYS_WINDOWS_VISIBLE = "dumpsys window -a visible";
     private static final String DUMPSYS_WINDOWS_VISIBLE_APPS = "dumpsys window visible-apps";
+    private static final String DUMPSYS_WINDOWS_POLICY = "dumpsys window policy";
 
     private static final Pattern sWindowPattern =
             Pattern.compile("Window #(\\d+) Window\\{([0-9a-fA-F]+) u(\\d+) (.+)\\}\\:");
@@ -62,6 +63,8 @@
     private static final Pattern sFocusedAppPattern =
             Pattern.compile("mFocusedApp=AppWindowToken\\{(.+) token=Token\\{(.+) "
                     + "ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)");
+    private static final Pattern sStableBoundsPattern = Pattern.compile(
+            "mStable=\\((\\d+),(\\d+)\\)-\\((\\d+),(\\d+)\\)");
 
     private static final Pattern sLastAppTransitionPattern =
             Pattern.compile("mLastUsedAppTransition=(.+)");
@@ -82,6 +85,7 @@
     private String mFocusedWindow = null;
     private String mFocusedApp = null;
     private String mLastTransition = null;
+    private Rectangle mStableBounds = new Rectangle();
     private final LinkedList<String> mSysDump = new LinkedList();
 
     void computeState(ITestDevice device, int dumpMode) throws DeviceNotAvailableException {
@@ -111,6 +115,8 @@
             switch (dumpMode) {
             case DUMP_MODE_APPS:
                 dumpsysCmd = DUMPSYS_WINDOWS_APPS; break;
+            case DUMP_MODE_POLICY:
+                dumpsysCmd = DUMPSYS_WINDOWS_POLICY; break;
             case DUMP_MODE_VISIBLE:
                 dumpsysCmd = DUMPSYS_WINDOWS_VISIBLE; break;
             case DUMP_MODE_VISIBLE_APPS:
@@ -234,6 +240,18 @@
                 mLastTransition = lastAppTransitionPattern;
                 continue;
             }
+
+            matcher = sStableBoundsPattern.matcher(line);
+            if (matcher.matches()) {
+                log(line);
+                int left = Integer.parseInt(matcher.group(1));
+                int top = Integer.parseInt(matcher.group(2));
+                int right = Integer.parseInt(matcher.group(3));
+                int bottom = Integer.parseInt(matcher.group(4));
+                mStableBounds.setBounds(left, top, right - left, bottom - top);
+                log(mStableBounds.toString());
+                continue;
+            }
         }
     }
 
@@ -315,6 +333,10 @@
         return null;
     }
 
+    Rectangle getStableBounds() {
+        return mStableBounds;
+    }
+
     private void reset() {
         mSysDump.clear();
         mStacks.clear();
@@ -328,9 +350,12 @@
     static class WindowStack extends WindowContainer {
 
         private static final Pattern sTaskIdPattern = Pattern.compile("taskId=(\\d+)");
+        private static final Pattern sWindowAnimationBackgroundSurfacePattern =
+                Pattern.compile("mWindowAnimationBackgroundSurface:");
 
         int mStackId;
         ArrayList<WindowTask> mTasks = new ArrayList();
+        boolean mWindowAnimationBackgroundSurfaceShowing;
 
         private WindowStack() {
 
@@ -362,6 +387,7 @@
             final List<Pattern> taskExitPatterns = new ArrayList();
             Collections.addAll(taskExitPatterns, exitPatterns);
             taskExitPatterns.add(sTaskIdPattern);
+            taskExitPatterns.add(sWindowAnimationBackgroundSurfacePattern);
             final Pattern[] taskExitPatternsArray =
                     taskExitPatterns.toArray(new Pattern[taskExitPatterns.size()]);
 
@@ -383,9 +409,22 @@
                 if (extractBounds(line)) {
                     continue;
                 }
+
+                if (extractWindowAnimationBackgroundSurface(line)) {
+                    continue;
+                }
             }
         }
 
+        boolean extractWindowAnimationBackgroundSurface(String line) {
+            if (sWindowAnimationBackgroundSurfacePattern.matcher(line).matches()) {
+                log(line);
+                mWindowAnimationBackgroundSurfaceShowing = true;
+                return true;
+            }
+            return false;
+        }
+
         WindowTask getTask(int taskId) {
             for (WindowTask task : mTasks) {
                 if (taskId == task.mTaskId) {
@@ -394,6 +433,10 @@
             }
             return null;
         }
+
+        boolean isWindowAnimationBackgroundSurfaceShowing() {
+            return mWindowAnimationBackgroundSurfaceShowing;
+        }
     }
 
     static class WindowTask extends WindowContainer {
@@ -631,6 +674,8 @@
         private static final int WINDOW_TYPE_DEBUGGER = 3;
 
         private static final String RECT_STR = "\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]";
+        private static final String NEGATIVE_VALUES_ALLOWED_RECT_STR =
+                "\\[([-\\d]+),([-\\d]+)\\]\\[([-\\d]+),([-\\d]+)\\]";
         private static final Pattern sMainFramePattern = Pattern.compile("mFrame=" + RECT_STR + ".+");
         private static final Pattern sFramePattern =
                 Pattern.compile("Frames: containing=" + RECT_STR + " parent=" + RECT_STR);
@@ -640,6 +685,8 @@
                 Pattern.compile("mDisplayId=(\\d+) stackId=(\\d+) (.+)");
         private static final Pattern sSurfaceInsetsPattern =
             Pattern.compile("Cur insets.+surface=" + RECT_STR + ".+");
+        private static final Pattern sContentInsetsPattern =
+                Pattern.compile("Cur insets.+content=" + NEGATIVE_VALUES_ALLOWED_RECT_STR + ".+");
         private static final Pattern sLayerPattern =
             Pattern.compile("Surface:.+layer=(\\d+).+");
         private static final Pattern sCropPattern =
@@ -656,6 +703,7 @@
         private Rectangle mContentFrame = new Rectangle();
         private Rectangle mFrame = new Rectangle();
         private Rectangle mSurfaceInsets = new Rectangle();
+        private Rectangle mContentInsets = new Rectangle();
         private Rectangle mCrop = new Rectangle();
 
 
@@ -709,6 +757,10 @@
             return mSurfaceInsets;
         }
 
+        Rectangle getContentInsets() {
+            return mContentInsets;
+        }
+
         Rectangle getContentFrame() {
             return mContentFrame;
         }
@@ -789,6 +841,12 @@
                     mSurfaceInsets = extractBounds(matcher);
                 }
 
+                matcher = sContentInsetsPattern.matcher(line);
+                if (matcher.matches()) {
+                    log(TAG + "CONTENT INSETS: " + line);
+                    mContentInsets = extractBounds(matcher);
+                }
+
                 matcher = sLayerPattern.matcher(line);
                 if (matcher.matches()) {
                     log(TAG + "LAYER: " + line);
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index f27eb4e..5a5c63b 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -125,7 +125,7 @@
         mCompletionService = new ExecutorCompletionService<>(mExecutionService);
     }
 
-    private Map<String, File> extractReferenceImages(String zipFile) {
+    private Map<String, File> extractReferenceImages(String zipFile) throws Exception {
         final Map<String, File> references = new HashMap<>();
         final InputStream zipStream = ThemeHostTest.class.getResourceAsStream(zipFile);
         if (zipStream != null) {
@@ -150,7 +150,12 @@
                 fail("Failed to unzip assets: " + zipFile);
             }
         } else {
-            fail("Failed to get resource: " + zipFile);
+            if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+                Log.logAndDisplay(LogLevel.WARN, LOG_TAG,
+                        "Could not obtain resources for skipped themes test: " + zipFile);
+            } else {
+                fail("Failed to get resource: " + zipFile);
+            }
         }
 
         return references;
diff --git a/libs/deviceutil/src/android/cts/util/SynchronousPixelCopy.java b/libs/deviceutil/src/android/cts/util/SynchronousPixelCopy.java
new file mode 100644
index 0000000..ce0855a
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/SynchronousPixelCopy.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.cts.util;
+
+import static org.junit.Assert.fail;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.view.PixelCopy;
+import android.view.Surface;
+import android.view.Window;
+import android.view.PixelCopy.OnPixelCopyFinishedListener;
+import android.view.SurfaceView;
+
+public class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
+    private static Handler sHandler;
+    static {
+        HandlerThread thread = new HandlerThread("PixelCopyHelper");
+        thread.start();
+        sHandler = new Handler(thread.getLooper());
+    }
+
+    private int mStatus = -1;
+
+    public int request(Surface source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Surface source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(SurfaceView source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(SurfaceView source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Window source, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    public int request(Window source, Rect srcRect, Bitmap dest) {
+        synchronized (this) {
+            PixelCopy.request(source, srcRect, dest, this, sHandler);
+            return getResultLocked();
+        }
+    }
+
+    private int getResultLocked() {
+        try {
+            this.wait(250);
+        } catch (InterruptedException e) {
+            fail("PixelCopy request didn't complete within 250ms");
+        }
+        return mStatus;
+    }
+
+    @Override
+    public void onPixelCopyFinished(int copyResult) {
+        synchronized (this) {
+            mStatus = copyResult;
+            this.notify();
+        }
+    }
+}
diff --git a/libs/deviceutil/src/android/cts/util/transition/TargetTracking.java b/libs/deviceutil/src/android/cts/util/transition/TargetTracking.java
new file mode 100644
index 0000000..008a0b9
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/transition/TargetTracking.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.cts.util.transition;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import java.util.ArrayList;
+
+public interface TargetTracking {
+    ArrayList<View> getTrackedTargets();
+    void clearTargets();
+    Rect getCapturedEpicenter();
+}
diff --git a/libs/deviceutil/src/android/cts/util/transition/TrackingTransition.java b/libs/deviceutil/src/android/cts/util/transition/TrackingTransition.java
new file mode 100644
index 0000000..38e6a5c
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/transition/TrackingTransition.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.cts.util.transition;
+
+import android.animation.Animator;
+import android.graphics.Rect;
+import android.transition.Transition;
+import android.transition.TransitionValues;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * A transition that tracks which targets are applied to it.
+ * It will assume any target that it applies to will have differences
+ * between the start and end state, regardless of the differences
+ * that actually exist. In other words, it doesn't actually check
+ * any size or position differences or any other property of the view.
+ * It just records the difference.
+ * <p>
+ * Both start and end value Views are recorded, but no actual animation
+ * is created.
+ */
+public class TrackingTransition extends Transition implements TargetTracking {
+    public final ArrayList<View> targets = new ArrayList<>();
+    private final Rect[] mEpicenter = new Rect[1];
+    private static String PROP = "tracking:prop";
+    private static String[] PROPS = { PROP };
+
+    @Override
+    public String[] getTransitionProperties() {
+        return PROPS;
+    }
+
+    @Override
+    public void captureStartValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROP, 0);
+    }
+
+    @Override
+    public void captureEndValues(TransitionValues transitionValues) {
+        transitionValues.values.put(PROP, 1);
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        if (startValues != null) {
+            targets.add(startValues.view);
+        }
+        if (endValues != null) {
+            targets.add(endValues.view);
+        }
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public ArrayList<View> getTrackedTargets() {
+        return targets;
+    }
+
+    @Override
+    public void clearTargets() {
+        targets.clear();
+    }
+
+    @Override
+    public Rect getCapturedEpicenter() {
+        return mEpicenter[0];
+    }
+}
diff --git a/libs/deviceutil/src/android/cts/util/transition/TrackingVisibility.java b/libs/deviceutil/src/android/cts/util/transition/TrackingVisibility.java
new file mode 100644
index 0000000..63486e3
--- /dev/null
+++ b/libs/deviceutil/src/android/cts/util/transition/TrackingVisibility.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.cts.util.transition;
+
+import android.animation.Animator;
+import android.graphics.Rect;
+import android.transition.TransitionValues;
+import android.transition.Visibility;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+
+/**
+ * Visibility transition that tracks which targets are applied to it.
+ * This transition does no animation.
+ */
+public class TrackingVisibility extends Visibility implements TargetTracking {
+    public final ArrayList<View> targets = new ArrayList<>();
+    private final Rect[] mEpicenter = new Rect[1];
+
+    @Override
+    public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        targets.add(endValues.view);
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues,
+            TransitionValues endValues) {
+        targets.add(startValues.view);
+        Rect epicenter = getEpicenter();
+        if (epicenter != null) {
+            mEpicenter[0] = new Rect(epicenter);
+        } else {
+            mEpicenter[0] = null;
+        }
+        return null;
+    }
+
+    @Override
+    public ArrayList<View> getTrackedTargets() {
+        return targets;
+    }
+
+    @Override
+    public void clearTargets() {
+        targets.clear();
+    }
+
+    @Override
+    public Rect getCapturedEpicenter() {
+        return mEpicenter[0];
+    }
+}
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index 3381f48..e13cdee 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -67,8 +67,7 @@
 
         <activity
             android:label="@string/accessibility_soft_keyboard_modes_activity"
-            android:name=".AccessibilitySoftKeyboardModesTest$SoftKeyboardModesActivity"
-            android:windowSoftInputMode="stateAlwaysVisible" />
+            android:name=".AccessibilitySoftKeyboardModesTest$SoftKeyboardModesActivity" />
 
         <service
             android:name=".InstrumentedAccessibilityService"
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index 6542778..8dbbeef 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -333,39 +333,38 @@
         }
     }
 
+    // This test assumes device's screen contains its center (W/2, H/2) with some surroundings
+    // and should work for rectangular, round and round with chin screens.
     public void testClickWhenMagnified_matchesActualTouch() throws InterruptedException {
         if (!mHasTouchScreen) {
             return;
         }
 
-        final int clickXInsideView = 10;
-        final int clickYInsideView = 20;
-        int clickX = clickXInsideView + mViewBounds.left;
-        int clickY = clickYInsideView + mViewBounds.top;
+        final int clickShiftFromCenterX = 10;
+        final int clickShiftFromCenterY = 20;
+        final Resources res = getInstrumentation().getTargetContext().getResources();
+        final DisplayMetrics metrics = res.getDisplayMetrics();
+        final int centerX = metrics.widthPixels / 2;
+        final int centerY = metrics.heightPixels / 2;
         final float TOUCH_TOLERANCE = 2.0f;
 
         StubMagnificationAccessibilityService magnificationService =
                 StubMagnificationAccessibilityService.enableSelf(this);
         android.accessibilityservice.AccessibilityService.MagnificationController
                 magnificationController = magnificationService.getMagnificationController();
-        final Resources res = getInstrumentation().getTargetContext().getResources();
-        final DisplayMetrics metrics = res.getDisplayMetrics();
         try {
-            // Magnify screen by 2x from upper left corner
+            // Magnify screen by 2x with a magnification center in the center of the screen
             final AtomicBoolean setScale = new AtomicBoolean();
             final float magnificationFactor = 2.0f;
-            // Center to have (0,0) in the upper-left corner
-            final float centerX = metrics.widthPixels / (2.0f * magnificationFactor) - 1.0f;
-            final float centerY = metrics.heightPixels / (2.0f * magnificationFactor) - 1.0f;
             magnificationService.runOnServiceSync(() -> {
                         setScale.set(magnificationController.setScale(magnificationFactor, false));
-                        // Make sure the upper right corner is on the screen
                         magnificationController.setCenter(centerX, centerY, false);
                     });
             assertTrue("Failed to set scale", setScale.get());
 
-            GestureDescription click = createClick((int) (clickX * magnificationFactor),
-                    (int) (clickY * magnificationFactor));
+            final int clickMagnifiedX = (int) (centerX + magnificationFactor * clickShiftFromCenterX);
+            final int clickMagnifiedY = (int) (centerY + magnificationFactor * clickShiftFromCenterY);
+            GestureDescription click = createClick(clickMagnifiedX, clickMagnifiedY);
             mService.runOnServiceSync(() -> mService.doDispatchGesture(click, mCallback, null));
             mCallback.assertGestureCompletes(GESTURE_COMPLETION_TIMEOUT);
             waitForMotionEvents(3);
@@ -382,14 +381,18 @@
         MotionEvent clickDown = mMotionEvents.get(0);
         MotionEvent clickUp = mMotionEvents.get(1);
 
+        final int centerXInsideView = centerX - mViewBounds.left;
+        final int centerYInsideView = centerY - mViewBounds.top;
+        final int expectedClickXInsideView = centerXInsideView + clickShiftFromCenterX;
+        final int expectedClickYInsideView = centerYInsideView + clickShiftFromCenterY;
         assertEquals(MotionEvent.ACTION_DOWN, clickDown.getActionMasked());
-        assertEquals((float) clickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
-        assertEquals((float) clickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
+        assertEquals((float) expectedClickXInsideView, clickDown.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) expectedClickYInsideView, clickDown.getY(), TOUCH_TOLERANCE);
         assertEquals(clickDown.getDownTime(), clickDown.getEventTime());
 
         assertEquals(MotionEvent.ACTION_UP, clickUp.getActionMasked());
-        assertEquals((float) clickXInsideView, clickUp.getX(), TOUCH_TOLERANCE);
-        assertEquals((float) clickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
+        assertEquals((float) expectedClickXInsideView, clickUp.getX(), TOUCH_TOLERANCE);
+        assertEquals((float) expectedClickYInsideView, clickUp.getY(), TOUCH_TOLERANCE);
     }
 
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
index 263c402..3c1db3b 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilitySoftKeyboardModesTest.java
@@ -16,24 +16,18 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityService.SoftKeyboardController;
+import android.app.Activity;
 import android.app.UiAutomation;
-import android.content.ContentResolver;
-import android.content.Context;
 import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
-import android.provider.Settings;
 import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
 
 import android.accessibilityservice.cts.R;
+import android.view.accessibility.AccessibilityWindowInfo;
+import android.view.inputmethod.InputMethodManager;
 
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.concurrent.TimeoutException;
 
@@ -91,7 +85,11 @@
 
     @Override
     public void tearDown() throws Exception {
+        mKeyboardController.setShowMode(SHOW_MODE_AUTO);
         mService.runOnServiceSync(() -> mService.disableSelf());
+        Activity activity = getActivity();
+        activity.getSystemService(InputMethodManager.class)
+                .hideSoftInputFromWindow(activity.getCurrentFocus().getWindowToken(), 0);
     }
 
     public void testApiReturnValues_shouldChangeValueOnRequestAndSendCallback() throws Exception {
@@ -109,7 +107,7 @@
                 };
         mKeyboardController.addOnShowModeChangedListener(listener);
 
-        // The soft keyboard should be in its' default mode.
+        // The soft keyboard should be in its default mode.
         assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
 
         // Set the show mode to SHOW_MODE_HIDDEN.
@@ -130,56 +128,18 @@
         assertTrue(mKeyboardController.removeOnShowModeChangedListener(listener));
     }
 
-    public void testHideSoftKeyboard_shouldHideAndShowKeyboardOnRequest() throws Exception {
-        // The soft keyboard should be in its' default mode.
+    public void testHideSoftKeyboard_shouldHideKeyboardOnRequest() throws Exception {
+        // The soft keyboard should be in its default mode.
         assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
 
-        // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
-        // to stateAlwaysVisible).
-        waitForIdle();
-        int numWindowsWithIme = mUiAutomation.getWindows().size();
-
+        forceImeToBeShown();
+        waitForImePresentToBe(true);
         // Request the keyboard be hidden.
         assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
-        waitForWindowStateChanged();
-        waitForIdle();
 
-        // Make sure the keyboard is hidden.
-        assertEquals(numWindowsWithIme - 1, mUiAutomation.getWindows().size());
+        waitForImePresentToBe(false);
 
-        // Request the default keyboard mode.
         assertTrue(mKeyboardController.setShowMode(SHOW_MODE_AUTO));
-        waitForWindowStateChanged();
-        waitForIdle();
-
-        // Make sure the keyboard is visible.
-        assertEquals(numWindowsWithIme, mUiAutomation.getWindows().size());
-    }
-
-    public void testHideSoftKeyboard_shouldHideKeyboardUntilServiceIsDisabled() throws Exception {
-        // The soft keyboard should be in its' default mode.
-        assertEquals(SHOW_MODE_AUTO, mKeyboardController.getShowMode());
-
-        // Note: This Activity always has a visible keyboard (due to windowSoftInputMode being set
-        // to stateAlwaysVisible).
-        waitForIdle();
-        int numWindowsWithIme = mUiAutomation.getWindows().size();
-
-        // Set the show mode to SHOW_MODE_HIDDEN.
-        assertTrue(mKeyboardController.setShowMode(SHOW_MODE_HIDDEN));
-        waitForWindowStateChanged();
-        waitForIdle();
-
-        // Make sure the keyboard is hidden.
-        assertEquals(numWindowsWithIme - 1, mUiAutomation.getWindows().size());
-
-        // Make sure we can see the soft keyboard once all Accessibility Services are disabled.
-        mService.disableSelf();
-        waitForWindowStateChanged();
-        waitForIdle();
-
-        // See how many windows are present.
-        assertEquals(numWindowsWithIme, mUiAutomation.getWindows().size());
     }
 
     private void waitForCallbackValueWithLock(int expectedValue) throws Exception {
@@ -202,7 +162,7 @@
                 + "> does not match expected value < " + expectedValue + ">");
     }
 
-    private void waitForWindowStateChanged() throws Exception {
+    private void waitForWindowChanges() {
         try {
             mUiAutomation.executeAndWaitForEvent(new Runnable() {
                 @Override
@@ -223,8 +183,31 @@
         }
     }
 
-    private void waitForIdle() throws TimeoutException {
-        mUiAutomation.waitForIdle(TIMEOUT_ACCESSIBILITY_STATE_IDLE, TIMEOUT_ASYNC_PROCESSING);
+    private boolean isImeWindowPresent() {
+        List<AccessibilityWindowInfo> windows = mUiAutomation.getWindows();
+        for (int i = 0; i < windows.size(); i++) {
+            if (windows.get(i).getType() == AccessibilityWindowInfo.TYPE_INPUT_METHOD) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void waitForImePresentToBe(boolean imeShown) {
+        long timeOutTime = System.currentTimeMillis() + TIMEOUT_ASYNC_PROCESSING;
+        while (isImeWindowPresent() != imeShown) {
+            assertTrue(System.currentTimeMillis() < timeOutTime);
+            waitForWindowChanges();
+        }
+    }
+
+    private void forceImeToBeShown() {
+        getInstrumentation().runOnMainSync(() -> {
+            Activity activity = getActivity();
+            View editText = activity.findViewById(R.id.edit_text);
+            activity.getSystemService(InputMethodManager.class)
+                    .showSoftInput(editText, InputMethodManager.SHOW_FORCED);
+        });
     }
 
     /**
diff --git a/tests/app/app/res/layout/fragment_b.xml b/tests/app/app/res/layout/fragment_b.xml
deleted file mode 100644
index d8ed961..0000000
--- a/tests/app/app/res/layout/fragment_b.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textB"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_c.xml b/tests/app/app/res/layout/fragment_c.xml
deleted file mode 100644
index ed3c753..0000000
--- a/tests/app/app/res/layout/fragment_c.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textC"
-              android:text="@string/hello"/>
-</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_end.xml b/tests/app/app/res/layout/fragment_end.xml
deleted file mode 100644
index aa3d9e8..0000000
--- a/tests/app/app/res/layout/fragment_end.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:transitionName="destination"
-              android:id="@+id/hello"
-              android:text="@string/hello"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:id="@+id/redSquare"/>
-</LinearLayout>
diff --git a/tests/app/src/android/app/cts/FragmentReplaceTest.java b/tests/app/src/android/app/cts/FragmentReplaceTest.java
deleted file mode 100644
index ad9e3af..0000000
--- a/tests/app/src/android/app/cts/FragmentReplaceTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app.cts;
-
-import android.app.stubs.FragmentTestActivity;
-import android.app.stubs.FragmentTestActivity.TestFragment;
-import android.app.stubs.R;
-import android.test.ActivityInstrumentationTestCase2;
-import android.test.UiThreadTest;
-
-/**
- * Test to prevent regressions in FragmentManager fragment replace method. See b/24693644
- */
-public class FragmentReplaceTest extends
-        ActivityInstrumentationTestCase2<FragmentTestActivity> {
-    private FragmentTestActivity mActivity;
-
-
-    public FragmentReplaceTest() {
-        super(FragmentTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mActivity = getActivity();
-    }
-
-    @UiThreadTest
-    public void testReplaceFragment() throws Throwable {
-        mActivity.getFragmentManager().beginTransaction()
-                .add(R.id.content, new TestFragment(R.layout.fragment_a))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
-
-        mActivity.getFragmentManager().beginTransaction()
-                .add(R.id.content, new TestFragment(R.layout.fragment_b))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNotNull(mActivity.findViewById(R.id.textA));
-        assertNotNull(mActivity.findViewById(R.id.textB));
-        assertNull(mActivity.findViewById(R.id.textC));
-
-        mActivity.getFragmentManager().beginTransaction()
-                .replace(R.id.content, new TestFragment(R.layout.fragment_c))
-                .addToBackStack(null)
-                .commit();
-        mActivity.getFragmentManager().executePendingTransactions();
-        assertNull(mActivity.findViewById(R.id.textA));
-        assertNull(mActivity.findViewById(R.id.textB));
-        assertNotNull(mActivity.findViewById(R.id.textC));
-    }
-}
diff --git a/tests/app/src/android/app/cts/FragmentTransitionTest.java b/tests/app/src/android/app/cts/FragmentTransitionTest.java
deleted file mode 100644
index 7270672..0000000
--- a/tests/app/src/android/app/cts/FragmentTransitionTest.java
+++ /dev/null
@@ -1,466 +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.
- */
-package android.app.cts;
-
-import android.app.FragmentManager;
-import android.app.stubs.FragmentTestActivity;
-import android.app.stubs.FragmentTestActivity.OnTransitionListener;
-import android.app.stubs.FragmentTestActivity.TestFragment;
-import android.app.stubs.R;
-import android.os.Debug;
-import android.os.SystemClock;
-import android.test.ActivityInstrumentationTestCase2;
-import android.view.View;
-
-public class FragmentTransitionTest extends
-        ActivityInstrumentationTestCase2<FragmentTestActivity> {
-    private TestFragment mStartFragment;
-    private TestFragment mMidFragment;
-    private TestFragment mEndFragment;
-    private FragmentTestActivity mActivity;
-
-    public FragmentTransitionTest() {
-        super(FragmentTestActivity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mStartFragment = null;
-        mMidFragment = null;
-        mEndFragment = null;
-        mActivity = getActivity();
-    }
-
-    public void testFragmentTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View sharedElement = mActivity.findViewById(R.id.hello);
-                assertEquals("source", sharedElement.getTransitionName());
-
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .addSharedElement(sharedElement, "destination")
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.SHARED_ELEMENT_ENTER));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                final View textView = mActivity.findViewById(R.id.hello);
-                assertEquals("destination", textView.getTransitionName());
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.REENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-    }
-
-    public void testFirstOutLastInTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        mStartFragment.clearNotifications();
-        mEndFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.RETURN);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testPopTwo() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mMidFragment, TestFragment.ENTER);
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertTrue(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertTrue(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        mStartFragment.clearNotifications();
-        mMidFragment.clearNotifications();
-        mEndFragment.clearNotifications();
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                FragmentManager fm = mActivity.getFragmentManager();
-                int id = fm.getBackStackEntryAt(0).getId();
-                fm.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
-                fm.executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.RETURN);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testNullTransition() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mStartFragment.clearTransitions();
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.ENTER);
-        // No transitions
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mMidFragment = new TestFragment(R.layout.checkbox_layout);
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mEndFragment.clearTransitions();
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mMidFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mEndFragment, TestFragment.ENTER);
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
-
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mEndFragment, TestFragment.RETURN);
-        assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
-
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    public void testRemoveAdded() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .replace(R.id.content, mStartFragment)
-                        .replace(R.id.content, mEndFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mEndFragment, TestFragment.ENTER);
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.REENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
-        assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
-    }
-
-    public void testAddRemoved() throws Throwable {
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mStartFragment = new TestFragment(R.layout.fragment_start);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mStartFragment)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForEnd(mStartFragment, TestFragment.ENTER);
-        assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
-        mStartFragment.clearNotifications();
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mEndFragment = new TestFragment(R.layout.fragment_end);
-                mActivity.getFragmentManager().beginTransaction()
-                        .replace(R.id.content, mEndFragment)
-                        .replace(R.id.content, mStartFragment)
-                        .addToBackStack(null)
-                        .commit();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.ENTER);
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.ENTER));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.EXIT));
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mActivity.getFragmentManager().popBackStack();
-                mActivity.getFragmentManager().executePendingTransactions();
-            }
-        });
-        waitForStart(mStartFragment, TestFragment.REENTER);
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.REENTER));
-        assertFalse(mEndFragment.wasStartCalled(TestFragment.RETURN));
-    }
-
-    private boolean waitForStart(TestFragment fragment, int key) throws InterruptedException {
-        final boolean started;
-        WaitForTransition listener = new WaitForTransition(key, true);
-        fragment.setOnTransitionListener(listener);
-        final long endTime = SystemClock.uptimeMillis() + 100;
-        synchronized (listener) {
-            long waitTime;
-            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
-                    !listener.isDone()) {
-                listener.wait(waitTime);
-            }
-            started = listener.isDone();
-        }
-        fragment.setOnTransitionListener(null);
-        getInstrumentation().waitForIdleSync();
-        return started;
-    }
-
-    private boolean waitForEnd(TestFragment fragment, int key) throws InterruptedException {
-        if (!waitForStart(fragment, key)) {
-            return false;
-        }
-        final boolean ended;
-        WaitForTransition listener = new WaitForTransition(key, false);
-        fragment.setOnTransitionListener(listener);
-        final long endTime = SystemClock.uptimeMillis() + 400;
-        synchronized (listener) {
-            long waitTime;
-            while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
-                    !listener.isDone()) {
-                listener.wait(waitTime);
-            }
-            ended = listener.isDone();
-        }
-        fragment.setOnTransitionListener(null);
-        getInstrumentation().waitForIdleSync();
-        return ended;
-    }
-
-    private static class WaitForTransition implements OnTransitionListener {
-        final int key;
-        final boolean isStart;
-        boolean isDone;
-
-        public WaitForTransition(int key, boolean isStart) {
-            this.key = key;
-            this.isStart = isStart;
-        }
-
-        protected boolean isComplete(TestFragment fragment) {
-            if (isStart) {
-                return fragment.wasStartCalled(key);
-            } else {
-                return fragment.wasEndCalled(key);
-            }
-        }
-
-        public synchronized boolean isDone() {
-            return isDone;
-        }
-
-        @Override
-        public synchronized void onTransition(TestFragment fragment) {
-            isDone = isComplete(fragment);
-            if (isDone) {
-                notifyAll();
-            }
-        }
-    }
-
-}
diff --git a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
index 5fbc682..de48dd6 100644
--- a/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -32,7 +32,6 @@
 
 import java.util.List;
 import java.util.ArrayList;
-import java.util.Arrays;
 
 public class BurstCaptureTest extends Camera2SurfaceViewTestCase {
     private static final String TAG = "BurstCaptureTest";
@@ -99,31 +98,8 @@
         final long minStillFrameDuration =
                 config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, stillSize);
 
-        // Add 0.05 here so Fps like 29.99 evaluated to 30
-        int minBurstFps = (int) Math.floor(1e9 / minStillFrameDuration + 0.05f);
-        boolean foundConstantMaxYUVRange = false;
-        boolean foundYUVStreamingRange = false;
 
-        // Find suitable target FPS range - as high as possible that covers the max YUV rate
-        // Also verify that there's a good preview rate as well
-        List<Range<Integer> > fpsRanges = Arrays.asList(
-                mStaticInfo.getAeAvailableTargetFpsRangesChecked());
-        Range<Integer> targetRange = null;
-        for (Range<Integer> fpsRange : fpsRanges) {
-            if (fpsRange.getLower() == minBurstFps && fpsRange.getUpper() == minBurstFps) {
-                foundConstantMaxYUVRange = true;
-                targetRange = fpsRange;
-            }
-            if (fpsRange.getLower() <= 15 && fpsRange.getUpper() == minBurstFps) {
-                foundYUVStreamingRange = true;
-            }
-        }
-
-        assertTrue(String.format("Cam %s: Target FPS range of (%d, %d) must be supported",
-                cameraId, minBurstFps, minBurstFps), foundConstantMaxYUVRange);
-        assertTrue(String.format(
-                "Cam %s: Target FPS range of (x, %d) where x <= 15 must be supported",
-                cameraId, minBurstFps), foundYUVStreamingRange);
+        Range<Integer> targetRange = getSuitableFpsRangeForDuration(cameraId, minStillFrameDuration);
 
         Log.i(TAG, String.format("Selected frame rate range %d - %d for YUV burst",
                         targetRange.getLower(), targetRange.getUpper()));
diff --git a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
index 7e28403..b88a80f 100644
--- a/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
@@ -22,6 +22,7 @@
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCaptureSession.CaptureCallback;
+import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.CaptureResult;
@@ -32,6 +33,7 @@
 import android.hardware.camera2.cts.helpers.StaticMetadata.CheckLevel;
 import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
 import android.hardware.camera2.params.InputConfiguration;
+import android.hardware.camera2.params.StreamConfigurationMap;
 import android.media.Image;
 import android.media.ImageReader;
 import android.media.ImageWriter;
@@ -39,6 +41,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Range;
 import android.util.Size;
 import android.view.Surface;
 
@@ -338,6 +341,209 @@
     }
 
     /**
+     * Test multiple capture KPI for YUV_420_888 format: the average time duration
+     * between sending out image capture requests and receiving capture results.
+     * <p>
+     * It measures capture latency, which is the time between sending out the capture
+     * request and getting the full capture result, and the frame duration, which is the timestamp
+     * gap between results.
+     * </p>
+     */
+    public void testMultipleCapture() throws Exception {
+        double[] avgResultTimes = new double[mCameraIds.length];
+        double[] avgDurationMs = new double[mCameraIds.length];
+
+        // A simple CaptureSession StateCallback to handle onCaptureQueueEmpty
+        class MultipleCaptureStateCallback extends CameraCaptureSession.StateCallback {
+            private ConditionVariable captureQueueEmptyCond = new ConditionVariable();
+            private int captureQueueEmptied = 0;
+
+            @Override
+            public void onConfigured(CameraCaptureSession session) {
+                // Empty implementation
+            }
+
+            @Override
+            public void onConfigureFailed(CameraCaptureSession session) {
+                // Empty implementation
+            }
+
+            @Override
+            public void onCaptureQueueEmpty(CameraCaptureSession session) {
+                captureQueueEmptied++;
+                if (VERBOSE) {
+                    Log.v(TAG, "onCaptureQueueEmpty received. captureQueueEmptied = "
+                        + captureQueueEmptied);
+                }
+
+                captureQueueEmptyCond.open();
+            }
+
+            /* Wait for onCaptureQueueEmpty, return immediately if an onCaptureQueueEmpty was
+             * already received, otherwise, wait for one to arrive. */
+            public void waitForCaptureQueueEmpty(long timeout) {
+                if (captureQueueEmptied > 0) {
+                    captureQueueEmptied--;
+                    return;
+                }
+
+                if (captureQueueEmptyCond.block(timeout)) {
+                    captureQueueEmptyCond.close();
+                    captureQueueEmptied = 0;
+                } else {
+                    throw new TimeoutRuntimeException("Unable to receive onCaptureQueueEmpty after "
+                        + timeout + "ms");
+                }
+            }
+        }
+
+        final MultipleCaptureStateCallback sessionListener = new MultipleCaptureStateCallback();
+
+        int counter = 0;
+        for (String id : mCameraIds) {
+            // Do NOT move these variables to outer scope
+            // They will be passed to DeviceReportLog and their references will be stored
+            String streamName = "test_multiple_capture";
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.addValue("camera_id", id, ResultType.NEUTRAL, ResultUnit.NONE);
+            long[] startTimes = new long[NUM_MAX_IMAGES];
+            double[] getResultTimes = new double[NUM_MAX_IMAGES];
+            double[] frameDurationMs = new double[NUM_MAX_IMAGES-1];
+            try {
+                openDevice(id);
+
+                if (!mStaticInfo.isColorOutputSupported()) {
+                    Log.i(TAG, "Camera " + id + " does not support color outputs, skipping");
+                    continue;
+                }
+
+                for (int i = 0; i < NUM_TEST_LOOPS; i++) {
+
+                    // setup builders and listeners
+                    CaptureRequest.Builder previewBuilder =
+                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+                    CaptureRequest.Builder captureBuilder =
+                            mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+                    SimpleCaptureCallback previewResultListener =
+                            new SimpleCaptureCallback();
+                    SimpleTimingResultListener captureResultListener =
+                            new SimpleTimingResultListener();
+                    SimpleImageReaderListener imageListener =
+                            new SimpleImageReaderListener(/*asyncMode*/true, NUM_MAX_IMAGES);
+
+                    Size maxYuvSize = CameraTestUtils.getSortedSizesForFormat(
+                        id, mCameraManager, ImageFormat.YUV_420_888, /*bound*/null).get(0);
+                    // Find minimum frame duration for YUV_420_888
+                    StreamConfigurationMap config = mStaticInfo.getCharacteristics().get(
+                            CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+                    final long minStillFrameDuration =
+                            config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, maxYuvSize);
+                    Range<Integer> targetRange = getSuitableFpsRangeForDuration(id,
+                            minStillFrameDuration);
+                    previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                            targetRange);
+                    captureBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                            targetRange);
+
+                    prepareCaptureAndStartPreview(previewBuilder, captureBuilder,
+                            mOrderedPreviewSizes.get(0), maxYuvSize,
+                            ImageFormat.YUV_420_888, previewResultListener,
+                            sessionListener, NUM_MAX_IMAGES, imageListener);
+
+                    // Converge AE
+                    waitForAeStable(previewResultListener, NUM_FRAMES_WAITED_FOR_UNKNOWN_LATENCY);
+
+                    if (mStaticInfo.isAeLockSupported()) {
+                        // Lock AE if possible to improve stability
+                        previewBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
+                        mSession.setRepeatingRequest(previewBuilder.build(), previewResultListener,
+                                mHandler);
+                        if (mStaticInfo.isHardwareLevelAtLeastLimited()) {
+                            // Legacy mode doesn't output AE state
+                            waitForResultValue(previewResultListener, CaptureResult.CONTROL_AE_STATE,
+                                    CaptureResult.CONTROL_AE_STATE_LOCKED, NUM_RESULTS_WAIT_TIMEOUT);
+                        }
+                    }
+
+                    // Capture NUM_MAX_IMAGES images based on onCaptureQueueEmpty callback
+                    for (int j = 0; j < NUM_MAX_IMAGES; j++) {
+
+                        // Capture an image and get image data
+                        startTimes[j] = SystemClock.elapsedRealtime();
+                        CaptureRequest request = captureBuilder.build();
+                        mSession.capture(request, captureResultListener, mHandler);
+
+                        // Wait for capture queue empty for the current request
+                        sessionListener.waitForCaptureQueueEmpty(
+                                CameraTestUtils.CAPTURE_IMAGE_TIMEOUT_MS);
+                    }
+
+                    // Acquire the capture result time and frame duration
+                    long prevTimestamp = -1;
+                    for (int j = 0; j < NUM_MAX_IMAGES; j++) {
+                        Pair<CaptureResult, Long> captureResultNTime =
+                                captureResultListener.getCaptureResultNTime(
+                                        CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS);
+
+                        getResultTimes[j] +=
+                                (double)(captureResultNTime.second - startTimes[j])/NUM_TEST_LOOPS;
+
+                        // Collect inter-frame timestamp
+                        long timestamp = captureResultNTime.first.get(CaptureResult.SENSOR_TIMESTAMP);
+                        if (prevTimestamp != -1) {
+                            frameDurationMs[j-1] +=
+                                    (double)(timestamp - prevTimestamp)/(NUM_TEST_LOOPS * 1000000.0);
+                        }
+                        prevTimestamp = timestamp;
+                    }
+
+                    // simulate real scenario (preview runs a bit)
+                    waitForNumResults(previewResultListener, NUM_RESULTS_WAIT);
+
+                    stopPreview();
+                }
+
+                for (int i = 0; i < getResultTimes.length; i++) {
+                    Log.v(TAG, "Camera " + id + " result time[" + i + "] is " +
+                            getResultTimes[i] + " ms");
+                }
+                for (int i = 0; i < NUM_MAX_IMAGES-1; i++) {
+                    Log.v(TAG, "Camera " + id + " frame duration time[" + i + "] is " +
+                            frameDurationMs[i] + " ms");
+                }
+
+                mReportLog.addValues("camera_multiple_capture_result_latency", getResultTimes,
+                        ResultType.LOWER_BETTER, ResultUnit.MS);
+                mReportLog.addValues("camera_multiple_capture_frame_duration", frameDurationMs,
+                        ResultType.LOWER_BETTER, ResultUnit.MS);
+
+
+                avgResultTimes[counter] = Stat.getAverage(getResultTimes);
+                avgDurationMs[counter] = Stat.getAverage(frameDurationMs);
+            }
+            finally {
+                closeImageReader();
+                closeDevice();
+            }
+            counter++;
+            mReportLog.submit(getInstrumentation());
+        }
+
+        // Result will not be reported in CTS report if no summary is printed.
+        if (mCameraIds.length != 0) {
+            String streamName = "test_multiple_capture_average";
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.setSummary("camera_multiple_capture_result_average_latency_for_all_cameras",
+                    Stat.getAverage(avgResultTimes), ResultType.LOWER_BETTER, ResultUnit.MS);
+            mReportLog.submit(getInstrumentation());
+            mReportLog = new DeviceReportLog(REPORT_LOG_NAME, streamName);
+            mReportLog.setSummary("camera_multiple_capture_frame_duration_average_for_all_cameras",
+                    Stat.getAverage(avgDurationMs), ResultType.LOWER_BETTER, ResultUnit.MS);
+            mReportLog.submit(getInstrumentation());
+        }
+    }
+
+    /**
      * Test reprocessing shot-to-shot latency with default NR and edge options, i.e., from the time
      * a reprocess request is issued to the time the reprocess image is returned.
      */
diff --git a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index d101036..d466662 100644
--- a/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -1282,14 +1282,15 @@
                                          duration, expectedDurationMs));
             }
 
-            // TODO: Don't skip this for video snapshot
-            if (!mStaticInfo.isHardwareLevelLegacy()) {
-                assertTrue(String.format(
-                        "Camera %s: Video duration doesn't match: recorded %fms, expected %fms.",
-                        mCamera.getId(), duration, expectedDurationMs),
-                        Math.abs(duration - expectedDurationMs) <
-                        DURATION_MARGIN * expectedDurationMs);
-            }
+            // Do rest of validation only for better-than-LEGACY devices
+            if (mStaticInfo.isHardwareLevelLegacy()) return;
+
+            // TODO: Don't skip this one for video snapshot on LEGACY
+            assertTrue(String.format(
+                    "Camera %s: Video duration doesn't match: recorded %fms, expected %fms.",
+                    mCamera.getId(), duration, expectedDurationMs),
+                    Math.abs(duration - expectedDurationMs) <
+                    DURATION_MARGIN * expectedDurationMs);
 
             // Check for framedrop
             long lastSampleUs = 0;
diff --git a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
index a95f4f3..feb0bc7 100644
--- a/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
+++ b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
@@ -55,6 +55,7 @@
 import com.android.ex.camera2.blocking.BlockingStateCallback;
 import com.android.ex.camera2.exceptions.TimeoutRuntimeException;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -696,6 +697,27 @@
             CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format,
             CaptureCallback resultListener, int maxNumImages,
             ImageReader.OnImageAvailableListener imageListener) throws Exception {
+        prepareCaptureAndStartPreview(previewRequest, stillRequest, previewSz, captureSz,
+            format, resultListener, null, maxNumImages, imageListener);
+    }
+
+    /**
+     * Setup single capture configuration and start preview.
+     *
+     * @param previewRequest The capture request to be used for preview
+     * @param stillRequest The capture request to be used for still capture
+     * @param previewSz Preview size
+     * @param captureSz Still capture size
+     * @param format The single capture image format
+     * @param resultListener Capture result listener
+     * @param sessionListener Session listener
+     * @param maxNumImages The max number of images set to the image reader
+     * @param imageListener The single capture capture image listener
+     */
+    protected void prepareCaptureAndStartPreview(CaptureRequest.Builder previewRequest,
+            CaptureRequest.Builder stillRequest, Size previewSz, Size captureSz, int format,
+            CaptureCallback resultListener, CameraCaptureSession.StateCallback sessionListener,
+            int maxNumImages, ImageReader.OnImageAvailableListener imageListener) throws Exception {
         if (VERBOSE) {
             Log.v(TAG, String.format("Prepare single capture (%s) and preview (%s)",
                     captureSz.toString(), previewSz.toString()));
@@ -711,7 +733,11 @@
         List<Surface> outputSurfaces = new ArrayList<Surface>();
         outputSurfaces.add(mPreviewSurface);
         outputSurfaces.add(mReaderSurface);
-        mSessionListener = new BlockingSessionCallback();
+        if (sessionListener == null) {
+            mSessionListener = new BlockingSessionCallback();
+        } else {
+            mSessionListener = new BlockingSessionCallback(sessionListener);
+        }
         mSession = configureCameraSession(mCamera, outputSurfaces, mSessionListener, mHandler);
 
         // Configure the requests.
@@ -791,4 +817,33 @@
         }
         return info.isCapabilitySupported(cap);
     }
+
+    protected Range<Integer> getSuitableFpsRangeForDuration(String cameraId, long frameDuration) {
+        // Add 0.05 here so Fps like 29.99 evaluated to 30
+        int minBurstFps = (int) Math.floor(1e9 / frameDuration + 0.05f);
+        boolean foundConstantMaxYUVRange = false;
+        boolean foundYUVStreamingRange = false;
+
+        // Find suitable target FPS range - as high as possible that covers the max YUV rate
+        // Also verify that there's a good preview rate as well
+        List<Range<Integer> > fpsRanges = Arrays.asList(
+                mStaticInfo.getAeAvailableTargetFpsRangesChecked());
+        Range<Integer> targetRange = null;
+        for (Range<Integer> fpsRange : fpsRanges) {
+            if (fpsRange.getLower() == minBurstFps && fpsRange.getUpper() == minBurstFps) {
+                foundConstantMaxYUVRange = true;
+                targetRange = fpsRange;
+            }
+            if (fpsRange.getLower() <= 15 && fpsRange.getUpper() == minBurstFps) {
+                foundYUVStreamingRange = true;
+            }
+        }
+
+        assertTrue(String.format("Cam %s: Target FPS range of (%d, %d) must be supported",
+                cameraId, minBurstFps, minBurstFps), foundConstantMaxYUVRange);
+        assertTrue(String.format(
+                "Cam %s: Target FPS range of (x, %d) where x <= 15 must be supported",
+                cameraId, minBurstFps), foundYUVStreamingRange);
+        return targetRange;
+    }
 }
diff --git a/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java b/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java
index a8e7cc1..d4f04de 100644
--- a/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java
+++ b/tests/deviceadmin/uninstalltest/src/android/devicepolicy/cts/uiautomatertest/DeviceAdminUninstallTest.java
@@ -15,6 +15,9 @@
  */
 package android.devicepolicy.cts.uiautomatertest;
 
+import static android.content.Intent.CATEGORY_DEFAULT;
+import static android.provider.Settings.ACTION_SETTINGS;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.app.admin.DevicePolicyManager;
@@ -26,6 +29,19 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.net.Uri;
 import android.provider.Settings;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
+import android.support.test.uiautomator.Until;
+import android.util.Log;
 import android.widget.ScrollView;
 
 import org.junit.After;
@@ -38,18 +54,6 @@
 import java.io.StringWriter;
 import java.util.List;
 import java.util.regex.Pattern;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.filters.LargeTest;
-import android.support.test.uiautomator.By;
-import android.support.test.uiautomator.BySelector;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiScrollable;
-import android.support.test.uiautomator.UiSelector;
-import android.support.test.uiautomator.Until;
-import android.util.Log;
 
 @RunWith(AndroidJUnit4.class)
 @LargeTest
@@ -60,14 +64,6 @@
     private static final String URI_PACKAGE_PREFIX = "package:";
     private static final String UNINSTALL_BUTTON_TEXT_REGEX = "(?i)uninstall";
 
-    private static final UiSelector DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR = new UiSelector()
-            .resourceId("com.android.settings:id/action_button");
-    // Changing the below two selectors to match the button based on text due to b/29960172
-    private static final UiSelector UNINSTALL_BUTTON_SELECTOR = new UiSelector()
-            .clickable(true).textMatches(UNINSTALL_BUTTON_TEXT_REGEX);
-    private static final BySelector UNINSTALL_BUTTON_BYSELECTOR = By
-            .clickable(true).text(Pattern.compile(UNINSTALL_BUTTON_TEXT_REGEX));
-
     private static final UiSelector OK_BUTTON_SELECTOR = new UiSelector()
             .resourceId("android:id/button1");
     private static final UiSelector SCROLL_VIEW_SELECTOR =
@@ -83,7 +79,10 @@
     private DevicePolicyManager mDpm;
     private PackageManager mPm;
     private Activity mActivity;
+    private UiSelector mDeactivateAndUninstallButtonSelector;
+    private BySelector mUninstallButtonSelector;
     private boolean mHasFeature;
+    private boolean mIsWatch;
 
     @Before
     public void setUp() throws Exception {
@@ -97,6 +96,17 @@
         mInstrumentation = InstrumentationRegistry.getInstrumentation();
         mUiDevice = UiDevice.getInstance(mInstrumentation);
         mDpm = mContext.getSystemService(DevicePolicyManager.class);
+        mIsWatch = mPm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+        if (mIsWatch) {
+            mUninstallButtonSelector = By.clickable(true).hasDescendant(
+                    By.text(Pattern.compile(UNINSTALL_BUTTON_TEXT_REGEX)));
+        } else {
+            mUninstallButtonSelector = By.clickable(true).text(
+                    Pattern.compile(UNINSTALL_BUTTON_TEXT_REGEX));
+        }
+        mDeactivateAndUninstallButtonSelector = new UiSelector().resourceId(
+                getDefaultSettingsPackageName() + ":id/action_button");
+
         startTestActivity();
     }
 
@@ -158,15 +168,21 @@
     private void automateUninstallThroughUi() {
         String errorMessage = "No exception in UI Automation";
 
-        UiObject uninstallButton = mUiDevice.findObject(UNINSTALL_BUTTON_SELECTOR);
         UiScrollable scrollable = new UiScrollable(SCROLL_VIEW_SELECTOR);
-        UiObject deactivateButton = mUiDevice.findObject(DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR);
+        UiObject deactivateButton = mUiDevice.findObject(mDeactivateAndUninstallButtonSelector);
         UiObject okButton = mUiDevice.findObject(OK_BUTTON_SELECTOR);
 
-        mUiDevice.wait(Until.hasObject(UNINSTALL_BUTTON_BYSELECTOR), WAIT_FOR_ACTIVITY_TIMEOUT);
         try {
-            uninstallButton.clickAndWaitForNewWindow();
-            scrollable.scrollIntoView(DEACTIVATE_AND_UNINSTALL_BUTTON_SELECTOR);
+            UiObject2 uninstallButton = mUiDevice.wait(
+                    Until.findObject(mUninstallButtonSelector), WAIT_FOR_ACTIVITY_TIMEOUT);
+            uninstallButton.clickAndWait(Until.newWindow(), WAIT_FOR_ACTIVITY_TIMEOUT);
+
+            /** Watch specific: Extra confirm button click */
+            if (mIsWatch) {
+                okButton.clickAndWaitForNewWindow();
+            }
+
+            scrollable.scrollIntoView(mDeactivateAndUninstallButtonSelector);
             deactivateButton.clickAndWaitForNewWindow();
             waitTillNoActiveAdmin();
             okButton.clickAndWaitForNewWindow();
@@ -185,6 +201,12 @@
         return errorWriter.toString();
     }
 
+    private String getDefaultSettingsPackageName() {
+        Intent intent = new Intent(ACTION_SETTINGS).addCategory(CATEGORY_DEFAULT);
+        String packageName = intent.resolveActivity(mPm).getPackageName();
+        return packageName;
+    }
+
     @Test
     public void uninstallPackageWithActiveAdmin() {
         if (!mHasFeature) {
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index 1d83241..dbba163 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -1,5 +1,12 @@
 [
 {
+  description: "Disable ListeningPortsTest",
+  names: [
+    "android.security.cts.ListeningPortsTest"
+  ],
+  bug: 31803630
+},
+{
   description: "some AlarmClockTests are not robust across different device types",
   names: [
     "android.alarmclock.cts.DismissAlarmTest#testAll",
diff --git a/tests/filesystem/src/android/filesystem/cts/FileUtil.java b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
index fc8eee0..8149105 100755
--- a/tests/filesystem/src/android/filesystem/cts/FileUtil.java
+++ b/tests/filesystem/src/android/filesystem/cts/FileUtil.java
@@ -41,6 +41,8 @@
     private static final String TAG = "FileUtil";
     private static final Random mRandom = new Random(0);
     private static long mFileId = 0;
+
+    public static final int BUFFER_SIZE = 10 * 1024 * 1024;
     /**
      * create array with different data per each call
      *
@@ -140,7 +142,6 @@
      */
     public static File createNewFilledFile(Context context, String dirName, long length)
             throws IOException {
-        final int BUFFER_SIZE = 10 * 1024 * 1024;
         File file = createNewFile(context, dirName);
         FileOutputStream out = new FileOutputStream(file);
         byte[] data = generateRandomData(BUFFER_SIZE);
diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
index a2df743..7b97f8f 100644
--- a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
@@ -17,7 +17,7 @@
 package android.filesystem.cts;
 
 import android.cts.util.CtsAndroidTestCase;
-
+import android.os.Environment;
 import com.android.compatibility.common.util.CddTest;
 import com.android.compatibility.common.util.DeviceReportLog;
 
@@ -51,11 +51,17 @@
     @CddTest(requirement="8.2")
     public void testRandomUpdate() throws Exception {
         final int WRITE_BUFFER_SIZE = 4 * 1024;
-        final long fileSize = 256 * 1024 * 1024;
+        final long usableSpace = Environment.getDataDirectory().getUsableSpace();
+        long fileSize = 256 * 1024 * 1024;
+        while (usableSpace < fileSize) {
+            fileSize = fileSize / 2;
+        }
         String streamName = "test_random_update";
         DeviceReportLog report = new DeviceReportLog(REPORT_LOG_NAME, streamName);
-        FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, report, fileSize,
+        if (fileSize > FileUtil.BUFFER_SIZE) {
+            FileUtil.doRandomWriteTest(getContext(), DIR_RANDOM_WR, report, fileSize,
                 WRITE_BUFFER_SIZE);
+        }
         report.submit(getInstrumentation());
     }
 }
diff --git a/tests/fragment/Android.mk b/tests/fragment/Android.mk
index 2352564..ab76caf 100644
--- a/tests/fragment/Android.mk
+++ b/tests/fragment/Android.mk
@@ -28,7 +28,14 @@
 
 LOCAL_PROGUARD_ENABLED := disabled
 
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES += \
+    android-support-test \
+    mockito-target-minus-junit4 \
+    android-common \
+    ctsdeviceutil \
+    ctstestrunner \
+    platform-test-annotations
+#LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/app/app/res/layout/fragment_a.xml b/tests/fragment/res/animator/slow_fade_out.xml
similarity index 60%
copy from tests/app/app/res/layout/fragment_a.xml
copy to tests/fragment/res/animator/slow_fade_out.xml
index 38e0423..d8d2ad2 100644
--- a/tests/app/app/res/layout/fragment_a.xml
+++ b/tests/fragment/res/animator/slow_fade_out.xml
@@ -13,13 +13,8 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
+<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+                android:duration="5000"
+                android:propertyName="alpha"
+                android:valueFrom="1.0"
+                android:valueTo="0.0"/>
diff --git a/tests/fragment/res/layout/scene1.xml b/tests/fragment/res/layout/scene1.xml
new file mode 100644
index 0000000..d0509c3
--- /dev/null
+++ b/tests/fragment/res/layout/scene1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+    <View android:id="@+id/blueSquare"
+          android:transitionName="blueSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/scene2.xml b/tests/fragment/res/layout/scene2.xml
new file mode 100644
index 0000000..ef809a42
--- /dev/null
+++ b/tests/fragment/res/layout/scene2.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/blueSquare"
+          android:transitionName="blueSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/fragment/res/layout/scene3.xml b/tests/fragment/res/layout/scene3.xml
new file mode 100644
index 0000000..15519fd
--- /dev/null
+++ b/tests/fragment/res/layout/scene3.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/squareContainer"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+    <View android:id="@+id/redSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#800"/>
+    <View android:id="@+id/blueSquare"
+          android:transitionName="shared"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:background="#008"/>
+    <View android:id="@+id/greenSquare"
+          android:layout_width="10dp"
+          android:layout_height="10dp"
+          android:transitionName="greenSquare"
+          android:background="#080"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/app/app/res/layout/fragment_a.xml b/tests/fragment/res/layout/text_a.xml
similarity index 61%
copy from tests/app/app/res/layout/fragment_a.xml
copy to tests/fragment/res/layout/text_a.xml
index 38e0423..b164469 100644
--- a/tests/app/app/res/layout/fragment_a.xml
+++ b/tests/fragment/res/layout/text_a.xml
@@ -13,13 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textA"/>
diff --git a/tests/app/app/res/layout/fragment_a.xml b/tests/fragment/res/layout/text_b.xml
similarity index 61%
copy from tests/app/app/res/layout/fragment_a.xml
copy to tests/fragment/res/layout/text_b.xml
index 38e0423..3d307fc 100644
--- a/tests/app/app/res/layout/fragment_a.xml
+++ b/tests/fragment/res/layout/text_b.xml
@@ -13,13 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textB"/>
diff --git a/tests/app/app/res/layout/fragment_a.xml b/tests/fragment/res/layout/text_c.xml
similarity index 61%
rename from tests/app/app/res/layout/fragment_a.xml
rename to tests/fragment/res/layout/text_c.xml
index 38e0423..e40b5ab 100644
--- a/tests/app/app/res/layout/fragment_a.xml
+++ b/tests/fragment/res/layout/text_c.xml
@@ -13,13 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"
-              android:orientation="vertical">
-    <TextView android:layout_width="wrap_content"
-              android:layout_height="wrap_content"
-              android:id="@+id/textA"
-              android:text="@string/hello"/>
-</LinearLayout>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:id="@+id/textC"/>
diff --git a/tests/fragment/src/android/fragment/cts/CountCallsFragment.java b/tests/fragment/src/android/fragment/cts/CountCallsFragment.java
new file mode 100644
index 0000000..a262772
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/CountCallsFragment.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Counts the number of onCreateView, onHiddenChanged (onHide, onShow), onAttach, and onDetach
+ * calls.
+ */
+public class CountCallsFragment extends StrictViewFragment {
+    public int onCreateViewCount = 0;
+    public int onDestroyViewCount = 0;
+    public int onHideCount = 0;
+    public int onShowCount = 0;
+    public int onAttachCount = 0;
+    public int onDetachCount = 0;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        onCreateViewCount++;
+        return super.onCreateView(inflater, container, savedInstanceState);
+    }
+
+    @Override
+    public void onHiddenChanged(boolean hidden) {
+        if (hidden) {
+            onHideCount++;
+        } else {
+            onShowCount++;
+        }
+        super.onHiddenChanged(hidden);
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        onAttachCount++;
+        super.onAttach(context);
+    }
+
+    @Override
+    public void onDetach() {
+        onDetachCount++;
+        super.onDetach();
+    }
+
+    @Override
+    public void onDestroyView() {
+        onDestroyViewCount++;
+        super.onDestroyView();
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
index 2d75395..f0dac9a 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentAnimatorTest.java
@@ -18,6 +18,9 @@
 import static junit.framework.Assert.*;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -26,14 +29,18 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.app.Fragment;
+import android.app.FragmentController;
 import android.app.FragmentManager;
+import android.app.FragmentManagerNonConfig;
 import android.app.Instrumentation;
 import android.os.Debug;
+import android.os.Parcelable;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -79,7 +86,7 @@
                 .add(R.id.fragmentContainer, fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertEnterPopExit(fragment);
     }
@@ -92,14 +99,14 @@
         // One fragment with a view
         final AnimatorFragment fragment = new AnimatorFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .remove(fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertExitPopEnter(fragment);
     }
@@ -112,14 +119,14 @@
         // One fragment with a view
         final AnimatorFragment fragment = new AnimatorFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .show(fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertEnterPopExit(fragment);
     }
@@ -132,14 +139,14 @@
         // One fragment with a view
         final AnimatorFragment fragment = new AnimatorFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .hide(fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertExitPopEnter(fragment);
     }
@@ -152,14 +159,14 @@
         // One fragment with a view
         final AnimatorFragment fragment = new AnimatorFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).detach(fragment).commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .attach(fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertEnterPopExit(fragment);
     }
@@ -172,14 +179,14 @@
         // One fragment with a view
         final AnimatorFragment fragment = new AnimatorFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         fm.beginTransaction()
                 .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
                 .detach(fragment)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertExitPopEnter(fragment);
     }
@@ -197,7 +204,7 @@
                 .add(R.id.fragmentContainer, fragment1, "1")
                 .add(R.id.fragmentContainer, fragment2, "2")
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         final AnimatorFragment fragment3 = new AnimatorFragment();
         fm.beginTransaction()
@@ -205,16 +212,14 @@
                 .replace(R.id.fragmentContainer, fragment3)
                 .addToBackStack(null)
                 .commit();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertFragmentAnimation(fragment1, 1, false, EXIT);
         assertFragmentAnimation(fragment2, 1, false, EXIT);
         assertFragmentAnimation(fragment3, 1, true, ENTER);
 
-        mInstrumentation.waitForIdleSync();
-
         fm.popBackStack();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertFragmentAnimation(fragment3, 2, false, POP_EXIT);
         final AnimatorFragment replacement1 = (AnimatorFragment) fm.findFragmentByTag("1");
@@ -224,24 +229,190 @@
         assertFragmentAnimation(replacement2, expectedAnimations, true, POP_ENTER);
     }
 
+    // Ensure that adding and popping a Fragment uses the enter and popExit animators,
+    // but the animators are delayed when an entering Fragment is postponed.
+    @Test
+    public void postponedAddAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fragment.postponeEnterTransition();
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .add(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment, 0);
+        fragment.startPostponedEnterTransition();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertEnterPopExit(fragment);
+    }
+
+    // Ensure that removing and popping a Fragment uses the exit and popEnter animators,
+    // but the animators are delayed when an entering Fragment is postponed.
+    @Test
+    public void postponedRemoveAnimators() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment = new AnimatorFragment();
+        fm.beginTransaction().add(R.id.fragmentContainer, fragment, "1").commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertExitPostponedPopEnter(fragment);
+    }
+
+    // Ensure that adding and popping a Fragment is postponed in both directions
+    // when the fragments have been marked for postponing.
+    @Test
+    public void postponedAddRemove() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment1 = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final AnimatorFragment fragment2 = new AnimatorFragment();
+        fragment2.postponeEnterTransition();
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment2, 0);
+        assertNotNull(fragment1.getView());
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertTrue(fragment1.getView().isAttachedToWindow());
+
+        fragment2.startPostponedEnterTransition();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertExitPostponedPopEnter(fragment1);
+    }
+
+    // Popping a postponed transaction should result in no animators
+    @Test
+    public void popPostponed() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final AnimatorFragment fragment1 = new AnimatorFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertEquals(0, fragment1.numAnimators);
+
+        final AnimatorFragment fragment2 = new AnimatorFragment();
+        fragment2.postponeEnterTransition();
+
+        fm.beginTransaction()
+                .setCustomAnimations(ENTER, EXIT, POP_ENTER, POP_EXIT)
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponed(fragment2, 0);
+
+        // Now pop the postponed transaction
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertNotNull(fragment1.getView());
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertTrue(fragment1.getView().isAttachedToWindow());
+        assertTrue(fragment1.isAdded());
+
+        assertNull(fragment2.getView());
+        assertFalse(fragment2.isAdded());
+
+        assertEquals(0, fragment1.numAnimators);
+        assertEquals(0, fragment2.numAnimators);
+        assertNull(fragment1.animator);
+        assertNull(fragment2.animator);
+    }
+
+    // Make sure that if the state was saved while a Fragment was animating that its
+    // state is proper after restoring.
+    @Test
+    public void saveWhileAnimatingAway() throws Throwable {
+        final FragmentController fc1 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc1, null);
+
+        final FragmentManager fm1 = fc1.getFragmentManager();
+
+        StrictViewFragment fragment1 = new StrictViewFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        fm1.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        StrictViewFragment fragment2 = new StrictViewFragment();
+
+        fm1.beginTransaction()
+                .setCustomAnimations(0, 0, 0, R.animator.slow_fade_out)
+                .replace(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack(null)
+                .commit();
+        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fm1.popBackStack();
+
+        mInstrumentation.runOnMainSync(fm1::executePendingTransactions);
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        // Now fragment2 should be animating away
+        assertFalse(fragment2.isAdded());
+        assertEquals(fragment2, fm1.findFragmentByTag("2")); // still exists because it is animating
+
+        Pair<Parcelable, FragmentManagerNonConfig> state =
+                FragmentTestUtil.destroy(mActivityRule, fc1);
+
+        final FragmentController fc2 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc2, state);
+
+        final FragmentManager fm2 = fc2.getFragmentManager();
+        Fragment fragment2restored = fm2.findFragmentByTag("2");
+        assertNull(fragment2restored);
+
+        Fragment fragment1restored = fm2.findFragmentByTag("1");
+        assertNotNull(fragment1restored);
+        assertNotNull(fragment1restored.getView());
+    }
+
     private void assertEnterPopExit(AnimatorFragment fragment) throws Throwable {
         assertFragmentAnimation(fragment, 1, true, ENTER);
-        mInstrumentation.waitForIdleSync();
 
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         fm.popBackStack();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         assertFragmentAnimation(fragment, 2, false, POP_EXIT);
     }
 
     private void assertExitPopEnter(AnimatorFragment fragment) throws Throwable {
         assertFragmentAnimation(fragment, 1, false, EXIT);
-        mInstrumentation.waitForIdleSync();
 
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         fm.popBackStack();
-        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.waitForExecution(mActivityRule);
 
         AnimatorFragment replacement = (AnimatorFragment) fm.findFragmentByTag("1");
 
@@ -250,6 +421,19 @@
         assertFragmentAnimation(replacement, expectedAnimators, true, POP_ENTER);
     }
 
+    private void assertExitPostponedPopEnter(AnimatorFragment fragment) throws Throwable {
+        assertFragmentAnimation(fragment, 1, false, EXIT);
+
+        fragment.postponeEnterTransition();
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponed(fragment, 1);
+
+        fragment.startPostponedEnterTransition();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertFragmentAnimation(fragment, 2, true, POP_ENTER);
+    }
+
     private void assertFragmentAnimation(AnimatorFragment fragment, int numAnimators,
             boolean isEnter, int animatorResourceId) throws InterruptedException {
         assertEquals(numAnimators, fragment.numAnimators);
@@ -257,7 +441,14 @@
         assertEquals(animatorResourceId, fragment.resourceId);
         assertNotNull(fragment.animator);
         assertTrue(fragment.wasStarted);
-        assertTrue(fragment.endLatch.await(100, TimeUnit.MILLISECONDS));
+        assertTrue(fragment.endLatch.await(200, TimeUnit.MILLISECONDS));
+    }
+
+    private void assertPostponed(AnimatorFragment fragment, int expectedAnimators)
+            throws InterruptedException {
+        assertTrue(fragment.mOnCreateViewCalled);
+        assertEquals(View.INVISIBLE, fragment.getView().getVisibility());
+        assertEquals(expectedAnimators, fragment.numAnimators);
     }
 
     public static class AnimatorFragment extends StrictViewFragment {
diff --git a/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
new file mode 100644
index 0000000..7d65b8c
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentExecuteTests.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import static junit.framework.Assert.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.FragmentManager;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentExecuteTests {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setupContentView() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+    }
+
+    // Test that when executePendingBindings is called after something has been
+    // committed that it returns true and that the transaction was executed.
+    @Test
+    public void executeAndPopNormal() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment, "1")
+                        .addToBackStack(null)
+                        .commit();
+                assertTrue(fm.executePendingTransactions());
+            }
+        });
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment, fm.findFragmentByTag("1"));
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertNull(fm.findFragmentById(R.id.fragmentContainer));
+        assertNull(fm.findFragmentByTag("1"));
+    }
+
+    // Test that when executePendingBindings is called when nothing has been
+    // committed that it returns false and that the fragment manager is unchanged.
+    @Test
+    public void executeAndPopNothing() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertFalse(FragmentTestUtil.executePendingTransactions(mActivityRule));
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+        assertEquals(0, fm.getBackStackEntryCount());
+    }
+
+    // Test that when popBackStackImmediate is called when something is in the queue and
+    // there is a back stack to pop, it will execute both and return true.
+    @Test
+    public void popBackStackImmediateSomething() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment, "1")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertNull(fm.findFragmentById(R.id.fragmentContainer));
+        assertNull(fm.findFragmentByTag("1"));
+    }
+
+    // Test that when popBackStackImmediate is called when something is in the queue and
+    // there is no back stack to pop, it will execute the thing in the queue and
+    // return false.
+    @Test
+    public void popBackStackImmediateNothing() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment = new StrictViewFragment();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment, "1")
+                .commit();
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule));
+
+        FragmentTestUtil.assertChildren(container, fragment);
+        assertEquals(0, fm.getBackStackEntryCount());
+        assertEquals(fragment, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment, fm.findFragmentByTag("1"));
+    }
+
+    // Test popBackStackImmediate(int, int)
+    @Test
+    public void popBackStackImmediateInt() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+
+        final int commit1 = fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment3, "3")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit1, 0));
+        assertFalse(fragment2.isAdded());
+        assertTrue(fragment2.mCalledOnDestroy || !fragment2.mCalledOnCreate);
+        assertFalse(fragment3.isAdded());
+        assertTrue(fragment3.mCalledOnDestroy || !fragment3.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit1, 0));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        final int commit4 = fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment4, "4")
+                .addToBackStack(null)
+                .commit();
+
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment5, "5")
+                .addToBackStack(null)
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit4,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+        assertFalse(fragment4.isAdded());
+        assertTrue(fragment4.mCalledOnDestroy || !fragment4.mCalledOnCreate);
+        assertFalse(fragment5.isAdded());
+        assertTrue(fragment5.mCalledOnDestroy || !fragment5.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, commit4,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+    }
+
+    // Test popBackStackImmediate(String, int)
+    @Test
+    public void popBackStackImmediateString() throws Throwable {
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .addToBackStack("1")
+                .commit();
+
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .addToBackStack("2")
+                .commit();
+
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment3, "3")
+                .addToBackStack("3")
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, "1", 0));
+        assertFalse(fragment2.isAdded());
+        assertTrue(fragment2.mCalledOnDestroy || !fragment2.mCalledOnCreate);
+        assertFalse(fragment3.isAdded());
+        assertTrue(fragment3.mCalledOnDestroy || !fragment3.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, "1", 0));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment4, "4")
+                .addToBackStack("4")
+                .commit();
+
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment5, "5")
+                .addToBackStack("5")
+                .commit();
+
+        assertTrue(FragmentTestUtil.popBackStackImmediate(mActivityRule, "4",
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+        assertFalse(fragment4.isAdded());
+        assertTrue(fragment4.mCalledOnDestroy || !fragment4.mCalledOnCreate);
+        assertFalse(fragment5.isAdded());
+        assertTrue(fragment5.mCalledOnDestroy || !fragment5.mCalledOnCreate);
+
+        assertFalse(FragmentTestUtil.popBackStackImmediate(mActivityRule, "4",
+                FragmentManager.POP_BACK_STACK_INCLUSIVE));
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+        assertEquals(1, fm.getBackStackEntryCount());
+        assertEquals(fragment1, fm.findFragmentById(R.id.fragmentContainer));
+        assertEquals(fragment1, fm.findFragmentByTag("1"));
+    }
+
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index 01c4e70..89812c3 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -17,18 +17,40 @@
 
 package android.fragment.cts;
 
+import android.app.FragmentController;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentHostCallback;
 import android.app.FragmentManager;
+import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Debug;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.MediumTest;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+
+import android.view.Window;
+import android.widget.TextView;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.TestCase.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class FragmentLifecycleTest {
 
@@ -37,7 +59,6 @@
             new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
 
     @Test
-    @MediumTest
     public void basicLifecycle() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment strictFragment = new StrictFragment();
@@ -65,7 +86,6 @@
     }
 
     @Test
-    @MediumTest
     public void detachment() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -105,7 +125,6 @@
     }
 
     @Test
-    @MediumTest
     public void basicBackStack() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -136,7 +155,6 @@
     }
 
     @Test
-    @MediumTest
     public void attachBackStack() throws Throwable {
         final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
         final StrictFragment f1 = new StrictFragment();
@@ -158,7 +176,6 @@
     }
 
     @Test
-    @MediumTest
     public void viewLifecycle() throws Throwable {
         // Test basic lifecycle when the fragment creates a view
 
@@ -183,7 +200,6 @@
     }
 
     @Test
-    @MediumTest
     public void viewReplace() throws Throwable {
         // Replace one view with another, then reverse it with the back stack
 
@@ -223,6 +239,160 @@
         assertTrue("fragment 1's view not attached", newView1.isAttachedToWindow());
     }
 
+    @Test
+    public void viewReplaceMultiple() throws Throwable {
+        // Replace several views with one, then reverse it with the back stack
+
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment f1 = new StrictViewFragment();
+        final StrictViewFragment f2 = new StrictViewFragment();
+        final StrictViewFragment f3 = new StrictViewFragment();
+
+        fm.beginTransaction().add(android.R.id.content, f1).commit();
+        fm.beginTransaction().add(android.R.id.content, f2).commit();
+        executePendingTransactions(fm);
+
+        assertTrue("fragment 1 is not added", f1.isAdded());
+        assertTrue("fragment 2 is not added", f2.isAdded());
+
+        View origView1 = f1.getView();
+        assertNotNull("fragment 1 returned null view", origView1);
+        assertTrue("fragment 1's view not attached", origView1.isAttachedToWindow());
+        assertSame(origView1, ((ViewGroup)origView1.getParent()).getChildAt(0));
+
+        View origView2 = f2.getView();
+        assertNotNull("fragment 2 returned null view", origView2);
+        assertTrue("fragment 2's view not attached", origView2.isAttachedToWindow());
+        assertSame(origView2, ((ViewGroup)origView1.getParent()).getChildAt(1));
+
+        fm.beginTransaction().replace(android.R.id.content, f3).addToBackStack("stack1").commit();
+        executePendingTransactions(fm);
+
+        assertFalse("fragment 1 is added", f1.isAdded());
+        assertFalse("fragment 2 is added", f2.isAdded());
+        assertTrue("fragment 3 is added", f3.isAdded());
+        assertNull("fragment 1 returned non-null view", f1.getView());
+        assertNull("fragment 2 returned non-null view", f2.getView());
+        assertFalse("fragment 1's old view still attached", origView1.isAttachedToWindow());
+        assertFalse("fragment 2's old view still attached", origView2.isAttachedToWindow());
+        View origView3 = f3.getView();
+        assertNotNull("fragment 3 returned null view", origView3);
+        assertTrue("fragment 3's view not attached", origView3.isAttachedToWindow());
+
+        fm.popBackStack();
+        executePendingTransactions(fm);
+
+        assertTrue("fragment 1 is not added", f1.isAdded());
+        assertTrue("fragment 2 is not added", f2.isAdded());
+        assertFalse("fragment 3 is added", f3.isAdded());
+        assertNull("fragment 3 returned non-null view", f3.getView());
+        assertFalse("fragment 3's view still attached", origView3.isAttachedToWindow());
+        View newView1 = f1.getView();
+        View newView2 = f2.getView();
+        assertNotSame("fragment 1 had same view from last attachment", origView1, newView1);
+        assertNotSame("fragment 2 had same view from last attachment", origView2, newView1);
+        assertTrue("fragment 1's view not attached", newView1.isAttachedToWindow());
+        assertTrue("fragment 2's view not attached", newView2.isAttachedToWindow());
+        assertSame(newView1, ((ViewGroup)newView1.getParent()).getChildAt(0));
+        assertSame(newView2, ((ViewGroup)newView1.getParent()).getChildAt(1));
+    }
+
+    /**
+     * This tests that fragments call onDestroy when the activity finishes.
+     */
+    @Test
+    public void fragmentDestroyedOnFinish() throws Throwable {
+        final FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, null);
+        final StrictViewFragment fragmentA = StrictViewFragment.create(R.layout.text_a);
+        final StrictViewFragment fragmentB = StrictViewFragment.create(R.layout.text_b);
+        mActivityRule.runOnUiThread(() -> {
+            FragmentManager fm = fc.getFragmentManager();
+
+            fm.beginTransaction()
+                    .add(android.R.id.content, fragmentA)
+                    .commit();
+            fm.executePendingTransactions();
+            fm.beginTransaction()
+                    .replace(android.R.id.content, fragmentB)
+                    .addToBackStack(null)
+                    .commit();
+            fm.executePendingTransactions();
+        });
+        FragmentTestUtil.destroy(mActivityRule, fc);
+        assertTrue(fragmentB.mCalledOnDestroy);
+        assertTrue(fragmentA.mCalledOnDestroy);
+    }
+
+    /**
+     * This test confirms that as long as a parent fragment has called super.onCreate,
+     * any child fragments added, committed and with transactions executed will be brought
+     * to at least the CREATED state by the time the parent fragment receives onCreateView.
+     * This means the child fragment will have received onAttach/onCreate.
+     */
+    @Test
+    @MediumTest
+    public void childFragmentManagerAttach() throws Throwable {
+        mActivityRule.runOnUiThread(new Runnable() {
+            public void run() {
+                FragmentController fc = FragmentController.createController(
+                        new HostCallbacks(mActivityRule.getActivity()));
+                fc.attachHost(null);
+                fc.dispatchCreate();
+
+                FragmentLifecycleCallbacks mockLc = mock(FragmentLifecycleCallbacks.class);
+                FragmentLifecycleCallbacks mockRecursiveLc = mock(FragmentLifecycleCallbacks.class);
+
+                FragmentManager fm = fc.getFragmentManager();
+                fm.registerFragmentLifecycleCallbacks(mockLc, false);
+                fm.registerFragmentLifecycleCallbacks(mockRecursiveLc, true);
+
+                ChildFragmentManagerFragment fragment = new ChildFragmentManagerFragment();
+                fm.beginTransaction()
+                        .add(android.R.id.content, fragment)
+                        .commitNow();
+
+                verify(mockLc, times(1)).onFragmentCreated(fm, fragment, null);
+
+                fc.dispatchActivityCreated();
+
+                Fragment childFragment = fragment.getChildFragment();
+
+                verify(mockLc, times(1)).onFragmentActivityCreated(fm, fragment, null);
+                verify(mockRecursiveLc, times(1)).onFragmentActivityCreated(fm, fragment, null);
+                verify(mockRecursiveLc, times(1)).onFragmentActivityCreated(fm, childFragment, null);
+
+                fc.dispatchStart();
+
+                verify(mockLc, times(1)).onFragmentStarted(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStarted(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStarted(fm, childFragment);
+
+                fc.dispatchResume();
+
+                verify(mockLc, times(1)).onFragmentResumed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentResumed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentResumed(fm, childFragment);
+
+                // Confirm that the parent fragment received onAttachFragment
+                assertTrue("parent fragment did not receive onAttachFragment",
+                        fragment.mCalledOnAttachFragment);
+
+                fc.dispatchStop();
+
+                verify(mockLc, times(1)).onFragmentStopped(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStopped(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentStopped(fm, childFragment);
+
+                fc.dispatchDestroy();
+
+                verify(mockLc, times(1)).onFragmentDestroyed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentDestroyed(fm, fragment);
+                verify(mockRecursiveLc, times(1)).onFragmentDestroyed(fm, childFragment);
+            }
+        });
+    }
+
     private void executePendingTransactions(final FragmentManager fm) throws Throwable {
         mActivityRule.runOnUiThread(new Runnable() {
             @Override
@@ -231,4 +401,135 @@
             }
         });
     }
+
+    /**
+     * This tests a deliberately odd use of a child fragment, added in onCreateView instead
+     * of elsewhere. It simulates creating a UI child fragment added to the view hierarchy
+     * created by this fragment.
+     */
+    public static class ChildFragmentManagerFragment extends StrictFragment {
+        private FragmentManager mSavedChildFragmentManager;
+        private ChildFragmentManagerChildFragment mChildFragment;
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            mSavedChildFragmentManager = getChildFragmentManager();
+        }
+
+
+        @Override
+        public View onCreateView(LayoutInflater inflater,  ViewGroup container,
+                 Bundle savedInstanceState) {
+            assertSame("child FragmentManagers not the same instance", mSavedChildFragmentManager,
+                    getChildFragmentManager());
+            ChildFragmentManagerChildFragment child =
+                    (ChildFragmentManagerChildFragment) mSavedChildFragmentManager
+                            .findFragmentByTag("tag");
+            if (child == null) {
+                child = new ChildFragmentManagerChildFragment("foo");
+                mSavedChildFragmentManager.beginTransaction()
+                        .add(child, "tag")
+                        .commitNow();
+                assertEquals("argument strings don't match", "foo", child.getString());
+            }
+            mChildFragment = child;
+            return new TextView(container.getContext());
+        }
+
+
+        public Fragment getChildFragment() {
+            return mChildFragment;
+        }
+    }
+
+    public static class ChildFragmentManagerChildFragment extends StrictFragment {
+        private String mString;
+
+        public ChildFragmentManagerChildFragment() {
+        }
+
+        public ChildFragmentManagerChildFragment(String arg) {
+            final Bundle b = new Bundle();
+            b.putString("string", arg);
+            setArguments(b);
+        }
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            mString = getArguments().getString("string", "NO VALUE");
+        }
+
+        public String getString() {
+            return mString;
+        }
+    }
+
+    static class HostCallbacks extends FragmentHostCallback<Activity> {
+        private final Activity mActivity;
+
+        public HostCallbacks(Activity activity) {
+            super(activity, null, 0);
+            mActivity = activity;
+        }
+
+        @Override
+        public void onDump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        }
+
+        @Override
+        public boolean onShouldSaveFragmentState(Fragment fragment) {
+            return !mActivity.isFinishing();
+        }
+
+        @Override
+        public LayoutInflater onGetLayoutInflater() {
+            return mActivity.getLayoutInflater().cloneInContext(mActivity);
+        }
+
+        @Override
+        public Activity onGetHost() {
+            return mActivity;
+        }
+
+        @Override
+        public void onStartActivityFromFragment(
+                Fragment fragment, Intent intent, int requestCode,  Bundle options) {
+            mActivity.startActivityFromFragment(fragment, intent, requestCode, options);
+        }
+
+        @Override
+        public void onRequestPermissionsFromFragment( Fragment fragment,
+                 String[] permissions, int requestCode) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean onHasWindowAnimations() {
+            return mActivity.getWindow() != null;
+        }
+
+        @Override
+        public int onGetWindowAnimations() {
+            final Window w = mActivity.getWindow();
+            return (w == null) ? 0 : w.getAttributes().windowAnimations;
+        }
+
+        @Override
+        public void onAttachFragment(Fragment fragment) {
+            mActivity.onAttachFragment(fragment);
+        }
+
+        @Override
+        public View onFindViewById(int id) {
+            return mActivity.findViewById(id);
+        }
+
+        @Override
+        public boolean onHasView() {
+            final Window w = mActivity.getWindow();
+            return (w != null && w.peekDecorView() != null);
+        }
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
new file mode 100644
index 0000000..253bbcb
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentOptimizationTest.java
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import static org.junit.Assert.*;
+
+import android.app.FragmentManager;
+import android.app.Instrumentation;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentOptimizationTest {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private ViewGroup mContainer;
+    private FragmentManager mFM;
+    private Instrumentation mInstrumentation;
+
+    @Before
+    public void setup() {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        mContainer = (ViewGroup) mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        mFM = mActivityRule.getActivity().getFragmentManager();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    // Test that when you add and replace a fragment that only the replace's add
+    // actually creates a View.
+    @Test
+    public void addReplace() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        assertEquals(0, fragment1.onCreateViewCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.popBackStack();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+    }
+
+    // Test that it is possible to merge a transaction that starts with pop and adds
+    // the same view back again.
+    @Test
+    public void startWithPop() throws Throwable {
+        // Start with a single fragment on the back stack
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        mFM.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // Now pop and add
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.popBackStack();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+    // Popping the back stack in the middle of other operations doesn't fool it.
+    @Test
+    public void middlePop() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.popBackStack();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+        assertEquals(0, fragment1.onAttachCount);
+        assertEquals(1, fragment2.onCreateViewCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(1, fragment2.onDetachCount);
+    }
+
+    // ensure that removing a view after adding it is optimized into no
+    // View being created. Hide still gets notified.
+    @Test
+    public void optimizeRemove() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final int[] id = new int[1];
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                id[0] = mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().remove(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(0, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(0, fragment1.onAttachCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id[0],
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        FragmentTestUtil.assertChildren(mContainer);
+        assertEquals(0, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(0, fragment1.onAttachCount);
+    }
+
+    // Ensure that removing and adding the same view results in no operation
+    @Test
+    public void optimizeAdd() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .remove(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // should be optimized out
+        assertEquals(1, fragment1.onCreateViewCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // optimize out going back, too
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+    // detaching, then attaching results in on change. Hide still functions
+    @Test
+    public void optimizeAttach() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(1, fragment1.onAttachCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // can optimize out the detach/attach
+        assertEquals(0, fragment1.onDestroyViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // optimized out again, but not the show
+        assertEquals(0, fragment1.onDestroyViewCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(1, fragment1.onCreateViewCount);
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+    }
+
+    // attaching, then detaching shouldn't result in a View being created
+    @Test
+    public void optimizeDetach() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .detach(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        // the add detach is not fully optimized out
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertTrue(fragment1.isDetached());
+        assertEquals(0, fragment1.onCreateViewCount);
+        FragmentTestUtil.assertChildren(mContainer);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer);
+        // can optimize out the attach/detach, and the hide call
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertTrue(fragment1.isHidden());
+        assertEquals(0, fragment1.onShowCount);
+
+        mFM.popBackStack(id, 0);
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer);
+
+        // we can optimize out the attach/detach on the way back
+        assertEquals(1, fragment1.onAttachCount);
+        assertEquals(0, fragment1.onDetachCount);
+        assertEquals(1, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+        assertFalse(fragment1.isHidden());
+    }
+
+    // show, then hide should optimize out
+    @Test
+    public void optimizeHide() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .hide(fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .show(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .remove(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .hide(fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // optimize out hide/show
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        // still optimized out
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        // The show/hide can be optimized out and nothing should change.
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        // the detach/attach should not affect the show/hide, so show/hide should cancel each other
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(1, fragment1.onHideCount);
+    }
+
+    // hiding and showing the same view should optimize out
+    @Test
+    public void optimizeShow() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction().hide(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().detach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().attach(fragment1).addToBackStack(null).commit();
+                mFM.beginTransaction().show(fragment1).addToBackStack(null).commit();
+                mFM.executePendingTransactions();
+            }
+        });
+
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+        // can optimize out the show/hide
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id,
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+        assertEquals(0, fragment1.onShowCount);
+        assertEquals(0, fragment1.onHideCount);
+    }
+
+    // The View order shouldn't be messed up by optimization -- a view that
+    // is optimized to not remove/add should be in its correct position after
+    // the transaction completes.
+    @Test
+    public void viewOrder() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        int id = mFM.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2, fragment1);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, id, 0);
+        FragmentTestUtil.assertChildren(mContainer, fragment1);
+    }
+
+    // Popping an added transaction results in no operation
+    @Test
+    public void addPopBackStack() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer);
+
+        // Was never instantiated because it was popped before anything could happen
+        assertEquals(0, fragment1.onCreateViewCount);
+    }
+
+    // A non-back-stack transaction doesn't interfere with back stack add/pop
+    // optimization.
+    @Test
+    public void popNonBackStack() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .commit();
+                mFM.popBackStack();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        // It should be optimized with the replace, so no View creation
+        assertEquals(0, fragment1.onCreateViewCount);
+    }
+
+    // When optimization is disabled, the transaction prior to the disabled optimization
+    // transaction should all be run prior to running the non-optimized transaction.
+    @Test
+    public void noOptimization() throws Throwable {
+        final CountCallsFragment fragment1 = new CountCallsFragment();
+        final CountCallsFragment fragment2 = new CountCallsFragment();
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFM.beginTransaction()
+                        .add(R.id.fragmentContainer, fragment1)
+                        .addToBackStack(null)
+                        .commit();
+                mFM.beginTransaction()
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .setAllowOptimization(false)
+                        .commit();
+                mFM.executePendingTransactions();
+            }
+        });
+        FragmentTestUtil.assertChildren(mContainer, fragment2);
+
+        // No optimization, so fragment1 should have created its View
+        assertEquals(1, fragment1.onCreateViewCount);
+    }
+
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
index c83d4fa..b4407a0 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTestUtil.java
@@ -15,20 +15,80 @@
  */
 package android.fragment.cts;
 
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentManagerNonConfig;
 import android.app.Instrumentation;
+import android.os.Handler;
+import android.os.Parcelable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
+import android.util.Pair;
+import android.view.ViewGroup;
 
 public class FragmentTestUtil {
-    public static void executePendingTransactions(final ActivityTestRule<FragmentTestActivity> rule)
-            throws Throwable {
+    public static void waitForExecution(final ActivityTestRule<FragmentTestActivity> rule) {
+        // Wait for two cycles. When starting a postponed transition, it will post to
+        // the UI thread and then the execution will be added onto the queue after that.
+        // The two-cycle wait makes sure fragments have the opportunity to complete both
+        // before returning.
         Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {});
+        instrumentation.runOnMainSync(() -> {});
+    }
+
+    public static boolean executePendingTransactions(
+            final ActivityTestRule<FragmentTestActivity> rule) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
         instrumentation.runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                rule.getActivity().getFragmentManager().executePendingTransactions();
+                ret[0] = rule.getActivity().getFragmentManager().executePendingTransactions();
             }
         });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate();
+            }
+        });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule,
+            final int id, final int flags) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate(id, flags);
+            }
+        });
+        return ret[0];
+    }
+
+    public static boolean popBackStackImmediate(final ActivityTestRule<FragmentTestActivity> rule,
+            final String name, final int flags) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final boolean[] ret = new boolean[1];
+        instrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = rule.getActivity().getFragmentManager().popBackStackImmediate(name, flags);
+            }
+        });
+        return ret[0];
     }
 
     public static void setContentView(final ActivityTestRule<FragmentTestActivity> rule,
@@ -41,4 +101,63 @@
             }
         });
     }
+
+    public static void assertChildren(ViewGroup container, Fragment... fragments) {
+        final int numFragments = fragments == null ? 0 : fragments.length;
+        assertEquals("There aren't the correct number of fragment Views in its container",
+                numFragments, container.getChildCount());
+        for (int i = 0; i < numFragments; i++) {
+            assertEquals("Wrong Fragment View order for [" + i + "]", container.getChildAt(i),
+                    fragments[i].getView());
+        }
+    }
+
+    public static FragmentController createController(ActivityTestRule<FragmentTestActivity> rule) {
+        final FragmentController[] controller = new FragmentController[1];
+        final FragmentTestActivity activity = rule.getActivity();
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            HostCallbacks hostCallbacks = new HostCallbacks(activity, null, 0);
+            controller[0] = FragmentController.createController(hostCallbacks);
+        });
+        return controller[0];
+    }
+
+
+    public static void resume(ActivityTestRule<FragmentTestActivity> rule,
+            FragmentController fragmentController,
+            Pair<Parcelable, FragmentManagerNonConfig> savedState) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.runOnMainSync(() -> {
+            fragmentController.attachHost(null);
+            if (savedState != null) {
+                fragmentController.restoreAllState(savedState.first, savedState.second);
+            }
+            fragmentController.dispatchCreate();
+            fragmentController.dispatchActivityCreated();
+            fragmentController.noteStateNotSaved();
+            fragmentController.execPendingActions();
+            fragmentController.dispatchStart();
+            fragmentController.reportLoaderStart();
+            fragmentController.dispatchResume();
+            fragmentController.execPendingActions();
+        });
+    }
+
+    public static Pair<Parcelable, FragmentManagerNonConfig> destroy(
+            ActivityTestRule<FragmentTestActivity> rule, FragmentController fragmentController) {
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        final Pair<Parcelable, FragmentManagerNonConfig>[] result = new Pair[1];
+        instrumentation.runOnMainSync(() -> {
+            fragmentController.dispatchPause();
+            final Parcelable savedState = fragmentController.saveAllState();
+            final FragmentManagerNonConfig nonConfig = fragmentController.retainNestedNonConfig();
+            fragmentController.dispatchStop();
+            fragmentController.doLoaderStop(false);
+            fragmentController.dispatchDestroy();
+            fragmentController.doLoaderDestroy();
+            result[0] = Pair.create(savedState, nonConfig);
+        });
+        return result[0];
+    }
 }
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
new file mode 100644
index 0000000..aec626f
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import static junit.framework.Assert.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.Instrumentation;
+import android.app.SharedElementCallback;
+import android.cts.util.transition.TargetTracking;
+import android.cts.util.transition.TrackingTransition;
+import android.graphics.Rect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.transition.TransitionSet;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.ArgumentCaptor;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@MediumTest
+@RunWith(Parameterized.class)
+public class FragmentTransitionTest {
+    private final boolean mOptimize;
+
+    @Parameterized.Parameters
+    public static Object[] data() {
+        return new Boolean[] {
+                false, true
+        };
+    }
+
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+    private FragmentManager mFragmentManager;
+
+    public FragmentTransitionTest(final boolean optimize) {
+        mOptimize = optimize;
+    }
+
+    @Before
+    public void setup() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mFragmentManager = mActivityRule.getActivity().getFragmentManager();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+    }
+
+    // Test that normal view transitions (enter, exit, reenter, return) run with
+    // a single fragment.
+    @Test
+    public void enterExitTransitions() throws Throwable {
+        // enter transition
+        TransitionFragment fragment = setupInitialFragment();
+        final View blue = findBlue();
+        final View green = findBlue();
+
+        // exit transition
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .remove(fragment)
+                .addToBackStack(null)
+                .commit();
+
+        fragment.waitForTransition();
+        verifyAndClearTransition(fragment.exitTransition, null, green, blue);
+        verifyNoOtherTransitions(fragment);
+
+        // reenter transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForTransition();
+        final View green2 = findGreen();
+        final View blue2 = findBlue();
+        verifyAndClearTransition(fragment.reenterTransition, null, green2, blue2);
+        verifyNoOtherTransitions(fragment);
+
+        // return transition
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+        fragment.waitForTransition();
+        verifyAndClearTransition(fragment.returnTransition, null, green2, blue2);
+        verifyNoOtherTransitions(fragment);
+    }
+
+    // Test that shared elements transition from one fragment to the next
+    // and back during pop.
+    @Test
+    public void sharedElement() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+
+        // Now pop the back stack
+        verifyPopTransition(1, fragment2, fragment1);
+    }
+
+    // Test that shared element transitions through multiple fragments work together
+    @Test
+    public void intermediateFragment() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        final TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene3);
+
+        verifyTransition(fragment1, fragment2, "shared");
+
+        final TransitionFragment fragment3 = new TransitionFragment();
+        fragment3.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment2, fragment3, "blueSquare");
+
+        // Should transfer backwards when popping multiple:
+        verifyPopTransition(2, fragment3, fragment1, fragment2);
+    }
+
+    // Adding/removing the same fragment multiple times shouldn't mess anything up
+    @Test
+    public void removeAdded() throws Throwable {
+        final TransitionFragment fragment1 = setupInitialFragment();
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        final TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mFragmentManager.beginTransaction()
+                        .setAllowOptimization(mOptimize)
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .replace(R.id.fragmentContainer, fragment1)
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // should be a normal transition from fragment1 to fragment2
+        fragment2.waitForTransition();
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+        verifyAndClearTransition(fragment1.exitTransition, null, startBlue, startGreen);
+        verifyAndClearTransition(fragment2.enterTransition, null, endBlue, endGreen);
+        verifyNoOtherTransitions(fragment1);
+        verifyNoOtherTransitions(fragment2);
+
+        // Pop should also do the same thing
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        final View popBlue = findBlue();
+        final View popGreen = findGreen();
+        verifyAndClearTransition(fragment1.reenterTransition, null, popBlue, popGreen);
+        verifyAndClearTransition(fragment2.returnTransition, null, endBlue, endGreen);
+        verifyNoOtherTransitions(fragment1);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Make sure that shared elements on two different fragment containers don't interact
+    @Test
+    public void crossContainer() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+        TransitionFragment fragment1 = new TransitionFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        final View greenSquare1 = findViewById(fragment1, R.id.greenSquare);
+        final View blueSquare1 = findViewById(fragment1, R.id.blueSquare);
+        verifyAndClearTransition(fragment1.enterTransition, null, greenSquare1, blueSquare1);
+        verifyNoOtherTransitions(fragment1);
+        fragment2.waitForTransition();
+        final View greenSquare2 = findViewById(fragment2, R.id.greenSquare);
+        final View blueSquare2 = findViewById(fragment2, R.id.blueSquare);
+        verifyAndClearTransition(fragment2.enterTransition, null, greenSquare2, blueSquare2);
+        verifyNoOtherTransitions(fragment2);
+
+        // Make sure the correct transitions are run when the target names
+        // are different in both shared elements. We may fool the system.
+        verifyCrossTransition(false, fragment1, fragment2);
+
+        // Make sure the correct transitions are run when the source names
+        // are different in both shared elements. We may fool the system.
+        verifyCrossTransition(true, fragment1, fragment2);
+    }
+
+    // Make sure that onSharedElementStart and onSharedElementEnd are called
+    @Test
+    public void callStartEndWithSharedElements() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        SharedElementCallback enterCallback = mock(SharedElementCallback.class);
+        fragment2.setEnterSharedElementCallback(enterCallback);
+
+        final View startBlue = findBlue();
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+
+        ArgumentCaptor<List> names = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List> views = ArgumentCaptor.forClass(List.class);
+        ArgumentCaptor<List> snapshots = ArgumentCaptor.forClass(List.class);
+        verify(enterCallback).onSharedElementStart(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(startBlue, views.getValue().get(0));
+
+        final View endBlue = findBlue();
+
+        verify(enterCallback).onSharedElementEnd(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(endBlue, views.getValue().get(0));
+
+        // Now pop the back stack
+        reset(enterCallback);
+        verifyPopTransition(1, fragment2, fragment1);
+
+        verify(enterCallback).onSharedElementStart(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(endBlue, views.getValue().get(0));
+
+        final View reenterBlue = findBlue();
+
+        verify(enterCallback).onSharedElementEnd(names.capture(), views.capture(),
+                snapshots.capture());
+        assertEquals(1, names.getValue().size());
+        assertEquals(1, views.getValue().size());
+        assertNull(snapshots.getValue());
+        assertEquals("blueSquare", names.getValue().get(0));
+        assertEquals(reenterBlue, views.getValue().get(0));
+    }
+
+    // Make sure that onMapSharedElement works to change the shared element going out
+    @Test
+    public void onMapSharedElementOut() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        final Rect startGreenBounds = getBoundsOnScreen(startGreen);
+
+        SharedElementCallback mapOut = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                assertEquals(startBlue, sharedElements.get("blueSquare"));
+                sharedElements.put("blueSquare", startGreen);
+            }
+        };
+        fragment1.setExitSharedElementCallback(mapOut);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final Rect endBlueBounds = getBoundsOnScreen(endBlue);
+
+        verifyAndClearTransition(fragment2.sharedElementEnter, startGreenBounds, startGreen,
+                endBlue);
+
+        SharedElementCallback mapBack = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                final View expectedBlue = findViewById(fragment1, R.id.blueSquare);
+                assertEquals(expectedBlue, sharedElements.get("blueSquare"));
+                final View greenSquare = findViewById(fragment1, R.id.greenSquare);
+                sharedElements.put("blueSquare", greenSquare);
+            }
+        };
+        fragment1.setExitSharedElementCallback(mapBack);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterGreen = findGreen();
+        verifyAndClearTransition(fragment2.sharedElementReturn, endBlueBounds, endBlue,
+                reenterGreen);
+    }
+
+    // Make sure that onMapSharedElement works to change the shared element target
+    @Test
+    public void onMapSharedElementIn() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        SharedElementCallback mapIn = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                final View blueSquare = findViewById(fragment2, R.id.blueSquare);
+                assertEquals(blueSquare, sharedElements.get("blueSquare"));
+                final View greenSquare = findViewById(fragment2, R.id.greenSquare);
+                sharedElements.put("blueSquare", greenSquare);
+            }
+        };
+        fragment2.setEnterSharedElementCallback(mapIn);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .setAllowOptimization(mOptimize)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final Rect endGreenBounds = getBoundsOnScreen(endGreen);
+
+        verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue,
+                endGreen);
+
+        SharedElementCallback mapBack = new SharedElementCallback() {
+            @Override
+            public void onMapSharedElements(List<String> names, Map<String, View> sharedElements) {
+                assertEquals(1, names.size());
+                assertEquals("blueSquare", names.get(0));
+                assertEquals(1, sharedElements.size());
+                assertEquals(endBlue, sharedElements.get("blueSquare"));
+                sharedElements.put("blueSquare", endGreen);
+            }
+        };
+        fragment2.setEnterSharedElementCallback(mapBack);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterBlue = findBlue();
+        verifyAndClearTransition(fragment2.sharedElementReturn, endGreenBounds, endGreen,
+                reenterBlue);
+    }
+
+    // Ensure that shared element transitions that have targets properly target the views
+    @Test
+    public void complexSharedElementTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        ComplexTransitionFragment fragment2 = new ComplexTransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .addSharedElement(startGreen, "greenSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endBlue = findBlue();
+        final View endGreen = findGreen();
+        final Rect endBlueBounds = getBoundsOnScreen(endBlue);
+
+        verifyAndClearTransition(fragment2.sharedElementEnterTransition1, startBlueBounds,
+                startBlue, endBlue);
+        verifyAndClearTransition(fragment2.sharedElementEnterTransition2, startBlueBounds,
+                startGreen, endGreen);
+
+        // Now see if it works when popped
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View reenterBlue = findBlue();
+        final View reenterGreen = findGreen();
+
+        verifyAndClearTransition(fragment2.sharedElementReturnTransition1, endBlueBounds,
+                endBlue, reenterBlue);
+        verifyAndClearTransition(fragment2.sharedElementReturnTransition2, endBlueBounds,
+                endGreen, reenterGreen);
+    }
+
+    // Ensure that after transitions have executed that they don't have any targets or other
+    // unfortunate modifications.
+    @Test
+    public void transitionsEndUnchanged() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+
+        // Now do a transition to scene2
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        verifyTransition(fragment1, fragment2, "blueSquare");
+        assertEquals(0, fragment1.exitTransition.getTargets().size());
+        assertEquals(0, fragment2.sharedElementEnter.getTargets().size());
+        assertEquals(0, fragment2.enterTransition.getTargets().size());
+        assertNull(fragment1.exitTransition.getEpicenterCallback());
+        assertNull(fragment2.enterTransition.getEpicenterCallback());
+        assertNull(fragment2.sharedElementEnter.getEpicenterCallback());
+
+        // Now pop the back stack
+        verifyPopTransition(1, fragment2, fragment1);
+
+        assertEquals(0, fragment2.returnTransition.getTargets().size());
+        assertEquals(0, fragment2.sharedElementReturn.getTargets().size());
+        assertEquals(0, fragment1.reenterTransition.getTargets().size());
+        assertNull(fragment2.returnTransition.getEpicenterCallback());
+        assertNull(fragment2.sharedElementReturn.getEpicenterCallback());
+        assertNull(fragment2.reenterTransition.getEpicenterCallback());
+    }
+
+    // Ensure that transitions are done when a fragment is shown and hidden
+    @Test
+    public void showHideTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment2)
+                .hide(fragment1)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        final View endGreen = findViewById(fragment2, R.id.greenSquare);
+        final View endBlue = findViewById(fragment2, R.id.blueSquare);
+
+        assertEquals(View.GONE, fragment1.getView().getVisibility());
+        assertEquals(View.VISIBLE, startGreen.getVisibility());
+        assertEquals(View.VISIBLE, startBlue.getVisibility());
+
+        verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+
+        verifyAndClearTransition(fragment1.reenterTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        assertEquals(View.VISIBLE, fragment1.getView().getVisibility());
+        assertEquals(View.VISIBLE, startGreen.getVisibility());
+        assertEquals(View.VISIBLE, startBlue.getVisibility());
+
+        verifyAndClearTransition(fragment2.returnTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    // Ensure that transitions are done when a fragment is attached and detached
+    @Test
+    public void attachDetachTransition() throws Throwable {
+        TransitionFragment fragment1 = setupInitialFragment();
+        TransitionFragment fragment2 = new TransitionFragment();
+        fragment2.setLayoutId(R.layout.scene2);
+
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment2)
+                .detach(fragment1)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View endGreen = findViewById(fragment2, R.id.greenSquare);
+        final View endBlue = findViewById(fragment2, R.id.blueSquare);
+
+        verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View reenterBlue = findBlue();
+        final View reenterGreen = findGreen();
+
+        verifyAndClearTransition(fragment1.reenterTransition, null, reenterGreen, reenterBlue);
+        verifyNoOtherTransitions(fragment1);
+
+        verifyAndClearTransition(fragment2.returnTransition, null, endGreen, endBlue);
+        verifyNoOtherTransitions(fragment2);
+    }
+
+    private TransitionFragment setupInitialFragment() throws Throwable {
+        TransitionFragment fragment1 = new TransitionFragment();
+        fragment1.setLayoutId(R.layout.scene1);
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .add(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.waitForTransition();
+        final View blueSquare1 = findBlue();
+        final View greenSquare1 = findGreen();
+        verifyAndClearTransition(fragment1.enterTransition, null, blueSquare1, greenSquare1);
+        verifyNoOtherTransitions(fragment1);
+        return fragment1;
+    }
+
+    private View findViewById(Fragment fragment, int id) {
+        return fragment.getView().findViewById(id);
+    }
+
+    private View findGreen() {
+        return mActivityRule.getActivity().findViewById(R.id.greenSquare);
+    }
+
+    private View findBlue() {
+        return mActivityRule.getActivity().findViewById(R.id.blueSquare);
+    }
+
+    private View findRed() {
+        return mActivityRule.getActivity().findViewById(R.id.redSquare);
+    }
+
+    private void verifyAndClearTransition(TargetTracking transition, Rect epicenter,
+            View... expected) {
+        if (epicenter == null) {
+            assertNull(transition.getCapturedEpicenter());
+        } else {
+            assertEquals(epicenter, transition.getCapturedEpicenter());
+        }
+        ArrayList<View> targets = transition.getTrackedTargets();
+        String errorMessage = "Expected: [" + expected.length + "] {" +
+                Arrays.stream(expected).map(v -> v.toString()).collect(Collectors.joining(", ")) +
+                "}, but got: [" + targets.size() + "] {" +
+                targets.stream().map(v -> v.toString()).collect(Collectors.joining(", ")) +
+                "}";
+        assertEquals(errorMessage, expected.length, targets.size());
+        for (View view : expected) {
+            assertTrue(errorMessage, targets.contains(view));
+        }
+        transition.clearTargets();
+    }
+
+    private void verifyNoOtherTransitions(TransitionFragment fragment) {
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.exitTransition.targets.size());
+        assertEquals(0, fragment.reenterTransition.targets.size());
+        assertEquals(0, fragment.returnTransition.targets.size());
+        assertEquals(0, fragment.sharedElementEnter.targets.size());
+        assertEquals(0, fragment.sharedElementReturn.targets.size());
+    }
+
+    private void verifyTransition(TransitionFragment from, TransitionFragment to,
+            String sharedElementName) throws Throwable {
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final View startRed = findRed();
+
+        final Rect startBlueRect = getBoundsOnScreen(startBlue);
+
+        mFragmentManager.beginTransaction()
+                .setAllowOptimization(mOptimize)
+                .addSharedElement(startBlue, sharedElementName)
+                .replace(R.id.fragmentContainer, to)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        to.waitForTransition();
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final View endRed = findRed();
+        final Rect endBlueRect = getBoundsOnScreen(endBlue);
+
+        if (startRed != null) {
+            verifyAndClearTransition(from.exitTransition, startBlueRect, startGreen, startRed);
+        } else {
+            verifyAndClearTransition(from.exitTransition, startBlueRect, startGreen);
+        }
+        verifyNoOtherTransitions(from);
+
+        if (endRed != null) {
+            verifyAndClearTransition(to.enterTransition, endBlueRect, endGreen, endRed);
+        } else {
+            verifyAndClearTransition(to.enterTransition, endBlueRect, endGreen);
+        }
+        verifyAndClearTransition(to.sharedElementEnter, startBlueRect, startBlue, endBlue);
+        verifyNoOtherTransitions(to);
+    }
+
+    private void verifyCrossTransition(boolean swapSource,
+            TransitionFragment from1, TransitionFragment from2) throws Throwable {
+
+        final TransitionFragment to1 = new TransitionFragment();
+        to1.setLayoutId(R.layout.scene2);
+        final TransitionFragment to2 = new TransitionFragment();
+        to2.setLayoutId(R.layout.scene2);
+
+        final View fromExit1 = findViewById(from1, R.id.greenSquare);
+        final View fromShared1 = findViewById(from1, R.id.blueSquare);
+        final Rect fromSharedRect1 = getBoundsOnScreen(fromShared1);
+
+        final int fromExitId2 = swapSource ? R.id.blueSquare : R.id.greenSquare;
+        final int fromSharedId2 = swapSource ? R.id.greenSquare : R.id.blueSquare;
+        final View fromExit2 = findViewById(from2, fromExitId2);
+        final View fromShared2 = findViewById(from2, fromSharedId2);
+        final Rect fromSharedRect2 = getBoundsOnScreen(fromShared2);
+
+        final String sharedElementName = swapSource ? "blueSquare" : "greenSquare";
+
+        mActivityRule.runOnUiThread(() -> {
+            mFragmentManager.beginTransaction()
+                    .setAllowOptimization(mOptimize)
+                    .addSharedElement(fromShared1, "blueSquare")
+                    .replace(R.id.fragmentContainer1, to1)
+                    .addToBackStack(null)
+                    .commit();
+            mFragmentManager.beginTransaction()
+                    .setAllowOptimization(mOptimize)
+                    .addSharedElement(fromShared2, sharedElementName)
+                    .replace(R.id.fragmentContainer2, to2)
+                    .addToBackStack(null)
+                    .commit();
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        from1.waitForTransition();
+        from2.waitForTransition();
+        to1.waitForTransition();
+        to2.waitForTransition();
+
+        final View toEnter1 = findViewById(to1, R.id.greenSquare);
+        final View toShared1 = findViewById(to1, R.id.blueSquare);
+        final Rect toSharedRect1 = getBoundsOnScreen(toShared1);
+
+        final View toEnter2 = findViewById(to2, fromSharedId2);
+        final View toShared2 = findViewById(to2, fromExitId2);
+        final Rect toSharedRect2 = getBoundsOnScreen(toShared2);
+
+        verifyAndClearTransition(from1.exitTransition, fromSharedRect1, fromExit1);
+        verifyAndClearTransition(from2.exitTransition, fromSharedRect2, fromExit2);
+        verifyNoOtherTransitions(from1);
+        verifyNoOtherTransitions(from2);
+
+        verifyAndClearTransition(to1.enterTransition, toSharedRect1, toEnter1);
+        verifyAndClearTransition(to2.enterTransition, toSharedRect2, toEnter2);
+        verifyAndClearTransition(to1.sharedElementEnter, fromSharedRect1, fromShared1, toShared1);
+        verifyAndClearTransition(to2.sharedElementEnter, fromSharedRect2, fromShared2, toShared2);
+        verifyNoOtherTransitions(to1);
+        verifyNoOtherTransitions(to2);
+
+        // Now pop it back
+        mActivityRule.runOnUiThread(() -> {
+            mFragmentManager.popBackStack();
+            mFragmentManager.popBackStack();
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        from1.waitForTransition();
+        from2.waitForTransition();
+        to1.waitForTransition();
+        to2.waitForTransition();
+
+        final View returnEnter1 = findViewById(from1, R.id.greenSquare);
+        final View returnShared1 = findViewById(from1, R.id.blueSquare);
+
+        final View returnEnter2 = findViewById(from2, fromExitId2);
+        final View returnShared2 = findViewById(from2, fromSharedId2);
+
+        verifyAndClearTransition(to1.returnTransition, toSharedRect1, toEnter1);
+        verifyAndClearTransition(to2.returnTransition, toSharedRect2, toEnter2);
+        verifyAndClearTransition(to1.sharedElementReturn, toSharedRect1, toShared1, returnShared1);
+        verifyAndClearTransition(to2.sharedElementReturn, toSharedRect2, toShared2, returnShared2);
+        verifyNoOtherTransitions(to1);
+        verifyNoOtherTransitions(to2);
+
+        verifyAndClearTransition(from1.reenterTransition, fromSharedRect1, returnEnter1);
+        verifyAndClearTransition(from2.reenterTransition, fromSharedRect2, returnEnter2);
+        verifyNoOtherTransitions(from1);
+        verifyNoOtherTransitions(from2);
+    }
+
+    private void verifyPopTransition(final int numPops, TransitionFragment from,
+            TransitionFragment to, TransitionFragment... others) throws Throwable {
+        final View startBlue = findBlue();
+        final View startGreen = findGreen();
+        final View startRed = findRed();
+        final Rect startSharedRect = getBoundsOnScreen(startBlue);
+
+        mInstrumentation.runOnMainSync(() -> {
+            for (int i = 0; i < numPops; i++) {
+                mFragmentManager.popBackStack();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        to.waitForTransition();
+        final View endGreen = findGreen();
+        final View endBlue = findBlue();
+        final View endRed = findRed();
+        final Rect endSharedRect = getBoundsOnScreen(endBlue);
+
+        if (startRed != null) {
+            verifyAndClearTransition(from.returnTransition, startSharedRect, startGreen, startRed);
+        } else {
+            verifyAndClearTransition(from.returnTransition, startSharedRect, startGreen);
+        }
+        verifyAndClearTransition(from.sharedElementReturn, startSharedRect, startBlue, endBlue);
+        verifyNoOtherTransitions(from);
+
+        if (endRed != null) {
+            verifyAndClearTransition(to.reenterTransition, endSharedRect, endGreen, endRed);
+        } else {
+            verifyAndClearTransition(to.reenterTransition, endSharedRect, endGreen);
+        }
+        verifyNoOtherTransitions(to);
+
+        if (others != null) {
+            for (TransitionFragment fragment : others) {
+                verifyNoOtherTransitions(fragment);
+            }
+        }
+    }
+
+    private static Rect getBoundsOnScreen(View view) {
+        final int[] loc = new int[2];
+        view.getLocationOnScreen(loc);
+        return new Rect(loc[0], loc[1], loc[0] + view.getWidth(), loc[1] + view.getHeight());
+    }
+
+    public static class ComplexTransitionFragment extends TransitionFragment {
+        public final TrackingTransition sharedElementEnterTransition1 = new TrackingTransition();
+        public final TrackingTransition sharedElementEnterTransition2 = new TrackingTransition();
+        public final TrackingTransition sharedElementReturnTransition1 = new TrackingTransition();
+        public final TrackingTransition sharedElementReturnTransition2 = new TrackingTransition();
+
+        public final TransitionSet sharedElementEnterTransition = new TransitionSet()
+                .addTransition(sharedElementEnterTransition1)
+                .addTransition(sharedElementEnterTransition2);
+        public final TransitionSet sharedElementReturnTransition = new TransitionSet()
+                .addTransition(sharedElementReturnTransition1)
+                .addTransition(sharedElementReturnTransition2);
+
+        public ComplexTransitionFragment() {
+            sharedElementEnterTransition1.addTarget(R.id.blueSquare);
+            sharedElementEnterTransition2.addTarget(R.id.greenSquare);
+            sharedElementReturnTransition1.addTarget(R.id.blueSquare);
+            sharedElementReturnTransition2.addTarget(R.id.greenSquare);
+            setSharedElementEnterTransition(sharedElementEnterTransition);
+            setSharedElementReturnTransition(sharedElementReturnTransition);
+        }
+
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
index ef28a1d..1599307 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -24,6 +24,7 @@
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.Instrumentation;
+import android.os.Debug;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
@@ -63,13 +64,13 @@
         final StrictViewFragment fragment1 = new StrictViewFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1);
+        FragmentTestUtil.assertChildren(container, fragment1);
 
         // Add another on top
         final StrictViewFragment fragment2 = new StrictViewFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment2).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1, fragment2);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
 
         // Now add two in one transaction:
         final StrictViewFragment fragment3 = new StrictViewFragment();
@@ -80,20 +81,20 @@
                 .addToBackStack(null)
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1, fragment2);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         assertEquals(1, container.getChildCount());
-        assertChildren(container, fragment1);
+        FragmentTestUtil.assertChildren(container, fragment1);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
     }
 
     // Add fragments to multiple containers in the same transaction. Make sure that
@@ -110,12 +111,12 @@
         final StrictViewFragment fragment1 = new StrictViewFragment();
         fm.beginTransaction().add(R.id.fragmentContainer1, fragment1).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container1, fragment1);
+        FragmentTestUtil.assertChildren(container1, fragment1);
 
         final StrictViewFragment fragment2 = new StrictViewFragment();
         fm.beginTransaction().add(R.id.fragmentContainer2, fragment2).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container2, fragment2);
+        FragmentTestUtil.assertChildren(container2, fragment2);
 
         final StrictViewFragment fragment3 = new StrictViewFragment();
         final StrictViewFragment fragment4 = new StrictViewFragment();
@@ -126,18 +127,18 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container1, fragment1, fragment3);
-        assertChildren(container2, fragment2, fragment4);
+        FragmentTestUtil.assertChildren(container1, fragment1, fragment3);
+        FragmentTestUtil.assertChildren(container2, fragment2, fragment4);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container1, fragment1);
-        assertChildren(container2, fragment2);
+        FragmentTestUtil.assertChildren(container1, fragment1);
+        FragmentTestUtil.assertChildren(container2, fragment2);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container1, fragment1);
-        assertChildren(container2);
+        FragmentTestUtil.assertChildren(container1, fragment1);
+        FragmentTestUtil.assertChildren(container2);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
@@ -189,19 +190,19 @@
                 .add(R.id.fragmentContainer, fragment4, "4")
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1, fragment2, fragment3, fragment4);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3, fragment4);
 
         // Remove a view
         fm.beginTransaction().remove(fragment4).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
         assertEquals(3, container.getChildCount());
-        assertChildren(container, fragment1, fragment2, fragment3);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2, fragment3);
 
         // remove another one
         fm.beginTransaction().remove(fragment2).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1, fragment3);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment3);
 
         // Now remove the remaining:
         fm.beginTransaction()
@@ -210,23 +211,23 @@
                 .addToBackStack(null)
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         final Fragment replacement1 = fm.findFragmentByTag("1");
         final Fragment replacement3 = fm.findFragmentByTag("3");
-        assertChildren(container, replacement1, replacement3);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement3);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         final Fragment replacement2 = fm.findFragmentByTag("2");
-        assertChildren(container, replacement1, replacement3, replacement2);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement3, replacement2);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         final Fragment replacement4 = fm.findFragmentByTag("4");
-        assertChildren(container, replacement1, replacement3, replacement2, replacement4);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement3, replacement2, replacement4);
     }
 
     // Removing a hidden fragment should remove the View and popping should bring it back hidden
@@ -239,20 +240,19 @@
         final StrictViewFragment fragment1 = new StrictViewFragment();
         fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").hide(fragment1).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment1);
+        FragmentTestUtil.assertChildren(container, fragment1);
         assertTrue(fragment1.isHidden());
 
         fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         final Fragment replacement1 = fm.findFragmentByTag("1");
-        assertChildren(container, replacement1);
+        FragmentTestUtil.assertChildren(container, replacement1);
         assertTrue(replacement1.isHidden());
         assertEquals(View.GONE, replacement1.getView().getVisibility());
-        mInstrumentation.waitForIdleSync();
     }
 
     // Removing a detached fragment should do nothing to the View and popping should bring
@@ -269,17 +269,17 @@
                 .detach(fragment1)
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment1.isDetached());
 
         fm.beginTransaction().remove(fragment1).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
         final Fragment replacement1 = fm.findFragmentByTag("1");
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(replacement1.isDetached());
     }
 
@@ -299,11 +299,11 @@
                 .addToBackStack(null)
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
     }
 
     // Removing a fragment that isn't in should throw
@@ -332,20 +332,20 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
 
         fm.beginTransaction().hide(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertTrue(fragment.isHidden());
         assertEquals(View.GONE, fragment.getView().getVisibility());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isHidden());
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
     }
@@ -387,7 +387,7 @@
     }
 
     // Show a hidden fragment and its View should be VISIBLE. Then pop it and the View should be
-    // BONE.
+    // GONE.
     @Test
     public void showFragment() throws Throwable {
         FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
@@ -398,21 +398,21 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertTrue(fragment.isHidden());
         assertEquals(View.GONE, fragment.getView().getVisibility());
 
         fm.beginTransaction().show(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isHidden());
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertTrue(fragment.isHidden());
         assertEquals(View.GONE, fragment.getView().getVisibility());
     }
@@ -464,20 +464,20 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isDetached());
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
 
         fm.beginTransaction().detach(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isDetached());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isDetached());
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
     }
@@ -494,7 +494,7 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).hide(fragment).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isDetached());
         assertTrue(fragment.isHidden());
         assertEquals(View.GONE, fragment.getView().getVisibility());
@@ -502,14 +502,14 @@
         fm.beginTransaction().detach(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isHidden());
         assertTrue(fragment.isDetached());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertTrue(fragment.isHidden());
         assertFalse(fragment.isDetached());
         assertEquals(View.GONE, fragment.getView().getVisibility());
@@ -563,20 +563,20 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment).detach(fragment).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isDetached());
 
         fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertFalse(fragment.isDetached());
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isDetached());
     }
 
@@ -596,14 +596,14 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isDetached());
         assertTrue(fragment.isHidden());
 
         fm.beginTransaction().attach(fragment).addToBackStack(null).commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertTrue(fragment.isHidden());
         assertFalse(fragment.isDetached());
         assertEquals(View.GONE, fragment.getView().getVisibility());
@@ -611,7 +611,7 @@
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
         assertTrue(fragment.isDetached());
         assertTrue(fragment.isHidden());
     }
@@ -662,7 +662,7 @@
         fm.beginTransaction().add(R.id.fragmentContainer, fragment1, "1").commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment1);
+        FragmentTestUtil.assertChildren(container, fragment1);
 
         final StrictViewFragment fragment2 = new StrictViewFragment();
         fm.beginTransaction()
@@ -671,7 +671,7 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment2);
+        FragmentTestUtil.assertChildren(container, fragment2);
         assertEquals(View.VISIBLE, fragment2.getView().getVisibility());
 
         fm.popBackStack();
@@ -679,7 +679,7 @@
 
         Fragment replacement1 = fm.findFragmentByTag("1");
         assertNotNull(replacement1);
-        assertChildren(container, replacement1);
+        FragmentTestUtil.assertChildren(container, replacement1);
         assertFalse(replacement1.isHidden());
         assertTrue(replacement1.isAdded());
         assertFalse(replacement1.isDetached());
@@ -702,7 +702,7 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment1, fragment2);
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
 
         final StrictViewFragment fragment3 = new StrictViewFragment();
         fm.beginTransaction()
@@ -711,7 +711,7 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment3);
+        FragmentTestUtil.assertChildren(container, fragment3);
         assertEquals(View.VISIBLE, fragment3.getView().getVisibility());
 
         fm.popBackStack();
@@ -721,7 +721,7 @@
         Fragment replacement2 = fm.findFragmentByTag("2");
         assertNotNull(replacement1);
         assertNotNull(replacement2);
-        assertChildren(container, replacement1, replacement2);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement2);
         assertFalse(replacement1.isHidden());
         assertTrue(replacement1.isAdded());
         assertFalse(replacement1.isDetached());
@@ -749,13 +749,129 @@
                 .commit();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container, fragment);
+        FragmentTestUtil.assertChildren(container, fragment);
         assertEquals(View.VISIBLE, fragment.getView().getVisibility());
 
         fm.popBackStack();
         FragmentTestUtil.executePendingTransactions(mActivityRule);
 
-        assertChildren(container);
+        FragmentTestUtil.assertChildren(container);
+    }
+
+    // Replace a fragment that exists with itself
+    @Test
+    public void replaceExisting() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        ViewGroup container = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .add(R.id.fragmentContainer, fragment2, "2")
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment1, fragment2);
+
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragment1)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        FragmentTestUtil.assertChildren(container, fragment1);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        final Fragment replacement1 = fm.findFragmentByTag("1");
+        final Fragment replacement2 = fm.findFragmentByTag("2");
+
+        assertSame(fragment1, replacement1);
+        FragmentTestUtil.assertChildren(container, replacement1, replacement2);
+    }
+
+    // Have two replace operations in the same transaction to ensure that they
+    // don't interfere with each other
+    @Test
+    public void replaceReplace() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+        ViewGroup container1 = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer1);
+        ViewGroup container2 = (ViewGroup)
+                mActivityRule.getActivity().findViewById(R.id.fragmentContainer2);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+        final StrictViewFragment fragment1 = new StrictViewFragment();
+        final StrictViewFragment fragment2 = new StrictViewFragment();
+        final StrictViewFragment fragment3 = new StrictViewFragment();
+        final StrictViewFragment fragment4 = new StrictViewFragment();
+        final StrictViewFragment fragment5 = new StrictViewFragment();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .replace(R.id.fragmentContainer1, fragment3)
+                .replace(R.id.fragmentContainer2, fragment4)
+                .replace(R.id.fragmentContainer1, fragment5)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container1, fragment5);
+        assertChildren(container2, fragment4);
+
+        fm.popBackStack();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertChildren(container1);
+        assertChildren(container2);
+    }
+
+    // Test to prevent regressions in FragmentManager fragment replace method. See b/24693644
+    @Test
+    public void testReplaceFragment() throws Throwable {
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        StrictViewFragment fragmentA = new StrictViewFragment();
+        fragmentA.setLayoutId(R.layout.text_a);
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragmentA)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+
+        assertNotNull(findViewById(R.id.textA));
+        assertNull(findViewById(R.id.textB));
+        assertNull(findViewById(R.id.textC));
+
+        StrictViewFragment fragmentB = new StrictViewFragment();
+        fragmentB.setLayoutId(R.layout.text_b);
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, fragmentB)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertNotNull(findViewById(R.id.textA));
+        assertNotNull(findViewById(R.id.textB));
+        assertNull(findViewById(R.id.textC));
+
+        StrictViewFragment fragmentC = new StrictViewFragment();
+        fragmentC.setLayoutId(R.layout.text_c);
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer, fragmentC)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.executePendingTransactions(mActivityRule);
+        assertNull(findViewById(R.id.textA));
+        assertNull(findViewById(R.id.textB));
+        assertNotNull(findViewById(R.id.textC));
+    }
+
+    private View findViewById(int viewId) {
+        return mActivityRule.getActivity().findViewById(viewId);
     }
 
     private void assertChildren(ViewGroup container, Fragment... fragments) {
diff --git a/tests/fragment/src/android/fragment/cts/HostCallbacks.java b/tests/fragment/src/android/fragment/cts/HostCallbacks.java
new file mode 100644
index 0000000..fd45aa1
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/HostCallbacks.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import android.app.FragmentHostCallback;
+import android.os.Handler;
+import android.view.View;
+
+class HostCallbacks extends FragmentHostCallback<FragmentTestActivity> {
+    private final FragmentTestActivity mActivity;
+
+    public HostCallbacks(FragmentTestActivity activity, Handler handler, int windowAnimations) {
+        super(activity, handler, windowAnimations);
+        mActivity = activity;
+    }
+
+    @Override
+    public FragmentTestActivity onGetHost() {
+        return mActivity;
+    }
+
+    @Override
+    public View onFindViewById(int id) {
+        return mActivity.findViewById(id);
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
new file mode 100644
index 0000000..29a723b
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/PostponedTransitionTest.java
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Fragment;
+import android.app.FragmentController;
+import android.app.FragmentManager;
+import android.app.FragmentManagerNonConfig;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class PostponedTransitionTest {
+    @Rule
+    public ActivityTestRule<FragmentTestActivity> mActivityRule =
+            new ActivityTestRule<FragmentTestActivity>(FragmentTestActivity.class);
+
+    private Instrumentation mInstrumentation;
+    private PostponedFragment1 mBeginningFragment;
+
+    @Before
+    public void setupContainer() throws Throwable {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        mBeginningFragment = new PostponedFragment1();
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer, mBeginningFragment)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        mBeginningFragment.startPostponedEnterTransition();
+        mBeginningFragment.waitForTransition();
+        clearTargets(mBeginningFragment);
+    }
+
+    // Ensure that replacing with a fragment that has a postponed transition
+    // will properly postpone it, both adding and popping.
+    @Test
+    public void replaceTransition() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment = new PostponedFragment2();
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // should be postponed now
+        assertPostponedTransition(mBeginningFragment, fragment, null);
+
+        // start the postponed transition
+        fragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(mBeginningFragment, fragment);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        // should be postponed going back, too
+        assertPostponedTransition(fragment, mBeginningFragment, null);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment, mBeginningFragment);
+    }
+
+    // Ensure that postponed transition is forced after another has been committed.
+    // This tests when the transactions are executed together
+    @Test
+    public void forcedTransition1() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+        final PostponedFragment1 fragment3 = new PostponedFragment1();
+
+        final int commit[] = new int[1];
+        // Need to run this on the UI thread so that the transaction doesn't start
+        // between the two
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                commit[0] = fm.beginTransaction()
+                        .addSharedElement(startBlue, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment2)
+                        .addToBackStack(null)
+                        .commit();
+
+                fm.beginTransaction()
+                        .addSharedElement(startBlue, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment3)
+                        .addToBackStack(null)
+                        .commit();
+            }
+        });
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // transition to fragment2 should be started
+        assertForwardTransition(mBeginningFragment, fragment2);
+
+        // fragment3 should be postponed, but fragment2 should be executed with no transition.
+        assertPostponedTransition(fragment2, fragment3, mBeginningFragment);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment3);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule, commit[0],
+                FragmentManager.POP_BACK_STACK_INCLUSIVE);
+
+        assertBackTransition(fragment3, fragment2);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, fragment3);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Ensure that postponed transition is forced after another has been committed.
+    // This tests when the transactions are processed separately.
+    @Test
+    public void forcedTransition2() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment2, null);
+
+        final PostponedFragment1 fragment3 = new PostponedFragment1();
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        // This should cancel the mBeginningFragment -> fragment2 transition
+        // and start fragment2 -> fragment3 transition postponed
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        // fragment3 should be postponed, but fragment2 should be executed with no transition.
+        assertPostponedTransition(fragment2, fragment3, mBeginningFragment);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment3);
+
+        // Pop back to fragment2, but it should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment3, fragment2, null);
+
+        // Pop to mBeginningFragment -- should cancel the fragment2 transition and
+        // start the mBeginningFragment transaction postponed
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, fragment3);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Do a bunch of things to one fragment in a transaction and see if it can screw things up.
+    @Test
+    public void crazyTransition() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mActivityRule.getActivity().findViewById(R.id.blueSquare);
+
+        final PostponedFragment2 fragment2 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .hide(mBeginningFragment)
+                .replace(R.id.fragmentContainer, fragment2)
+                .hide(fragment2)
+                .detach(fragment2)
+                .attach(fragment2)
+                .show(fragment2)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment2, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(mBeginningFragment, fragment2);
+
+        // Pop back to fragment2, but it should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment2, mBeginningFragment, null);
+
+        // start the postponed transition
+        mBeginningFragment.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment2, mBeginningFragment);
+    }
+
+    // Execute transactions on different containers and ensure that they don't conflict
+    @Test
+    public void differentContainers() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+        TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue2, "blueSquare")
+                .replace(R.id.fragmentContainer2, fragment4)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment1, fragment3);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment2, fragment4);
+
+        // Pop back to fragment2 -- should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // Pop back to fragment1 -- also should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment4, fragment2);
+
+        // but not the postponed one
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment3, fragment1);
+    }
+
+    // Execute transactions on different containers and ensure that they don't conflict.
+    // The postponement can be started out-of-order
+    @Test
+    public void outOfOrderContainers() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+        TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue2, "blueSquare")
+                .replace(R.id.fragmentContainer2, fragment4)
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment2, fragment4);
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment1, fragment3);
+
+        // Pop back to fragment2 -- should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // Pop back to fragment1 -- also should be postponed
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        assertPostponedTransition(fragment4, fragment2, null);
+        assertPostponedTransition(fragment3, fragment1, null);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment3, fragment1);
+
+        // but not the postponed one
+        assertPostponedTransition(fragment4, fragment2, null);
+
+        // start the postponed transition
+        fragment2.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertBackTransition(fragment4, fragment2);
+    }
+
+    // Make sure that commitNow for a transaction on a different fragment container doesn't
+    // affect the postponed transaction
+    @Test
+    public void commitNowNoEffect() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        final TransitionFragment fragment1 = new PostponedFragment1();
+        final TransitionFragment fragment2 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .add(R.id.fragmentContainer2, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment2.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        fragment2.waitForTransition();
+        clearTargets(fragment1);
+        clearTargets(fragment2);
+
+        final View startBlue1 = fragment1.getView().findViewById(R.id.blueSquare);
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment3 = new PostponedFragment2();
+        final StrictFragment strictFragment1 = new StrictFragment();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer1, fragment3)
+                .add(strictFragment1, "1")
+                .addToBackStack(null)
+                .commit();
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        final TransitionFragment fragment4 = new PostponedFragment2();
+        final StrictFragment strictFragment2 = new StrictFragment();
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .addSharedElement(startBlue2, "blueSquare")
+                        .replace(R.id.fragmentContainer2, fragment4)
+                        .remove(strictFragment1)
+                        .add(strictFragment2, "2")
+                        .commitNow();
+            }
+        });
+
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment3, null);
+        assertPostponedTransition(fragment2, fragment4, null);
+
+        // start the postponed transition
+        fragment4.startPostponedEnterTransition();
+
+        // make sure only one ran
+        assertForwardTransition(fragment2, fragment4);
+        assertPostponedTransition(fragment1, fragment3, null);
+
+        // start the postponed transition
+        fragment3.startPostponedEnterTransition();
+
+        // make sure it ran
+        assertForwardTransition(fragment1, fragment3);
+    }
+
+    // Make sure that commitNow for a transaction affecting a postponed fragment in the same
+    // container forces the postponed transition to start.
+    @Test
+    public void commitNowStartsPostponed() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue1 = mBeginningFragment.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment2 = new PostponedFragment2();
+        final TransitionFragment fragment1 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue1, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment2)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        final View startBlue2 = fragment2.getView().findViewById(R.id.blueSquare);
+
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                fm.beginTransaction()
+                        .addSharedElement(startBlue2, "blueSquare")
+                        .replace(R.id.fragmentContainer, fragment1)
+                        .commitNow();
+            }
+        });
+
+        assertPostponedTransition(fragment2, fragment1, mBeginningFragment);
+
+        // start the postponed transition
+        fragment1.startPostponedEnterTransition();
+
+        assertForwardTransition(fragment2, fragment1);
+    }
+
+    // Make sure that when a transaction that removes a view is postponed that
+    // another transaction doesn't accidentally remove the view early.
+    @Test
+    public void noAccidentalRemoval() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        fm.beginTransaction().remove(mBeginningFragment).commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        FragmentTestUtil.setContentView(mActivityRule, R.layout.double_container);
+
+        TransitionFragment fragment1 = new PostponedFragment1();
+
+        fm.beginTransaction()
+                .add(R.id.fragmentContainer1, fragment1)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        fragment1.startPostponedEnterTransition();
+        fragment1.waitForTransition();
+        clearTargets(fragment1);
+
+        TransitionFragment fragment2 = new PostponedFragment2();
+        // Create a postponed transaction that removes a view
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer1, fragment2)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+        assertPostponedTransition(fragment1, fragment2, null);
+
+        TransitionFragment fragment3 = new PostponedFragment1();
+        // Create a transaction that doesn't interfere with the previously postponed one
+        fm.beginTransaction()
+                .replace(R.id.fragmentContainer2, fragment3)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(fragment1, fragment2, null);
+
+        fragment3.startPostponedEnterTransition();
+        fragment3.waitForTransition();
+        clearTargets(fragment3);
+
+        assertPostponedTransition(fragment1, fragment2, null);
+    }
+
+    // Ensure that a postponed transaction that is popped runs immediately and that
+    // the transaction results in the original state with no transition.
+    @Test
+    public void popPostponedTransaction() throws Throwable {
+        final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+        final View startBlue = mBeginningFragment.getView().findViewById(R.id.blueSquare);
+
+        final TransitionFragment fragment = new PostponedFragment2();
+
+        fm.beginTransaction()
+                .addSharedElement(startBlue, "blueSquare")
+                .replace(R.id.fragmentContainer, fragment)
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        assertPostponedTransition(mBeginningFragment, fragment, null);
+
+        FragmentTestUtil.popBackStackImmediate(mActivityRule);
+
+        fragment.waitForNoTransition();
+        mBeginningFragment.waitForNoTransition();
+
+        assureNoTransition(fragment);
+        assureNoTransition(mBeginningFragment);
+
+        assertFalse(fragment.isAdded());
+        assertNull(fragment.getView());
+        assertNotNull(mBeginningFragment.getView());
+        assertEquals(View.VISIBLE, mBeginningFragment.getView().getVisibility());
+        assertTrue(mBeginningFragment.getView().isAttachedToWindow());
+    }
+
+    // Make sure that when saving the state during a postponed transaction that it saves
+    // the state as if it wasn't postponed.
+    @Test
+    public void saveWhilePostponed() throws Throwable {
+        final FragmentController fc1 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc1, null);
+
+        final FragmentManager fm1 = fc1.getFragmentManager();
+
+        PostponedFragment1 fragment1 = new PostponedFragment1();
+        fm1.beginTransaction()
+                .add(R.id.fragmentContainer, fragment1, "1")
+                .addToBackStack(null)
+                .commit();
+        FragmentTestUtil.waitForExecution(mActivityRule);
+
+        Pair<Parcelable, FragmentManagerNonConfig> state =
+                FragmentTestUtil.destroy(mActivityRule, fc1);
+
+        final FragmentController fc2 = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc2, state);
+
+        final FragmentManager fm2 = fc2.getFragmentManager();
+        Fragment fragment2 = fm2.findFragmentByTag("1");
+        assertNotNull(fragment2);
+        assertNotNull(fragment2.getView());
+        assertEquals(View.VISIBLE, fragment2.getView().getVisibility());
+        assertTrue(fragment2.isResumed());
+        assertTrue(fragment2.isAdded());
+        assertTrue(fragment2.getView().isAttachedToWindow());
+
+        mInstrumentation.runOnMainSync(() -> {
+            assertTrue(fm2.popBackStackImmediate());
+        });
+
+        assertFalse(fragment2.isResumed());
+        assertFalse(fragment2.isAdded());
+        assertNull(fragment2.getView());
+    }
+
+    private void assertPostponedTransition(TransitionFragment fromFragment,
+            TransitionFragment toFragment, TransitionFragment removedFragment)
+            throws InterruptedException {
+        if (removedFragment != null) {
+            assertNull(removedFragment.getView());
+            assureNoTransition(removedFragment);
+        }
+
+        toFragment.waitForNoTransition();
+        assertNotNull(fromFragment.getView());
+        assertNotNull(toFragment.getView());
+        assertTrue(fromFragment.getView().isAttachedToWindow());
+        assertTrue(toFragment.getView().isAttachedToWindow());
+        assertEquals(View.VISIBLE, fromFragment.getView().getVisibility());
+        assertEquals(View.INVISIBLE, toFragment.getView().getVisibility());
+        assureNoTransition(fromFragment);
+        assureNoTransition(toFragment);
+        assertTrue(fromFragment.isResumed());
+        assertFalse(toFragment.isResumed());
+    }
+
+    private void clearTargets(TransitionFragment fragment) {
+        fragment.enterTransition.targets.clear();
+        fragment.reenterTransition.targets.clear();
+        fragment.exitTransition.targets.clear();
+        fragment.returnTransition.targets.clear();
+        fragment.sharedElementEnter.targets.clear();
+        fragment.sharedElementReturn.targets.clear();
+    }
+
+    private void assureNoTransition(TransitionFragment fragment) {
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.reenterTransition.targets.size());
+        assertEquals(0, fragment.enterTransition.targets.size());
+        assertEquals(0, fragment.returnTransition.targets.size());
+        assertEquals(0, fragment.sharedElementEnter.targets.size());
+        assertEquals(0, fragment.sharedElementReturn.targets.size());
+    }
+
+    private void assertForwardTransition(TransitionFragment start, TransitionFragment end)
+            throws InterruptedException {
+        start.waitForTransition();
+        end.waitForTransition();
+        assertEquals(0, start.enterTransition.targets.size());
+        assertEquals(1, end.enterTransition.targets.size());
+
+        assertEquals(0, start.reenterTransition.targets.size());
+        assertEquals(0, end.reenterTransition.targets.size());
+
+        assertEquals(0, start.returnTransition.targets.size());
+        assertEquals(0, end.returnTransition.targets.size());
+
+        assertEquals(1, start.exitTransition.targets.size());
+        assertEquals(0, end.exitTransition.targets.size());
+
+        assertEquals(0, start.sharedElementEnter.targets.size());
+        assertEquals(2, end.sharedElementEnter.targets.size());
+
+        assertEquals(0, start.sharedElementReturn.targets.size());
+        assertEquals(0, end.sharedElementReturn.targets.size());
+
+        final View blue = end.getView().findViewById(R.id.blueSquare);
+        assertTrue(end.sharedElementEnter.targets.contains(blue));
+        assertEquals("blueSquare", end.sharedElementEnter.targets.get(0).getTransitionName());
+        assertEquals("blueSquare", end.sharedElementEnter.targets.get(1).getTransitionName());
+
+        assertNoTargets(start);
+        assertNoTargets(end);
+
+        clearTargets(start);
+        clearTargets(end);
+    }
+
+    private void assertBackTransition(TransitionFragment start, TransitionFragment end)
+            throws InterruptedException {
+        start.waitForTransition();
+        end.waitForTransition();
+        assertEquals(1, end.reenterTransition.targets.size());
+        assertEquals(0, start.reenterTransition.targets.size());
+
+        assertEquals(0, end.returnTransition.targets.size());
+        assertEquals(1, start.returnTransition.targets.size());
+
+        assertEquals(0, start.enterTransition.targets.size());
+        assertEquals(0, end.enterTransition.targets.size());
+
+        assertEquals(0, start.exitTransition.targets.size());
+        assertEquals(0, end.exitTransition.targets.size());
+
+        assertEquals(0, start.sharedElementEnter.targets.size());
+        assertEquals(0, end.sharedElementEnter.targets.size());
+
+        assertEquals(2, start.sharedElementReturn.targets.size());
+        assertEquals(0, end.sharedElementReturn.targets.size());
+
+        final View blue = end.getView().findViewById(R.id.blueSquare);
+        assertTrue(start.sharedElementReturn.targets.contains(blue));
+        assertEquals("blueSquare", start.sharedElementReturn.targets.get(0).getTransitionName());
+        assertEquals("blueSquare", start.sharedElementReturn.targets.get(1).getTransitionName());
+
+        assertNoTargets(end);
+        assertNoTargets(start);
+
+        clearTargets(start);
+        clearTargets(end);
+    }
+
+    private static void assertNoTargets(TransitionFragment fragment) {
+        assertTrue(fragment.enterTransition.getTargets().isEmpty());
+        assertTrue(fragment.reenterTransition.getTargets().isEmpty());
+        assertTrue(fragment.exitTransition.getTargets().isEmpty());
+        assertTrue(fragment.returnTransition.getTargets().isEmpty());
+        assertTrue(fragment.sharedElementEnter.getTargets().isEmpty());
+        assertTrue(fragment.sharedElementReturn.getTargets().isEmpty());
+    }
+
+    public static class PostponedFragment1 extends TransitionFragment {
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            postponeEnterTransition();
+            return inflater.inflate(R.layout.scene1, container, false);
+        }
+    }
+
+    public static class PostponedFragment2 extends TransitionFragment {
+        @Override
+        public View onCreateView(LayoutInflater inflater, ViewGroup container,
+                Bundle savedInstanceState) {
+            postponeEnterTransition();
+            return inflater.inflate(R.layout.scene2, container, false);
+        }
+    }
+}
diff --git a/tests/fragment/src/android/fragment/cts/StrictFragment.java b/tests/fragment/src/android/fragment/cts/StrictFragment.java
index f0c4a8a..f552eaa 100644
--- a/tests/fragment/src/android/fragment/cts/StrictFragment.java
+++ b/tests/fragment/src/android/fragment/cts/StrictFragment.java
@@ -37,7 +37,8 @@
 
     boolean mCalledOnAttach, mCalledOnCreate, mCalledOnActivityCreated,
             mCalledOnStart, mCalledOnResume, mCalledOnSaveInstanceState,
-            mCalledOnPause, mCalledOnStop, mCalledOnDestroy, mCalledOnDetach;
+            mCalledOnPause, mCalledOnStop, mCalledOnDestroy, mCalledOnDetach,
+            mCalledOnAttachFragment;
 
     static String stateToString(int state) {
         switch (state) {
@@ -82,6 +83,12 @@
     }
 
     @Override
+    public void onAttachFragment(Fragment childFragment) {
+        super.onAttachFragment(childFragment);
+        mCalledOnAttachFragment = true;
+    }
+
+    @Override
     public void onAttach(Context context) {
         super.onAttach(context);
         mCalledOnAttach = true;
@@ -134,7 +141,10 @@
         super.onSaveInstanceState(outState);
         mCalledOnSaveInstanceState = true;
         checkGetActivity();
-        checkStateAtLeast("onSaveInstanceState", STARTED);
+        // FIXME: We should not allow onSaveInstanceState except when STARTED or greater.
+        // But FragmentManager currently does it in saveAllState for fragments on the
+        // back stack, so fragments may be in the CREATED state.
+        checkStateAtLeast("onSaveInstanceState", CREATED);
     }
 
     @Override
diff --git a/tests/fragment/src/android/fragment/cts/StrictViewFragment.java b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
index 8c0ab51..d39cc125 100644
--- a/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
+++ b/tests/fragment/src/android/fragment/cts/StrictViewFragment.java
@@ -24,13 +24,24 @@
 
 public class StrictViewFragment extends StrictFragment {
     boolean mOnCreateViewCalled, mOnViewCreatedCalled, mOnDestroyViewCalled;
+    int mLayoutId = R.layout.strict_view_fragment;
+
+    public void setLayoutId(int layoutId) {
+        mLayoutId = layoutId;
+    }
+
+    public static StrictViewFragment create(int layoutId) {
+        StrictViewFragment fragment = new StrictViewFragment();
+        fragment.mLayoutId = layoutId;
+        return fragment;
+    }
 
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
         checkGetActivity();
         checkState("onCreateView", CREATED);
-        final View result = inflater.inflate(R.layout.strict_view_fragment, container, false);
+        final View result = inflater.inflate(mLayoutId, container, false);
         mOnCreateViewCalled = true;
         return result;
     }
diff --git a/tests/fragment/src/android/fragment/cts/TransitionFragment.java b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
new file mode 100644
index 0000000..3fede11
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.fragment.cts;
+
+import static android.cts.util.CtsMockitoUtils.within;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import android.cts.util.transition.TrackingTransition;
+import android.cts.util.transition.TrackingVisibility;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.transition.Transition;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A fragment that has transitions that can be tracked.
+ */
+public class TransitionFragment extends StrictViewFragment {
+    public final TrackingVisibility enterTransition = new TrackingVisibility();
+    public final TrackingVisibility reenterTransition = new TrackingVisibility();
+    public final TrackingVisibility exitTransition = new TrackingVisibility();
+    public final TrackingVisibility returnTransition = new TrackingVisibility();
+    public final TrackingTransition sharedElementEnter = new TrackingTransition();
+    public final TrackingTransition sharedElementReturn = new TrackingTransition();
+
+    private Transition.TransitionListener mListener = mock(Transition.TransitionListener.class);
+
+    public TransitionFragment() {
+        setEnterTransition(enterTransition);
+        setReenterTransition(reenterTransition);
+        setExitTransition(exitTransition);
+        setReturnTransition(returnTransition);
+        setSharedElementEnterTransition(sharedElementEnter);
+        setSharedElementReturnTransition(sharedElementReturn);
+        enterTransition.addListener(mListener);
+        reenterTransition.addListener(mListener);
+        exitTransition.addListener(mListener);
+        returnTransition.addListener(mListener);
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container,
+            Bundle savedInstanceState) {
+        checkGetActivity();
+        checkState("onCreateView", CREATED);
+        mOnCreateViewCalled = true;
+        return super.onCreateView(inflater, container, savedInstanceState);
+    }
+
+    void waitForTransition() throws InterruptedException {
+        verify(mListener, within(300)).onTransitionEnd(any());
+        reset(mListener);
+    }
+
+    void waitForNoTransition() throws InterruptedException {
+        SystemClock.sleep(250);
+        verify(mListener, never()).onTransitionStart(any());
+    }
+}
diff --git a/tests/tests/bionic/Android.build.copy.libs.mk b/tests/tests/bionic/Android.build.copy.libs.mk
index 0e99d41..dd7d4e0 100644
--- a/tests/tests/bionic/Android.build.copy.libs.mk
+++ b/tests/tests/bionic/Android.build.copy.libs.mk
@@ -92,6 +92,8 @@
   prebuilt-elf-files/libtest_invalid-zero_shdr_table_offset.so \
   prebuilt-elf-files/libtest_invalid-zero_shentsize.so \
   prebuilt-elf-files/libtest_invalid-zero_shstrndx.so \
+  prebuilt-elf-files/libtest_invalid-textrels.so \
+  prebuilt-elf-files/libtest_invalid-textrels2.so \
   private_namespace_libs_external/libnstest_private_external.so \
   private_namespace_libs/libnstest_dlopened.so \
   private_namespace_libs/libnstest_private.so \
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png
new file mode 100644
index 0000000..2e77270
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_160.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png
new file mode 100644
index 0000000..5a5c3d2
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_320.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png
new file mode 100644
index 0000000..611b27b
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_am_density_golden_80.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png
new file mode 100644
index 0000000..2e77270
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_160.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png
new file mode 100644
index 0000000..e8beaa5
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_320.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png
new file mode 100644
index 0000000..b869ed7
--- /dev/null
+++ b/tests/tests/graphics/res/drawable-nodpi/bitmap_shader_density_golden_80.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml b/tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml
new file mode 100644
index 0000000..dfecfbb
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/bitmap_shader_am_density.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+    
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+    
+          http://www.apache.org/licenses/LICENSE-2.0
+    
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/bitmap_shader_density_internal"
+        android:tileModeX="repeat"
+        android:tileModeY="clamp"
+        android:autoMirrored="true" />
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png b/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png
new file mode 100644
index 0000000..b6d4d89
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/bitmap_shader_am_density_internal.png
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_density.xml b/tests/tests/graphics/res/drawable/bitmap_shader_density.xml
new file mode 100644
index 0000000..435b06a
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/bitmap_shader_density.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2016 The Android Open Source Project
+    
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+    
+          http://www.apache.org/licenses/LICENSE-2.0
+    
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+        android:src="@drawable/bitmap_shader_density_internal"
+        android:tileModeX="repeat"
+        android:tileModeY="clamp" />
diff --git a/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png b/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png
new file mode 100644
index 0000000..b6d4d89
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/bitmap_shader_density_internal.png
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index a37704a..4197bf0 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -55,6 +55,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.AttributeSet;
+import android.util.LayoutDirection;
 import android.util.Xml;
 import android.view.Gravity;
 
@@ -534,15 +535,9 @@
     };
 
     private static final int[] DENSITY_IMAGES = new int[] {
-            R.drawable.bitmap_density
-    };
-
-    private static final int[][] DENSITY_GOLDEN_IMAGES = new int[][] {
-            {
-                    R.drawable.bitmap_density_golden_160,
-                    R.drawable.bitmap_density_golden_80,
-                    R.drawable.bitmap_density_golden_320,
-            }
+            R.drawable.bitmap_density,
+            R.drawable.bitmap_shader_density,
+            R.drawable.bitmap_shader_am_density,
     };
 
     @Test
@@ -550,15 +545,16 @@
         final Resources res = mContext.getResources();
         final int densityDpi = res.getConfiguration().densityDpi;
         try {
-            verifyPreloadDensityInner(res, DENSITY_IMAGES[0], DENSITY_VALUES,
-                    DENSITY_GOLDEN_IMAGES[0]);
+            for (int i = 0; i < DENSITY_IMAGES.length; i++) {
+                verifyPreloadDensityInner(res, DENSITY_IMAGES[i], DENSITY_VALUES);
+            }
         } finally {
             DrawableTestUtils.setResourcesDensity(res, densityDpi);
         }
     }
 
-    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities,
-            int[] goldenResIds) throws XmlPullParserException, IOException {
+    private void verifyPreloadDensityInner(Resources res, int sourceResId, int[] densities)
+            throws XmlPullParserException, IOException {
         final Rect tempPadding = new Rect();
 
         // Capture initial state at preload density.
@@ -574,7 +570,7 @@
         final int origHeight = preloadedDrawable.getIntrinsicHeight();
         assertFalse(preloadedDrawable.getPadding(tempPadding));
 
-        compareOrSave(preloadedDrawable, preloadDensityDpi, sourceResId, goldenResIds[0]);
+        compareOrSave(preloadedDrawable, preloadDensityDpi, sourceResId);
 
         for (int i = 1; i < densities.length; i++) {
             final int scaledDensityDpi = densities[i];
@@ -583,6 +579,7 @@
 
             final BitmapDrawable scaledDrawable =
                     (BitmapDrawable) preloadedConstantState.newDrawable(res);
+            scaledDrawable.setLayoutDirection(LayoutDirection.RTL);
 
             // Sizes are rounded.
             assertEquals(Math.round(origWidth * scale), scaledDrawable.getIntrinsicWidth());
@@ -591,7 +588,7 @@
             // Bitmaps have no padding.
             assertFalse(scaledDrawable.getPadding(tempPadding));
 
-            compareOrSave(scaledDrawable, scaledDensityDpi, sourceResId, goldenResIds[i]);
+            compareOrSave(scaledDrawable, scaledDensityDpi, sourceResId);
 
             // Ensure theme density is applied correctly. Unlike most
             // drawables, we don't have any loss of accuracy because density
@@ -606,7 +603,7 @@
         }
     }
 
-    private void compareOrSave(Drawable dr, int densityDpi, int sourceResId, int goldenResId) {
+    private void compareOrSave(Drawable dr, int densityDpi, int sourceResId) {
         final int width = dr.getIntrinsicWidth();
         final int height = dr.getIntrinsicHeight();
         final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
@@ -619,6 +616,7 @@
         if (DBG_DUMP_PNG) {
             saveGoldenImage(bitmap, sourceResId, densityDpi);
         } else {
+            final int goldenResId = getGoldenImageResId(sourceResId, densityDpi);
             final Bitmap golden = BitmapFactory.decodeResource(
                     mContext.getResources(), goldenResId);
             DrawableTestUtils.compareImages(densityDpi + " dpi", golden, bitmap,
@@ -626,28 +624,32 @@
         }
     }
 
+    private int getGoldenImageResId(int sourceResId, int densityDpi) {
+        final String name = getGoldenImageName(sourceResId, densityDpi);
+        return mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
+    }
+
+    private String getGoldenImageName(int sourceResId, int densityDpi) {
+        return mContext.getResources().getResourceEntryName(sourceResId) + "_golden_" + densityDpi;
+    }
+
     private void saveGoldenImage(Bitmap bitmap, int sourceResId, int densityDpi) {
         // Save the image to the disk.
         FileOutputStream out = null;
 
         try {
-            final String outputFolder = "/sdcard/temp/";
-            final File folder = new File(outputFolder);
-            if (!folder.exists()) {
-                folder.mkdir();
+            final File outputFolder = new File("/sdcard/temp/");
+            if (!outputFolder.exists()) {
+                outputFolder.mkdir();
             }
 
-            final String sourceFilename = new File(
-                    mContext.getResources().getString(sourceResId)).getName();
-            final String sourceTitle = sourceFilename.substring(0, sourceFilename.lastIndexOf("."));
-            final String outputTitle = sourceTitle + "_golden_" + densityDpi;
-            final String outputFilename = outputFolder + outputTitle + ".png";
-            final File outputFile = new File(outputFilename);
-            if (!outputFile.exists()) {
-                outputFile.createNewFile();
+            final String goldenFilename = getGoldenImageName(sourceResId, densityDpi) + ".png";
+            final File goldenFile = new File(outputFolder, goldenFilename);
+            if (!goldenFile.exists()) {
+                goldenFile.createNewFile();
             }
 
-            out = new FileOutputStream(outputFile, false);
+            out = new FileOutputStream(goldenFile, false);
             bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
         } catch (Exception e) {
             e.printStackTrace();
diff --git a/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java b/tests/tests/hardware/src/android/hardware/cts/LowRamDeviceTest.java
old mode 100755
new mode 100644
diff --git a/tests/tests/jni/Android.mk b/tests/tests/jni/Android.mk
index 4a81a85..7672d2f 100644
--- a/tests/tests/jni/Android.mk
+++ b/tests/tests/jni/Android.mk
@@ -32,7 +32,13 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner android-support-test
 
-LOCAL_JNI_SHARED_LIBRARIES := libjnitest libnativehelper_compat_libc++
+LOCAL_JNI_SHARED_LIBRARIES := \
+  libjninamespacea1 \
+  libjninamespacea2 \
+  libjninamespaceb \
+  libjnicommon \
+  libjnitest \
+  libnativehelper_compat_libc++
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -41,4 +47,4 @@
 include $(BUILD_CTS_PACKAGE)
 
 # Include the associated library's makefile.
-include $(LOCAL_PATH)/libjnitest/Android.mk
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/jni/libjnicommon/Android.mk b/tests/tests/jni/libjnicommon/Android.mk
new file mode 100644
index 0000000..0f8044e
--- /dev/null
+++ b/tests/tests/jni/libjnicommon/Android.mk
@@ -0,0 +1,37 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libjnicommon
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := common.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+
+LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper_compat_libc++
+
+LOCAL_SDK_VERSION := 23
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/jni/libjnicommon/common.cpp b/tests/tests/jni/libjnicommon/common.cpp
new file mode 100644
index 0000000..02cdb24
--- /dev/null
+++ b/tests/tests/jni/libjnicommon/common.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+int global = 0;
+
+void incrementGlobal() {
+    ++global;
+}
+
+int getGlobal() {
+    return global;
+}
diff --git a/tests/tests/jni/libjnicommon/common.h b/tests/tests/jni/libjnicommon/common.h
new file mode 100644
index 0000000..c82eece
--- /dev/null
+++ b/tests/tests/jni/libjnicommon/common.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+void incrementGlobal();
+int getGlobal();
+
+#endif // COMMON_H
diff --git a/tests/tests/jni/libjninamespacea1/Android.mk b/tests/tests/jni/libjninamespacea1/Android.mk
new file mode 100644
index 0000000..8016c50
--- /dev/null
+++ b/tests/tests/jni/libjninamespacea1/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libjninamespacea1
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := namespacea1.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(LOCAL_PATH)/../libjnicommon/
+
+LOCAL_LDLIBS += -llog
+LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper_compat_libc++ libjnicommon
+
+LOCAL_SDK_VERSION := 23
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/jni/libjninamespacea1/namespacea1.cpp b/tests/tests/jni/libjninamespacea1/namespacea1.cpp
new file mode 100644
index 0000000..decb4f1
--- /dev/null
+++ b/tests/tests/jni/libjninamespacea1/namespacea1.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+#include <android/log.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,"namespacea1",__VA_ARGS__)
+
+int global = 0;
+
+jint JNI_OnLoad(JavaVM*, void*) {
+    LOGI("JNI_OnLoad namespacea1");
+    return JNI_VERSION_1_4;
+}
+
+extern "C" JNIEXPORT void JNICALL
+    Java_android_jni_cts_ClassNamespaceA1_incrementGlobal(JNIEnv*, jclass) {
+  incrementGlobal();
+}
+
+extern "C" JNIEXPORT jint JNICALL
+    Java_android_jni_cts_ClassNamespaceA1_getGlobal(JNIEnv*, jclass) {
+  return getGlobal();
+}
diff --git a/tests/tests/jni/libjninamespacea2/Android.mk b/tests/tests/jni/libjninamespacea2/Android.mk
new file mode 100644
index 0000000..9b515c9
--- /dev/null
+++ b/tests/tests/jni/libjninamespacea2/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libjninamespacea2
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := namespacea2.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(LOCAL_PATH)/../libjnicommon/
+
+LOCAL_LDLIBS += -llog
+LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper_compat_libc++ libjnicommon
+
+LOCAL_SDK_VERSION := 23
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/jni/libjninamespacea2/namespacea2.cpp b/tests/tests/jni/libjninamespacea2/namespacea2.cpp
new file mode 100644
index 0000000..809266e
--- /dev/null
+++ b/tests/tests/jni/libjninamespacea2/namespacea2.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+#include <android/log.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,"namespacea2",__VA_ARGS__)
+
+int global = 0;
+
+jint JNI_OnLoad(JavaVM*, void*) {
+    LOGI("JNI_OnLoad namespacea2");
+    return JNI_VERSION_1_4;
+}
+
+extern "C" JNIEXPORT void JNICALL
+    Java_android_jni_cts_ClassNamespaceA2_incrementGlobal(JNIEnv*, jclass) {
+  incrementGlobal();
+}
+
+extern "C" JNIEXPORT jint JNICALL
+    Java_android_jni_cts_ClassNamespaceA2_getGlobal(JNIEnv*, jclass) {
+  return getGlobal();
+}
diff --git a/tests/tests/jni/libjninamespaceb/Android.mk b/tests/tests/jni/libjninamespaceb/Android.mk
new file mode 100644
index 0000000..4d3e158b
--- /dev/null
+++ b/tests/tests/jni/libjninamespaceb/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This is the shared library included by the JNI test app.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libjninamespaceb
+
+# Don't include this package in any configuration by default.
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := namespaceb.cpp
+
+LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) $(LOCAL_PATH)/../libjnicommon/
+
+LOCAL_LDLIBS += -llog
+LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper_compat_libc++ libjnicommon
+
+LOCAL_SDK_VERSION := 23
+LOCAL_NDK_STL_VARIANT := c++_static
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/tests/tests/jni/libjninamespaceb/namespaceb.cpp b/tests/tests/jni/libjninamespaceb/namespaceb.cpp
new file mode 100644
index 0000000..b3bedcb
--- /dev/null
+++ b/tests/tests/jni/libjninamespaceb/namespaceb.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common.h"
+
+#include <android/log.h>
+#include <jni.h>
+#include <JNIHelp.h>
+
+#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,"namespaceb",__VA_ARGS__)
+
+int global = 0;
+
+jint JNI_OnLoad(JavaVM*, void*) {
+    LOGI("JNI_OnLoad namespaceb");
+    return JNI_VERSION_1_4;
+}
+
+extern "C" JNIEXPORT void JNICALL
+    Java_android_jni_cts_ClassNamespaceB_incrementGlobal(JNIEnv*, jclass) {
+  incrementGlobal();
+}
+
+extern "C" JNIEXPORT jint JNICALL
+    Java_android_jni_cts_ClassNamespaceB_getGlobal(JNIEnv*, jclass) {
+  return getGlobal();
+}
diff --git a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
index 91ebe73..d2e90c6 100644
--- a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
+++ b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
@@ -42,6 +42,13 @@
         }
     }
 
+    public void test_linker_namespaces_classloaders() throws Exception {
+        String error = LinkerNamespacesHelper.runClassLoaderNamespaces();
+        if (error != null) {
+            fail(error);
+        }
+    }
+
     /**
      * Test that accessing classes true JNI works as expected. b/19382130
      */
diff --git a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
index 132a21f..754e6b2 100644
--- a/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
+++ b/tests/tests/jni/src/android/jni/cts/LinkerNamespacesHelper.java
@@ -17,8 +17,11 @@
 package android.jni.cts;
 
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.support.test.InstrumentationRegistry;
+import dalvik.system.PathClassLoader;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -85,4 +88,139 @@
 
     private static native String runAccessibilityTestImpl(String[] publicSystemLibs,
                                                           String[] publicVendorLibs);
+
+    private static void invokeIncrementGlobal(Class<?> clazz) throws Exception {
+        clazz.getMethod("incrementGlobal").invoke(null);
+    }
+    private static int invokeGetGlobal(Class<?> clazz) throws Exception  {
+        return (Integer)clazz.getMethod("getGlobal").invoke(null);
+    }
+
+    private static ApplicationInfo getApplicationInfo(String packageName) {
+        PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        try {
+            return pm.getApplicationInfo(packageName, 0);
+        } catch (NameNotFoundException nnfe) {
+            throw new RuntimeException(nnfe);
+        }
+    }
+
+    private static String getSourcePath(String packageName) {
+        String sourcePath = getApplicationInfo(packageName).sourceDir;
+        if (sourcePath == null) {
+            throw new IllegalStateException("No source path path found for " + packageName);
+        }
+        return sourcePath;
+    }
+
+    private static String getNativePath(String packageName) {
+        String nativePath = getApplicationInfo(packageName).nativeLibraryDir;
+        if (nativePath == null) {
+            throw new IllegalStateException("No native path path found for " + packageName);
+        }
+        return nativePath;
+    }
+
+    // Verify the behaviour of native library loading in class loaders.
+    // In this test:
+    //    - libjninamespacea1, libjninamespacea2 and libjninamespaceb depend on libjnicommon
+    //    - loaderA will load ClassNamespaceA1 (loading libjninamespacea1)
+    //    - loaderA will load ClassNamespaceA2 (loading libjninamespacea2)
+    //    - loaderB will load ClassNamespaceB (loading libjninamespaceb)
+    //    - incrementGlobal/getGlobal operate on a static global from libjnicommon
+    //      and each class should get its own view on it.
+    //
+    // This is a test case for 2 different scenarios:
+    //    - loading native libraries in different class loaders
+    //    - loading native libraries in the same class loader
+    // Ideally we would have 2 different tests but JNI doesn't allow loading the same library in
+    // different class loaders. So to keep the number of native libraries manageable we just
+    // re-use the same class loaders for the two tests.
+    public static String runClassLoaderNamespaces() throws Exception {
+        // Test for different class loaders.
+        // Verify that common dependencies get a separate copy in each class loader.
+        // libjnicommon should be loaded twice:
+        // in the namespace for loaderA and the one for loaderB.
+        String apkPath = getSourcePath("android.jni.cts");
+        String nativePath = getNativePath("android.jni.cts");
+        PathClassLoader loaderA = new PathClassLoader(
+                apkPath, nativePath, ClassLoader.getSystemClassLoader());
+        Class<?> testA1Class = loaderA.loadClass("android.jni.cts.ClassNamespaceA1");
+        PathClassLoader loaderB = new PathClassLoader(
+                apkPath, nativePath, ClassLoader.getSystemClassLoader());
+        Class<?> testBClass = loaderB.loadClass("android.jni.cts.ClassNamespaceB");
+
+        int globalA1 = invokeGetGlobal(testA1Class);
+        int globalB = invokeGetGlobal(testBClass);
+        if (globalA1 != 0 || globalB != 0) {
+            return "Expected globals to be 0/0: globalA1=" + globalA1 + " globalB=" + globalB;
+        }
+
+        invokeIncrementGlobal(testA1Class);
+        globalA1 = invokeGetGlobal(testA1Class);
+        globalB = invokeGetGlobal(testBClass);
+        if (globalA1 != 1 || globalB != 0) {
+            return "Expected globals to be 1/0: globalA1=" + globalA1 + " globalB=" + globalB;
+        }
+
+        invokeIncrementGlobal(testBClass);
+        globalA1 = invokeGetGlobal(testA1Class);
+        globalB = invokeGetGlobal(testBClass);
+        if (globalA1 != 1 || globalB != 1) {
+            return "Expected globals to be 1/1: globalA1=" + globalA1 + " globalB=" + globalB;
+        }
+
+        // Test for the same class loaders.
+        // Verify that if we load ClassNamespaceA2 into loaderA we get the same view on the
+        // globals.
+        Class<?> testA2Class = loaderA.loadClass("android.jni.cts.ClassNamespaceA2");
+
+        int globalA2 = invokeGetGlobal(testA2Class);
+        if (globalA1 != 1 || globalA2 !=1) {
+            return "Expected globals to be 1/1: globalA1=" + globalA1 + " globalA2=" + globalA2;
+        }
+
+        invokeIncrementGlobal(testA1Class);
+        globalA1 = invokeGetGlobal(testA1Class);
+        globalA2 = invokeGetGlobal(testA2Class);
+        if (globalA1 != 2 || globalA2 != 2) {
+            return "Expected globals to be 2/2: globalA1=" + globalA1 + " globalA2=" + globalA2;
+        }
+
+        invokeIncrementGlobal(testA2Class);
+        globalA1 = invokeGetGlobal(testA1Class);
+        globalA2 = invokeGetGlobal(testA2Class);
+        if (globalA1 != 3 || globalA2 != 3) {
+            return "Expected globals to be 2/2: globalA1=" + globalA1 + " globalA2=" + globalA2;
+        }
+        // On success we return null.
+        return null;
+    }
+}
+
+class ClassNamespaceA1 {
+    static {
+        System.loadLibrary("jninamespacea1");
+    }
+
+    public static native void incrementGlobal();
+    public static native int getGlobal();
+}
+
+class ClassNamespaceA2 {
+    static {
+        System.loadLibrary("jninamespacea2");
+    }
+
+    public static native void incrementGlobal();
+    public static native int getGlobal();
+}
+
+class ClassNamespaceB {
+    static {
+        System.loadLibrary("jninamespaceb");
+    }
+
+    public static native void incrementGlobal();
+    public static native int getGlobal();
 }
diff --git a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
index 6988a3f..d69be8b 100644
--- a/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
+++ b/tests/tests/location/src/android/location/cts/GnssNavigationMessageTest.java
@@ -79,13 +79,19 @@
         mTestLocationManager
                 .registerGnssNavigationMessageCallback(mTestGnssNavigationMessageListener);
 
-        mTestGnssNavigationMessageListener.await();
+        boolean success = mTestGnssNavigationMessageListener.await();
+
         if (!mTestGnssNavigationMessageListener.verifyState()) {
             return;
         }
+        SoftAssert.failOrWarning(isMeasurementTestStrict(),
+            "Time elapsed without getting enough navigation messages."
+                + " Possibly, the test has been run deep indoors."
+                + " Consider retrying test outdoors.",
+            success);
+
 
         List<GnssNavigationMessage> events = mTestGnssNavigationMessageListener.getEvents();
-        assertTrue("No Gps Navigation Message received.", !events.isEmpty());
 
         // Verify mandatory GnssNavigationMessage field values.
         TestMeasurementUtil.verifyGnssNavMessageMandatoryField(mTestLocationManager, events);
diff --git a/tests/tests/location/src/android/location/cts/GnssStatusTest.java b/tests/tests/location/src/android/location/cts/GnssStatusTest.java
new file mode 100644
index 0000000..e8f3cb13
--- /dev/null
+++ b/tests/tests/location/src/android/location/cts/GnssStatusTest.java
@@ -0,0 +1,49 @@
+package android.location.cts;
+
+import android.location.GnssStatus;
+
+public class GnssStatusTest extends GnssTestCase  {
+
+    private static final String TAG = "GnssStatusTest";
+    private static final int LOCATION_TO_COLLECT_COUNT = 1;
+    private static final int STATUS_TO_COLLECT_COUNT = 3;
+
+  @Override
+  protected void setUp() throws Exception {
+    super.setUp();
+    mTestLocationManager = new TestLocationManager(getContext());
+  }
+
+  /**
+   * Tests that one can listen for {@link GnssStatus}.
+   */
+  public void testGnssStatusChanges() throws Exception {
+    // Checks if GPS hardware feature is present, skips test (pass) if not,
+    // and hard asserts that Location/GPS (Provider) is turned on if is Cts Verifier.
+    if (!TestMeasurementUtil.canTestRunOnCurrentDevice(mTestLocationManager,
+        TAG, MIN_HARDWARE_YEAR_MEASUREMENTS_REQUIRED, isCtsVerifierTest())) {
+      return;
+    }
+
+    // Register Gps Status Listener.
+    TestGnssStatusCallback testGnssStatusCallback =
+        new TestGnssStatusCallback(TAG, STATUS_TO_COLLECT_COUNT);
+    mTestLocationManager.registerGnssStatusCallback(testGnssStatusCallback);
+
+    TestLocationListener locationListener = new TestLocationListener(LOCATION_TO_COLLECT_COUNT);
+    mTestLocationManager.requestLocationUpdates(locationListener);
+
+    boolean success = testGnssStatusCallback.awaitStart();
+    success = success ? testGnssStatusCallback.awaitStatus() : false;
+    success = success ? testGnssStatusCallback.awaitTtff() : false;
+    mTestLocationManager.removeLocationUpdates(locationListener);
+    success = success ? testGnssStatusCallback.awaitStop() : false;
+    mTestLocationManager.unregisterGnssStatusCallback(testGnssStatusCallback);
+
+    SoftAssert.failOrWarning(isMeasurementTestStrict(),
+        "Time elapsed without getting the right status changes."
+            + " Possibly, the test has been run deep indoors."
+            + " Consider retrying test outdoors.",
+        success);
+  }
+}
diff --git a/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java b/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
index cc4c930..c63fb01 100644
--- a/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
+++ b/tests/tests/location/src/android/location/cts/TestGnssStatusCallback.java
@@ -18,6 +18,7 @@
 
 import android.location.GnssStatus;
 
+import android.util.Log;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
@@ -28,34 +29,50 @@
  */
 class TestGnssStatusCallback extends GnssStatus.Callback {
 
+    private final String mTag;
     private volatile boolean mGpsStatusReceived;
     private GnssStatus mGnssStatus = null;
     // Timeout in sec for count down latch wait
     private static final int TIMEOUT_IN_SEC = 90;
-    private final CountDownLatch mCountDownLatch;
+    private final CountDownLatch mLatchStart;
+    private final CountDownLatch mLatchStatus;
+    private final CountDownLatch mLatchTtff;
+    private final CountDownLatch mLatchStop;
+
     // Store list of Prn for Satellites.
     private List<List<Integer>> mGpsSatellitePrns;
 
-    TestGnssStatusCallback(int gpsStatusCountToCollect) {
-        mCountDownLatch = new CountDownLatch(gpsStatusCountToCollect);
+    TestGnssStatusCallback(String tag, int gpsStatusCountToCollect) {
+        this.mTag = tag;
+        mLatchStart = new CountDownLatch(1);
+        mLatchStatus = new CountDownLatch(gpsStatusCountToCollect);
+        mLatchTtff = new CountDownLatch(1);
+        mLatchStop = new CountDownLatch(1);
         mGpsSatellitePrns = new ArrayList<List<Integer>>();
     }
 
     @Override
     public void onStarted() {
+        Log.i(mTag, "Gnss Status Listener Started");
+        mLatchStart.countDown();
     }
 
     @Override
     public void onStopped() {
+        Log.i(mTag, "Gnss Status Listener Stopped");
+        mLatchStop.countDown();
     }
 
     @Override
     public void onFirstFix(int ttffMillis) {
+        Log.i(mTag, "Gnss Status Listener Received TTFF");
+        mLatchTtff.countDown();
     }
 
     @Override
     public void onSatelliteStatusChanged(GnssStatus status) {
-        mCountDownLatch.countDown();
+        Log.i(mTag, "Gnss Status Listener Received Status Update");
+        mLatchStatus.countDown();
     }
 
     /**
@@ -86,7 +103,19 @@
         return mGnssStatus;
     }
 
-    public boolean await() throws InterruptedException {
-        return TestUtils.waitFor(mCountDownLatch, TIMEOUT_IN_SEC);
+    public boolean awaitStart() throws InterruptedException {
+        return TestUtils.waitFor(mLatchStart, TIMEOUT_IN_SEC);
+    }
+
+    public boolean awaitStatus() throws InterruptedException {
+        return TestUtils.waitFor(mLatchStatus, TIMEOUT_IN_SEC);
+    }
+
+    public boolean awaitTtff() throws InterruptedException {
+        return TestUtils.waitFor(mLatchTtff, TIMEOUT_IN_SEC);
+    }
+
+    public boolean awaitStop() throws InterruptedException {
+        return TestUtils.waitFor(mLatchStop, TIMEOUT_IN_SEC);
     }
 }
diff --git a/tests/tests/location/src/android/location/cts/TestLocationManager.java b/tests/tests/location/src/android/location/cts/TestLocationManager.java
index 26cc057..cca2b78 100644
--- a/tests/tests/location/src/android/location/cts/TestLocationManager.java
+++ b/tests/tests/location/src/android/location/cts/TestLocationManager.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.location.GnssMeasurementsEvent;
 import android.location.GnssNavigationMessage;
+import android.location.GnssStatus;
 import android.location.GpsStatus;
 import android.location.LocationListener;
 import android.location.LocationManager;
@@ -193,6 +194,28 @@
     }
 
     /**
+     * Add a GNSS Status callback.
+     *
+     * @param callback a {@link GnssStatus.Callback} object to register.
+     * @return {@code true} if the listener was added successfully, {@code false} otherwise.
+     */
+    public boolean registerGnssStatusCallback(GnssStatus.Callback callback) {
+        Log.i(TAG, "Add Gnss Status Callback.");
+        return mLocationManager.registerGnssStatusCallback(
+            callback, new Handler(Looper.getMainLooper()));
+    }
+
+    /**
+     * Removes a GNSS Status callback.
+     *
+     * @param callback a {@link GnssStatus.Callback} object to remove.
+     */
+    public void unregisterGnssStatusCallback(GnssStatus.Callback callback) {
+        Log.i(TAG, "Remove Gnss Status Callback.");
+        mLocationManager.unregisterGnssStatusCallback(callback);
+    }
+
+    /**
      * Get LocationManager
      *
      * @return locationManager
diff --git a/tests/tests/media/src/android/media/cts/AudioNativeTest.java b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
index bfc34d1..7301cc7 100644
--- a/tests/tests/media/src/android/media/cts/AudioNativeTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioNativeTest.java
@@ -24,7 +24,6 @@
 import android.media.AudioManager;
 
 public class AudioNativeTest extends CtsAndroidTestCase {
-    // Assume stereo here until b/23899814 is fixed.
     public static final int MAX_CHANNEL_COUNT = 2;
     public static final int MAX_INDEX_MASK = (1 << MAX_CHANNEL_COUNT) - 1;
 
@@ -215,11 +214,7 @@
         }
         AudioTrackNative track = new AudioTrackNative();
 
-        // TODO: when b/23899814 is fixed, use AudioManager.getDevices() to enumerate
-        // actual devices and their channel counts instead of assuming stereo.
-        //
         int maxOutputChannels = 2;
-
         int validIndexMask = (1 << maxOutputChannels) - 1;
 
         for (int mask = 0; mask <= MAX_INDEX_MASK; ++mask) {
@@ -241,14 +236,20 @@
         if (!hasMicrophone()) {
             return;
         }
+
+        AudioManager audioManager =
+                (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
         AudioRecordNative recorder = new AudioRecordNative();
 
-        // TODO: when b/23899814 is fixed, use AudioManager.getDevices() to enumerate
-        // actual devices and their channel counts instead of assuming stereo.
-        //
-        int maxInputChannels = 2;
+        int maxInputChannels = 0;
+        for (AudioDeviceInfo deviceInfo :
+                audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
+            for (int channels : deviceInfo.getChannelCounts()) {
+                maxInputChannels = Math.max(channels, maxInputChannels);
+            }
+        }
 
-        int validIndexMask = (1 << maxInputChannels) -1;
+        int validIndexMask = (1 << maxInputChannels) - 1;
 
         for (int mask = 0; mask <= MAX_INDEX_MASK; ++mask) {
             int channelCount = Long.bitCount(mask);
diff --git a/tests/tests/os/assets/minijail/isolated-i386.policy b/tests/tests/os/assets/minijail/isolated-i386.policy
index 63f651c..43ece54 100644
--- a/tests/tests/os/assets/minijail/isolated-i386.policy
+++ b/tests/tests/os/assets/minijail/isolated-i386.policy
@@ -56,6 +56,7 @@
 rename: return EPERM
 rmdir: return EPERM
 select: 1
+set_thread_area: 1
 setfsgid32: return EPERM
 setfsuid32: return EPERM
 setgid32: return EPERM
diff --git a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
index 5bf1f59..1c9aaba 100644
--- a/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
+++ b/tests/tests/os/src/android/os/cts/AsyncTaskTest.java
@@ -16,12 +16,14 @@
 
 package android.os.cts;
 
+import android.support.annotation.NonNull;
 
 import android.cts.util.PollingCheck;
 import android.os.AsyncTask;
 import android.test.InstrumentationTestCase;
 
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
 public class AsyncTaskTest extends InstrumentationTestCase {
@@ -169,6 +171,47 @@
         }
     }
 
+    public void testException() throws Throwable {
+        final CountDownLatch calledOnCancelled = new CountDownLatch(1);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mAsyncTask = new AsyncTask() {
+                    @Override
+                    protected Object doInBackground(Object... params) {
+                        throw new RuntimeException();
+                    }
+
+                    @Override
+                    protected void onPostExecute(Object o) {
+                        fail("onPostExecute should not be called");
+                    }
+
+                    @Override
+                    protected void onCancelled(Object o) {
+                        calledOnCancelled.countDown();
+                    }
+                };
+            }
+        });
+
+        mAsyncTask.executeOnExecutor(new Executor() {
+            @Override
+            public void execute(@NonNull Runnable command) {
+                try {
+                    command.run();
+                    fail("Exception not thrown");
+                } catch (Throwable tr) {
+                    // expected
+                }
+            }
+        });
+
+        if (!calledOnCancelled.await(5, TimeUnit.SECONDS)) {
+            fail("onCancelled not called!");
+        }
+    }
+
     private void startAsyncTask() throws Throwable {
         runTestOnUiThread(new Runnable() {
             public void run() {
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 9f9c029..938596f 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -3015,7 +3015,7 @@
     <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
         @hide -->
     <permission android:name="android.permission.PEERS_MAC_ADDRESS"
-                android:protectionLevel="signature" />
+                android:protectionLevel="signature|setup" />
 
     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
         can use this permission to ensure incoming Nfc messages are from the Nfc stack
diff --git a/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java b/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java
index 0256738..24021a7 100644
--- a/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java
+++ b/tests/tests/provider/src/android/provider/cts/ContactsContract_AllUriTest.java
@@ -16,18 +16,24 @@
 
 package android.provider.cts;
 
+import android.content.ContentResolver;
+import android.content.ContentValues;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.CancellationSignal;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.SyncState;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
 import junit.framework.AssertionFailedError;
 
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayList;
 
 @LargeTest
@@ -39,67 +45,74 @@
     // The following markers are planned, but not implemented and the definition below is not all
     // correct yet.
     // "d" : supports delete.
-    // "u" : supports delete.
+    // "u" : supports update.
     // "i" : supports insert.
     // "r" : supports read.
     // "w" : supports write.
     // "s" : has x_times_contacted and x_last_time_contacted.
     // "t" : has x_times_used and x_last_time_used.
     private static final String[][] URIs = {
-            {"content://com.android.contacts/contacts", "s"},
-            {"content://com.android.contacts/contacts/1", "s"},
+            {"content://com.android.contacts/contacts", "sud"},
+            {"content://com.android.contacts/contacts/1", "sud"},
             {"content://com.android.contacts/contacts/1/data", "t"},
             {"content://com.android.contacts/contacts/1/entities", "t"},
             {"content://com.android.contacts/contacts/1/suggestions"},
             {"content://com.android.contacts/contacts/1/suggestions/XXX"},
-            {"content://com.android.contacts/contacts/1/photo"},
-            {"content://com.android.contacts/contacts/1/display_photo", "-rw"},
-            {"content://com.android.contacts/contacts_corp/1/photo", "-rw"},
-            {"content://com.android.contacts/contacts_corp/1/display_photo", "-rw"},
-            {"content://com.android.contacts/contacts/1/stream_items"},
+            {"content://com.android.contacts/contacts/1/photo", "r"},
+            {"content://com.android.contacts/contacts/1/display_photo", "-r"},
+            {"content://com.android.contacts/contacts_corp/1/photo", "-r"},
+            {"content://com.android.contacts/contacts_corp/1/display_photo", "-r"},
+
             {"content://com.android.contacts/contacts/filter", "s"},
             {"content://com.android.contacts/contacts/filter/XXX", "s"},
-            {"content://com.android.contacts/contacts/lookup/nlookup", "s"},
+
+            {"content://com.android.contacts/contacts/lookup/nlookup", "sud"},
             {"content://com.android.contacts/contacts/lookup/nlookup/data", "t"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/photo", "t"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/1", "s"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/photo", "tr"},
+
+            {"content://com.android.contacts/contacts/lookup/nlookup/1", "sud"},
             {"content://com.android.contacts/contacts/lookup/nlookup/1/data"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/1/photo"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/display_photo", "-rw"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/1/display_photo", "-rw"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/photo", "r"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/display_photo", "-r"},
+            {"content://com.android.contacts/contacts/lookup/nlookup/1/display_photo", "-r"},
             {"content://com.android.contacts/contacts/lookup/nlookup/entities"},
             {"content://com.android.contacts/contacts/lookup/nlookup/1/entities"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/stream_items"},
-            {"content://com.android.contacts/contacts/lookup/nlookup/1/stream_items"},
-            {"content://com.android.contacts/contacts/as_vcard/nlookup"},
+
+            {"content://com.android.contacts/contacts/as_vcard/nlookup", "r"},
             {"content://com.android.contacts/contacts/as_multi_vcard/XXX"},
+
             {"content://com.android.contacts/contacts/strequent/", "s"},
             {"content://com.android.contacts/contacts/strequent/filter/XXX", "s"},
+
             {"content://com.android.contacts/contacts/group/XXX"},
+
             {"content://com.android.contacts/contacts/frequent", "s"},
             {"content://com.android.contacts/contacts/delete_usage", "-d"},
             {"content://com.android.contacts/contacts/filter_enterprise?directory=0", "s"},
             {"content://com.android.contacts/contacts/filter_enterprise/XXX?directory=0", "s"},
-            {"content://com.android.contacts/raw_contacts", "s"},
-            {"content://com.android.contacts/raw_contacts/1", "s"},
-            {"content://com.android.contacts/raw_contacts/1/data", "t"},
+
+            {"content://com.android.contacts/raw_contacts", "siud"},
+            {"content://com.android.contacts/raw_contacts/1", "sud"},
+            {"content://com.android.contacts/raw_contacts/1/data", "tu"},
             {"content://com.android.contacts/raw_contacts/1/display_photo", "-rw"},
             {"content://com.android.contacts/raw_contacts/1/entity"},
-            {"content://com.android.contacts/raw_contacts/1/stream_items"},
-            {"content://com.android.contacts/raw_contacts/1/stream_items/1"},
+
             {"content://com.android.contacts/raw_contact_entities"},
             {"content://com.android.contacts/raw_contact_entities_corp", "!"},
-            {"content://com.android.contacts/data", "t"},
-            {"content://com.android.contacts/data/1", "t"},
+
+            {"content://com.android.contacts/data", "tud"},
+            {"content://com.android.contacts/data/1", "tudr"},
             {"content://com.android.contacts/data/phones", "t"},
             {"content://com.android.contacts/data_enterprise/phones", "!"},
-            {"content://com.android.contacts/data/phones/1", "t"},
+            {"content://com.android.contacts/data/phones/1", "tud"},
             {"content://com.android.contacts/data/phones/filter", "t"},
             {"content://com.android.contacts/data/phones/filter/XXX", "t"},
+
             {"content://com.android.contacts/data/phones/filter_enterprise?directory=0", "t"},
             {"content://com.android.contacts/data/phones/filter_enterprise/XXX?directory=0", "t"},
+
             {"content://com.android.contacts/data/emails", "t"},
-            {"content://com.android.contacts/data/emails/1", "t"},
+            {"content://com.android.contacts/data/emails/1", "tud"},
             {"content://com.android.contacts/data/emails/lookup", "t"},
             {"content://com.android.contacts/data/emails/lookup/XXX", "t"},
             {"content://com.android.contacts/data/emails/filter", "t"},
@@ -109,10 +122,10 @@
             {"content://com.android.contacts/data/emails/lookup_enterprise", "t"},
             {"content://com.android.contacts/data/emails/lookup_enterprise/XXX", "t"},
             {"content://com.android.contacts/data/postals", "t"},
-            {"content://com.android.contacts/data/postals/1", "t"},
-            {"content://com.android.contacts/data/usagefeedback/XXX", "-u"},
+            {"content://com.android.contacts/data/postals/1", "tud"},
+            {"content://com.android.contacts/data/usagefeedback/1,2,3", "-u"},
             {"content://com.android.contacts/data/callables/", "t"},
-            {"content://com.android.contacts/data/callables/1", "t"},
+            {"content://com.android.contacts/data/callables/1", "tud"},
             {"content://com.android.contacts/data/callables/filter", "t"},
             {"content://com.android.contacts/data/callables/filter/XXX", "t"},
             {"content://com.android.contacts/data/callables/filter_enterprise?directory=0", "t"},
@@ -121,95 +134,54 @@
             {"content://com.android.contacts/data/contactables/", "t"},
             {"content://com.android.contacts/data/contactables/filter", "t"},
             {"content://com.android.contacts/data/contactables/filter/XXX", "t"},
-            {"content://com.android.contacts/groups"},
-            {"content://com.android.contacts/groups/1"},
+
+            {"content://com.android.contacts/groups", "iud"},
+            {"content://com.android.contacts/groups/1", "ud"},
             {"content://com.android.contacts/groups_summary"},
-            {"content://com.android.contacts/syncstate"},
-            {"content://com.android.contacts/syncstate/1", "-du"},
-            {"content://com.android.contacts/profile/syncstate"},
+            {"content://com.android.contacts/syncstate", "iud"},
+            {"content://com.android.contacts/syncstate/1", "-ud"},
+            {"content://com.android.contacts/profile/syncstate", "iud"},
             {"content://com.android.contacts/phone_lookup/XXX"},
             {"content://com.android.contacts/phone_lookup_enterprise/XXX"},
-            {"content://com.android.contacts/aggregation_exceptions"},
-            {"content://com.android.contacts/settings"},
-            {"content://com.android.contacts/status_updates"},
+            {"content://com.android.contacts/aggregation_exceptions", "u"},
+            {"content://com.android.contacts/settings", "ud"},
+            {"content://com.android.contacts/status_updates", "ud"},
             {"content://com.android.contacts/status_updates/1"},
             {"content://com.android.contacts/search_suggest_query"},
             {"content://com.android.contacts/search_suggest_query/XXX"},
             {"content://com.android.contacts/search_suggest_shortcut/XXX"},
             {"content://com.android.contacts/provider_status"},
-            {"content://com.android.contacts/directories"},
+            {"content://com.android.contacts/directories", "u"},
             {"content://com.android.contacts/directories/1"},
             {"content://com.android.contacts/directories_enterprise"},
             {"content://com.android.contacts/directories_enterprise/1"},
             {"content://com.android.contacts/complete_name"},
-            {"content://com.android.contacts/profile", "s"},
+            {"content://com.android.contacts/profile", "su"},
             {"content://com.android.contacts/profile/entities", "s"},
-            {"content://com.android.contacts/profile/data", "t"},
-            {"content://com.android.contacts/profile/data/1", "t"},
+            {"content://com.android.contacts/profile/data", "tud"},
+            {"content://com.android.contacts/profile/data/1", "td"},
             {"content://com.android.contacts/profile/photo", "t"},
-            {"content://com.android.contacts/profile/display_photo", "-rw"},
-            {"content://com.android.contacts/profile/as_vcard"},
-            {"content://com.android.contacts/profile/raw_contacts", "s"},
-            {"content://com.android.contacts/profile/raw_contacts/1", "s"},
-            {"content://com.android.contacts/profile/raw_contacts/1/data", "t"},
+            {"content://com.android.contacts/profile/display_photo", "-r"},
+            {"content://com.android.contacts/profile/as_vcard", "r"},
+            {"content://com.android.contacts/profile/raw_contacts", "siud"},
+
+            // Note this should have supported update... Too late to add.
+            {"content://com.android.contacts/profile/raw_contacts/1", "sd"},
+            {"content://com.android.contacts/profile/raw_contacts/1/data", "tu"},
             {"content://com.android.contacts/profile/raw_contacts/1/entity"},
-            {"content://com.android.contacts/profile/status_updates"},
+            {"content://com.android.contacts/profile/status_updates", "ud"},
             {"content://com.android.contacts/profile/raw_contact_entities"},
-            {"content://com.android.contacts/stream_items"},
-            {"content://com.android.contacts/stream_items/photo"},
-            {"content://com.android.contacts/stream_items/1"},
-            {"content://com.android.contacts/stream_items/1/photo"},
-            {"content://com.android.contacts/stream_items/1/photo/1"},
-            {"content://com.android.contacts/stream_items_limit"},
-            {"content://com.android.contacts/display_photo/1", "-rw"},
+            {"content://com.android.contacts/display_photo/1", "-r"},
             {"content://com.android.contacts/photo_dimensions"},
             {"content://com.android.contacts/deleted_contacts"},
             {"content://com.android.contacts/deleted_contacts/1"},
-            {"content://com.android.contacts/directory_file_enterprise/XXX", "-rw"},
-
-            {"content://contacts/extensions"},
-            {"content://contacts/extensions/1"},
-            {"content://contacts/groups"},
-            {"content://contacts/groups/1"},
-            {"content://contacts/groups/name/XXX/members"},
-            {"content://contacts/groups/system_id/XXX/members"},
-            {"content://contacts/groupmembership"},
-            {"content://contacts/groupmembership/1"},
-            {"content://contacts/people", "s"},
-            {"content://contacts/people/filter/XXX"},
-            {"content://contacts/people/1"},
-            {"content://contacts/people/1/extensions"},
-            {"content://contacts/people/1/extensions/1"},
-            {"content://contacts/people/1/phones"},
-            {"content://contacts/people/1/phones/1"},
-            {"content://contacts/people/1/photo"},
-            {"content://contacts/people/1/contact_methods"},
-            {"content://contacts/people/1/contact_methods/1"},
-            {"content://contacts/people/1/organizations"},
-            {"content://contacts/people/1/organizations/1"},
-            {"content://contacts/people/1/groupmembership"},
-            {"content://contacts/people/1/groupmembership/1"},
-            {"content://contacts/people/1/update_contact_time", "-u"},
-            {"content://contacts/deleted_people", "-"},
-            {"content://contacts/deleted_groups", "-"},
-            {"content://contacts/phones"},
-            {"content://contacts/phones/filter/XXX"},
-            {"content://contacts/phones/1"},
-            {"content://contacts/photos"},
-            {"content://contacts/photos/1"},
-            {"content://contacts/contact_methods"},
-            {"content://contacts/contact_methods/email"},
-            {"content://contacts/contact_methods/1"},
-            {"content://contacts/organizations"},
-            {"content://contacts/organizations/1"},
-            {"content://contacts/search_suggest_query"},
-            {"content://contacts/search_suggest_query/XXX"},
-            {"content://contacts/search_suggest_shortcut/XXX"},
-            {"content://contacts/settings"},
+            {"content://com.android.contacts/directory_file_enterprise/XXX?directory=0", "-"},
     };
 
     private static final String[] ARG1 = {"-1"};
 
+    private ContentResolver mResolver;
+
     private ArrayList<String> mFailures;
 
     @Override
@@ -217,6 +189,7 @@
         super.setUp();
 
         mFailures = new ArrayList<>();
+        mResolver = getContext().getContentResolver();
     }
 
     @Override
@@ -228,11 +201,14 @@
         super.tearDown();
     }
 
-    private void addFailure(String message) {
-        mFailures.add(message);
-        Log.e(TAG, "Failed: " + message);
-        if (mFailures.size() > 100) {
-            // Too many failures...
+    private void addFailure(String message, Throwable th) {
+        Log.e(TAG, "Failed: " + message, th);
+
+        final int MAX = 100;
+        if (mFailures.size() == MAX) {
+            mFailures.add("Too many failures.");
+        } else if (mFailures.size() > MAX) {
+            // Too many failures already...
         } else {
             mFailures.add(message);
         }
@@ -261,6 +237,10 @@
         mFailures = null;
     }
 
+    private static Uri getUri(String[] path) {
+        return Uri.parse(path[0]);
+    }
+
     private static boolean supportsQuery(String[] path) {
         if (path.length == 1) {
             return true; // supports query by default.
@@ -268,12 +248,28 @@
         return !(path[1].contains("-") || path[1].contains("!"));
     }
 
-    private static Uri getUri(String[] path) {
-        return Uri.parse(path[0]);
+    private static boolean supportsInsert(String[] path) {
+        return (path.length) >= 2 && path[1].contains("i");
+    }
+
+    private static boolean supportsUpdate(String[] path) {
+        return (path.length) >= 2 && path[1].contains("u");
+    }
+
+    private static boolean supportsDelete(String[] path) {
+        return (path.length) >= 2 && path[1].contains("d");
+    }
+
+    private static boolean supportsRead(String[] path) {
+        return (path.length) >= 2 && path[1].contains("r");
+    }
+
+    private static boolean supportsWrite(String[] path) {
+        return (path.length) >= 2 && path[1].contains("w");
     }
 
     private String[] getColumns(Uri uri) {
-        try (Cursor c = getContext().getContentResolver().query(uri,
+        try (Cursor c = mResolver.query(uri,
                 null, // projection
                 "1=2", // selection
                 null, // selection args
@@ -287,32 +283,47 @@
             String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
         try {
-            try (Cursor c = getContext().getContentResolver().query(uri, projection, selection,
+            try (Cursor c = mResolver.query(uri, projection, selection,
                     selectionArgs, sortOrder)) {
                 c.moveToFirst();
             }
         } catch (Throwable th) {
-            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage());
+            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage(), th);
         }
         try {
             // With CancellationSignal.
-            try (Cursor c = getContext().getContentResolver().query(uri, projection, selection,
+            try (Cursor c = mResolver.query(uri, projection, selection,
                     selectionArgs, sortOrder, new CancellationSignal())) {
                 c.moveToFirst();
             }
         } catch (Throwable th) {
-            addFailure("Query with cancel failed: URI=" + uri + " Message=" + th.getMessage());
+            addFailure("Query with cancel failed: URI=" + uri + " Message=" + th.getMessage(), th);
         }
         try {
             // With limit.
-            try (Cursor c = getContext().getContentResolver().query(
+            try (Cursor c = mResolver.query(
                     uri.buildUpon().appendQueryParameter(
                             ContactsContract.LIMIT_PARAM_KEY, "0").build(),
                     projection, selection, selectionArgs, sortOrder)) {
                 c.moveToFirst();
             }
         } catch (Throwable th) {
-            addFailure("Query with limit failed: URI=" + uri + " Message=" + th.getMessage());
+            addFailure("Query with limit failed: URI=" + uri + " Message=" + th.getMessage(), th);
+        }
+
+        try {
+            // With account.
+            try (Cursor c = mResolver.query(
+                    uri.buildUpon()
+                            .appendQueryParameter(RawContacts.ACCOUNT_NAME, "a")
+                            .appendQueryParameter(RawContacts.ACCOUNT_TYPE, "b")
+                            .appendQueryParameter(RawContacts.DATA_SET, "c")
+                            .build(),
+                    projection, selection, selectionArgs, sortOrder)) {
+                c.moveToFirst();
+            }
+        } catch (Throwable th) {
+            addFailure("Query with limit failed: URI=" + uri + " Message=" + th.getMessage(), th);
         }
     }
 
@@ -320,7 +331,7 @@
             String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
         try {
-            try (Cursor c = getContext().getContentResolver().query(uri, projection, selection,
+            try (Cursor c = mResolver.query(uri, projection, selection,
                     selectionArgs, sortOrder)) {
                 c.moveToFirst();
             }
@@ -328,7 +339,7 @@
             // pass.
             return;
         }
-        addFailure("Query on " + uri + " expected to fail, but succeeded.");
+        addFailure("Query on " + uri + " expected to fail, but succeeded.", null);
     }
 
     /**
@@ -355,8 +366,8 @@
             final Uri uri = getUri(path);
 
             for (String column : getColumns(uri)) {
-                if (column.toLowerCase().startsWith(ContactsContract.HIDDEN_COLUMN_PREFIX)) {  // doesn't seem to be working
-                    addFailure("Uri " + uri + " returned hidden column " + column);
+                if (column.toLowerCase().startsWith(ContactsContract.HIDDEN_COLUMN_PREFIX)) {
+                    addFailure("Uri " + uri + " returned hidden column " + column, null);
                 }
             }
         }
@@ -514,13 +525,13 @@
 
     private void checkColumnAccessible(Uri uri, String column) {
         try {
-            try (Cursor c = getContext().getContentResolver().query(
+            try (Cursor c = mResolver.query(
                     uri, new String[]{column}, column + "=0", null, column
             )) {
                 c.moveToFirst();
             }
         } catch (Throwable th) {
-            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage());
+            addFailure("Query failed: URI=" + uri + " Message=" + th.getMessage(), th);
         }
     }
 
@@ -538,7 +549,7 @@
     private void checkColumnNotAccessibleInner(Uri uri, String[] projection, String selection,
             String[] selectionArgs, String sortOrder) {
         try {
-            try (Cursor c = getContext().getContentResolver().query(uri, projection, selection,
+            try (Cursor c = mResolver.query(uri, projection, selection,
                     selectionArgs, sortOrder)) {
                 c.moveToFirst();
             }
@@ -547,7 +558,7 @@
             return;
         }
         addFailure("Query on " + uri +
-                " expected to throw IllegalArgumentException, but succeeded.");
+                " expected to throw IllegalArgumentException, but succeeded.", null);
     }
 
     private void checkColumnNotAccessible(Uri uri, String column) {
@@ -590,4 +601,93 @@
         }
         failIfFailed();
     }
+
+    private void checkExecutable(String operation, Uri uri, boolean shouldWork, Runnable r) {
+        if (shouldWork) {
+            try {
+                r.run();
+            } catch (Exception e) {
+                addFailure(operation + " for '" + uri + "' failed: " + e.getMessage(), e);
+            }
+        } else {
+            try {
+                r.run();
+                addFailure(operation + " for '" + uri + "' NOT failed.", null);
+            } catch (Exception expected) {
+            }
+        }
+    }
+
+    public void testAllOperations() {
+        final ContentValues cv = new ContentValues();
+
+        for (String[] path : URIs) {
+            final Uri uri = getUri(path);
+
+            cv.clear();
+            if (supportsQuery(path)) {
+                cv.put(getColumns(uri)[0], 1);
+            } else {
+                cv.put("_id", 1);
+            }
+            if (uri.toString().contains("syncstate")) {
+                cv.put(SyncState.ACCOUNT_NAME, "abc");
+                cv.put(SyncState.ACCOUNT_TYPE, "def");
+            }
+
+            checkExecutable("insert", uri, supportsInsert(path), () -> {
+                final Uri newUri = mResolver.insert(uri, cv);
+                if (newUri == null) {
+                    addFailure("Insert for '" + uri + "' returned null.", null);
+                } else {
+                    // "profile/raw_contacts/#" is missing update support.  too late to add, so
+                    // just skip.
+                    if (!newUri.toString().startsWith(
+                            "content://com.android.contacts/profile/raw_contacts/")) {
+                        checkExecutable("insert -> update", newUri, true, () -> {
+                            mResolver.update(newUri, cv, null, null);
+                        });
+                    }
+                    checkExecutable("insert -> delete", newUri, true, () -> {
+                        mResolver.delete(newUri, null, null);
+                    });
+                }
+            });
+            checkExecutable("update", uri, supportsUpdate(path), () -> {
+                mResolver.update(uri, cv, "1=2", null);
+            });
+            checkExecutable("delete", uri, supportsDelete(path), () -> {
+                mResolver.delete(uri, "1=2", null);
+            });
+        }
+        failIfFailed();
+    }
+
+    public void testAllFileOperations() {
+        for (String[] path : URIs) {
+            final Uri uri = getUri(path);
+
+            checkExecutable("openInputStream", uri, supportsRead(path), () -> {
+                try (InputStream st = mResolver.openInputStream(uri)) {
+                } catch (FileNotFoundException e) {
+                    // TODO This happens because we try to read nonexistent photos.  Ideally
+                    // we should actually check it's readable.
+                    if (e.getMessage().contains("Stream I/O not supported")) {
+                        throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                    }
+                } catch (Exception e) {
+                    throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                }
+            });
+            checkExecutable("openOutputStream", uri, supportsWrite(path), () -> {
+                try (OutputStream st = mResolver.openOutputStream(uri)) {
+                } catch (Exception e) {
+                    throw new RuntimeException("Caught Exception: " + e.toString(), e);
+                }
+            });
+        }
+        failIfFailed();
+    }
 }
+
+
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 00c08fe..4668107 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -57,7 +57,8 @@
 		libeffects
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)\
-                   src/android/security/cts/activity/ISecureRandomService.aidl
+                   src/android/security/cts/activity/ISecureRandomService.aidl\
+                   aidl/android/security/cts/IIsolatedService.aidl
 
 LOCAL_PACKAGE_NAME := CtsSecurityTestCases
 
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 33dbf2f..757d719 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -36,6 +36,10 @@
                  android:isolatedProcess="true"
                  android:exported="true"/>
 
+        <service android:name="android.security.cts.IsolatedService"
+                 android:process=":Isolated"
+                 android:isolatedProcess="true"/>
+
         <service android:name="android.security.cts.activity.SecureRandomService"
                  android:process=":secureRandom"/>
         <activity
diff --git a/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
new file mode 100644
index 0000000..16db0fe
--- /dev/null
+++ b/tests/tests/security/aidl/android/security/cts/IIsolatedService.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+interface IIsolatedService {
+    String[] getCachedSystemServices();
+    IBinder getSystemService(String serviceName);
+}
diff --git a/tests/tests/security/res/raw/cve_2016_3755.mp4 b/tests/tests/security/res/raw/cve_2016_3755.mp4
new file mode 100644
index 0000000..014bd06
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2016_3755.mp4
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2016_3878_b_29493002.mp4 b/tests/tests/security/res/raw/cve_2016_3878_b_29493002.mp4
new file mode 100644
index 0000000..469a1b3
--- /dev/null
+++ b/tests/tests/security/res/raw/cve_2016_3878_b_29493002.mp4
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/CryptoProviderWorkaroundTest.java b/tests/tests/security/src/android/security/cts/CryptoProviderWorkaroundTest.java
new file mode 100644
index 0000000..861c443
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/CryptoProviderWorkaroundTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import dalvik.system.VMRuntime;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Security;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * http://b/28550092 : Removal of "Crypto" provider in N caused application compatibility
+ * issues for callers of SecureRandom. To improve compatibility the provider is not registered
+ * as a JCA Provider obtainable via Security.getProvider() but is made available for
+ * SecureRandom.getInstance() iff the application targets API <= 23.
+ */
+@RunWith(JUnit4.class)
+public class CryptoProviderWorkaroundTest {
+    @Test
+    public void cryptoProvider_withWorkaround_Success() throws Exception {
+        // Assert that SecureRandom is still using the default value. Sanity check.
+        assertEquals(SecureRandom.DEFAULT_SDK_TARGET_FOR_CRYPTO_PROVIDER_WORKAROUND,
+                SecureRandom.getSdkTargetForCryptoProviderWorkaround());
+
+        try {
+            // Modify the maximum target SDK to apply the workaround, thereby enabling the
+            // workaround for the current SDK and enabling it to be tested.
+            SecureRandom.setSdkTargetForCryptoProviderWorkaround(
+                    VMRuntime.getRuntime().getTargetSdkVersion());
+
+            // Assert that the crypto provider is not installed...
+            assertNull(Security.getProvider("Crypto"));
+            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
+            assertNotNull(sr);
+            // ...but we can get a SecureRandom from it...
+            assertEquals("org.apache.harmony.security.provider.crypto.CryptoProvider",
+                    sr.getProvider().getClass().getName());
+            // ...yet it's not installed. So the workaround worked.
+            assertNull(Security.getProvider("Crypto"));
+        } finally {
+            // Reset the target SDK for the workaround to the default / real value.
+            SecureRandom.setSdkTargetForCryptoProviderWorkaround(
+                    SecureRandom.DEFAULT_SDK_TARGET_FOR_CRYPTO_PROVIDER_WORKAROUND);
+        }
+    }
+
+    @Test
+    public void cryptoProvider_withoutWorkaround_Failure() throws Exception {
+        // Assert that SecureRandom is still using the default value. Sanity check.
+        assertEquals(SecureRandom.DEFAULT_SDK_TARGET_FOR_CRYPTO_PROVIDER_WORKAROUND,
+                SecureRandom.getSdkTargetForCryptoProviderWorkaround());
+
+        try {
+            // We set the limit SDK for the workaround at the previous one, indicating that the
+            // workaround shouldn't be in place.
+            SecureRandom.setSdkTargetForCryptoProviderWorkaround(
+                    VMRuntime.getRuntime().getTargetSdkVersion() - 1);
+
+            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto");
+            fail("Should throw " + NoSuchProviderException.class.getName());
+        } catch(NoSuchProviderException expected) {
+            // The workaround doesn't work. As expected.
+        } finally {
+            // Reset the target SDK for the workaround to the default / real value.
+            SecureRandom.setSdkTargetForCryptoProviderWorkaround(
+                    SecureRandom.DEFAULT_SDK_TARGET_FOR_CRYPTO_PROVIDER_WORKAROUND);
+        }
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
new file mode 100644
index 0000000..ac264d0
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/IsolatedProcessTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.security.cts;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.security.cts.IIsolatedService;
+import android.security.cts.IsolatedService;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import com.android.internal.util.ArrayUtils;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import junit.framework.Assert;
+
+public class IsolatedProcessTest extends AndroidTestCase {
+    static final String TAG = IsolatedProcessTest.class.getSimpleName();
+
+    private static final long BIND_SERVICE_TIMEOUT = 5000;
+
+    // No service other than these should be visible to an isolated process
+    private static final String[] SERVICES_ALLOWED_TO_ISOLATED_PROCESS = {
+            "package",
+            Context.ACTIVITY_SERVICE
+    };
+    // Arbitrary set of services to test accessibility from an isolated process
+    private static final String[] RESTRICTED_SERVICES_TO_TEST = {
+            Context.ALARM_SERVICE,
+            Context.WINDOW_SERVICE,
+            Context.POWER_SERVICE
+    };
+
+    private CountDownLatch mLatch;
+    private IIsolatedService mService;
+    private final ServiceConnection mServiceConnection = new ServiceConnection() {
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            Log.e(TAG, "Isolated service " + name + " died abruptly");
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            mService = IIsolatedService.Stub.asInterface(service);
+            mLatch.countDown();
+        }
+    };
+
+    @Override
+    public void setUp() throws InterruptedException {
+        mLatch = new CountDownLatch(1);
+        Intent serviceIntent = new Intent(mContext, IsolatedService.class);
+        mContext.bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+        Assert.assertTrue("Timed out while waiting to bind to isolated service",
+                mLatch.await(BIND_SERVICE_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    public void testGetCachedServicesFromIsolatedService() throws RemoteException {
+        String[] cachedServices = mService.getCachedSystemServices();
+        for (String serviceName : cachedServices) {
+            Assert.assertTrue(serviceName + " should not be accessbible from an isolated process",
+                    ArrayUtils.contains(SERVICES_ALLOWED_TO_ISOLATED_PROCESS, serviceName));
+        }
+    }
+
+    public void testGetServiceFromIsolatedService() throws RemoteException {
+        for (String serviceName : RESTRICTED_SERVICES_TO_TEST) {
+            IBinder service = mService.getSystemService(serviceName);
+            Assert.assertNull(serviceName + " should not be accessible from an isolated process",
+                    service);
+        }
+    }
+
+    @Override
+    public void tearDown() {
+        mContext.unbindService(mServiceConnection);
+    }
+
+}
diff --git a/tests/tests/security/src/android/security/cts/IsolatedService.java b/tests/tests/security/src/android/security/cts/IsolatedService.java
new file mode 100644
index 0000000..28d2a65
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/IsolatedService.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.cts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.util.Log;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class IsolatedService extends Service {
+
+    private static final String TAG = IsolatedService.class.getSimpleName();
+    private static final String SERVICE_MANAGER_CLASS_NAME = "android.os.ServiceManager";
+    private static final String SERVICE_MANAGER_INTERNAL_CACHE_NAME = "sCache";
+    private static final String GET_SERVICE_METHOD_NAME = "getService";
+
+    private String[] getServicesCachedInServiceManager() {
+        ArrayList<String> cachedServices = new ArrayList<String>();
+        try {
+            Class<?> serviceManager = Class.forName(SERVICE_MANAGER_CLASS_NAME);
+            Field cacheField = serviceManager.getDeclaredField(SERVICE_MANAGER_INTERNAL_CACHE_NAME);
+            cacheField.setAccessible(true);
+            HashMap<String, IBinder> sCache = (HashMap<String, IBinder>) cacheField.get(null);
+            for (Map.Entry<String, IBinder> serviceEntry : sCache.entrySet()) {
+                if (serviceEntry.getValue() != null) {
+                    cachedServices.add(serviceEntry.getKey());
+                }
+            }
+        } catch (ClassCastException | ReflectiveOperationException exc) {
+            Log.w(TAG, "Unable to retrieve service manager cache via reflection ", exc);
+        }
+        return cachedServices.toArray(new String[cachedServices.size()]);
+    }
+
+    private IBinder getServiceFromServiceManager(String serviceName) {
+        try {
+            Class<?> serviceManager = Class.forName(SERVICE_MANAGER_CLASS_NAME);
+            Method getServiceMethod =
+                    serviceManager.getDeclaredMethod(GET_SERVICE_METHOD_NAME, String.class);
+            IBinder service = (IBinder) getServiceMethod.invoke(null, serviceName);
+            return service;
+        } catch (ClassCastException | ReflectiveOperationException exc) {
+            Log.w(TAG, "Unable to call ServiceManager.getService() ", exc);
+        }
+        return null;
+    }
+
+    private final IIsolatedService.Stub mBinder = new IIsolatedService.Stub() {
+
+        public String[] getCachedSystemServices() {
+            return getServicesCachedInServiceManager();
+        }
+
+        public IBinder getSystemService(String serviceName) {
+            return getServiceFromServiceManager(serviceName);
+        }
+    };
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
+    }
+}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index a2679ad..d3b08af 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -158,10 +158,18 @@
         doStagefrightTest(R.raw.bug_28333006);
     }
 
-   public void testStagefright_bug_14388161() throws Exception {
+    public void testStagefright_bug_14388161() throws Exception {
         doStagefrightTestMediaPlayer(R.raw.bug_14388161);
     }
 
+    public void testStagefright_cve_2016_3755() throws Exception {
+        doStagefrightTest(R.raw.cve_2016_3755);
+    }
+
+    public void testStagefright_cve_2016_3878_b_29493002() throws Exception {
+        doStagefrightTest(R.raw.cve_2016_3878_b_29493002);
+    }
+
     private void doStagefrightTest(final int rid) throws Exception {
         doStagefrightTestMediaPlayer(rid);
         doStagefrightTestMediaCodec(rid);
diff --git a/tests/tests/telecom/src/android/telecom/cts/MockConference.java b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
index d84610d..302f91f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/MockConference.java
+++ b/tests/tests/telecom/src/android/telecom/cts/MockConference.java
@@ -143,6 +143,10 @@
 
     public void setRemoteConference(RemoteConference remoteConference) {
         mRemoteConference = remoteConference;
+        Bundle bundle = remoteConference.getExtras();
+        if (bundle != null) {
+            this.putExtras(bundle);
+        }
     }
 
     public RemoteConference getRemoteConference() {
@@ -155,6 +159,7 @@
 
     @Override
     public void onExtrasChanged(Bundle extras) {
+        setExtras(extras);
         mOnExtrasChanged.invoke(extras);
     }
 }
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
index 3246b9c..57654f40 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConferenceTest.java
@@ -455,7 +455,8 @@
         mRemoteConference.setExtras(extras);
         callbackInvoker.waitForCount(1, WAIT_FOR_STATE_CHANGE_TIMEOUT_MS);
         assertEquals(mRemoteConferenceObject, callbackInvoker.getArgs(0)[0]);
-        assertTrue(areBundlesEqual(extras, (Bundle) callbackInvoker.getArgs(0)[1]));
+        assertTrue(((Bundle) callbackInvoker.getArgs(0)[1]).containsKey(
+                TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE));
         mRemoteConferenceObject.unregisterCallback(callback);
     }
 
@@ -469,8 +470,9 @@
             remoteConnections.add(((MockConnection)c).getRemoteConnection());
         }
         assertEquals(remoteConnections, remoteConferenceObject.getConnections());
-        assertEquals(remoteConference.getDisconnectCause(), remoteConferenceObject.getDisconnectCause());
-        assertEquals(remoteConference.getExtras(), remoteConferenceObject.getExtras());
+        assertEquals(remoteConference.getDisconnectCause(),
+                remoteConferenceObject.getDisconnectCause());
+        assertTrue(areBundlesEqual(remoteConferenceObject.getExtras(), conference.getExtras()));
     }
 
     private void addRemoteConnectionOutgoingCalls() {
@@ -572,7 +574,7 @@
             setupConnectionServices(managerConnectionService, remoteConnectionService,
                     FLAG_REGISTER | FLAG_ENABLE);
         } catch(Exception e) {
-            fail("Error in setting up the connection services");
+            fail("Error in setting up the connection services: " + e.toString());
         }
 
         placeAndVerifyCall();
diff --git a/tests/tests/transition/AndroidManifest.xml b/tests/tests/transition/AndroidManifest.xml
index 63de0cd..1fb4f0e 100644
--- a/tests/tests/transition/AndroidManifest.xml
+++ b/tests/tests/transition/AndroidManifest.xml
@@ -21,6 +21,8 @@
     <application>
         <activity android:name="android.transition.cts.TransitionActivity"
             android:label="TransitionActivity"/>
+        <activity android:name="android.transition.cts.TargetActivity"
+            android:label="TargetActivity"/>
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/tests/tests/transition/res/layout/scene10.xml b/tests/tests/transition/res/layout/scene10.xml
index 16e3c20..5403354 100644
--- a/tests/tests/transition/res/layout/scene10.xml
+++ b/tests/tests/transition/res/layout/scene10.xml
@@ -14,33 +14,39 @@
      limitations under the License.
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:transitionName="holder"
-                android:id="@+id/holder">
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#F00"
-          android:layout_alignParentLeft="true"
-          android:layout_alignParentTop="true"
-          android:id="@+id/redSquare" />
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#0F0"
-          android:layout_alignParentRight="true"
-          android:layout_alignParentTop="true"
-          android:id="@+id/greenSquare"/>
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#00F"
-          android:layout_alignParentRight="true"
-          android:layout_alignParentBottom="true"
-          android:id="@+id/blueSquare" />
-    <View android:layout_width="10dp"
-          android:layout_height="10dp"
-          android:background="#FF0"
-          android:layout_alignParentLeft="true"
-          android:layout_alignParentBottom="true"
-          android:id="@+id/yellowSquare"/>
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:transitionGroup="false"
+    android:transitionName="holder"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentBottom="true"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentBottom="true"
+        android:id="@+id/yellowSquare"/>
 </RelativeLayout>
diff --git a/tests/tests/transition/res/layout/scene11.xml b/tests/tests/transition/res/layout/scene11.xml
index 8ecad8d..dc6ef19 100644
--- a/tests/tests/transition/res/layout/scene11.xml
+++ b/tests/tests/transition/res/layout/scene11.xml
@@ -14,11 +14,12 @@
      limitations under the License.
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:transitionName="holder"
-                android:id="@+id/holder">
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:transitionName="holder"
+    android:id="@+id/holder">
     <ImageView
         android:id="@+id/redSquare"
         android:src="#F00"
diff --git a/tests/tests/transition/res/layout/scene12.xml b/tests/tests/transition/res/layout/scene12.xml
new file mode 100644
index 0000000..559ab39
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene12.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:transitionName="holder"
+    android:transitionGroup="false"
+    android:orientation="horizontal"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:id="@+id/yellowSquare"/>
+</LinearLayout>
diff --git a/tests/tests/transition/res/layout/scene13.xml b/tests/tests/transition/res/layout/scene13.xml
new file mode 100644
index 0000000..b7c783f
--- /dev/null
+++ b/tests/tests/transition/res/layout/scene13.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:transitionGroup="false"
+    android:transitionName="holder"
+    android:id="@+id/holder">
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#F00"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentTop="true"
+        android:transitionName="redSquare"
+        android:id="@+id/redSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#0F0"
+        android:layout_toRightOf="@id/redSquare"
+        android:id="@+id/greenSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#00F"
+        android:layout_toRightOf="@id/greenSquare"
+        android:id="@+id/blueSquare"/>
+    <View
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:background="#FF0"
+        android:layout_toRightOf="@id/blueSquare"
+        android:id="@+id/yellowSquare"/>
+</RelativeLayout>
diff --git a/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
new file mode 100644
index 0000000..e568072
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/ActivityTransitionTest.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.transition.cts;
+
+import static android.cts.util.CtsMockitoUtils.within;
+
+import static junit.framework.Assert.*;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.cts.util.PollingCheck;
+import android.cts.util.transition.TargetTracking;
+import android.cts.util.transition.TrackingTransition;
+import android.cts.util.transition.TrackingVisibility;
+import android.os.Bundle;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.transition.Transition.TransitionListener;
+import android.view.View;
+
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ActivityTransitionTest extends BaseTransitionTest {
+    private TransitionListener mExitListener;
+    private TransitionListener mReenterListener;
+    private TransitionListener mSharedElementReenterListener;
+    private TrackingVisibility mExitTransition;
+    private TrackingVisibility mReenterTransition;
+    private TrackingTransition mSharedElementReenterTransition;
+
+    @Override
+    public void setup() {
+        super.setup();
+        mExitTransition = new TrackingVisibility();
+        mExitListener = mock(TransitionListener.class);
+        mExitTransition.addListener(mExitListener);
+        mActivity.getWindow().setExitTransition(mExitTransition);
+
+        mReenterTransition = new TrackingVisibility();
+        mReenterListener = mock(TransitionListener.class);
+        mReenterTransition.addListener(mReenterListener);
+        mActivity.getWindow().setReenterTransition(mReenterTransition);
+
+        mSharedElementReenterTransition = new TrackingTransition();
+        mSharedElementReenterListener = mock(TransitionListener.class);
+        mSharedElementReenterTransition.addListener(mSharedElementReenterListener);
+        mActivity.getWindow().setSharedElementReenterTransition(mSharedElementReenterTransition);
+    }
+
+    @After
+    public void cleanup() {
+        if (TargetActivity.sLastCreated != null) {
+            mInstrumentation.runOnMainSync(() -> TargetActivity.sLastCreated.finish());
+        }
+        TargetActivity.sLastCreated = null;
+    }
+
+    // Views that are outside the visible area only during the shared element start
+    // should not be stripped from the transition.
+    @Test
+    public void viewsNotStripped() throws Throwable {
+        enterScene(R.layout.scene10);
+        mInstrumentation.runOnMainSync(() -> {
+            View sharedElement = mActivity.findViewById(R.id.blueSquare);
+            Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
+                    sharedElement, "holder").toBundle();
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            intent.putExtra(TargetActivity.EXTRA_LAYOUT_ID, R.layout.scene12);
+            mActivity.startActivity(intent, options);
+        });
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        verify(targetActivity.enterListener, within(3000)).onTransitionEnd(any());
+        verify(mExitListener, times(1)).onTransitionEnd(any());
+
+        // Now check the targets... they should all be there
+        assertTargetContains(targetActivity.enterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+        assertTargetExcludes(targetActivity.enterTransition, R.id.holder);
+
+        assertTargetContains(targetActivity.sharedElementEnterTransition, R.id.holder);
+        assertTargetExcludes(targetActivity.sharedElementEnterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mExitTransition, R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+        assertTargetExcludes(mExitTransition, R.id.blueSquare, R.id.holder);
+
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, targetActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        mInstrumentation.runOnMainSync(() -> targetActivity.finishAfterTransition());
+        verify(mReenterListener, within(3000)).onTransitionEnd(any());
+        verify(mSharedElementReenterListener, within(3000)).onTransitionEnd(any());
+        verify(targetActivity.returnListener, times(1)).onTransitionEnd(any());
+
+        // return targets are stripped also
+        assertTargetContains(targetActivity.returnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+        assertTargetExcludes(targetActivity.returnTransition, R.id.holder);
+
+        assertTargetContains(mReenterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+        assertTargetExcludes(mReenterTransition, R.id.blueSquare, R.id.holder);
+
+        assertTargetContains(targetActivity.sharedElementReturnTransition,
+                R.id.holder);
+        assertTargetExcludes(targetActivity.sharedElementReturnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mSharedElementReenterTransition, R.id.blueSquare);
+        assertTargetExcludes(mSharedElementReenterTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, mActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        TargetActivity.sLastCreated = null;
+    }
+
+    // Views that are outside the visible area during initial layout should be stripped from
+    // the transition.
+    @Test
+    public void viewsStripped() throws Throwable {
+        enterScene(R.layout.scene13);
+        mInstrumentation.runOnMainSync(() -> {
+            View sharedElement = mActivity.findViewById(R.id.redSquare);
+            Bundle options = ActivityOptions.makeSceneTransitionAnimation(mActivity,
+                    sharedElement, "redSquare").toBundle();
+            Intent intent = new Intent(mActivity, TargetActivity.class);
+            intent.putExtra(TargetActivity.EXTRA_LAYOUT_ID, R.layout.scene13);
+            mActivity.startActivity(intent, options);
+        });
+
+        TargetActivity targetActivity = waitForTargetActivity();
+        verify(targetActivity.enterListener, within(3000)).onTransitionEnd(any());
+        verify(mExitListener, times(1)).onTransitionEnd(any());
+
+        // Now check the targets... they should all be stripped
+        assertTargetExcludes(targetActivity.enterTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetExcludes(mExitTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(targetActivity.sharedElementEnterTransition, R.id.redSquare);
+        assertTargetExcludes(targetActivity.sharedElementEnterTransition,
+                R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.redSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, targetActivity.findViewById(R.id.holder).getVisibility());
+
+        assertEquals(1, targetActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, targetActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        mInstrumentation.runOnMainSync(() -> targetActivity.finishAfterTransition());
+        verify(mReenterListener, within(3000)).onTransitionEnd(any());
+        verify(mSharedElementReenterListener, within(3000)).onTransitionEnd(any());
+        verify(targetActivity.returnListener, times(1)).onTransitionEnd(any());
+
+        // return targets are stripped also
+        assertTargetExcludes(targetActivity.returnTransition,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetExcludes(mReenterTransition, R.id.holder,
+                R.id.redSquare, R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(targetActivity.sharedElementReturnTransition,
+                R.id.redSquare);
+        assertTargetExcludes(targetActivity.sharedElementReturnTransition,
+                R.id.greenSquare, R.id.blueSquare, R.id.yellowSquare);
+
+        assertTargetContains(mSharedElementReenterTransition, R.id.redSquare);
+        assertTargetExcludes(mSharedElementReenterTransition,
+                R.id.blueSquare, R.id.greenSquare, R.id.yellowSquare);
+
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.greenSquare).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.holder).getVisibility());
+        assertEquals(View.VISIBLE, mActivity.findViewById(R.id.redSquare).getVisibility());
+
+        assertEquals(1, mActivity.findViewById(R.id.redSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.greenSquare).getAlpha(), 0.01f);
+        assertEquals(1, mActivity.findViewById(R.id.holder).getAlpha(), 0.01f);
+
+        TargetActivity.sLastCreated = null;
+    }
+
+    private TargetActivity waitForTargetActivity() {
+        PollingCheck.waitFor(() -> TargetActivity.sLastCreated != null);
+        // Just make sure that we're not in the middle of running on the UI thread.
+        mInstrumentation.runOnMainSync(() -> {});
+        return TargetActivity.sLastCreated;
+    }
+
+    private Set<Integer> getTargetViewIds(TargetTracking transition) {
+        return transition.getTrackedTargets().stream()
+                .map(v -> v.getId())
+                .collect(Collectors.toSet());
+    }
+
+    private void assertTargetContains(TargetTracking transition, int... ids) {
+        Set<Integer> targets = getTargetViewIds(transition);
+        for (int id : ids) {
+            assertTrueWithId(id, "%s was not included from the transition", targets.contains(id));
+        }
+    }
+
+    private void assertTargetExcludes(TargetTracking transition, int... ids) {
+        Set<Integer> targets = getTargetViewIds(transition);
+        for (int id : ids) {
+            assertTrueWithId(id, "%s was not excluded from the transition", !targets.contains(id));
+        }
+    }
+
+    private void assertTrueWithId(int id, String message, boolean valueToAssert) {
+        if (!valueToAssert) {
+            fail(String.format(message, mActivity.getResources().getResourceName(id)));
+        }
+    }
+}
diff --git a/tests/tests/transition/src/android/transition/cts/TargetActivity.java b/tests/tests/transition/src/android/transition/cts/TargetActivity.java
new file mode 100644
index 0000000..dd4bd08
--- /dev/null
+++ b/tests/tests/transition/src/android/transition/cts/TargetActivity.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.transition.cts;
+
+import static org.mockito.Mockito.mock;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.cts.util.transition.TrackingTransition;
+import android.cts.util.transition.TrackingVisibility;
+import android.os.Bundle;
+import android.transition.Transition.TransitionListener;
+
+public class TargetActivity extends Activity {
+    public static final String EXTRA_LAYOUT_ID = "layoutId";
+
+    final TrackingVisibility enterTransition = new TrackingVisibility();
+    final TrackingVisibility returnTransition = new TrackingVisibility();
+    final TrackingTransition sharedElementEnterTransition = new TrackingTransition();
+    final TrackingTransition sharedElementReturnTransition = new TrackingTransition();
+
+    final TransitionListener enterListener = mock(TransitionListener.class);
+    final TransitionListener returnListener = mock(TransitionListener.class);
+
+    public static TargetActivity sLastCreated;
+
+    @Override
+    public void onCreate(Bundle bundle){
+        super.onCreate(bundle);
+        Intent intent = getIntent();
+        int layoutId = R.layout.transition_main;
+        if (intent != null) {
+            layoutId = intent.getIntExtra(EXTRA_LAYOUT_ID, layoutId);
+        }
+        setContentView(layoutId);
+        getWindow().setEnterTransition(enterTransition);
+        getWindow().setReturnTransition(returnTransition);
+        getWindow().setSharedElementEnterTransition(sharedElementEnterTransition);
+        getWindow().setSharedElementReturnTransition(sharedElementReturnTransition);
+        enterTransition.addListener(enterListener);
+        returnTransition.addListener(returnListener);
+
+        sLastCreated = this;
+    }
+}
diff --git a/tests/tests/uirendering/Android.mk b/tests/tests/uirendering/Android.mk
index f101fcc..4dd9b1d 100644
--- a/tests/tests/uirendering/Android.mk
+++ b/tests/tests/uirendering/Android.mk
@@ -28,6 +28,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ctstestrunner \
+    ctsdeviceutil \
     mockito-target-minus-junit4 \
     android-support-test
 
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
index 7c27d5d..61d239b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayerTests.java
@@ -17,8 +17,8 @@
 package android.uirendering.cts.testclasses;
 
 import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
-import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
@@ -152,8 +152,8 @@
                 root.addView(child);
 
                 mAnimator = ObjectAnimator.ofInt(child, "translationY", 0, 20);
-                mAnimator.setRepeatMode(mAnimator.REVERSE);
-                mAnimator.setRepeatCount(mAnimator.INFINITE);
+                mAnimator.setRepeatMode(ValueAnimator.REVERSE);
+                mAnimator.setRepeatCount(ValueAnimator.INFINITE);
                 mAnimator.setDuration(200);
                 mAnimator.start();
             }
@@ -165,8 +165,7 @@
 
         createTest()
                 .addLayout(R.layout.frame_layout, initializer, true)
-                .runWithAnimationVerifier(new ColorCountVerifier(Color.WHITE, 90 * 90 - 50 * 50),
-                        null);
+                .runWithAnimationVerifier(new ColorCountVerifier(Color.WHITE, 90 * 90 - 50 * 50));
     }
 
     @Test
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
index 64c4b77..8b83dc0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/SurfaceViewTests.java
@@ -16,9 +16,13 @@
 package android.uirendering.cts.testclasses;
 
 import android.animation.ObjectAnimator;
+import android.cts.util.SynchronousPixelCopy;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.Rect;
 import android.support.test.filters.MediumTest;
 import android.uirendering.cts.R;
 import android.uirendering.cts.bitmapverifiers.ColorVerifier;
@@ -26,14 +30,18 @@
 import android.uirendering.cts.testinfrastructure.CanvasClient;
 import android.uirendering.cts.testinfrastructure.ViewInitializer;
 import android.view.Gravity;
+import android.view.PixelCopy;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.animation.LinearInterpolator;
 import android.widget.FrameLayout;
 
+import org.junit.Assert;
 import org.junit.Test;
 
+import java.util.concurrent.CountDownLatch;
+
 @MediumTest
 public class SurfaceViewTests extends ActivityTestBase {
 
@@ -99,13 +107,79 @@
             }
         };
         Screenshotter screenshotter = testOffset -> {
-            getInstrumentation().waitForIdleSync();
             Bitmap source = getInstrumentation().getUiAutomation().takeScreenshot();
             return Bitmap.createBitmap(source, testOffset.x, testOffset.y, TEST_WIDTH, TEST_HEIGHT);
         };
         createTest()
                 .addLayout(R.layout.frame_layout, initializer, true)
-                .runWithAnimationVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */),
-                        screenshotter);
+                .withScreenshotter(screenshotter)
+                .runWithAnimationVerifier(new ColorVerifier(Color.WHITE, 0 /* zero tolerance */));
+    }
+
+    private static class SurfaceViewHelper implements ViewInitializer, Screenshotter, SurfaceHolder.Callback {
+        private final CanvasClient mCanvasClient;
+        private final CountDownLatch mFence = new CountDownLatch(1);
+        private SurfaceView mSurfaceView;
+
+        public SurfaceViewHelper(CanvasClient canvasClient) {
+            mCanvasClient = canvasClient;
+        }
+
+        @Override
+        public Bitmap takeScreenshot(Point point /* ignored */) {
+            SynchronousPixelCopy copy = new SynchronousPixelCopy();
+            Bitmap dest = Bitmap.createBitmap(
+                    TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
+            Rect srcRect = new Rect(0, 0, TEST_WIDTH, TEST_HEIGHT);
+            int copyResult = copy.request(mSurfaceView, srcRect, dest);
+            Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
+            return dest;
+        }
+
+        @Override
+        public void initializeView(View view) {
+            FrameLayout root = (FrameLayout) view.findViewById(R.id.frame_layout);
+            mSurfaceView = new SurfaceView(view.getContext());
+            mSurfaceView.getHolder().addCallback(this);
+            root.addView(mSurfaceView, new FrameLayout.LayoutParams(
+                    FrameLayout.LayoutParams.MATCH_PARENT,
+                    FrameLayout.LayoutParams.MATCH_PARENT));
+        }
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            // TODO: Remove the post() which is a temporary workaround for b/32484713
+            mSurfaceView.post(() -> {
+                Canvas canvas = holder.lockHardwareCanvas();
+                mCanvasClient.draw(canvas, width, height);
+                holder.unlockCanvasAndPost(canvas);
+                mFence.countDown();
+            });
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+        }
+
+        public CountDownLatch getFence() {
+            return mFence;
+        }
+    }
+
+    @Test
+    public void testSurfaceHolderHardwareCanvas() {
+        SurfaceViewHelper helper = new SurfaceViewHelper((canvas, width, height) -> {
+            Assert.assertNotNull(canvas);
+            Assert.assertTrue(canvas.isHardwareAccelerated());
+            canvas.drawColor(Color.GREEN);
+        });
+        createTest()
+                .addLayout(R.layout.frame_layout, helper, true, helper.getFence())
+                .withScreenshotter(helper)
+                .runWithVerifier(new ColorVerifier(Color.GREEN, 0 /* zero tolerance */));
     }
 }
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 76c4ee3..f961cdb 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -15,25 +15,20 @@
  */
 package android.uirendering.cts.testinfrastructure;
 
-import static org.junit.Assert.fail;
-
 import android.annotation.Nullable;
 import android.app.Instrumentation;
 import android.content.Intent;
+import android.cts.util.SynchronousPixelCopy;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.support.test.InstrumentationRegistry;
 import android.uirendering.cts.bitmapcomparers.BitmapComparer;
 import android.uirendering.cts.bitmapverifiers.BitmapVerifier;
 import android.uirendering.cts.util.BitmapAsserter;
 import android.util.Log;
 import android.view.PixelCopy;
-import android.view.PixelCopy.OnPixelCopyFinishedListener;
-import android.view.Window;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -61,6 +56,7 @@
     public static final int TEST_HEIGHT = 90;
 
     private TestCaseBuilder mTestCaseBuilder;
+    private Screenshotter mScreenshotter;
 
     private static DrawActivity sActivity;
 
@@ -124,14 +120,18 @@
     }
 
     public Bitmap takeScreenshot(Point testOffset) {
-        SynchronousPixelCopy copy = new SynchronousPixelCopy();
-        Bitmap dest = Bitmap.createBitmap(
-                TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
-        Rect srcRect = new Rect(testOffset.x, testOffset.y,
-                testOffset.x + TEST_WIDTH, testOffset.y + TEST_HEIGHT);
-        int copyResult = copy.request(getActivity().getWindow(), srcRect, dest);
-        Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
-        return dest;
+        if (mScreenshotter == null) {
+            SynchronousPixelCopy copy = new SynchronousPixelCopy();
+            Bitmap dest = Bitmap.createBitmap(
+                    TEST_WIDTH, TEST_HEIGHT, Config.ARGB_8888);
+            Rect srcRect = new Rect(testOffset.x, testOffset.y,
+                    testOffset.x + TEST_WIDTH, testOffset.y + TEST_HEIGHT);
+            int copyResult = copy.request(getActivity().getWindow(), srcRect, dest);
+            Assert.assertEquals(PixelCopy.SUCCESS, copyResult);
+            return dest;
+        } else {
+            return mScreenshotter.takeScreenshot(testOffset);
+        }
     }
 
     protected Point runRenderSpec(TestCase testCase) {
@@ -159,6 +159,7 @@
 
     protected TestCaseBuilder createTest() {
         mTestCaseBuilder = new TestCaseBuilder();
+        mScreenshotter = null;
         return mTestCaseBuilder;
     }
 
@@ -221,8 +222,7 @@
          * A screenshot is captured several times in a loop, to ensure that valid output is produced
          * at many different times during the animation.
          */
-        public void runWithAnimationVerifier(BitmapVerifier bitmapVerifier,
-                @Nullable Screenshotter screenshotter) {
+        public void runWithAnimationVerifier(BitmapVerifier bitmapVerifier) {
             if (mTestCases.size() == 0) {
                 throw new IllegalStateException("Need at least one test to run");
             }
@@ -236,12 +236,7 @@
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
-                    Bitmap testCaseBitmap;
-                    if (screenshotter == null) {
-                        testCaseBitmap = takeScreenshot(testOffset);
-                    } else {
-                        testCaseBitmap = screenshotter.takeScreenshot(testOffset);
-                    }
+                    Bitmap testCaseBitmap = takeScreenshot(testOffset);
                     mBitmapAsserter.assertBitmapIsVerified(testCaseBitmap, bitmapVerifier,
                             getName(), testCase.getDebugString());
                 }
@@ -262,6 +257,12 @@
             });
         }
 
+        public TestCaseBuilder withScreenshotter(Screenshotter screenshotter) {
+            Assert.assertNull("Screenshotter is already set!", mScreenshotter);
+            mScreenshotter = screenshotter;
+            return this;
+        }
+
         public TestCaseBuilder addLayout(int layoutId, @Nullable ViewInitializer viewInitializer) {
             return addLayout(layoutId, viewInitializer, false)
                     .addLayout(layoutId, viewInitializer, true);
@@ -349,39 +350,4 @@
             return debug;
         }
     }
-
-    private static class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
-        private static Handler sHandler;
-        static {
-            HandlerThread thread = new HandlerThread("PixelCopyHelper");
-            thread.start();
-            sHandler = new Handler(thread.getLooper());
-        }
-
-        private int mStatus = -1;
-
-        public int request(Window source, Rect srcRect, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, srcRect, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        private int getResultLocked() {
-            try {
-                this.wait(250);
-            } catch (InterruptedException e) {
-                fail("PixelCopy request didn't complete within 250ms");
-            }
-            return mStatus;
-        }
-
-        @Override
-        public void onPixelCopyFinished(int copyResult) {
-            synchronized (this) {
-                mStatus = copyResult;
-                this.notify();
-            }
-        }
-    }
 }
diff --git a/tests/tests/util/src/android/util/cts/HalfTest.java b/tests/tests/util/src/android/util/cts/HalfTest.java
new file mode 100644
index 0000000..a82a982
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/HalfTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util.cts;
+
+import android.util.Half;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.util.Half.*;
+
+import static org.junit.Assert.assertEquals;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class HalfTest {
+    private static void assertShortEquals(short a, short b) {
+        assertEquals((long) (a & 0xffff), (long) (b & 0xffff));
+    }
+
+    private static void assertShortEquals(int a, short b) {
+        assertEquals((long) (a & 0xffff), (long) (b & 0xffff));
+    }
+
+    @Test
+    public void testSingleToHalf() {
+        // Zeroes, NaN and infinities
+        assertShortEquals(POSITIVE_ZERO, valueOf(0.0f));
+        assertShortEquals(NEGATIVE_ZERO, valueOf(-0.0f));
+        assertShortEquals(NaN, valueOf(Float.NaN));
+        assertShortEquals(POSITIVE_INFINITY, valueOf(Float.POSITIVE_INFINITY));
+        assertShortEquals(NEGATIVE_INFINITY, valueOf(Float.NEGATIVE_INFINITY));
+        // Known values
+        assertShortEquals(0x3c01, valueOf(1.0009765625f));
+        assertShortEquals(0xc000, valueOf(-2.0f));
+        assertShortEquals(0x0400, valueOf(6.10352e-5f));
+        assertShortEquals(0x7bff, valueOf(65504.0f));
+        assertShortEquals(0x3555, valueOf(1.0f / 3.0f));
+        // Denormals
+        assertShortEquals(0x03ff, valueOf(6.09756e-5f));
+        assertShortEquals(MIN_VALUE, valueOf(5.96046e-8f));
+        assertShortEquals(0x83ff, valueOf(-6.09756e-5f));
+        assertShortEquals(0x8001, valueOf(-5.96046e-8f));
+        // Denormals (flushed to +/-0)
+        assertShortEquals(POSITIVE_ZERO, valueOf(5.96046e-9f));
+        assertShortEquals(NEGATIVE_ZERO, valueOf(-5.96046e-9f));
+    }
+
+    @Test
+    public void testHalfToSingle() {
+        // Zeroes, NaN and infinities
+        assertEquals(0.0f, toFloat(valueOf(0.0f)), 0.00001f);
+        assertEquals(-0.0f, toFloat(valueOf(-0.0f)), 0.00001f);
+        assertEquals(Float.NaN, toFloat(valueOf(Float.NaN)), 0.00001f);
+        assertEquals(Float.POSITIVE_INFINITY, toFloat(valueOf(Float.POSITIVE_INFINITY)), 0.00001f);
+        assertEquals(Float.NEGATIVE_INFINITY, toFloat(valueOf(Float.NEGATIVE_INFINITY)), 0.00001f);
+        // Known values
+        assertEquals(1.0009765625f, toFloat(valueOf(1.0009765625f)), 0.00001f);
+        assertEquals(-2.0f, toFloat(valueOf(-2.0f)), 0.00001f);
+        assertEquals(6.1035156e-5f, toFloat(valueOf(6.10352e-5f)), 0.00001f); // Inexact
+        assertEquals(65504.0f, toFloat(valueOf(65504.0f)), 0.00001f);
+        assertEquals(0.33325195f, toFloat(valueOf(1.0f / 3.0f)), 0.00001f); // Inexact
+        // Denormals (flushed to +/-0)
+        assertEquals(6.097555e-5f, toFloat(valueOf(6.09756e-5f)), 1e-6f);
+        assertEquals(5.9604645e-8f, toFloat(valueOf(5.96046e-8f)), 1e-9f);
+        assertEquals(-6.097555e-5f, toFloat(valueOf(-6.09756e-5f)), 1e-6f);
+        assertEquals(-5.9604645e-8f, toFloat(valueOf(-5.96046e-8f)), 1e-9f);
+    }
+
+    @Test
+    public void testHexString() {
+        assertEquals("NaN", toHexString(NaN));
+        assertEquals("Infinity", toHexString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", toHexString(NEGATIVE_INFINITY));
+        assertEquals("0x0.0p0", toHexString(POSITIVE_ZERO));
+        assertEquals("-0x0.0p0", toHexString(NEGATIVE_ZERO));
+        assertEquals("0x1.0p0", toHexString(valueOf(1.0f)));
+        assertEquals("-0x1.0p0", toHexString(valueOf(-1.0f)));
+        assertEquals("0x1.0p1", toHexString(valueOf(2.0f)));
+        assertEquals("0x1.0p8", toHexString(valueOf(256.0f)));
+        assertEquals("0x1.0p-1", toHexString(valueOf(0.5f)));
+        assertEquals("0x1.0p-2", toHexString(valueOf(0.25f)));
+        assertEquals("0x1.3ffp15", toHexString(MAX_VALUE));
+        assertEquals("0x0.1p-14", toHexString(MIN_VALUE));
+        assertEquals("0x1.0p-14", toHexString(MIN_NORMAL));
+        assertEquals("-0x1.3ffp15", toHexString(LOWEST_VALUE));
+    }
+
+    @Test
+    public void testString() {
+        assertEquals("NaN", Half.toString(NaN));
+        assertEquals("Infinity", Half.toString(POSITIVE_INFINITY));
+        assertEquals("-Infinity", Half.toString(NEGATIVE_INFINITY));
+        assertEquals("0.0", Half.toString(POSITIVE_ZERO));
+        assertEquals("-0.0", Half.toString(NEGATIVE_ZERO));
+        assertEquals("1.0", Half.toString(valueOf(1.0f)));
+        assertEquals("-1.0", Half.toString(valueOf(-1.0f)));
+        assertEquals("2.0", Half.toString(valueOf(2.0f)));
+        assertEquals("256.0", Half.toString(valueOf(256.0f)));
+        assertEquals("0.5", Half.toString(valueOf(0.5f)));
+        assertEquals("0.25", Half.toString(valueOf(0.25f)));
+        assertEquals("65504.0", Half.toString(MAX_VALUE));
+        assertEquals("5.9604645E-8", Half.toString(MIN_VALUE));
+        assertEquals("6.1035156E-5", Half.toString(MIN_NORMAL));
+        assertEquals("-65504.0", Half.toString(LOWEST_VALUE));
+    }
+}
diff --git a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
index d6d1453..3362caf 100644
--- a/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
+++ b/tests/tests/util/src/android/util/cts/TimeUtilsTest.java
@@ -118,4 +118,33 @@
                                      c.getTimeInMillis(),
                                      country);
     }
+
+    @Test
+    public void testFormatDuration() {
+        assertFormatDuration("0", 0);
+        assertFormatDuration("-1ms", -1);
+        assertFormatDuration("+1ms", 1);
+        assertFormatDuration("+10ms", 10);
+        assertFormatDuration("+100ms", 100);
+        assertFormatDuration("+101ms", 101);
+        assertFormatDuration("+330ms", 330);
+        assertFormatDuration("+1s0ms", 1000);
+        assertFormatDuration("+1s330ms", 1330);
+        assertFormatDuration("+10s24ms", 10024);
+        assertFormatDuration("+1m0s30ms", 60030);
+        assertFormatDuration("+1h0m0s30ms", 3600030);
+        assertFormatDuration("+1d0h0m0s30ms", 86400030);
+    }
+
+    @Test
+    public void testFormatHugeDuration() {
+        assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
+        assertFormatDuration("-15542d1h11m11s555ms", -1342833071555L);
+    }
+
+    private void assertFormatDuration(String expected, long duration) {
+        StringBuilder sb = new StringBuilder();
+        TimeUtils.formatDuration(duration, sb);
+        assertEquals("formatDuration(" + duration + ")", expected, sb.toString());
+    }
 }
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index e9a32d4..7c4ca3e 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Instrumentation;
+import android.cts.util.SynchronousPixelCopy;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Color;
@@ -31,8 +32,6 @@
 import android.graphics.SurfaceTexture;
 import android.os.Debug;
 import android.os.Debug.MemoryInfo;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
 import android.support.test.filters.MediumTest;
@@ -40,9 +39,7 @@
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
 import android.view.PixelCopy;
-import android.view.PixelCopy.OnPixelCopyFinishedListener;
 import android.view.Surface;
-import android.view.SurfaceView;
 import android.view.View;
 import android.view.Window;
 
@@ -451,76 +448,6 @@
         return (error < threshold);
     }
 
-    private static class SynchronousPixelCopy implements OnPixelCopyFinishedListener {
-        private static Handler sHandler;
-        static {
-            HandlerThread thread = new HandlerThread("PixelCopyHelper");
-            thread.start();
-            sHandler = new Handler(thread.getLooper());
-        }
-
-        private int mStatus = -1;
-
-        public int request(Surface source, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(Surface source, Rect srcRect, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, srcRect, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(SurfaceView source, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(SurfaceView source, Rect srcRect, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, srcRect, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(Window source, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        public int request(Window source, Rect srcRect, Bitmap dest) {
-            synchronized (this) {
-                PixelCopy.request(source, srcRect, dest, this, sHandler);
-                return getResultLocked();
-            }
-        }
-
-        private int getResultLocked() {
-            try {
-                this.wait(1000);
-            } catch (InterruptedException e) {
-                fail("PixelCopy request didn't complete within 1s");
-            }
-            return mStatus;
-        }
-
-        @Override
-        public void onPixelCopyFinished(int copyResult) {
-            synchronized (this) {
-                mStatus = copyResult;
-                this.notify();
-            }
-        }
-    }
-
     private static class SurfaceTextureRule implements TestRule {
         private SurfaceTexture mSurfaceTexture = null;
         private Surface mSurface = null;
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index 75f5f40..f09b581 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -100,7 +100,7 @@
   google-tf-prod-tests"
 
 for JAR in $OPTIONAL_JARS; do
-    if [ -f "$JAR.jar" ]; then
+    if [ -f "${JAR_DIR}/${JAR}.jar" ]; then
         JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
     fi;
 done
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 83b6382..10bb65c 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -215,4 +215,7 @@
 
     <!-- b/26235244 -->
     <option name="compatibility:exclude-filter" value="android.util.cts.EventLogTest#testWriteEventWithOversizeValue" />
+
+    <!-- b/31803630 -->
+    <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.ListeningPortsTest" />
 </configuration>
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/TestStubs.java
index 7745918..b5de007 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private int TestStubField = 50;
-    // used by testVFE15
+    // used by testVFE15 and testVFE35
     protected int TestStubProtectedField = 50;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/Test_iget.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/Test_iget.java
index c3a0f09..938beec 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/Test_iget.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/Test_iget.java
@@ -31,7 +31,7 @@
 import dot.junit.opcodes.iget.d.T_iget_9;
 
 public class Test_iget extends DxTestCase {
-    
+
     /**
      * @title type - int
      */
@@ -64,9 +64,9 @@
     public void testE2() {
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_9", NullPointerException.class);
     }
-    
+
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -74,23 +74,22 @@
     }
 
     /**
-     * 
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget.d.T_iget_3", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B13 
-     * @title read integer from long field - only field with same name but 
+     * @constraint B13
+     * @title read integer from long field - only field with same name but
      * different type exist
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible private field.
@@ -115,7 +114,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -124,69 +123,63 @@
         //@uses dot.junit.opcodes.iget.d.T_iget_1
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget.d.T_iget_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for short fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget.d.T_iget_15", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for boolean fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget.d.T_iget_16", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for char fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget.d.T_iget_17", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for byte fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget.d.T_iget_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget.d.T_iget_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget.d.T_iget_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read protected field of unrelated class.
@@ -195,18 +188,17 @@
         //@uses dot.junit.opcodes.iget.TestStubs
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_21", IllegalAccessError.class);
     }
-    
+
     /**
      * @constraint A11
      * @title Attempt to read static field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget.TestStubs
         loadAndRun("dot.junit.opcodes.iget.d.T_iget_5", IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
+     * @constraint B6
      * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
@@ -214,11 +206,20 @@
     }
 
     /**
-     * @constraint N/A 
+     * @constraint N/A
      * @title instance fields may only be accessed on reference values.
      */
     public void testVFE31() {
         load("dot.junit.opcodes.iget.d.T_iget_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget.TestStubs
+        load("dot.junit.opcodes.iget.d.T_iget_35", VerifyError.class);
+    }
 }
 
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.d
new file mode 100644
index 0000000..57df084
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.d
@@ -0,0 +1,31 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_35.java
+.class public dot.junit.opcodes.iget.d.T_iget_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()I
+.limit regs 2
+       iget v0, v1, dot.junit.opcodes.iget.TestStubs.TestStubProtectedField I
+       return v0
+.end method
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.java
new file mode 100644
index 0000000..696a6a1f
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget/d/T_iget_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget.d;
+
+public class T_iget_35 {
+
+    public int run() {
+        return 0;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/TestStubs.java
index 8dcd427..af78d741 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private boolean TestStubField = true;
-    // used by testVFE15
+    // used by testVFE15 and testVFE35
     protected boolean TestStubProtectedField = true;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/Test_iget_boolean.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/Test_iget_boolean.java
index f16b89c..1f6a94a 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/Test_iget_boolean.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/Test_iget_boolean.java
@@ -30,16 +30,15 @@
 import dot.junit.opcodes.iget_boolean.d.T_iget_boolean_9;
 
 public class Test_iget_boolean extends DxTestCase {
-    
+
     /**
-     * @title get boolean from field 
+     * @title get boolean from field
      */
     public void testN1() {
         T_iget_boolean_1 t = new T_iget_boolean_1();
         assertEquals(true, t.run());
     }
 
-
     /**
      * @title access protected field from subclass
      */
@@ -59,7 +58,7 @@
     }
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -67,22 +66,22 @@
     }
 
     /**
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_3", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B13 
-     * @title read boolean from long field - only field with same name but 
+     * @constraint B13
+     * @title read boolean from long field - only field with same name but
      * different type exists
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field
@@ -108,7 +107,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -118,64 +117,63 @@
         //@uses dot.junit.opcodes.iget_boolean.d.T_iget_boolean_12
         loadAndRun("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for short fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_15", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for int fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_16", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for char fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_17", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for byte fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_boolean shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -191,14 +189,13 @@
      * @title Attempt to read static field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget_boolean.TestStubs
         loadAndRun("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_5",
                    IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_30", VerifyError.class);
@@ -211,4 +208,13 @@
     public void testVFE31() {
         load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_boolean.TestStubs
+        load("dot.junit.opcodes.iget_boolean.d.T_iget_boolean_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.d
new file mode 100644
index 0000000..babcc08
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.d
@@ -0,0 +1,31 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_boolean_35.java
+.class public dot.junit.opcodes.iget_boolean.d.T_iget_boolean_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()Z
+.limit regs 2
+       iget-boolean v0, v1, dot.junit.opcodes.iget_boolean.TestStubs.TestStubProtectedField Z
+       return v0
+.end method
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.java
new file mode 100644
index 0000000..7c95c37
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_boolean/d/T_iget_boolean_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_boolean.d;
+
+public class T_iget_boolean_35 {
+
+    public boolean run(){
+        return false;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/TestStubs.java
index 90b1f13..ffae3b1 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private byte TestStubField = 50;
-    // ussed by testVFE15
+    // used by testVFE15 and testVFE35
     protected byte TestStubProtectedField = 50;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/Test_iget_byte.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/Test_iget_byte.java
index 410dad4..4e7bbc7 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/Test_iget_byte.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/Test_iget_byte.java
@@ -30,16 +30,15 @@
 import dot.junit.opcodes.iget_byte.d.T_iget_byte_9;
 
 public class Test_iget_byte extends DxTestCase {
-    
+
     /**
-     * @title get byte from field 
+     * @title get byte from field
      */
     public void testN1() {
         T_iget_byte_1 t = new T_iget_byte_1();
         assertEquals(77, t.run());
     }
 
-
     /**
      * @title access protected field from subclass
      */
@@ -55,10 +54,10 @@
      */
     public void testE2() {
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_9", NullPointerException.class);
-    }   
+    }
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title  constant pool index
      */
     public void testVFE1() {
@@ -66,22 +65,22 @@
     }
 
     /**
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_3", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B13 
-     * @title read byte from long field - only field with same name but 
+     * @constraint B13
+     * @title read byte from long field - only field with same name but
      * different type exists
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field.
@@ -106,7 +105,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -115,63 +114,63 @@
         //@uses dot.junit.opcodes.iget_byte.d.T_iget_byte_1
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_14", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for short fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_15", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for int fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_16", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for char fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_17", VerifyError.class);
     }
-    
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for boolean fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_byte shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -181,20 +180,18 @@
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_21", IllegalAccessError.class);
     }
 
-
     /**
      * @constraint A11
      * @title Attempt to read static  field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget_byte.TestStubs
         loadAndRun("dot.junit.opcodes.iget_byte.d.T_iget_byte_5",
                    IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_30", VerifyError.class);
@@ -207,4 +204,13 @@
     public void testVFE31() {
         load("dot.junit.opcodes.iget_byte.d.T_iget_byte_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_byte.TestStubs
+        load("dot.junit.opcodes.iget_byte.d.T_iget_byte_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.d
new file mode 100644
index 0000000..8792c96
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.d
@@ -0,0 +1,33 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_byte_35.java
+.class public dot.junit.opcodes.iget_byte.d.T_iget_byte_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()B
+.limit regs 2
+       iget-byte v0, v1, dot.junit.opcodes.iget_byte.TestStubs.TestStubProtectedField B
+       return v0
+.end method
+
+
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.java
new file mode 100644
index 0000000..17e78f1
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_byte/d/T_iget_byte_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_byte.d;
+
+public class T_iget_byte_35 {
+
+    public byte run() {
+        return 0;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/TestStubs.java
index 5bf73ae..6969a104 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private char TestStubField = 50;
-    // ussed by testVFE15
+    // ussed by testVFE15 and testVFE35
     protected char TestStubProtectedField = 50;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/Test_iget_char.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/Test_iget_char.java
index ff86ae3..c2b8f1c 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/Test_iget_char.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/Test_iget_char.java
@@ -30,9 +30,9 @@
 import dot.junit.opcodes.iget_char.d.T_iget_char_9;
 
 public class Test_iget_char extends DxTestCase {
-    
+
     /**
-     * @title get char from field 
+     * @title get char from field
      */
     public void testN1() {
         T_iget_char_1 t = new T_iget_char_1();
@@ -56,10 +56,9 @@
     public void testE2() {
         loadAndRun("dot.junit.opcodes.iget_char.d.T_iget_char_9", NullPointerException.class);
     }
-   
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -67,24 +66,22 @@
     }
 
     /**
-     * 
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_3", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B13 
-     * @title read char from long field - only field with same name but 
+     * @constraint B13
+     * @title read char from long field - only field with same name but
      * different type exists
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_char.d.T_iget_char_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field.
@@ -109,7 +106,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget_char.d.T_iget_char_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -118,67 +115,63 @@
         //@uses dot.junit.opcodes.iget_char.d.T_iget_char_1
         loadAndRun("dot.junit.opcodes.iget_char.d.T_iget_char_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for short fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_15", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for int fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_16", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for byte fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_17", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for boolean fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_char shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -194,15 +187,13 @@
      * @title Attempt to read static  field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget_char.TestStubs
         loadAndRun("dot.junit.opcodes.iget_char.d.T_iget_char_5",
                    IncompatibleClassChangeError.class);
     }
-    
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_30", VerifyError.class);
@@ -215,4 +206,13 @@
     public void testVFE31() {
         load("dot.junit.opcodes.iget_char.d.T_iget_char_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_char.TestStubs
+        load("dot.junit.opcodes.iget_char.d.T_iget_char_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.d
new file mode 100644
index 0000000..53ac999
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.d
@@ -0,0 +1,31 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_char_35.java
+.class public dot.junit.opcodes.iget_char.d.T_iget_char_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()C
+.limit regs 2
+       iget-char v0, v1, dot.junit.opcodes.iget_char.TestStubs.TestStubProtectedField C
+       return v0
+.end method
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.java
new file mode 100644
index 0000000..0b3434a
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_char/d/T_iget_char_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_char.d;
+
+public class T_iget_char_35 {
+
+    public char run() {
+        return 0;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/TestStubs.java
index 0a68e56..74d7f93 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private Object TestStubField = null;
-    // used by testVFE15
+    // used by testVFE16 and testVFE35
     protected Object TestStubProtectedField = null;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/Test_iget_object.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/Test_iget_object.java
index 7314141..9ae5548 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/Test_iget_object.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/Test_iget_object.java
@@ -24,6 +24,7 @@
 import dot.junit.opcodes.iget_object.d.T_iget_object_13;
 import dot.junit.opcodes.iget_object.d.T_iget_object_21;
 import dot.junit.opcodes.iget_object.d.T_iget_object_22;
+import dot.junit.opcodes.iget_object.d.T_iget_object_35;
 import dot.junit.opcodes.iget_object.d.T_iget_object_5;
 import dot.junit.opcodes.iget_object.d.T_iget_object_6;
 import dot.junit.opcodes.iget_object.d.T_iget_object_7;
@@ -31,9 +32,9 @@
 import dot.junit.opcodes.iget_object.d.T_iget_object_9;
 
 public class Test_iget_object extends DxTestCase {
-    
+
     /**
-     * @title get reference from field 
+     * @title get reference from field
      */
     public void testN1() {
         T_iget_object_1 t = new T_iget_object_1();
@@ -56,10 +57,10 @@
      */
     public void testE2() {
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_9", NullPointerException.class);
-    }  
+    }
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -67,24 +68,22 @@
     }
 
     /**
-     * 
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_3", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B13 
-     * @title  (read object from long field - only field with same name but 
+     * @constraint B13
+     * @title  (read object from long field - only field with same name but
      * different type exists)
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field.
@@ -109,7 +108,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -118,78 +117,71 @@
         //@uses dot.junit.opcodes.iget_object.d.T_iget_object_1
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for short fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for char fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_15", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for int fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_16", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for byte fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_17", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for boolean fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_object shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_20", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * 
-     * @constraint B13 
+     * @constraint B13
      * @title  only field of different type exists
      */
     public void testVFE15() {
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_21", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -204,14 +196,13 @@
      * @title Attempt to read static field.
      */
     public void testVFE17() {
-        //@uses dot.junit.opcodes.iget_object.TestStubs
         loadAndRun("dot.junit.opcodes.iget_object.d.T_iget_object_5",
                    IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_30", VerifyError.class);
@@ -219,9 +210,18 @@
 
     /**
      * @constraint N/A
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE31() {
         load("dot.junit.opcodes.iget_object.d.T_iget_object_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_object.TestStubs
+        load("dot.junit.opcodes.iget_object.d.T_iget_object_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.d
new file mode 100644
index 0000000..a4fc423
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.d
@@ -0,0 +1,31 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_object_35.java
+.class public dot.junit.opcodes.iget_object.d.T_iget_object_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()Ljava/lang/Object;
+.limit regs 2
+       iget-object v0, v1, dot.junit.opcodes.iget_object.TestStubs.TestStubProtectedField Ljava/lang/Object;
+       return-object v0
+.end method
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.java
new file mode 100644
index 0000000..f7ceb9b
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_object/d/T_iget_object_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_object.d;
+
+public class T_iget_object_35  {
+
+    public Object run() {
+        return null;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/TestStubs.java
index 8580ec3..f299301 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private short TestStubField = 50;
-    // used by testVFE15
+    // used by testVFE15 and testVFE35
     protected short TestStubProtectedField = 50;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/Test_iget_short.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/Test_iget_short.java
index 566ec3f..bd77708 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/Test_iget_short.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/Test_iget_short.java
@@ -30,7 +30,7 @@
 import dot.junit.opcodes.iget_short.d.T_iget_short_9;
 
 public class Test_iget_short extends DxTestCase {
-    
+
     /**
      * @title get short from field
      */
@@ -58,7 +58,7 @@
     }
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -66,24 +66,22 @@
     }
 
     /**
-     * 
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_3", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B13 
-     * @title read short from long field - only field with same name but 
+     * @constraint B13
+     * @title read short from long field - only field with same name but
      * different type exists
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_short.d.T_iget_short_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field.
@@ -108,7 +106,7 @@
     public void testVFE6() {
         loadAndRun("dot.junit.opcodes.iget_short.d.T_iget_short_8", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read superclass' private field from subclass.
@@ -117,69 +115,63 @@
         //@uses dot.junit.opcodes.iget_short.d.T_iget_short_1
         loadAndRun("dot.junit.opcodes.iget_short.d.T_iget_short_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for char fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_15", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for int fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_16", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for byte fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_17", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for boolean fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for double fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget_short shall not work for long fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -194,24 +186,32 @@
      * @title Attempt to read static  field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget_short.TestStubs
         loadAndRun("dot.junit.opcodes.iget_short.d.T_iget_short_5",
                    IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_30", VerifyError.class);
     }
 
     /**
-     * @constraint N/A 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint N/A
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE31() {
         load("dot.junit.opcodes.iget_short.d.T_iget_short_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_short.TestStubs
+        load("dot.junit.opcodes.iget_short.d.T_iget_short_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.d
index e806df2..f3298fb 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.d
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.d
@@ -24,14 +24,14 @@
        return-void
 .end method
 
-.method public run()V
+.method public run()S
 .limit regs 3
 
        new-instance v0, Ldot/junit/opcodes/iget_short/TestStubs;
        invoke-direct {v0}, dot/junit/opcodes/iget_short/TestStubs/<init>()V
-       
+
        iget-short v1, v0, dot.junit.opcodes.iget_short.TestStubs.TestStubProtectedField S
-       return-void
+       return v1
 .end method
 
 
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.java
index 5bb7f6e..bcb8dca 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_21.java
@@ -18,6 +18,7 @@
 
 public class T_iget_short_21 {
 
-    public void run() {
+    public short run() {
+        return 0;
     }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.d
new file mode 100644
index 0000000..5cde5bb
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.d
@@ -0,0 +1,32 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_short_35.java
+.class public dot.junit.opcodes.iget_short.d.T_iget_short_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()S
+.limit regs 2
+       iget-short v0, v1, dot.junit.opcodes.iget_short.TestStubs.TestStubProtectedField S
+       return v0
+.end method
+
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.java
new file mode 100644
index 0000000..f92f2b6
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_short/d/T_iget_short_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_short.d;
+
+public class T_iget_short_35 {
+
+    public short run() {
+        return 0;
+    }
+}
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/TestStubs.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/TestStubs.java
index f90a470..79e71c4 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/TestStubs.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/TestStubs.java
@@ -19,6 +19,6 @@
 public class TestStubs {
     // used by testVFE4
     private long TestStubField = 50;
-    // ussed by testVFE15
+    // ussed by testVFE15 and testVFE35
     protected long TestStubProtectedField = 50;
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/Test_iget_wide.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/Test_iget_wide.java
index f82a1d3..6bb996f 100644
--- a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/Test_iget_wide.java
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/Test_iget_wide.java
@@ -31,7 +31,7 @@
 import dot.junit.opcodes.iget_wide.d.T_iget_wide_9;
 
 public class Test_iget_wide extends DxTestCase {
-    
+
     /**
      * @title type - long
      */
@@ -63,10 +63,10 @@
      */
     public void testE2() {
         loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_9", NullPointerException.class);
-    }   
+    }
 
     /**
-     * @constraint A11 
+     * @constraint A11
      * @title constant pool index
      */
     public void testVFE1() {
@@ -74,24 +74,22 @@
     }
 
     /**
-     * 
-     * @constraint A23 
+     * @constraint A23
      * @title number of registers
      */
     public void testVFE2() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_3", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B13 
-     * @title read long from integer field - only field with same name but 
+     * @constraint B13
+     * @title read long from integer field - only field with same name but
      * different type exists
      */
     public void testVFE3() {
         loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_13", NoSuchFieldError.class);
     }
-    
+
     /**
      * @constraint n/a
      * @title Attempt to read inaccessible field.
@@ -103,7 +101,7 @@
 
     /**
      * @constraint n/a
-     * @title Attempt to read field of undefined class. 
+     * @title Attempt to read field of undefined class.
      */
     public void testVFE5() {
         loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_7", NoClassDefFoundError.class);
@@ -125,69 +123,63 @@
         //@uses dot.junit.opcodes.iget_wide.d.T_iget_wide_1
         loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_12", IllegalAccessError.class);
     }
-   
+
     /**
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for reference fields
      */
     public void testVFE8() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_14", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for short fields
      */
     public void testVFE9() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_15", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for boolean fields
      */
     public void testVFE10() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_16", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for char fields
      */
     public void testVFE11() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_17", VerifyError.class);
     }
-    
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for byte fields
      */
     public void testVFE12() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_18", VerifyError.class);
-    }    
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for float fields
      */
     public void testVFE13() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_19", VerifyError.class);
-    } 
-    
+    }
+
     /**
-     * 
-     * @constraint B1 
+     * @constraint B1
      * @title iget-wide shall not work for int fields
      */
     public void testVFE14() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_20", VerifyError.class);
     }
-    
+
     /**
      * @constraint B12
      * @title Attempt to read inaccessible protected field.
@@ -202,14 +194,13 @@
      * @title Attempt to read static  field.
      */
     public void testVFE16() {
-        //@uses dot.junit.opcodes.iget_wide.TestStubs
-        loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_5", 
+        loadAndRun("dot.junit.opcodes.iget_wide.d.T_iget_wide_5",
                    IncompatibleClassChangeError.class);
     }
 
     /**
-     * @constraint B6 
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @constraint B6
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE30() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_30", VerifyError.class);
@@ -217,9 +208,18 @@
 
     /**
      * @constraint N/A
-     * @title instance fields may only be accessed on already initialized instances. 
+     * @title instance fields may only be accessed on already initialized instances.
      */
     public void testVFE31() {
         load("dot.junit.opcodes.iget_wide.d.T_iget_wide_31", VerifyError.class);
     }
+
+    /**
+     * @constraint N/A
+     * @title Attempt to read inaccessible protected field on uninitialized reference.
+     */
+    public void testVFE35() {
+        //@uses dot.junit.opcodes.iget_wide.TestStubs
+        load("dot.junit.opcodes.iget_wide.d.T_iget_wide_35", VerifyError.class);
+    }
 }
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.d b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.d
new file mode 100644
index 0000000..505b06e
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.d
@@ -0,0 +1,31 @@
+; Copyright (C) 2016 The Android Open Source Project
+;
+; Licensed under the Apache License, Version 2.0 (the "License");
+; you may not use this file except in compliance with the License.
+; You may obtain a copy of the License at
+;
+;      http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing, software
+; distributed under the License is distributed on an "AS IS" BASIS,
+; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+; See the License for the specific language governing permissions and
+; limitations under the License.
+
+.source T_iget_wide_35.java
+.class public dot.junit.opcodes.iget_wide.d.T_iget_wide_35
+.super java/lang/Object
+
+.method public <init>()V
+.limit regs 1
+       invoke-direct {v0}, java/lang/Object/<init>()V
+       return-void
+.end method
+
+.method public run()J
+.limit regs 2
+       iget-wide v0, v1, dot.junit.opcodes.iget_wide.TestStubs.TestStubProtectedField J
+       return-wide v0
+.end method
+
+
diff --git a/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.java b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.java
new file mode 100644
index 0000000..5a8fc86
--- /dev/null
+++ b/tools/vm-tests-tf/src/dot/junit/opcodes/iget_wide/d/T_iget_wide_35.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package dot.junit.opcodes.iget_wide.d;
+
+public class T_iget_wide_35 {
+
+    public long run() {
+        return -99;
+    }
+}