1/* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.v4.content; 18 19import android.content.Context; 20import android.content.Intent; 21import android.os.Build; 22import android.os.Bundle; 23import android.os.Environment; 24import android.os.StatFs; 25import android.support.v4.os.EnvironmentCompat; 26 27import java.io.File; 28 29/** 30 * Helper for accessing features in {@link android.content.Context} 31 * introduced after API level 4 in a backwards compatible fashion. 32 */ 33public class ContextCompat { 34 35 private static final String DIR_ANDROID = "Android"; 36 private static final String DIR_DATA = "data"; 37 private static final String DIR_OBB = "obb"; 38 private static final String DIR_FILES = "files"; 39 private static final String DIR_CACHE = "cache"; 40 41 /** 42 * Start a set of activities as a synthesized task stack, if able. 43 * 44 * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 45 * app navigation using the back key changed. The back key's behavior is local 46 * to the current task and does not capture navigation across different tasks. 47 * Navigating across tasks and easily reaching the previous task is accomplished 48 * through the "recents" UI, accessible through the software-provided Recents key 49 * on the navigation or system bar. On devices with the older hardware button configuration 50 * the recents UI can be accessed with a long press on the Home key.</p> 51 * 52 * <p>When crossing from one task stack to another post-Android 3.0, 53 * the application should synthesize a back stack/history for the new task so that 54 * the user may navigate out of the new task and back to the Launcher by repeated 55 * presses of the back key. Back key presses should not navigate across task stacks.</p> 56 * 57 * <p>startActivities provides a mechanism for constructing a synthetic task stack of 58 * multiple activities. If the underlying API is not available on the system this method 59 * will return false.</p> 60 * 61 * @param context Start activities using this activity as the starting context 62 * @param intents Array of intents defining the activities that will be started. The element 63 * length-1 will correspond to the top activity on the resulting task stack. 64 * @return true if the underlying API was available and the call was successful, false otherwise 65 */ 66 public static boolean startActivities(Context context, Intent[] intents) { 67 return startActivities(context, intents, null); 68 } 69 70 /** 71 * Start a set of activities as a synthesized task stack, if able. 72 * 73 * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 74 * app navigation using the back key changed. The back key's behavior is local 75 * to the current task and does not capture navigation across different tasks. 76 * Navigating across tasks and easily reaching the previous task is accomplished 77 * through the "recents" UI, accessible through the software-provided Recents key 78 * on the navigation or system bar. On devices with the older hardware button configuration 79 * the recents UI can be accessed with a long press on the Home key.</p> 80 * 81 * <p>When crossing from one task stack to another post-Android 3.0, 82 * the application should synthesize a back stack/history for the new task so that 83 * the user may navigate out of the new task and back to the Launcher by repeated 84 * presses of the back key. Back key presses should not navigate across task stacks.</p> 85 * 86 * <p>startActivities provides a mechanism for constructing a synthetic task stack of 87 * multiple activities. If the underlying API is not available on the system this method 88 * will return false.</p> 89 * 90 * @param context Start activities using this activity as the starting context 91 * @param intents Array of intents defining the activities that will be started. The element 92 * length-1 will correspond to the top activity on the resulting task stack. 93 * @param options Additional options for how the Activity should be started. 94 * See {@link android.content.Context#startActivity(Intent, Bundle) 95 * @return true if the underlying API was available and the call was successful, false otherwise 96 */ 97 public static boolean startActivities(Context context, Intent[] intents, 98 Bundle options) { 99 final int version = Build.VERSION.SDK_INT; 100 if (version >= 16) { 101 ContextCompatJellybean.startActivities(context, intents, options); 102 return true; 103 } else if (version >= 11) { 104 ContextCompatHoneycomb.startActivities(context, intents); 105 return true; 106 } 107 return false; 108 } 109 110 /** 111 * Returns absolute paths to application-specific directories on all 112 * external storage devices where the application's OBB files (if there are 113 * any) can be found. Note if the application does not have any OBB files, 114 * these directories may not exist. 115 * <p> 116 * This is like {@link Context#getFilesDir()} in that these files will be 117 * deleted when the application is uninstalled, however there are some 118 * important differences: 119 * <ul> 120 * <li>External files are not always available: they will disappear if the 121 * user mounts the external storage on a computer or removes it. 122 * <li>There is no security enforced with these files. 123 * </ul> 124 * <p> 125 * External storage devices returned here are considered a permanent part of 126 * the device, including both emulated external storage and physical media 127 * slots, such as SD cards in a battery compartment. The returned paths do 128 * not include transient devices, such as USB flash drives. 129 * <p> 130 * An application may store data on any or all of the returned devices. For 131 * example, an app may choose to store large files on the device with the 132 * most available space, as measured by {@link StatFs}. 133 * <p> 134 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 135 * are required to write to the returned paths; they're always accessible to 136 * the calling app. Before then, 137 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 138 * write. Write access outside of these paths on secondary external storage 139 * devices is not available. To request external storage access in a 140 * backwards compatible way, consider using {@code android:maxSdkVersion} 141 * like this: 142 * 143 * <pre class="prettyprint"><uses-permission 144 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 145 * android:maxSdkVersion="18" /></pre> 146 * <p> 147 * The first path returned is the same as {@link Context#getObbDir()}. 148 * Returned paths may be {@code null} if a storage device is unavailable. 149 * 150 * @see Context#getObbDir() 151 * @see EnvironmentCompat#getStorageState(File) 152 */ 153 public static File[] getObbDirs(Context context) { 154 final int version = Build.VERSION.SDK_INT; 155 if (version >= 19) { 156 return ContextCompatKitKat.getObbDirs(context); 157 } else { 158 final File single; 159 if (version >= 11) { 160 single = ContextCompatHoneycomb.getObbDir(context); 161 } else { 162 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_OBB, 163 context.getPackageName()); 164 } 165 return new File[] { single }; 166 } 167 } 168 169 /** 170 * Returns absolute paths to application-specific directories on all 171 * external storage devices where the application can place persistent files 172 * it owns. These files are internal to the application, and not typically 173 * visible to the user as media. 174 * <p> 175 * This is like {@link Context#getFilesDir()} in that these files will be 176 * deleted when the application is uninstalled, however there are some 177 * important differences: 178 * <ul> 179 * <li>External files are not always available: they will disappear if the 180 * user mounts the external storage on a computer or removes it. 181 * <li>There is no security enforced with these files. 182 * </ul> 183 * <p> 184 * External storage devices returned here are considered a permanent part of 185 * the device, including both emulated external storage and physical media 186 * slots, such as SD cards in a battery compartment. The returned paths do 187 * not include transient devices, such as USB flash drives. 188 * <p> 189 * An application may store data on any or all of the returned devices. For 190 * example, an app may choose to store large files on the device with the 191 * most available space, as measured by {@link StatFs}. 192 * <p> 193 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 194 * are required to write to the returned paths; they're always accessible to 195 * the calling app. Before then, 196 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 197 * write. Write access outside of these paths on secondary external storage 198 * devices is not available. To request external storage access in a 199 * backwards compatible way, consider using {@code android:maxSdkVersion} 200 * like this: 201 * 202 * <pre class="prettyprint"><uses-permission 203 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 204 * android:maxSdkVersion="18" /></pre> 205 * <p> 206 * The first path returned is the same as 207 * {@link Context#getExternalFilesDir(String)}. Returned paths may be 208 * {@code null} if a storage device is unavailable. 209 * 210 * @see Context#getExternalFilesDir(String) 211 * @see EnvironmentCompat#getStorageState(File) 212 */ 213 public static File[] getExternalFilesDirs(Context context, String type) { 214 final int version = Build.VERSION.SDK_INT; 215 if (version >= 19) { 216 return ContextCompatKitKat.getExternalFilesDirs(context, type); 217 } else { 218 final File single; 219 if (version >= 8) { 220 single = ContextCompatFroyo.getExternalFilesDir(context, type); 221 } else { 222 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 223 context.getPackageName(), DIR_FILES, type); 224 } 225 return new File[] { single }; 226 } 227 } 228 229 /** 230 * Returns absolute paths to application-specific directories on all 231 * external storage devices where the application can place cache files it 232 * owns. These files are internal to the application, and not typically 233 * visible to the user as media. 234 * <p> 235 * This is like {@link Context#getCacheDir()} in that these files will be 236 * deleted when the application is uninstalled, however there are some 237 * important differences: 238 * <ul> 239 * <li>External files are not always available: they will disappear if the 240 * user mounts the external storage on a computer or removes it. 241 * <li>There is no security enforced with these files. 242 * </ul> 243 * <p> 244 * External storage devices returned here are considered a permanent part of 245 * the device, including both emulated external storage and physical media 246 * slots, such as SD cards in a battery compartment. The returned paths do 247 * not include transient devices, such as USB flash drives. 248 * <p> 249 * An application may store data on any or all of the returned devices. For 250 * example, an app may choose to store large files on the device with the 251 * most available space, as measured by {@link StatFs}. 252 * <p> 253 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 254 * are required to write to the returned paths; they're always accessible to 255 * the calling app. Before then, 256 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 257 * write. Write access outside of these paths on secondary external storage 258 * devices is not available. To request external storage access in a 259 * backwards compatible way, consider using {@code android:maxSdkVersion} 260 * like this: 261 * 262 * <pre class="prettyprint"><uses-permission 263 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 264 * android:maxSdkVersion="18" /></pre> 265 * <p> 266 * The first path returned is the same as 267 * {@link Context#getExternalCacheDir()}. Returned paths may be {@code null} 268 * if a storage device is unavailable. 269 * 270 * @see Context#getExternalCacheDir() 271 * @see EnvironmentCompat#getStorageState(File) 272 */ 273 public static File[] getExternalCacheDirs(Context context) { 274 final int version = Build.VERSION.SDK_INT; 275 if (version >= 19) { 276 return ContextCompatKitKat.getExternalCacheDirs(context); 277 } else { 278 final File single; 279 if (version >= 8) { 280 single = ContextCompatFroyo.getExternalCacheDir(context); 281 } else { 282 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 283 context.getPackageName(), DIR_CACHE); 284 } 285 return new File[] { single }; 286 } 287 } 288 289 private static File buildPath(File base, String... segments) { 290 File cur = base; 291 for (String segment : segments) { 292 if (cur == null) { 293 cur = new File(segment); 294 } else if (segment != null) { 295 cur = new File(cur, segment); 296 } 297 } 298 return cur; 299 } 300} 301