diff options
-rw-r--r-- | api/test-current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 21 | ||||
-rw-r--r-- | core/java/android/content/Context.java | 25 | ||||
-rw-r--r-- | core/java/android/content/ContextWrapper.java | 10 | ||||
-rw-r--r-- | test-mock/src/android/test/mock/MockContext.java | 10 |
5 files changed, 67 insertions, 0 deletions
diff --git a/api/test-current.txt b/api/test-current.txt index 8dcc09590ddb..3fbbd61d7f6e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -697,6 +697,7 @@ package android.content { public abstract class Context { method @NonNull public android.content.Context createContextAsUser(@NonNull android.os.UserHandle, int); method @NonNull public android.content.Context createPackageContextAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; + method @NonNull public java.io.File getCrateDir(@NonNull String); method public abstract android.view.Display getDisplay(); method public abstract int getDisplayId(); method public android.os.UserHandle getUser(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 46f88d5c81e4..155e93f9be19 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -99,6 +99,7 @@ import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteOrder; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; @@ -251,6 +252,8 @@ class ContextImpl extends Context { @GuardedBy("mSync") private File mFilesDir; @GuardedBy("mSync") + private File mCratesDir; + @GuardedBy("mSync") private File mNoBackupFilesDir; @GuardedBy("mSync") private File mCacheDir; @@ -702,6 +705,24 @@ class ContextImpl extends Context { } @Override + public File getCrateDir(@NonNull String crateId) { + Preconditions.checkArgument(FileUtils.isValidExtFilename(crateId), "invalidated crateId"); + final Path cratesRootPath = getDataDir().toPath().resolve("crates"); + final Path absoluteNormalizedCratePath = cratesRootPath.resolve(crateId) + .toAbsolutePath().normalize(); + + synchronized (mSync) { + if (mCratesDir == null) { + mCratesDir = cratesRootPath.toFile(); + } + ensurePrivateDirExists(mCratesDir); + } + + File cratedDir = absoluteNormalizedCratePath.toFile(); + return ensurePrivateDirExists(cratedDir); + } + + @Override public File getNoBackupFilesDir() { synchronized (mSync) { if (mNoBackupFilesDir == null) { diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index fe774f8f639a..09b5132646c3 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1060,6 +1060,31 @@ public abstract class Context { public abstract File getFilesDir(); /** + * Returns the absolute path to the directory that is related to the crate on the filesystem. + * <p> + * The crateId require a validated file name. It can't contain any "..", ".", + * {@link File#separatorChar} etc.. + * </p> + * <p> + * The returned path may change over time if the calling app is moved to an + * adopted storage device, so only relative paths should be persisted. + * </p> + * <p> + * No additional permissions are required for the calling app to read or + * write files under the returned path. + *</p> + * + * @param crateId the relative validated file name under {@link Context#getDataDir()}/crates + * @return the crate directory file. + * @hide + */ + @NonNull + @TestApi + public File getCrateDir(@NonNull String crateId) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * 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 diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index d6442e28439f..d1b5135e959d 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -252,6 +252,16 @@ public class ContextWrapper extends Context { return mBase.getFilesDir(); } + /** + * {@inheritDoc Context#getCrateDir()} + * @hide + */ + @NonNull + @Override + public File getCrateDir(@NonNull String cratedId) { + return mBase.getCrateDir(cratedId); + } + @Override public File getNoBackupFilesDir() { return mBase.getNoBackupFilesDir(); diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index 0208c3a0a0de..9d913b9861e5 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -16,6 +16,7 @@ package android.test.mock; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.IApplicationThread; import android.app.IServiceConnection; @@ -211,6 +212,15 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** + * {@inheritDoc Context#getCrateDir()} + * @hide + */ + @Override + public File getCrateDir(@NonNull String crateId) { + throw new UnsupportedOperationException(); + } + @Override public File getNoBackupFilesDir() { throw new UnsupportedOperationException(); |