Shift around encryption public APIs.

There are far too many Context APIs with special directory paths
to replicate device-encryption versions of them all.  Instead, add
methods to clone a Context that explicitly stores its data in either
credential- or device-encrypted storage.

Methods to test the behavior of a given Context.

Bug: 22358539
Change-Id: I6a6290a9b282605ce9a1f82742fc2c4c50536754
diff --git a/api/current.txt b/api/current.txt
index 007ed13..0a1289a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7779,6 +7779,8 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -7802,7 +7804,6 @@
     method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
-    method public abstract java.io.File getDeviceEncryptedFilesDir();
     method public abstract java.io.File getDir(java.lang.String, int);
     method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
@@ -7835,6 +7836,8 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public abstract boolean isCredentialEncrypted();
+    method public abstract boolean isDeviceEncrypted();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -7966,6 +7969,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -7988,7 +7993,6 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -8016,6 +8020,8 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -9097,8 +9103,10 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
+    field public java.lang.String credentialEncryptedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
+    field public java.lang.String deviceEncryptedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
@@ -36234,6 +36242,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -36255,7 +36265,6 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -36283,6 +36292,8 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
diff --git a/api/system-current.txt b/api/system-current.txt
index 1a05551..29b6abd 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8023,6 +8023,8 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -8045,9 +8047,7 @@
     method public final int getColor(int);
     method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
-    method public abstract java.io.File getCredentialEncryptedFilesDir();
     method public abstract java.io.File getDatabasePath(java.lang.String);
-    method public abstract java.io.File getDeviceEncryptedFilesDir();
     method public abstract java.io.File getDir(java.lang.String, int);
     method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
@@ -8080,6 +8080,8 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public abstract boolean isCredentialEncrypted();
+    method public abstract boolean isDeviceEncrypted();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -8219,6 +8221,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -8240,9 +8244,7 @@
     method public java.lang.ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
-    method public java.io.File getCredentialEncryptedFilesDir();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -8270,6 +8272,8 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -9361,8 +9365,10 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
+    field public java.lang.String credentialEncryptedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
+    field public java.lang.String deviceEncryptedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
@@ -38560,6 +38566,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -38580,9 +38588,7 @@
     method public java.lang.ClassLoader getClassLoader();
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
-    method public java.io.File getCredentialEncryptedFilesDir();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -38610,6 +38616,8 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
diff --git a/api/test-current.txt b/api/test-current.txt
index 7be966e..02e081e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -7779,6 +7779,8 @@
     method public abstract int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public abstract deprecated void clearWallpaper() throws java.io.IOException;
     method public abstract android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public abstract android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public abstract android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public abstract android.content.Context createDisplayContext(android.view.Display);
     method public abstract android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract java.lang.String[] databaseList();
@@ -7802,7 +7804,6 @@
     method public final android.content.res.ColorStateList getColorStateList(int);
     method public abstract android.content.ContentResolver getContentResolver();
     method public abstract java.io.File getDatabasePath(java.lang.String);
-    method public abstract java.io.File getDeviceEncryptedFilesDir();
     method public abstract java.io.File getDir(java.lang.String, int);
     method public final android.graphics.drawable.Drawable getDrawable(int);
     method public abstract java.io.File getExternalCacheDir();
@@ -7835,6 +7836,8 @@
     method public abstract deprecated int getWallpaperDesiredMinimumHeight();
     method public abstract deprecated int getWallpaperDesiredMinimumWidth();
     method public abstract void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public abstract boolean isCredentialEncrypted();
+    method public abstract boolean isDeviceEncrypted();
     method public boolean isRestricted();
     method public final android.content.res.TypedArray obtainStyledAttributes(int[]);
     method public final android.content.res.TypedArray obtainStyledAttributes(int, int[]) throws android.content.res.Resources.NotFoundException;
@@ -7966,6 +7969,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public deprecated void clearWallpaper() throws java.io.IOException;
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -7988,7 +7993,6 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -8016,6 +8020,8 @@
     method public deprecated int getWallpaperDesiredMinimumHeight();
     method public deprecated int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
@@ -9097,8 +9103,10 @@
     field public java.lang.String backupAgentName;
     field public java.lang.String className;
     field public int compatibleWidthLimitDp;
+    field public java.lang.String credentialEncryptedDataDir;
     field public java.lang.String dataDir;
     field public int descriptionRes;
+    field public java.lang.String deviceEncryptedDataDir;
     field public boolean enabled;
     field public int flags;
     field public int largestWidthLimitDp;
@@ -36236,6 +36244,8 @@
     method public int checkUriPermission(android.net.Uri, java.lang.String, java.lang.String, int, int, int);
     method public void clearWallpaper();
     method public android.content.Context createConfigurationContext(android.content.res.Configuration);
+    method public android.content.Context createCredentialEncryptedContext(android.content.Context);
+    method public android.content.Context createDeviceEncryptedContext(android.content.Context);
     method public android.content.Context createDisplayContext(android.view.Display);
     method public android.content.Context createPackageContext(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public java.lang.String[] databaseList();
@@ -36257,7 +36267,6 @@
     method public java.io.File getCodeCacheDir();
     method public android.content.ContentResolver getContentResolver();
     method public java.io.File getDatabasePath(java.lang.String);
-    method public java.io.File getDeviceEncryptedFilesDir();
     method public java.io.File getDir(java.lang.String, int);
     method public java.io.File getExternalCacheDir();
     method public java.io.File[] getExternalCacheDirs();
@@ -36285,6 +36294,8 @@
     method public int getWallpaperDesiredMinimumHeight();
     method public int getWallpaperDesiredMinimumWidth();
     method public void grantUriPermission(java.lang.String, android.net.Uri, int);
+    method public boolean isCredentialEncrypted();
+    method public boolean isDeviceEncrypted();
     method public java.io.FileInputStream openFileInput(java.lang.String) throws java.io.FileNotFoundException;
     method public java.io.FileOutputStream openFileOutput(java.lang.String, int) throws java.io.FileNotFoundException;
     method public android.database.sqlite.SQLiteDatabase openOrCreateDatabase(java.lang.String, int, android.database.sqlite.SQLiteDatabase.CursorFactory);
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a703c53..36e98f9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -74,6 +74,7 @@
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Objects;
 
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
@@ -148,7 +149,7 @@
     private final Display mDisplay; // may be null if default display
     private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
 
-    private final boolean mRestricted;
+    private final int mFlags;
 
     private Context mOuterContext;
     private int mThemeResource = 0;
@@ -443,22 +444,6 @@
     }
 
     @Override
-    public File getDeviceEncryptedFilesDir() {
-        if (mPackageInfo != null) {
-            return mPackageInfo.getDeviceEncryptedDataDirFile();
-        }
-        throw new RuntimeException("Not supported in system context");
-    }
-
-    @Override
-    public File getCredentialEncryptedFilesDir() {
-        if (mPackageInfo != null) {
-            return mPackageInfo.getCredentialEncryptedDataDirFile();
-        }
-        throw new RuntimeException("Not supported in system context");
-    }
-
-    @Override
     public File getNoBackupFilesDir() {
         synchronized (mSync) {
             if (mNoBackupFilesDir == null) {
@@ -1684,9 +1669,8 @@
         LoadedApk pi = mMainThread.getPackageInfo(application, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE);
         if (pi != null) {
-            final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
-                    new UserHandle(UserHandle.getUserId(application.uid)), restricted,
+                    new UserHandle(UserHandle.getUserId(application.uid)), flags,
                     mDisplay, null, Display.INVALID_DISPLAY);
             if (c.mResources != null) {
                 return c;
@@ -1707,17 +1691,16 @@
     @Override
     public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
             throws NameNotFoundException {
-        final boolean restricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
         if (packageName.equals("system") || packageName.equals("android")) {
             return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                    user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+                    user, flags, mDisplay, null, Display.INVALID_DISPLAY);
         }
 
         LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
                 flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
         if (pi != null) {
             ContextImpl c = new ContextImpl(this, mMainThread, pi, mActivityToken,
-                    user, restricted, mDisplay, null, Display.INVALID_DISPLAY);
+                    user, flags, mDisplay, null, Display.INVALID_DISPLAY);
             if (c.mResources != null) {
                 return c;
             }
@@ -1735,7 +1718,7 @@
         }
 
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mRestricted, mDisplay, overrideConfiguration, Display.INVALID_DISPLAY);
+                mUser, mFlags, mDisplay, overrideConfiguration, Display.INVALID_DISPLAY);
     }
 
     @Override
@@ -1745,7 +1728,7 @@
         }
 
         return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
-                mUser, mRestricted, display, null, Display.INVALID_DISPLAY);
+                mUser, mFlags, display, null, Display.INVALID_DISPLAY);
     }
 
     Display getDisplay() {
@@ -1761,8 +1744,34 @@
     }
 
     @Override
+    public Context createDeviceEncryptedContext(Context context) {
+        final int flags = (mFlags & ~Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED)
+                | Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED;
+        return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
+                mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
+    }
+
+    @Override
+    public Context createCredentialEncryptedContext(Context context) {
+        final int flags = (mFlags & ~Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED)
+                | Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+        return new ContextImpl(this, mMainThread, mPackageInfo, mActivityToken,
+                mUser, flags, mDisplay, null, Display.INVALID_DISPLAY);
+    }
+
+    @Override
     public boolean isRestricted() {
-        return mRestricted;
+        return (mFlags & Context.CONTEXT_RESTRICTED) != 0;
+    }
+
+    @Override
+    public boolean isDeviceEncrypted() {
+        return (mFlags & Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED) != 0;
+    }
+
+    @Override
+    public boolean isCredentialEncrypted() {
+        return (mFlags & Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED) != 0;
     }
 
     @Override
@@ -1772,7 +1781,14 @@
 
     private File getDataDirFile() {
         if (mPackageInfo != null) {
-            return mPackageInfo.getDataDirFile();
+            if (isCredentialEncrypted()) {
+                return mPackageInfo.getCredentialEncryptedDataDirFile();
+            } else if (isDeviceEncrypted()) {
+                return mPackageInfo.getDeviceEncryptedDataDirFile();
+            } else {
+                throw new RuntimeException(
+                        "Storage location is neither credential nor device encrypted");
+            }
         }
         throw new RuntimeException("Not supported in system context");
     }
@@ -1798,7 +1814,7 @@
     static ContextImpl createSystemContext(ActivityThread mainThread) {
         LoadedApk packageInfo = new LoadedApk(mainThread);
         ContextImpl context = new ContextImpl(null, mainThread,
-                packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
         context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
                 context.mResourcesManager.getDisplayMetricsLocked());
         return context;
@@ -1807,24 +1823,38 @@
     static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
         return new ContextImpl(null, mainThread,
-                packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
+                packageInfo, null, null, 0, null, null, Display.INVALID_DISPLAY);
     }
 
     static ContextImpl createActivityContext(ActivityThread mainThread,
             LoadedApk packageInfo, int displayId, Configuration overrideConfiguration) {
         if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
-        return new ContextImpl(null, mainThread, packageInfo, null, null, false,
+        return new ContextImpl(null, mainThread, packageInfo, null, null, 0,
                 null, overrideConfiguration, displayId);
     }
 
     private ContextImpl(ContextImpl container, ActivityThread mainThread,
-            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
+            LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
             Display display, Configuration overrideConfiguration, int createDisplayWithId) {
         mOuterContext = this;
 
+        // If creator didn't specify which storage to use, use the default
+        // location for application.
+        if ((flags & Context.CONTEXT_STORAGE_MASK) == 0) {
+            final File dataDir = packageInfo.getDataDirFile();
+            if (Objects.equals(dataDir, packageInfo.getCredentialEncryptedDataDirFile())) {
+                flags |= Context.CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+            } else if (Objects.equals(dataDir, packageInfo.getDeviceEncryptedDataDirFile())) {
+                flags |= Context.CONTEXT_STORAGE_DEVICE_ENCRYPTED;
+            } else {
+                throw new IllegalStateException("Storage location " + dataDir
+                        + " doesn't match either credential or device encrypted storage");
+            }
+        }
+
         mMainThread = mainThread;
         mActivityToken = activityToken;
-        mRestricted = restricted;
+        mFlags = flags;
 
         if (user == null) {
             user = Process.myUserHandle();
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 4c7e853..1f7fd9d 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -771,27 +771,6 @@
     public abstract File getFilesDir();
 
     /**
-     * Return the filesystem directory for storing device-encrypted private app
-     * data. Files stored in this location are typically encrypted with a key
-     * tied to the physical device, and they can be accessed whenever the device
-     * has booted successfully, both <em>before and after</em> the user has
-     * entered their credentials (such as a lock pattern or PIN).
-     */
-    public abstract File getDeviceEncryptedFilesDir();
-
-    /**
-     * Return the filesystem directory for storing credential-encrypted private
-     * app data. Files stored in this location are typically encrypted with a
-     * key tied to user credentials, and they can be accessed
-     * <em>only after</em> the user has entered their credentials (such as a
-     * lock pattern or PIN).
-     *
-     * @hide
-     */
-    @SystemApi
-    public abstract File getCredentialEncryptedFilesDir();
-
-    /**
      * Returns the absolute path to the directory on the filesystem similar to
      * {@link #getFilesDir()}. The difference is that files placed under this
      * directory will be excluded from automatic backup to remote storage. See
@@ -3886,6 +3865,26 @@
     public static final int CONTEXT_RESTRICTED = 0x00000004;
 
     /**
+     * Flag for use with {@link #createPackageContext}: point all file APIs at
+     * device-encrypted storage.
+     *
+     * @hide
+     */
+    public static final int CONTEXT_STORAGE_DEVICE_ENCRYPTED = 0x00000008;
+
+    /**
+     * Flag for use with {@link #createPackageContext}: point all file APIs at
+     * credential-encrypted storage.
+     *
+     * @hide
+     */
+    public static final int CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED = 0x00000010;
+
+    /** {@hide} */
+    public static final int CONTEXT_STORAGE_MASK = CONTEXT_STORAGE_DEVICE_ENCRYPTED
+            | CONTEXT_STORAGE_CREDENTIAL_ENCRYPTED;
+
+    /**
      * @hide Used to indicate we should tell the activity manager about the process
      * loading this code.
      */
@@ -3985,6 +3984,42 @@
     public abstract Context createDisplayContext(@NonNull Display display);
 
     /**
+     * Return a new Context object for the current Context but whose storage
+     * APIs are backed by device-encrypted storage.
+     * <p>
+     * Data stored in device-encrypted storage is typically encrypted with a
+     * key tied to the physical device, and they can be accessed whenever the
+     * device has booted successfully, both <em>before and after</em> the user
+     * has entered their credentials (such as a lock pattern or PIN).
+     * <p>
+     * Each call to this method returns a new instance of a Context object;
+     * Context objects are not shared, however common state (ClassLoader, other
+     * Resources for the same configuration) may be so the Context itself can be
+     * fairly lightweight.
+     *
+     * @see #isDeviceEncrypted()
+     */
+    public abstract Context createDeviceEncryptedContext(Context context);
+
+    /**
+     * Return a new Context object for the current Context but whose storage
+     * APIs are backed by credential-encrypted storage.
+     * <p>
+     * Data stored in credential-encrypted storage is typically encrypted with a
+     * key tied to user credentials, and they can be accessed
+     * <em>only after</em> the user has entered their credentials (such as a
+     * lock pattern or PIN).
+     * <p>
+     * Each call to this method returns a new instance of a Context object;
+     * Context objects are not shared, however common state (ClassLoader, other
+     * Resources for the same configuration) may be so the Context itself can be
+     * fairly lightweight.
+     *
+     * @see #isCredentialEncrypted()
+     */
+    public abstract Context createCredentialEncryptedContext(Context context);
+
+    /**
      * Gets the display adjustments holder for this context.  This information
      * is provided on a per-application or activity basis and is used to simulate lower density
      * display metrics for legacy applications and restricted screen sizes.
@@ -4005,4 +4040,20 @@
     public boolean isRestricted() {
         return false;
     }
+
+    /**
+     * Indicates if the storage APIs of this Context are backed by
+     * device-encrypted storage.
+     *
+     * @see #createDeviceEncryptedContext(Context)
+     */
+    public abstract boolean isDeviceEncrypted();
+
+    /**
+     * Indicates if the storage APIs of this Context are backed by
+     * credential-encrypted storage.
+     *
+     * @see #createCredentialEncryptedContext(Context)
+     */
+    public abstract boolean isCredentialEncrypted();
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index f5e9159..73d0ddc 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -208,18 +208,6 @@
     }
 
     @Override
-    public File getDeviceEncryptedFilesDir() {
-        return mBase.getDeviceEncryptedFilesDir();
-    }
-
-    /** {@hide} */
-    @SystemApi
-    @Override
-    public File getCredentialEncryptedFilesDir() {
-        return mBase.getCredentialEncryptedFilesDir();
-    }
-
-    @Override
     public File getNoBackupFilesDir() {
         return mBase.getNoBackupFilesDir();
     }
@@ -802,4 +790,24 @@
     public DisplayAdjustments getDisplayAdjustments(int displayId) {
         return mBase.getDisplayAdjustments(displayId);
     }
+
+    @Override
+    public Context createDeviceEncryptedContext(Context context) {
+        return mBase.createDeviceEncryptedContext(context);
+    }
+
+    @Override
+    public Context createCredentialEncryptedContext(Context context) {
+        return mBase.createCredentialEncryptedContext(context);
+    }
+
+    @Override
+    public boolean isDeviceEncrypted() {
+        return mBase.isDeviceEncrypted();
+    }
+
+    @Override
+    public boolean isCredentialEncrypted() {
+        return mBase.isCredentialEncrypted();
+    }
 }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 545478c..4816734 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -591,13 +591,21 @@
     public String[] sharedLibraryFiles;
     
     /**
-     * Full path to a directory assigned to the package for its persistent data.
+     * Full path to the default directory assigned to the package for its
+     * persistent data.
      */
     public String dataDir;
 
-    /** {@hide} */
+    /**
+     * Full path to the device-encrypted directory assigned to the package for
+     * its persistent data.
+     */
     public String deviceEncryptedDataDir;
-    /** {@hide} */
+
+    /**
+     * Full path to the credential-encrypted directory assigned to the package
+     * for its persistent data.
+     */
     public String credentialEncryptedDataDir;
 
     /**
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 225edf8..4c3b598 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -181,18 +181,6 @@
     }
 
     @Override
-    public File getDeviceEncryptedFilesDir() {
-        throw new UnsupportedOperationException();
-    }
-
-    /** {@hide} */
-    @SystemApi
-    @Override
-    public File getCredentialEncryptedFilesDir() {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public File getNoBackupFilesDir() {
         throw new UnsupportedOperationException();
     }
@@ -705,4 +693,24 @@
     public File[] getExternalMediaDirs() {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public Context createDeviceEncryptedContext(Context context) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Context createCredentialEncryptedContext(Context context) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isDeviceEncrypted() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean isCredentialEncrypted() {
+        throw new UnsupportedOperationException();
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 9214759..bd5335e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -1377,18 +1377,6 @@
     }
 
     @Override
-    public File getDeviceEncryptedFilesDir() {
-        // pass
-        return null;
-    }
-
-    @Override
-    public File getCredentialEncryptedFilesDir() {
-        // pass
-        return null;
-    }
-
-    @Override
     public File getNoBackupFilesDir() {
         // pass
         return null;
@@ -1814,4 +1802,26 @@
         Integer pos = mScrollYPos.get(view);
         return pos != null ? pos : 0;
     }
+
+    @Override
+    public Context createDeviceEncryptedContext(Context context) {
+        // pass
+        return null;
+    }
+
+    @Override
+    public Context createCredentialEncryptedContext(Context context) {
+        // pass
+        return null;
+    }
+
+    @Override
+    public boolean isDeviceEncrypted() {
+        return false;
+    }
+
+    @Override
+    public boolean isCredentialEncrypted() {
+        return false;
+    }
 }