Merge "Add empty DynamicConfig.xml at suite-level to CTS"
diff --git a/common/device-side/device-info/Android.mk b/common/device-side/device-info/Android.mk
index c04b51d..927101b 100644
--- a/common/device-side/device-info/Android.mk
+++ b/common/device-side/device-info/Android.mk
@@ -22,7 +22,8 @@
 
 LOCAL_MODULE := compatibility-device-info
 
-LOCAL_SDK_VERSION := current
+# uncomment when b/13282254 is fixed
+#LOCAL_SDK_VERSION := current
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
index 969e85d..467269e 100644
--- a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GenericDeviceInfo.java
@@ -17,6 +17,10 @@
 
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Environment;
+import android.os.SystemProperties;
+import android.os.UserManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 
 import java.lang.Integer;
@@ -51,7 +55,7 @@
     public static final String BUILD_VERSION_SDK = "build_version_sdk";
     public static final String BUILD_VERSION_SDK_INT = "build_version_sdk_int";
     public static final String BUILD_VERSION_BASE_OS = "build_version_base_os";
-    public static final String BUILD_VERSION_SECURITY_PATH = "build_version_security_patch";
+    public static final String BUILD_VERSION_SECURITY_PATCH = "build_version_security_patch";
 
     private final Map<String, String> mDeviceInfo = new HashMap<>();
 
@@ -73,12 +77,23 @@
         addDeviceInfo(BUILD_VERSION_SDK, Build.VERSION.SDK);
         addDeviceInfo(BUILD_VERSION_SDK_INT, Integer.toString(Build.VERSION.SDK_INT));
 
+        // Collect build fields available in API level 21
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             addDeviceInfo(BUILD_ABIS, TextUtils.join(",", Build.SUPPORTED_ABIS));
             addDeviceInfo(BUILD_ABIS_32, TextUtils.join(",", Build.SUPPORTED_32_BIT_ABIS));
             addDeviceInfo(BUILD_ABIS_64, TextUtils.join(",", Build.SUPPORTED_64_BIT_ABIS));
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             addDeviceInfo(BUILD_VERSION_BASE_OS, Build.VERSION.BASE_OS);
-            addDeviceInfo(BUILD_VERSION_SECURITY_PATH, Build.VERSION.SECURITY_PATCH);
+            addDeviceInfo(BUILD_VERSION_SECURITY_PATCH, Build.VERSION.SECURITY_PATCH);
+        } else {
+            // Access system properties directly because Build.Version.BASE_OS and
+            // Build.Version.SECURITY_PATCH are not defined pre-M.
+            addDeviceInfo(BUILD_VERSION_BASE_OS,
+                    SystemProperties.get("ro.build.version.base_os", ""));
+            addDeviceInfo(BUILD_VERSION_SECURITY_PATCH,
+                    SystemProperties.get("ro.build.version.security_patch", ""));
         }
     }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 32a1789..c49340e 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -164,15 +164,20 @@
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(READ_PKG);
             getDevice().uninstallPackage(WRITE_PKG);
-            String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+            final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+
+            // We purposefully delay the installation of the reading apps to
+            // verify that the daemon correctly invalidates any caches.
+            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
+            for (int user : users) {
+                runDeviceTests(WRITE_PKG, ".WriteGiftTest", user);
+            }
+
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
-            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
-
             for (int user : users) {
-                runDeviceTests(WRITE_PKG, "WriteGiftTest", user);
-                runDeviceTests(READ_PKG, "ReadGiftTest", user);
-                runDeviceTests(NONE_PKG, "GiftTest", user);
+                runDeviceTests(READ_PKG, ".ReadGiftTest", user);
+                runDeviceTests(NONE_PKG, ".GiftTest", user);
             }
         } finally {
             getDevice().uninstallPackage(NONE_PKG);
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
index 40d3cff..ba27114 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/src/com/android/cts/appaccessdata/AccessPrivateDataTest.java
@@ -18,17 +18,20 @@
 
 import java.io.BufferedReader;
 import java.io.DataInputStream;
+import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.IOException;
 
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.test.AndroidTestCase;
 
 /**
  * Test that another app's private data cannot be accessed, while its public data can.
  *
- * Assumes that {@link APP_WITH_DATA_PKG} has already created the private and public data.
+ * Assumes that {@link #APP_WITH_DATA_PKG} has already created the private and public data.
  */
 public class AccessPrivateDataTest extends AndroidTestCase {
 
@@ -39,12 +42,12 @@
 
     /**
      * Name of private file to access. This must match the name of the file created by
-     * {@link APP_WITH_DATA_PKG}.
+     * {@link #APP_WITH_DATA_PKG}.
      */
     private static final String PRIVATE_FILE_NAME = "private_file.txt";
     /**
      * Name of public file to access. This must match the name of the file created by
-     * {@link APP_WITH_DATA_PKG}.
+     * {@link #APP_WITH_DATA_PKG}.
      */
     private static final String PUBLIC_FILE_NAME = "public_file.txt";
 
@@ -56,20 +59,26 @@
     public void testAccessPrivateData() throws IOException {
         try {
             // construct the absolute file path to the app's private file
-            String privateFilePath = String.format("/data/data/%s/%s", APP_WITH_DATA_PKG,
-                    PRIVATE_FILE_NAME);
-            FileInputStream inputStream = new FileInputStream(privateFilePath);
+            ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+            File privateFile = new File(applicationInfo.dataDir, "files/" + PRIVATE_FILE_NAME);
+            FileInputStream inputStream = new FileInputStream(privateFile);
             inputStream.read();
             inputStream.close();
             fail("Was able to access another app's private data");
-        } catch (FileNotFoundException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             // expected
-        } catch (SecurityException e) {
-            // also valid
         }
         accessPrivateTrafficStats();
     }
 
+    private ApplicationInfo getApplicationInfo(String packageName) {
+        try {
+            return mContext.getPackageManager().getApplicationInfo(packageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new IllegalStateException("Expected package not found: " + e);
+        }
+    }
+
     /**
      * Tests that another app's public file can be accessed
      * @throws IOException
@@ -86,10 +95,10 @@
 
     private int getOtherAppUid() throws IOException, FileNotFoundException, SecurityException {
         // construct the absolute file path to the other app's public file
-        String publicFilePath = String.format("/data/data/%s/files/%s", APP_WITH_DATA_PKG,
-                PUBLIC_FILE_NAME);
-        DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFilePath));
-        int otherAppUid = (int)inputStream.readInt();
+        ApplicationInfo applicationInfo = getApplicationInfo(APP_WITH_DATA_PKG);
+        File publicFile = new File(applicationInfo.dataDir, "files/" + PUBLIC_FILE_NAME);
+        DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFile));
+        int otherAppUid = inputStream.readInt();
         inputStream.close();
         return otherAppUid;
     }
@@ -98,9 +107,7 @@
         int otherAppUid = -1;
         try {
             otherAppUid = getOtherAppUid();
-        } catch (FileNotFoundException e) {
-            fail("Was not able to access another app's public file: " + e);
-        } catch (SecurityException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             fail("Was not able to access another app's public file: " + e);
         }
 
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
index e11681a..378ef42 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/src/com/android/cts/appwithdata/CreatePrivateDataTest.java
@@ -24,8 +24,8 @@
 import android.database.sqlite.SQLiteOpenHelper;
 import android.net.TrafficStats;
 import android.test.AndroidTestCase;
-import android.util.Log;
 
+import java.io.File;
 import java.net.ServerSocket;
 import java.net.Socket;
 
@@ -97,14 +97,11 @@
         try {
             // construct the absolute file path to the app's public's file the same
             // way as the appaccessdata package will.
-            String publicFilePath = String.format("/data/data/%s/files/%s", APP_WITH_DATA_PKG,
-                    PUBLIC_FILE_NAME);
-            DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFilePath));
-            int otherAppUid = (int)inputStream.readInt();
+            File publicFile = new File(mContext.getFilesDir(), PUBLIC_FILE_NAME);
+            DataInputStream inputStream = new DataInputStream(new FileInputStream(publicFile));
+            inputStream.readInt();
             inputStream.close();
-        } catch (FileNotFoundException e) {
-            fail("Was not able to access own public file: " + e);
-        } catch (SecurityException e) {
+        } catch (FileNotFoundException | SecurityException e) {
             fail("Was not able to access own public file: " + e);
         }
     }
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 7fe0b80..4bd494d 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -149,6 +149,22 @@
         return paths;
     }
 
+    /**
+     * Return a set of several package-specific external storage paths pointing
+     * at "gift" files designed to be exchanged with the target package.
+     */
+    public static List<File> getAllPackageSpecificGiftPaths(Context context,
+            String targetPackageName) {
+        final List<File> files = getAllPackageSpecificPaths(context);
+        final List<File> targetFiles = new ArrayList<>();
+        for (File file : files) {
+            final File targetFile = new File(
+                    file.getAbsolutePath().replace(context.getPackageName(), targetPackageName));
+            targetFiles.add(new File(targetFile, targetPackageName + ".gift"));
+        }
+        return targetFiles;
+    }
+
     public static List<File> getPrimaryPackageSpecificPaths(Context context) {
         final List<File> paths = new ArrayList<File>();
         Collections.addAll(paths, context.getExternalCacheDir());
@@ -189,12 +205,6 @@
         return after;
     }
 
-    public static File buildGiftForPackage(Context context, String packageName) {
-        final File myCache = context.getExternalCacheDir();
-        return new File(myCache.getAbsolutePath().replace(context.getPackageName(), packageName),
-                packageName + ".gift");
-    }
-
     public static File buildProbeFile(File dir) {
         return new File(dir, ".probe_" + System.nanoTime());
     }
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
index e482b2f..14a0180 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
@@ -21,26 +21,33 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class GiftTest extends AndroidTestCase {
     /**
      * Verify we can read only our gifts.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        assertFileReadWriteAccess(none);
-        assertEquals(100, readInt(none));
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            assertFileReadWriteAccess(none);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        assertFileNoAccess(read);
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            assertFileNoAccess(read);
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        assertFileNoAccess(write);
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            assertFileNoAccess(write);
+        }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
index e72be77..78bb738 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
@@ -21,28 +21,35 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadOnlyAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class ReadGiftTest extends AndroidTestCase {
     /**
      * Verify we can read all gifts.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        assertFileReadOnlyAccess(none);
-        assertEquals(100, readInt(none));
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            assertFileReadOnlyAccess(none);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        assertFileReadWriteAccess(read);
-        assertEquals(101, readInt(read));
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            assertFileReadWriteAccess(read);
+            assertEquals(101, readInt(read));
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        assertFileReadOnlyAccess(write);
-        assertEquals(102, readInt(write));
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            assertFileReadOnlyAccess(write);
+            assertEquals(102, readInt(write));
+        }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 3861ddf..ea6c0ea 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -16,6 +16,7 @@
 
 package com.android.cts.writeexternalstorageapp;
 
+import static android.test.MoreAsserts.assertNotEqual;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.TAG;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoWriteAccess;
@@ -31,7 +32,10 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
 
 import android.os.Environment;
+import android.os.SystemClock;
+import android.system.Os;
 import android.test.AndroidTestCase;
+import android.text.format.DateUtils;
 import android.util.Log;
 
 import com.android.cts.externalstorageapp.CommonExternalStorageTest;
@@ -297,4 +301,29 @@
             }
         }
     }
+
+    /**
+     * Verify that moving around package-specific directories causes permissions
+     * to be updated.
+     */
+    public void testMovePackageSpecificPaths() throws Exception {
+        final File before = getContext().getExternalCacheDir();
+        final File beforeFile = new File(before, "test.probe");
+        assertTrue(beforeFile.createNewFile());
+        assertEquals(Os.getuid(), Os.stat(before.getAbsolutePath()).st_uid);
+        assertEquals(Os.getuid(), Os.stat(beforeFile.getAbsolutePath()).st_uid);
+
+        final File after = new File(before.getAbsolutePath()
+                .replace(getContext().getPackageName(), "com.example.does.not.exist"));
+        after.getParentFile().mkdirs();
+
+        Os.rename(before.getAbsolutePath(), after.getAbsolutePath());
+
+        // Sit around long enough for VFS cache to expire
+        SystemClock.sleep(15 * DateUtils.SECOND_IN_MILLIS);
+
+        final File afterFile = new File(after, "test.probe");
+        assertNotEqual(Os.getuid(), Os.stat(after.getAbsolutePath()).st_uid);
+        assertNotEqual(Os.getuid(), Os.stat(afterFile.getAbsolutePath()).st_uid);
+    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
index 5da42da..db3813f 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
@@ -20,41 +20,48 @@
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.buildGiftForPackage;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.writeInt;
 
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
 
 public class WriteGiftTest extends AndroidTestCase {
     /**
      * Leave gifts for other packages in their primary external cache dirs.
      */
     public void testGifts() throws Exception {
-        final File none = buildGiftForPackage(getContext(), PACKAGE_NONE);
-        none.getParentFile().mkdirs();
-        none.createNewFile();
-        assertFileReadWriteAccess(none);
+        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+        for (File none : noneList) {
+            none.getParentFile().mkdirs();
+            none.createNewFile();
+            assertFileReadWriteAccess(none);
 
-        writeInt(none, 100);
-        assertEquals(100, readInt(none));
+            writeInt(none, 100);
+            assertEquals(100, readInt(none));
+        }
 
-        final File read = buildGiftForPackage(getContext(), PACKAGE_READ);
-        read.getParentFile().mkdirs();
-        read.createNewFile();
-        assertFileReadWriteAccess(read);
+        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+        for (File read : readList) {
+            read.getParentFile().mkdirs();
+            read.createNewFile();
+            assertFileReadWriteAccess(read);
 
-        writeInt(read, 101);
-        assertEquals(101, readInt(read));
+            writeInt(read, 101);
+            assertEquals(101, readInt(read));
+        }
 
-        final File write = buildGiftForPackage(getContext(), PACKAGE_WRITE);
-        write.getParentFile().mkdirs();
-        write.createNewFile();
-        assertFileReadWriteAccess(write);
+        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
+        for (File write : writeList) {
+            write.getParentFile().mkdirs();
+            write.createNewFile();
+            assertFileReadWriteAccess(write);
 
-        writeInt(write, 102);
-        assertEquals(102, readInt(write));
+            writeInt(write, 102);
+            assertEquals(102, readInt(write));
+        }
     }
 }
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 7bf46a3..022e2f4 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -353,9 +353,9 @@
      */
     public void testValidServiceContexts() throws Exception {
 
-        /* run checkfc -p on service_contexts */
+        /* run checkfc -s on service_contexts */
         ProcessBuilder pb = new ProcessBuilder(checkFc.getAbsolutePath(),
-                "-p", devicePolicyFile.getAbsolutePath(),
+                "-s", devicePolicyFile.getAbsolutePath(),
                 deviceSvcFile.getAbsolutePath());
         pb.redirectOutput(ProcessBuilder.Redirect.PIPE);
         pb.redirectErrorStream(true);
diff --git a/hostsidetests/services/activitymanager/OldAndroidTest.xml b/hostsidetests/services/activitymanager/OldAndroidTest.xml
index 669fe02..ba9d998 100644
--- a/hostsidetests/services/activitymanager/OldAndroidTest.xml
+++ b/hostsidetests/services/activitymanager/OldAndroidTest.xml
@@ -15,5 +15,6 @@
 -->
 <configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
     <include name="common-config" />
-    <option name="cts-apk-installer:test-file-name" value="CtsDeviceServicesTestApp.apk" />
+    <!-- This will tell tradefed to install the test apk. -->
+    <option name="cts-apk-installer:test-file-name" value="CtsServicesTestApp.apk" />
 </configuration>
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
index 027a73d..3cd5219 100755
--- a/hostsidetests/services/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
@@ -21,8 +21,14 @@
     <application>
         <activity android:name=".TestActivity"
                 android:resizeable="true"
+        />
+        <activity android:name=".LaunchToSideActivity"
+                android:resizeable="true"
+        />
+        <activity android:name=".PipActivity"
+                android:resizeable="true"
                 android:supportsPictureInPicture="true"
-                />
+        />
     </application>
 </manifest>
 
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
new file mode 100644
index 0000000..31c169e
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/LaunchToSideActivity.java
@@ -0,0 +1,24 @@
+package android.server.app;
+
+import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class LaunchToSideActivity extends Activity {
+    private static final String TAG = "LaunchToSide";
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        final Bundle extras = intent.getExtras();
+         if (extras != null && extras.getBoolean("launch_to_the_side")) {
+            Intent newIntent = new Intent("android.settings.SETTINGS");
+            newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_LAUNCH_TO_SIDE);
+            startActivity(newIntent);
+        }
+    }
+}
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
new file mode 100644
index 0000000..8a89deb
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/PipActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.server.app;
+
+import android.app.Activity;
+
+public class PipActivity extends Activity {
+    @Override
+    protected void onResume() {
+        super.onResume();
+        enterPictureInPictureMode();
+    }
+}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
index b31a945..aed23d8 100644
--- a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
@@ -20,6 +20,7 @@
 import com.android.tradefed.device.CollectingOutputReceiver;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceTestCase;
 
@@ -44,21 +45,32 @@
     /** ID of stack that occupies a dedicated region of the screen. */
     public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
 
+    /** ID of stack that always on top (always visible) when it exist. */
+    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+
     private static final String STACK_ID_PREFIX = "Stack id=";
     private static final String TASK_ID_PREFIX = "taskId";
 
     private static final String TEST_ACTIVITY_NAME = "TestActivity";
+    private static final String LAUNCH_TO_SIDE_ACTIVITY_NAME = "LaunchToSideActivity";
+    private static final String PIP_ACTIVITY_NAME = "PipActivity";
 
     private static final String AM_STACK_LIST = "am stack list";
-    private static final String AM_START_ACTIVITY = "am start -n android.server.app/.TestActivity";
-    private static final String AM_FORCE_STOP = "am force-stop android.server.app";
+    private static final String AM_START_TEST_ACTIVITY =
+            "am start -n android.server.app/." + TEST_ACTIVITY_NAME;
+    private static final String AM_START_LAUNCH_TO_SIDE_ACTIVITY =
+            "am start -n android.server.app/." + LAUNCH_TO_SIDE_ACTIVITY_NAME;
+    private static final String AM_START_PIP_ACTIVITY =
+            "am start -n android.server.app/." + PIP_ACTIVITY_NAME;
+    private static final String AM_FORCE_STOP_TEST = "am force-stop android.server.app";
+    private static final String AM_FORCE_STOP_SETTINGS = "com.android.settings";
     private static final String AM_MOVE_TASK = "am stack movetask ";
 
-    /**
-     * A reference to the device under test.
-     */
+    /** A reference to the device under test. */
     private ITestDevice mDevice;
 
+    private HashSet<String> mAvailableFeatures;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -70,27 +82,15 @@
     @Override
     protected void tearDown() {
         try {
-            mDevice.executeShellCommand(AM_FORCE_STOP);
+            mDevice.executeShellCommand(AM_FORCE_STOP_TEST);
+            mDevice.executeShellCommand(AM_FORCE_STOP_SETTINGS);
         } catch (DeviceNotAvailableException e) {
         }
     }
 
     public void testStackList() throws Exception {
-        mDevice.executeShellCommand(AM_START_ACTIVITY);
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
-        mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
-        String output = outputReceiver.getOutput();
-        HashSet<Integer> stacks = new HashSet<>();
-        for (String line : output.split("\\n")) {
-            CLog.logAndDisplay(LogLevel.INFO, line);
-            if (line.startsWith(STACK_ID_PREFIX)) {
-                final String sub = line.substring(STACK_ID_PREFIX.length());
-                final int index = sub.indexOf(" ");
-                final int currentStack = Integer.parseInt(sub.substring(0, index));
-                stacks.add(currentStack);
-            } else if (line.startsWith(TASK_ID_PREFIX)) {
-            }
-        }
+        mDevice.executeShellCommand(AM_START_TEST_ACTIVITY);
+        HashSet<Integer> stacks = collectStacks();
         assertTrue("At least two stacks expected, home and fullscreen.", stacks.size() >= 2);
         assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
         assertTrue("Stacks must contain fullscreen stack.", stacks.contains(
@@ -107,12 +107,12 @@
         }
     }
 
-    private int getTestActivityTaskId() throws DeviceNotAvailableException {
+    private int getActivityTaskId(String name) throws DeviceNotAvailableException {
         CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
         final String output = outputReceiver.getOutput();
         for (String line : output.split("\\n")) {
-            if (line.contains(TEST_ACTIVITY_NAME)) {
+            if (line.contains(name)) {
                 for (String word : line.split("\\s+")) {
                     if (word.startsWith(TASK_ID_PREFIX)) {
                         final String withColon = word.split("=")[1];
@@ -125,11 +125,45 @@
     }
 
     public void testDockActivity() throws Exception {
-        mDevice.executeShellCommand(AM_START_ACTIVITY);
-        final int taskId = getTestActivityTaskId();
+        mDevice.executeShellCommand(AM_START_TEST_ACTIVITY);
+        final int taskId = getActivityTaskId(TEST_ACTIVITY_NAME);
         final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
         mDevice.executeShellCommand(cmd);
-        CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+        HashSet<Integer> stacks = collectStacks();
+        assertTrue("At least two stacks expected, home and docked.", stacks.size() >= 2);
+        assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
+        assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+    }
+
+    public void testLaunchToSide() throws Exception {
+        mDevice.executeShellCommand(AM_START_LAUNCH_TO_SIDE_ACTIVITY);
+        final int taskId = getActivityTaskId(LAUNCH_TO_SIDE_ACTIVITY_NAME);
+        final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
+        mDevice.executeShellCommand(cmd);
+        printStacksAndTasks();
+        mDevice.executeShellCommand(AM_START_LAUNCH_TO_SIDE_ACTIVITY
+                + " -f 0x20000000 --ez launch_to_the_side true");
+        HashSet<Integer> stacks = collectStacks();
+        assertTrue("At least two stacks expected, docked and fullscreen.", stacks.size() >= 2);
+        assertTrue("Stacks must contain fullscreen stack.", stacks.contains(
+                FULLSCREEN_WORKSPACE_STACK_ID));
+        assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+    }
+
+    public void testEnterPictureInPictureMode() throws Exception {
+        final boolean supportsPip = hasDeviceFeature("android.software.picture_in_picture");
+        mDevice.executeShellCommand(AM_START_PIP_ACTIVITY);
+        final HashSet<Integer> stacks = collectStacks();
+        final boolean containsPinnedStack = stacks.contains(PINNED_STACK_ID);
+        if (supportsPip) {
+            assertTrue("Stacks must contain pinned stack.", containsPinnedStack);
+        } else {
+            assertFalse("Stacks must not contain pinned stack.", containsPinnedStack);
+        }
+    }
+
+    private HashSet<Integer> collectStacks() throws DeviceNotAvailableException {
+        final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
         mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
         final String output = outputReceiver.getOutput();
         HashSet<Integer> stacks = new HashSet<>();
@@ -142,8 +176,32 @@
                 stacks.add(currentStack);
             }
         }
-        assertTrue("At least two stacks expected, home and docked.", stacks.size() >= 2);
-        assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
-        assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+        return stacks;
+    }
+
+    private boolean hasDeviceFeature(String requiredFeature) throws DeviceNotAvailableException {
+        if (mAvailableFeatures == null) {
+            // TODO: Move this logic to ITestDevice.
+            String command = "pm list features";
+            String commandOutput = mDevice.executeShellCommand(command);
+            CLog.i("Output for command " + command + ": " + commandOutput);
+
+            // Extract the id of the new user.
+            mAvailableFeatures = new HashSet<>();
+            for (String feature: commandOutput.split("\\s+")) {
+                // Each line in the output of the command has the format "feature:{FEATURE_VALUE}".
+                String[] tokens = feature.split(":");
+                assertTrue("\"" + feature + "\" expected to have format feature:{FEATURE_VALUE}",
+                        tokens.length > 1);
+                assertEquals(feature, "feature", tokens[0]);
+                mAvailableFeatures.add(tokens[1]);
+            }
+        }
+        boolean result = mAvailableFeatures.contains(requiredFeature);
+        if (!result) {
+            CLog.logAndDisplay(LogLevel.INFO, "Device doesn't have required feature "
+                    + requiredFeature + ". Test won't run.");
+        }
+        return result;
     }
 }
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 86c708a..2e79557 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -37,6 +37,7 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 
 /**
+ * TODO: Make sure DO APIs are not called by PO.
  * Test that exercises {@link DevicePolicyManager}. The test requires that the
  * CtsDeviceAdminReceiver be installed via the CtsDeviceAdmin.apk and be
  * activated via "Settings > Location & security > Select device administrators".
@@ -1142,4 +1143,18 @@
             return false;
         }
     }
+
+    public void testReboot_failIfNotDeviceOwner() {
+        if (!mDeviceAdmin) {
+            Log.w(TAG, "Skipping testReboot_failIfNotDeviceOwner");
+            return;
+        }
+        try {
+            mDevicePolicyManager.reboot(mComponent);
+            fail("did not throw expected SecurityException");
+        } catch (SecurityException e) {
+            assertDeviceOwnerMessage(e.getMessage());
+        }
+    }
+
 }
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 21cf064..c45bb2f 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -287,6 +287,39 @@
         <activity android:name="android.app.stubs.ActivityManagerMemoryClassTestActivity"
                 android:process=":memoryclass" />
 
+        <activity android:name="android.app.stubs.PipActivity"
+                  android:label="PipActivity"
+                  android:resizeable="true"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.PipNotResizeableActivity"
+                  android:label="PipNotResizeableActivity"
+                  android:resizeable="false"
+                  android:supportsPictureInPicture="true"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.app.stubs.PipNotSupportedActivity"
+                  android:label="PipNotSupportedActivity"
+                  android:resizeable="true"
+                  android:supportsPictureInPicture="false"
+                  android:configChanges="smallestScreenSize|orientation|screenSize">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
     </application>
 
 </manifest>
diff --git a/tests/app/app/src/android/app/stubs/PipActivity.java b/tests/app/app/src/android/app/stubs/PipActivity.java
new file mode 100644
index 0000000..533f054
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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.stubs;
+
+import android.app.Activity;
+
+public class PipActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java b/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java
new file mode 100644
index 0000000..7ed1acc
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipNotResizeableActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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.stubs;
+
+import android.app.Activity;
+
+public class PipNotResizeableActivity extends Activity {
+
+}
diff --git a/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java b/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java
new file mode 100644
index 0000000..e6656a0
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/PipNotSupportedActivity.java
@@ -0,0 +1,23 @@
+/*
+ * 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.stubs;
+
+import android.app.Activity;
+
+public class PipNotSupportedActivity extends Activity {
+
+}
diff --git a/tests/app/src/android/app/cts/PipActivityTest.java b/tests/app/src/android/app/cts/PipActivityTest.java
new file mode 100644
index 0000000..a553169
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipActivityTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.Instrumentation;
+import android.app.stubs.PipActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
+
+public class PipActivityTest extends ActivityInstrumentationTestCase2<PipActivity> {
+
+    private Instrumentation mInstrumentation;
+    private PipActivity mActivity;
+
+    public PipActivityTest() {
+        super("android.app.stubs", PipActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testLaunchPipActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                final boolean supportsPip =
+                        mActivity.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
+                if (supportsPip) {
+                    mActivity.enterPictureInPictureMode();
+                    assertTrue(mActivity.inMultiWindowMode());
+                    assertTrue(mActivity.inPictureInPictureMode());
+                } else {
+                    boolean pipSupportDisabled = false;
+                    try {
+                        mActivity.enterPictureInPictureMode();
+                    } catch (IllegalStateException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    }
+                    assertTrue(pipSupportDisabled);
+                    assertFalse(mActivity.inMultiWindowMode());
+                    assertFalse(mActivity.inPictureInPictureMode());
+                }
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
new file mode 100644
index 0000000..4f7f63e
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipNotResizeableActivityTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.Instrumentation;
+import android.app.stubs.PipNotResizeableActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class PipNotResizeableActivityTest
+        extends ActivityInstrumentationTestCase2<PipNotResizeableActivity> {
+
+        private Instrumentation mInstrumentation;
+        private PipNotResizeableActivity mActivity;
+
+        public PipNotResizeableActivityTest() {
+            super("android.app.stubs", PipNotResizeableActivity.class);
+        }
+
+        @Override
+        protected void setUp() throws Exception {
+            super.setUp();
+            mInstrumentation = getInstrumentation();
+            mActivity = getActivity();
+        }
+
+        public void testLaunchPipNotResizeableActivity() throws Throwable {
+            runTestOnUiThread(new Runnable() {
+                public void run() {
+                    boolean pipSupportDisabled = false;
+                    try {
+                        mActivity.enterPictureInPictureMode();
+                    } catch (IllegalStateException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    } catch (IllegalArgumentException e) {
+                        // Pip not supported
+                        pipSupportDisabled = true;
+                    }
+                    assertTrue(pipSupportDisabled);
+                    assertFalse(mActivity.inMultiWindowMode());
+                    assertFalse(mActivity.inPictureInPictureMode());
+                }
+            });
+            mInstrumentation.waitForIdleSync();
+        }
+    }
diff --git a/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
new file mode 100644
index 0000000..245421a
--- /dev/null
+++ b/tests/app/src/android/app/cts/PipNotSupportedActivityTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.Instrumentation;
+import android.app.stubs.PipNotSupportedActivity;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class PipNotSupportedActivityTest
+        extends ActivityInstrumentationTestCase2<PipNotSupportedActivity> {
+
+    private Instrumentation mInstrumentation;
+    private PipNotSupportedActivity mActivity;
+
+    public PipNotSupportedActivityTest() {
+        super("android.app.stubs", PipNotSupportedActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mInstrumentation = getInstrumentation();
+        mActivity = getActivity();
+    }
+
+    public void testLaunchPipNotSupportedActivity() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            public void run() {
+                boolean pipSupportDisabled = false;
+                try {
+                    mActivity.enterPictureInPictureMode();
+                } catch (IllegalStateException e) {
+                    // Pip not supported
+                    pipSupportDisabled = true;
+                } catch (IllegalArgumentException e) {
+                    // Pip not supported
+                    pipSupportDisabled = true;
+                }
+                assertTrue(pipSupportDisabled);
+                assertFalse(mActivity.inMultiWindowMode());
+                assertFalse(mActivity.inPictureInPictureMode());
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 924c639..1c8fbfc 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -25,10 +25,13 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctsdeviceutil ctstestrunner
 
-# Resource unit tests use a private locale and some densities
-LOCAL_AAPT_FLAGS = -c xx_YY -c cs -c small -c normal -c large -c xlarge \
+# Resource unit tests use various locales (including a private locale) and some densities
+LOCAL_AAPT_FLAGS = -c small -c normal -c large -c xlarge \
         -c 320dpi -c 240dpi -c 160dpi -c 32dpi \
-        -c kok,kok_IN,kok_419,kok_419_VARIANT,kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda,tgl,tgl_PH
+        -c cs,fa_IR \
+        -c kok,kok_IN,kok_419,kok_419_VARIANT \
+        -c kok_Knda_419,kok_Knda_419_VARIANT,kok_VARIANT,kok_Knda \
+        -c tgl,tgl_PH,xx_YY
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/tests/tests/content/res/values-fa-rIR/strings.xml b/tests/tests/content/res/values-fa-rIR/strings.xml
new file mode 100644
index 0000000..25fd20c
--- /dev/null
+++ b/tests/tests/content/res/values-fa-rIR/strings.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="am">صبح</string>
+</resources>
diff --git a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
index edf1d4b..a3c1b49 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
@@ -272,6 +272,67 @@
         assertEquals(LocaleList.getDefault(), res.getConfiguration().getLocales());
     }
 
+    public void testUpdateConfiguration_ResolvedLocaleIsRecalculated() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+
+        // Avestan has no assets, but Czech does
+        cfg.setLocales(LocaleList.forLanguageTags("ae"));
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        cfg.setLocales(LocaleList.forLanguageTags("ae,cs"));
+        res.updateConfiguration(cfg, null);
+        assertEquals("cs", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_unsupportedLocale() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        cfg.setLocales(LocaleList.forLanguageTags("ae"));  // Avestan has no assets
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("ae", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_secondaryLocaleIsSupported() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        // Avestan has no assets, but Czech does
+        cfg.setLocales(LocaleList.forLanguageTags("ae,cs"));
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("cs", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_secondaryLocaleIsPartiallySupported() {
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        // Avestan has no assets;
+        // Persian has assets for Iran, but not Afghanistan (partial match is accepted);
+        // Czech has assets (but we don't get to it)
+        cfg.setLocales(LocaleList.forLanguageTags("ae,fa-AF,cs"));
+
+        Resources res = new Resources(mResources.getAssets(), dm, cfg);
+        assertEquals("fa-AF", res.getResolvedLocale().toLanguageTag());
+    }
+
+    public void testGetResolvedLocale_SystemResourcesLocaleNonNull() {
+        Resources res = Resources.getSystem();
+        assertNotNull(res.getResolvedLocale());
+    }
+
+    public void testGetResolvedLocale_NonNull() {
+        Resources res = createNewResources();
+        assertNotNull(res.getResolvedLocale());
+    }
+
     public void testGetDimensionPixelSize() {
         try {
             mResources.getDimensionPixelSize(-1);
diff --git a/tests/tests/graphics/res/drawable/grayscale_jpg.jpg b/tests/tests/graphics/res/drawable/grayscale_jpg.jpg
new file mode 100644
index 0000000..6c6ae32
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/grayscale_jpg.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/grayscale_png.png b/tests/tests/graphics/res/drawable/grayscale_png.png
new file mode 100644
index 0000000..9f1beac
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/grayscale_png.png
Binary files differ
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 2b05f99..a93fd27 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -571,6 +571,116 @@
         verifyScaled(BitmapFactory.decodeStream(obtainInputStream(), null, scaledOpt));
     }
 
+    public void testConfigs() {
+        // The output Config of a BitmapFactory decode depends on the request from the
+        // client and the properties of the image to be decoded.
+        //
+        // Options.inPreferredConfig = Config.ARGB_8888
+        //     This is the default value of inPreferredConfig.  In this case, the image
+        //     will always be decoded to Config.ARGB_8888.
+        // Options.inPreferredConfig = Config.RGB_565
+        //     If the encoded image is opaque, we will decode to Config.RGB_565,
+        //     otherwise we will decode to whichever color type is the most natural match
+        //     for the encoded data.
+        // Options.inPreferredConfig = Config.ARGB_4444
+        //     This is deprecated and will always decode to Config.ARGB_8888.
+        // Options.inPreferredConfig = Config.ALPHA_8
+        //     If the encoded image is gray, we will decode to 8-bit grayscale values
+        //     and indicate that the output bitmap is Config.ALPHA_8.  This is somewhat
+        //     misleading because the image is really opaque and grayscale, but we are
+        //     labeling each pixel as if it is a translucency (alpha) value.  If the
+        //     encoded image is not gray, we will decode to whichever color type is the
+        //     most natural match for the encoded data.
+        // Options.inPreferredConfig = null
+        //     We will decode to whichever Config is the most natural match with the
+        //     encoded data.  This could be 8-bit indices into a color table (call this
+        //     INDEX_8), ALPHA_8 (gray), or ARGB_8888.
+        //
+        // This test ensures that images are decoded to the intended Config and that the
+        // decodes match regardless of the Config.
+        decodeConfigs(R.drawable.alpha, 31, 31, true, false, false);
+        decodeConfigs(R.drawable.baseline_jpeg, 1280, 960, false, false, false);
+        decodeConfigs(R.drawable.bmp_test, 320, 240, false, false, false);
+        decodeConfigs(R.drawable.scaled2, 6, 8, false, false, true);
+        decodeConfigs(R.drawable.grayscale_jpg, 128, 128, false, true, false);
+        decodeConfigs(R.drawable.grayscale_png, 128, 128, false, true, false);
+    }
+
+    private void decodeConfigs(int id, int width, int height, boolean hasAlpha, boolean isGray,
+            boolean hasColorTable) {
+        Options opts = new BitmapFactory.Options();
+        opts.inScaled = false;
+        assertEquals(Config.ARGB_8888, opts.inPreferredConfig);
+        Bitmap reference = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(reference);
+        assertEquals(width, reference.getWidth());
+        assertEquals(height, reference.getHeight());
+        assertEquals(Config.ARGB_8888, reference.getConfig());
+
+        opts.inPreferredConfig = Config.ARGB_4444;
+        Bitmap argb4444 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(argb4444);
+        assertEquals(width, argb4444.getWidth());
+        assertEquals(height, argb4444.getHeight());
+        // ARGB_4444 is deprecated and we should decode to ARGB_8888.
+        assertEquals(Config.ARGB_8888, argb4444.getConfig());
+        compareBitmaps(reference, argb4444, 0, true, true);
+
+        opts.inPreferredConfig = Config.RGB_565;
+        Bitmap rgb565 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(rgb565);
+        assertEquals(width, rgb565.getWidth());
+        assertEquals(height, rgb565.getHeight());
+        if (!hasAlpha) {
+            assertEquals(Config.RGB_565, rgb565.getConfig());
+            // Convert the RGB_565 bitmap to ARGB_8888 and test that it is similar to
+            // the reference.  We lose information when decoding to 565, so there must
+            // be some tolerance.  The tolerance is intentionally loose to allow us some
+            // flexibility regarding if we dither and how we color convert.
+            compareBitmaps(reference, rgb565.copy(Config.ARGB_8888, false), 30, true, true);
+        }
+
+        opts.inPreferredConfig = Config.ALPHA_8;
+        Bitmap alpha8 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(alpha8);
+        assertEquals(width, reference.getWidth());
+        assertEquals(height, reference.getHeight());
+        if (isGray) {
+            assertEquals(Config.ALPHA_8, alpha8.getConfig());
+            // Convert the ALPHA_8 bitmap to ARGB_8888 and test that it is identical to
+            // the reference.  We must do this manually because we are abusing ALPHA_8
+            // in order to represent grayscale.
+            compareBitmaps(reference, grayToARGB(alpha8), 0, true, true);
+        }
+
+        // Setting inPreferredConfig to null selects the most natural color type for
+        // the encoded data.  If the image has a color table, this should be INDEX_8.
+        // If we decode to INDEX_8, the output bitmap will report that the Config is
+        // null.
+        opts.inPreferredConfig = null;
+        Bitmap index8 = BitmapFactory.decodeResource(mRes, id, opts);
+        assertNotNull(index8);
+        assertEquals(width, index8.getWidth());
+        assertEquals(height, index8.getHeight());
+        if (hasColorTable) {
+            assertEquals(null, index8.getConfig());
+            // Convert the INDEX_8 bitmap to ARGB_8888 and test that it is identical to
+            // the reference.
+            compareBitmaps(reference, index8.copy(Config.ARGB_8888, false), 0, true, true);
+        }
+    }
+
+    private Bitmap grayToARGB(Bitmap gray) {
+        Bitmap argb = Bitmap.createBitmap(gray.getWidth(), gray.getHeight(), Config.ARGB_8888);
+        for (int y = 0; y < argb.getHeight(); y++) {
+            for (int x = 0; x < argb.getWidth(); x++) {
+                int grayByte = Color.alpha(gray.getPixel(x, y));
+                argb.setPixel(x, y, Color.rgb(grayByte, grayByte, grayByte));
+            }
+        }
+        return argb;
+    }
+
     private byte[] obtainArray() {
         ByteArrayOutputStream stm = new ByteArrayOutputStream();
         Options opt = new BitmapFactory.Options();