am 6652ef46: am dd55de3d: am 9767f9e2: am 7df86ef4: am 9e36f588: Merge "update storage doc for secondary external storage in KK and add some new sample code and remove documentation for APIs below level 8 and add information about permission changes in KK bug: 1190750
* commit '6652ef463dd7976f522dac7fca5be06e11188cd4':
update storage doc for secondary external storage in KK and add some new sample code and remove documentation for APIs below level 8 and add information about permission changes in KK bug: 11907502
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 6fca02f0..24e7f54 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -233,138 +233,197 @@
(non-removable) storage. Files saved to the external storage are world-readable and can
be modified by the user when they enable USB mass storage to transfer files on a computer.</p>
-<p>It's possible that a device using a partition of the
-internal storage for the external storage may also offer an SD card slot. In this case,
-the SD card is <em>not</em> part of the external storage and your app cannot access it (the extra
-storage is intended only for user-provided media that the system scans).</p>
-
<p class="caution"><strong>Caution:</strong> External storage can become unavailable if the user mounts the
external storage on a computer or removes the media, and there's no security enforced upon files you
save to the external storage. All applications can read and write files placed on the external
storage and the user can remove them.</p>
+<h3 id="ExternalPermissions">Getting access to external storage</h3>
+
+<p>In order to read or write files on the external storage, your app must acquire the
+{@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
+or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} system
+permissions. For example:</p>
+<pre>
+<manifest ...>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ ...
+</manifest>
+</pre>
+
+<p>If you need to both read and write files, then you need to request only the
+{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} permission, because it
+implicitly requires read access as well.</p>
+
+<p class="note"><strong>Note:</strong> Beginning with Android 4.4, these permissions are not
+required if you're reading or writing only files that are private to your app. For more
+information, see the section below about
+<a href="#AccessingExtFiles">saving files that are app-private</a>.</p>
+
+
<h3 id="MediaAvail">Checking media availability</h3>
<p>Before you do any work with the external storage, you should always call {@link
android.os.Environment#getExternalStorageState()} to check whether the media is available. The
media might be mounted to a computer, missing, read-only, or in some other state. For example,
-here's how you can check the availability:</p>
+here are a couple methods you can use to check the availability:</p>
<pre>
-boolean mExternalStorageAvailable = false;
-boolean mExternalStorageWriteable = false;
-String state = Environment.getExternalStorageState();
+/* Checks if external storage is available for read and write */
+public boolean isExternalStorageWritable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ return true;
+ }
+ return false;
+}
-if (Environment.MEDIA_MOUNTED.equals(state)) {
- // We can read and write the media
- mExternalStorageAvailable = mExternalStorageWriteable = true;
-} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- // We can only read the media
- mExternalStorageAvailable = true;
- mExternalStorageWriteable = false;
-} else {
- // Something else is wrong. It may be one of many other states, but all we need
- // to know is we can neither read nor write
- mExternalStorageAvailable = mExternalStorageWriteable = false;
+/* Checks if external storage is available to at least read */
+public boolean isExternalStorageReadable() {
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state) ||
+ Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ return true;
+ }
+ return false;
}
</pre>
-<p>This example checks whether the external storage is available to read and write. The
-{@link android.os.Environment#getExternalStorageState()} method returns other states that you
+<p>The {@link android.os.Environment#getExternalStorageState()} method returns other states that you
might want to check, such as whether the media is being shared (connected to a computer), is missing
entirely, has been removed badly, etc. You can use these to notify the user with more information
when your application needs to access the media.</p>
-<h3 id="AccessingExtFiles">Accessing files on external storage</h3>
+<h3 id="SavingSharedFiles">Saving files that can be shared with other apps</h3>
-<p>If you're using API Level 8 or greater, use {@link
-android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} to open a {@link
-java.io.File} that represents the external storage directory where you should save your
-files. This method takes a <code>type</code> parameter that specifies the type of subdirectory you
-want, such as {@link android.os.Environment#DIRECTORY_MUSIC} and
-{@link android.os.Environment#DIRECTORY_RINGTONES} (pass <code>null</code> to receive
-the root of your application's file directory). This method will create the
-appropriate directory if necessary. By specifying the type of directory, you
-ensure that the Android's media scanner will properly categorize your files in the system (for
-example, ringtones are identified as ringtones and not music). If the user uninstalls your
-application, this directory and all its contents will be deleted.</p>
-
-<p>If you're using API Level 7 or lower, use {@link
-android.os.Environment#getExternalStorageDirectory()}, to open a {@link
-java.io.File} representing the root of the external storage. You should then write your data in the
-following directory:</p>
-<pre class="no-pretty-print classic">
-/Android/data/<em><package_name></em>/files/
-</pre>
-<p>The {@code <em><package_name></em>} is your Java-style package name, such as "{@code
-com.example.android.app}". If the user's device is running API Level 8 or greater and they
-uninstall your application, this directory and all its contents will be deleted.</p>
-
-
-<div class="sidebox-wrapper" style="margin-top:3em">
+<div class="sidebox-wrapper" >
<div class="sidebox">
<h4>Hiding your files from the Media Scanner</h4>
<p>Include an empty file named {@code .nomedia} in your external files directory (note the dot
-prefix in the filename). This will prevent Android's media scanner from reading your media
-files and including them in apps like Gallery or Music.</p>
+prefix in the filename). This prevents media scanner from reading your media
+files and providing them to other apps through the {@link android.provider.MediaStore}
+content provider. However, if your files are truly private to your app, you should
+<a href="#AccessingExtFiles">save them in an app-private directory</a>.</p>
</div>
</div>
+<p>Generally, new files that the user may acquire through your app should be saved to a "public"
+location on the device where other apps can access them and the user can easily copy them from the
+device. When doing so, you should use to one of the shared public directories, such as {@code
+Music/}, {@code Pictures/}, and {@code Ringtones/}.</p>
-<h3 id="SavingSharedFiles">Saving files that should be shared</h3>
-
-<p>If you want to save files that are not specific to your application and that should <em>not</em>
-be deleted when your application is uninstalled, save them to one of the public directories on the
-external storage. These directories lay at the root of the external storage, such as {@code
-Music/}, {@code Pictures/}, {@code Ringtones/}, and others.</p>
-
-<p>In API Level 8 or greater, use {@link
+<p>To get a {@link java.io.File} representing the appropriate public directory, call {@link
android.os.Environment#getExternalStoragePublicDirectory(String)
-getExternalStoragePublicDirectory()}, passing it the type of public directory you want, such as
+getExternalStoragePublicDirectory()}, passing it the type of directory you want, such as
{@link android.os.Environment#DIRECTORY_MUSIC}, {@link android.os.Environment#DIRECTORY_PICTURES},
-{@link android.os.Environment#DIRECTORY_RINGTONES}, or others. This method will create the
-appropriate directory if necessary.</p>
+{@link android.os.Environment#DIRECTORY_RINGTONES}, or others. By saving your files to the
+corresponding media-type directory,
+the system's media scanner can properly categorize your files in the system (for
+instance, ringtones appear in system settings as ringtones, not as music).</p>
-<p>If you're using API Level 7 or lower, use {@link
-android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents
-the root of the external storage, then save your shared files in one of the following
-directories:</p>
-<ul class="nolist"></li>
- <li><code>Music/</code> - Media scanner classifies all media found here as user music.</li>
- <li><code>Podcasts/</code> - Media scanner classifies all media found here as a podcast.</li>
- <li><code>Ringtones/ </code> - Media scanner classifies all media found here as a ringtone.</li>
- <li><code>Alarms/</code> - Media scanner classifies all media found here as an alarm sound.</li>
- <li><code>Notifications/</code> - Media scanner classifies all media found here as a notification
-sound.</li>
- <li><code>Pictures/</code> - All photos (excluding those taken with the camera).</li>
- <li><code>Movies/</code> - All movies (excluding those taken with the camcorder).</li>
- <li><code>Download/</code> - Miscellaneous downloads.</li>
-</ul>
+<p>For example, here's a method that creates a directory for a new photo album in
+the public pictures directory:</p>
+
+<pre>
+public File getAlbumStorageDir(String albumName) {
+ // Get the directory for the user's public pictures directory.
+ File file = new File(Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES), albumName);
+ if (!file.mkdirs()) {
+ Log.e(LOG_TAG, "Directory not created");
+ }
+ return file;
+}
+</pre>
+
+
+
+<h3 id="AccessingExtFiles">Saving files that are app-private</h3>
+
+<p>If you are handling files that are not intended for other apps to use
+(such as graphic textures or sound effects used by only your app), you should use
+a private storage directory on the external storage by calling {@link
+android.content.Context#getExternalFilesDir(String) getExternalFilesDir()}.
+This method also takes a <code>type</code> argument to specify the type of subdirectory
+(such as {@link android.os.Environment#DIRECTORY_MOVIES}). If you don't need a specific
+media directory, pass <code>null</code> to receive
+the root directory of your app's private directory.</p>
+
+<p>Beginning with Android 4.4, reading or writing files in your app's private
+directories does not require the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE}
+or {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE}
+permissions. So you can declare the permission should be requested only on the lower versions
+of Android by adding the <a
+href="{@docRoot}guide/topics/manifest/uses-permission-element.html#maxSdk">{@code maxSdkVersion}</a>
+attribute:</p>
+<pre>
+<manifest ...>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
+ android:maxSdkVersion="18" />
+ ...
+</manifest>
+</pre>
+
+<p class="note"><strong>Note:</strong>
+When the user uninstalls your application, this directory and all its contents are deleted.
+Also, the system media scanner does not read files in these directories, so they are not accessible
+from the {@link android.provider.MediaStore} content provider. As such, you <b>should not
+use these directories</b> for media that ultimately belongs to the user, such as photos
+captured or edited with your app, or music the user has purchased with your app—those
+files should be <a href="#SavingSharedFiles">saved in the public directories</a>.</p>
+
+<p>Sometimes, a device that has allocated a partition of the
+internal memory for use as the external storage may also offer an SD card slot.
+When such a device is running Android 4.3 and lower, the {@link
+android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} method provides
+access to only the internal partition and your app cannot read or write to the SD card.
+Beginning with Android 4.4, however, you can access both locations by calling
+{@link android.content.Context#getExternalFilesDirs getExternalFilesDirs()},
+which returns a {@link
+java.io.File} array with entries each location. The first entry in the array is considered
+the primary external storage and you should use that location unless it's full or
+unavailable. If you'd like to access both possible locations while also supporting Android
+4.3 and lower, use the <a href="{@docRoot}tools/support-library/index.html">support library's</a>
+static method, {@link android.support.v4.content.ContextCompat#getExternalFilesDirs
+ContextCompat.getExternalFilesDirs()}. This also returns a {@link
+java.io.File} array, but always includes only one entry on Android 4.3 and lower.</p>
+
+<p class="caution"><strong>Caution</strong> Although the directories provided by {@link
+android.content.Context#getExternalFilesDir(String) getExternalFilesDir()} and {@link
+android.content.Context#getExternalFilesDirs getExternalFilesDirs()} are not accessible by the
+{@link android.provider.MediaStore} content provider, other apps with the {@link
+android.Manifest.permission#READ_EXTERNAL_STORAGE} permission can access all files on the external
+storage, including these. If you need to completely restrict access for your files, you should
+instead write your files to the <a href="#filesInternal">internal storage</a>.</p>
+
+
+
<h3 id="ExternalCache">Saving cache files</h3>
-<p>If you're using API Level 8 or greater, use {@link
-android.content.Context#getExternalCacheDir()} to open a {@link java.io.File} that represents the
-external storage directory where you should save cache files. If the user uninstalls your
-application, these files will be automatically deleted. However, during the life of your
-application, you should manage these cache files and remove those that aren't needed in order to
-preserve file space.</p>
+<p>To open a {@link java.io.File} that represents the
+external storage directory where you should save cache files, call {@link
+android.content.Context#getExternalCacheDir()}. If the user uninstalls your
+application, these files will be automatically deleted.</p>
-<p>If you're using API Level 7 or lower, use {@link
-android.os.Environment#getExternalStorageDirectory()} to open a {@link java.io.File} that represents
-the root of the external storage, then write your cache data in the following directory:</p>
-<pre class="no-pretty-print classic">
-/Android/data/<em><package_name></em>/cache/
-</pre>
-<p>The {@code <em><package_name></em>} is your Java-style package name, such as "{@code
-com.example.android.app}".</p>
+<p>Similar to {@link android.support.v4.content.ContextCompat#getExternalFilesDirs
+ContextCompat.getExternalFilesDirs()}, mentioned above, you can also access a cache directory on
+a secondary external storage (if available) by calling
+{@link android.support.v4.content.ContextCompat#getExternalCacheDirs
+ContextCompat.getExternalCacheDirs()}.</p>
+
+<p class="note"><strong>Tip:</strong>
+To preserve file space and maintain your app's performance,
+it's important that you carefully manage your cache files and remove those that aren't
+needed anymore throughout your app's lifecycle.</p>
+