1575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell/* 2575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Copyright (C) 2012 The Android Open Source Project 3575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 4575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 5575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * you may not use this file except in compliance with the License. 6575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * You may obtain a copy of the License at 7575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 8575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 9575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 10575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Unless required by applicable law or agreed to in writing, software 11575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 12575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * See the License for the specific language governing permissions and 14575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * limitations under the License. 15575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell */ 16575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell 17575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellpackage android.support.v4.content; 18575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell 19575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellimport android.content.Context; 20575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellimport android.content.Intent; 215525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tateimport android.content.pm.ApplicationInfo; 22479dd28f2936062d37166a949419d332053af44cAlan Viveretteimport android.graphics.drawable.Drawable; 23575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellimport android.os.Build; 24575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellimport android.os.Bundle; 25145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkeyimport android.os.Environment; 26145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkeyimport android.os.StatFs; 27145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkeyimport android.support.v4.os.EnvironmentCompat; 28c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkeyimport android.util.Log; 29145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 30145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkeyimport java.io.File; 31575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell 32575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell/** 33575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Helper for accessing features in {@link android.content.Context} 34575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * introduced after API level 4 in a backwards compatible fashion. 35575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell */ 36575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellpublic class ContextCompat { 37c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey private static final String TAG = "ContextCompat"; 38575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell 39145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static final String DIR_ANDROID = "Android"; 40145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static final String DIR_DATA = "data"; 41145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static final String DIR_OBB = "obb"; 42145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static final String DIR_FILES = "files"; 43145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static final String DIR_CACHE = "cache"; 44145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 45575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell /** 46575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Start a set of activities as a synthesized task stack, if able. 47575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 48575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 49575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * app navigation using the back key changed. The back key's behavior is local 50575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * to the current task and does not capture navigation across different tasks. 51575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Navigating across tasks and easily reaching the previous task is accomplished 52575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * through the "recents" UI, accessible through the software-provided Recents key 53575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * on the navigation or system bar. On devices with the older hardware button configuration 54575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the recents UI can be accessed with a long press on the Home key.</p> 55575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 56575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>When crossing from one task stack to another post-Android 3.0, 57575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the application should synthesize a back stack/history for the new task so that 58575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the user may navigate out of the new task and back to the Launcher by repeated 59575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * presses of the back key. Back key presses should not navigate across task stacks.</p> 60575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 61575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>startActivities provides a mechanism for constructing a synthetic task stack of 62575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * multiple activities. If the underlying API is not available on the system this method 63575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * will return false.</p> 64575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 65575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @param context Start activities using this activity as the starting context 66575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @param intents Array of intents defining the activities that will be started. The element 67575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * length-1 will correspond to the top activity on the resulting task stack. 68575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @return true if the underlying API was available and the call was successful, false otherwise 69575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell */ 70575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell public static boolean startActivities(Context context, Intent[] intents) { 71575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell return startActivities(context, intents, null); 72575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell } 73575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell 74575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell /** 75575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Start a set of activities as a synthesized task stack, if able. 76575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 77575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 78575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * app navigation using the back key changed. The back key's behavior is local 79575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * to the current task and does not capture navigation across different tasks. 80575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * Navigating across tasks and easily reaching the previous task is accomplished 81575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * through the "recents" UI, accessible through the software-provided Recents key 82575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * on the navigation or system bar. On devices with the older hardware button configuration 83575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the recents UI can be accessed with a long press on the Home key.</p> 84575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 85575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>When crossing from one task stack to another post-Android 3.0, 86575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the application should synthesize a back stack/history for the new task so that 87575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * the user may navigate out of the new task and back to the Launcher by repeated 88575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * presses of the back key. Back key presses should not navigate across task stacks.</p> 89575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 90575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * <p>startActivities provides a mechanism for constructing a synthetic task stack of 91575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * multiple activities. If the underlying API is not available on the system this method 92575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * will return false.</p> 93575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * 94575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @param context Start activities using this activity as the starting context 95575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @param intents Array of intents defining the activities that will be started. The element 96575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * length-1 will correspond to the top activity on the resulting task stack. 97575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @param options Additional options for how the Activity should be started. 98575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * See {@link android.content.Context#startActivity(Intent, Bundle) 99575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell * @return true if the underlying API was available and the call was successful, false otherwise 100575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell */ 101575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell public static boolean startActivities(Context context, Intent[] intents, 102575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell Bundle options) { 103575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell final int version = Build.VERSION.SDK_INT; 104575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell if (version >= 16) { 105575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell ContextCompatJellybean.startActivities(context, intents, options); 106575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell return true; 107575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell } else if (version >= 11) { 108575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell ContextCompatHoneycomb.startActivities(context, intents); 109575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell return true; 110575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell } 111575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell return false; 112575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell } 113145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 114145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey /** 115145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Returns absolute paths to application-specific directories on all 116145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * external storage devices where the application's OBB files (if there are 117145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * any) can be found. Note if the application does not have any OBB files, 118145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * these directories may not exist. 119145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 120145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * This is like {@link Context#getFilesDir()} in that these files will be 121145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * deleted when the application is uninstalled, however there are some 122145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * important differences: 123145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <ul> 124145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>External files are not always available: they will disappear if the 125145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * user mounts the external storage on a computer or removes it. 126145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>There is no security enforced with these files. 127145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * </ul> 128145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 129145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * External storage devices returned here are considered a permanent part of 130145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the device, including both emulated external storage and physical media 131145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * slots, such as SD cards in a battery compartment. The returned paths do 132145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * not include transient devices, such as USB flash drives. 133145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 134145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * An application may store data on any or all of the returned devices. For 135145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * example, an app may choose to store large files on the device with the 136145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * most available space, as measured by {@link StatFs}. 137145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 138145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 139145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * are required to write to the returned paths; they're always accessible to 140145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the calling app. Before then, 141145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 142145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * write. Write access outside of these paths on secondary external storage 143145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * devices is not available. To request external storage access in a 144145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * backwards compatible way, consider using {@code android:maxSdkVersion} 145145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * like this: 146145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 147145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <pre class="prettyprint"><uses-permission 148145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 149145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:maxSdkVersion="18" /></pre> 150145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 151145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * The first path returned is the same as {@link Context#getObbDir()}. 152145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Returned paths may be {@code null} if a storage device is unavailable. 153145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 154145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see Context#getObbDir() 155145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see EnvironmentCompat#getStorageState(File) 156145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey */ 157145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey public static File[] getObbDirs(Context context) { 158145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final int version = Build.VERSION.SDK_INT; 159145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 19) { 160145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return ContextCompatKitKat.getObbDirs(context); 161145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 162145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final File single; 163145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 11) { 164145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = ContextCompatHoneycomb.getObbDir(context); 165145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 166145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_OBB, 167145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey context.getPackageName()); 168145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 169145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return new File[] { single }; 170145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 171145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 172145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 173145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey /** 174145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Returns absolute paths to application-specific directories on all 175145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * external storage devices where the application can place persistent files 176145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * it owns. These files are internal to the application, and not typically 177145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * visible to the user as media. 178145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 179145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * This is like {@link Context#getFilesDir()} in that these files will be 180145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * deleted when the application is uninstalled, however there are some 181145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * important differences: 182145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <ul> 183145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>External files are not always available: they will disappear if the 184145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * user mounts the external storage on a computer or removes it. 185145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>There is no security enforced with these files. 186145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * </ul> 187145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 188145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * External storage devices returned here are considered a permanent part of 189145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the device, including both emulated external storage and physical media 190145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * slots, such as SD cards in a battery compartment. The returned paths do 191145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * not include transient devices, such as USB flash drives. 192145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 193145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * An application may store data on any or all of the returned devices. For 194145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * example, an app may choose to store large files on the device with the 195145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * most available space, as measured by {@link StatFs}. 196145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 197145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 198145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * are required to write to the returned paths; they're always accessible to 199145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the calling app. Before then, 200145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 201145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * write. Write access outside of these paths on secondary external storage 202145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * devices is not available. To request external storage access in a 203145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * backwards compatible way, consider using {@code android:maxSdkVersion} 204145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * like this: 205145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 206145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <pre class="prettyprint"><uses-permission 207145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 208145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:maxSdkVersion="18" /></pre> 209145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 210145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * The first path returned is the same as 211145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@link Context#getExternalFilesDir(String)}. Returned paths may be 212145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@code null} if a storage device is unavailable. 213145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 214145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see Context#getExternalFilesDir(String) 215145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see EnvironmentCompat#getStorageState(File) 216145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey */ 217145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey public static File[] getExternalFilesDirs(Context context, String type) { 218145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final int version = Build.VERSION.SDK_INT; 219145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 19) { 220145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return ContextCompatKitKat.getExternalFilesDirs(context, type); 221145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 222145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final File single; 223145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 8) { 224145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = ContextCompatFroyo.getExternalFilesDir(context, type); 225145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 226145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 227145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey context.getPackageName(), DIR_FILES, type); 228145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 229145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return new File[] { single }; 230145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 231145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 232145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 233145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey /** 234145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Returns absolute paths to application-specific directories on all 235145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * external storage devices where the application can place cache files it 236145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * owns. These files are internal to the application, and not typically 237145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * visible to the user as media. 238145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 239145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * This is like {@link Context#getCacheDir()} in that these files will be 240145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * deleted when the application is uninstalled, however there are some 241145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * important differences: 242145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <ul> 243145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>External files are not always available: they will disappear if the 244145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * user mounts the external storage on a computer or removes it. 245145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <li>There is no security enforced with these files. 246145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * </ul> 247145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 248145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * External storage devices returned here are considered a permanent part of 249145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the device, including both emulated external storage and physical media 250145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * slots, such as SD cards in a battery compartment. The returned paths do 251145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * not include transient devices, such as USB flash drives. 252145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 253145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * An application may store data on any or all of the returned devices. For 254145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * example, an app may choose to store large files on the device with the 255145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * most available space, as measured by {@link StatFs}. 256145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 257145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 258145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * are required to write to the returned paths; they're always accessible to 259145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * the calling app. Before then, 260145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 261145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * write. Write access outside of these paths on secondary external storage 262145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * devices is not available. To request external storage access in a 263145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * backwards compatible way, consider using {@code android:maxSdkVersion} 264145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * like this: 265145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 266145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <pre class="prettyprint"><uses-permission 267145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 268145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * android:maxSdkVersion="18" /></pre> 269145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * <p> 270145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * The first path returned is the same as 271145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * {@link Context#getExternalCacheDir()}. Returned paths may be {@code null} 272145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * if a storage device is unavailable. 273145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * 274145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see Context#getExternalCacheDir() 275145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey * @see EnvironmentCompat#getStorageState(File) 276145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey */ 277145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey public static File[] getExternalCacheDirs(Context context) { 278145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final int version = Build.VERSION.SDK_INT; 279145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 19) { 280145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return ContextCompatKitKat.getExternalCacheDirs(context); 281145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 282145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey final File single; 283145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (version >= 8) { 284145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = ContextCompatFroyo.getExternalCacheDir(context); 285145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else { 286145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 287145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey context.getPackageName(), DIR_CACHE); 288145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 289145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return new File[] { single }; 290145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 291145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 292145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey 293145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey private static File buildPath(File base, String... segments) { 294145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey File cur = base; 295145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey for (String segment : segments) { 296145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey if (cur == null) { 297145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey cur = new File(segment); 298145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } else if (segment != null) { 299145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey cur = new File(cur, segment); 300145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 301145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 302145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey return cur; 303145d27f9dd22e953d05e01327c9c2dac68634ae8Jeff Sharkey } 304479dd28f2936062d37166a949419d332053af44cAlan Viverette 305479dd28f2936062d37166a949419d332053af44cAlan Viverette /** 306479dd28f2936062d37166a949419d332053af44cAlan Viverette * Return a drawable object associated with a particular resource ID. 307479dd28f2936062d37166a949419d332053af44cAlan Viverette * <p> 30895a62c18174e92eb2bf90b808cef5fd6f36ad944Dianne Hackborn * Starting in {@link android.os.Build.VERSION_CODES#LOLLIPOP}, the returned 309479dd28f2936062d37166a949419d332053af44cAlan Viverette * drawable will be styled for the specified Context's theme. 310479dd28f2936062d37166a949419d332053af44cAlan Viverette * 311479dd28f2936062d37166a949419d332053af44cAlan Viverette * @param id The desired resource identifier, as generated by the aapt tool. 312479dd28f2936062d37166a949419d332053af44cAlan Viverette * This integer encodes the package, type, and resource entry. 313479dd28f2936062d37166a949419d332053af44cAlan Viverette * The value 0 is an invalid identifier. 314479dd28f2936062d37166a949419d332053af44cAlan Viverette * @return Drawable An object that can be used to draw this resource. 315479dd28f2936062d37166a949419d332053af44cAlan Viverette */ 316d333fbf215cc2fd93e8081ea5181ebf5795e0b87Alan Viverette public static final Drawable getDrawable(Context context, int id) { 317479dd28f2936062d37166a949419d332053af44cAlan Viverette final int version = Build.VERSION.SDK_INT; 318479dd28f2936062d37166a949419d332053af44cAlan Viverette if (version >= 21) { 319479dd28f2936062d37166a949419d332053af44cAlan Viverette return ContextCompatApi21.getDrawable(context, id); 320479dd28f2936062d37166a949419d332053af44cAlan Viverette } else { 321479dd28f2936062d37166a949419d332053af44cAlan Viverette return context.getResources().getDrawable(id); 322479dd28f2936062d37166a949419d332053af44cAlan Viverette } 323479dd28f2936062d37166a949419d332053af44cAlan Viverette } 3245525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate 3255525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate /** 3265525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * Returns the absolute path to the directory on the filesystem similar to 3279218f2cb7518b7647f3d6daf8d51f45c1ded7fe2Ying Wang * {@link Context#getFilesDir()}. The difference is that files placed under this 3285525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * directory will be excluded from automatic backup to remote storage on 32995a62c18174e92eb2bf90b808cef5fd6f36ad944Dianne Hackborn * devices running {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later. See 3305525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * {@link android.app.backup.BackupAgent BackupAgent} for a full discussion 3315525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * of the automatic backup mechanism in Android. 3325525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * 3335525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * <p>No permissions are required to read or write to the returned path, since this 3345525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * path is internal storage. 3355525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * 3365525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * @return The path of the directory holding application files that will not be 3375525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * automatically backed up to remote storage. 3385525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * 3395525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate * @see android.content.Context.getFilesDir 3405525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate */ 3415525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate public final File getNoBackupFilesDir(Context context) { 3425525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate final int version = Build.VERSION.SDK_INT; 3435525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate if (version >= 21) { 3445525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate return ContextCompatApi21.getNoBackupFilesDir(context); 3455525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate } else { 3465525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate ApplicationInfo appInfo = context.getApplicationInfo(); 347c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return createFilesDir(new File(appInfo.dataDir, "no_backup")); 3485525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate } 3495525d0e30d8d9d068790e9420a433f63dd1f0e00Christopher Tate } 350c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey 351c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey /** 352c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * Returns the absolute path to the application specific cache directory on 353c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * the filesystem designed for storing cached code. On devices running 35495a62c18174e92eb2bf90b808cef5fd6f36ad944Dianne Hackborn * {@link android.os.Build.VERSION_CODES#LOLLIPOP} or later, the system will delete 355c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * any files stored in this location both when your specific application is 356c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * upgraded, and when the entire platform is upgraded. 357c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * <p> 358c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * This location is optimal for storing compiled or optimized code generated 359c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * by your application at runtime. 360c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * <p> 361c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * Apps require no extra permissions to read or write to the returned path, 362c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * since this path lives in their private storage. 363c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * 364c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey * @return The path of the directory holding application code cache files. 365c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey */ 366c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey public final File getCodeCacheDir(Context context) { 367c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey final int version = Build.VERSION.SDK_INT; 368c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey if (version >= 21) { 369c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return ContextCompatApi21.getCodeCacheDir(context); 370c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } else { 371c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey ApplicationInfo appInfo = context.getApplicationInfo(); 372c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return createFilesDir(new File(appInfo.dataDir, "code_cache")); 373c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 374c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 375c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey 376c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey private synchronized static File createFilesDir(File file) { 377c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey if (!file.exists()) { 378c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey if (!file.mkdirs()) { 379c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey if (file.exists()) { 380c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey // spurious failure; probably racing with another process for this app 381c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return file; 382c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 383c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey Log.w(TAG, "Unable to create files subdir " + file.getPath()); 384c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return null; 385c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 386c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 387c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey return file; 388c40d36383f21a8ad199f440b1f233c923910e82aJeff Sharkey } 389575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell} 390