ContextCompat.java revision 9218f2cb7518b7647f3d6daf8d51f45c1ded7fe2
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.content.pm.ApplicationInfo; 22import android.content.res.Resources.Theme; 23import android.graphics.drawable.Drawable; 24import android.os.Build; 25import android.os.Bundle; 26import android.os.Environment; 27import android.os.StatFs; 28import android.support.v4.os.EnvironmentCompat; 29 30import java.io.File; 31 32/** 33 * Helper for accessing features in {@link android.content.Context} 34 * introduced after API level 4 in a backwards compatible fashion. 35 */ 36public class ContextCompat { 37 38 private static final String DIR_ANDROID = "Android"; 39 private static final String DIR_DATA = "data"; 40 private static final String DIR_OBB = "obb"; 41 private static final String DIR_FILES = "files"; 42 private static final String DIR_CACHE = "cache"; 43 44 /** 45 * Start a set of activities as a synthesized task stack, if able. 46 * 47 * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 48 * app navigation using the back key changed. The back key's behavior is local 49 * to the current task and does not capture navigation across different tasks. 50 * Navigating across tasks and easily reaching the previous task is accomplished 51 * through the "recents" UI, accessible through the software-provided Recents key 52 * on the navigation or system bar. On devices with the older hardware button configuration 53 * the recents UI can be accessed with a long press on the Home key.</p> 54 * 55 * <p>When crossing from one task stack to another post-Android 3.0, 56 * the application should synthesize a back stack/history for the new task so that 57 * the user may navigate out of the new task and back to the Launcher by repeated 58 * presses of the back key. Back key presses should not navigate across task stacks.</p> 59 * 60 * <p>startActivities provides a mechanism for constructing a synthetic task stack of 61 * multiple activities. If the underlying API is not available on the system this method 62 * will return false.</p> 63 * 64 * @param context Start activities using this activity as the starting context 65 * @param intents Array of intents defining the activities that will be started. The element 66 * length-1 will correspond to the top activity on the resulting task stack. 67 * @return true if the underlying API was available and the call was successful, false otherwise 68 */ 69 public static boolean startActivities(Context context, Intent[] intents) { 70 return startActivities(context, intents, null); 71 } 72 73 /** 74 * Start a set of activities as a synthesized task stack, if able. 75 * 76 * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for 77 * app navigation using the back key changed. The back key's behavior is local 78 * to the current task and does not capture navigation across different tasks. 79 * Navigating across tasks and easily reaching the previous task is accomplished 80 * through the "recents" UI, accessible through the software-provided Recents key 81 * on the navigation or system bar. On devices with the older hardware button configuration 82 * the recents UI can be accessed with a long press on the Home key.</p> 83 * 84 * <p>When crossing from one task stack to another post-Android 3.0, 85 * the application should synthesize a back stack/history for the new task so that 86 * the user may navigate out of the new task and back to the Launcher by repeated 87 * presses of the back key. Back key presses should not navigate across task stacks.</p> 88 * 89 * <p>startActivities provides a mechanism for constructing a synthetic task stack of 90 * multiple activities. If the underlying API is not available on the system this method 91 * will return false.</p> 92 * 93 * @param context Start activities using this activity as the starting context 94 * @param intents Array of intents defining the activities that will be started. The element 95 * length-1 will correspond to the top activity on the resulting task stack. 96 * @param options Additional options for how the Activity should be started. 97 * See {@link android.content.Context#startActivity(Intent, Bundle) 98 * @return true if the underlying API was available and the call was successful, false otherwise 99 */ 100 public static boolean startActivities(Context context, Intent[] intents, 101 Bundle options) { 102 final int version = Build.VERSION.SDK_INT; 103 if (version >= 16) { 104 ContextCompatJellybean.startActivities(context, intents, options); 105 return true; 106 } else if (version >= 11) { 107 ContextCompatHoneycomb.startActivities(context, intents); 108 return true; 109 } 110 return false; 111 } 112 113 /** 114 * Returns absolute paths to application-specific directories on all 115 * external storage devices where the application's OBB files (if there are 116 * any) can be found. Note if the application does not have any OBB files, 117 * these directories may not exist. 118 * <p> 119 * This is like {@link Context#getFilesDir()} in that these files will be 120 * deleted when the application is uninstalled, however there are some 121 * important differences: 122 * <ul> 123 * <li>External files are not always available: they will disappear if the 124 * user mounts the external storage on a computer or removes it. 125 * <li>There is no security enforced with these files. 126 * </ul> 127 * <p> 128 * External storage devices returned here are considered a permanent part of 129 * the device, including both emulated external storage and physical media 130 * slots, such as SD cards in a battery compartment. The returned paths do 131 * not include transient devices, such as USB flash drives. 132 * <p> 133 * An application may store data on any or all of the returned devices. For 134 * example, an app may choose to store large files on the device with the 135 * most available space, as measured by {@link StatFs}. 136 * <p> 137 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 138 * are required to write to the returned paths; they're always accessible to 139 * the calling app. Before then, 140 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 141 * write. Write access outside of these paths on secondary external storage 142 * devices is not available. To request external storage access in a 143 * backwards compatible way, consider using {@code android:maxSdkVersion} 144 * like this: 145 * 146 * <pre class="prettyprint"><uses-permission 147 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 148 * android:maxSdkVersion="18" /></pre> 149 * <p> 150 * The first path returned is the same as {@link Context#getObbDir()}. 151 * Returned paths may be {@code null} if a storage device is unavailable. 152 * 153 * @see Context#getObbDir() 154 * @see EnvironmentCompat#getStorageState(File) 155 */ 156 public static File[] getObbDirs(Context context) { 157 final int version = Build.VERSION.SDK_INT; 158 if (version >= 19) { 159 return ContextCompatKitKat.getObbDirs(context); 160 } else { 161 final File single; 162 if (version >= 11) { 163 single = ContextCompatHoneycomb.getObbDir(context); 164 } else { 165 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_OBB, 166 context.getPackageName()); 167 } 168 return new File[] { single }; 169 } 170 } 171 172 /** 173 * Returns absolute paths to application-specific directories on all 174 * external storage devices where the application can place persistent files 175 * it owns. These files are internal to the application, and not typically 176 * visible to the user as media. 177 * <p> 178 * This is like {@link Context#getFilesDir()} in that these files will be 179 * deleted when the application is uninstalled, however there are some 180 * important differences: 181 * <ul> 182 * <li>External files are not always available: they will disappear if the 183 * user mounts the external storage on a computer or removes it. 184 * <li>There is no security enforced with these files. 185 * </ul> 186 * <p> 187 * External storage devices returned here are considered a permanent part of 188 * the device, including both emulated external storage and physical media 189 * slots, such as SD cards in a battery compartment. The returned paths do 190 * not include transient devices, such as USB flash drives. 191 * <p> 192 * An application may store data on any or all of the returned devices. For 193 * example, an app may choose to store large files on the device with the 194 * most available space, as measured by {@link StatFs}. 195 * <p> 196 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 197 * are required to write to the returned paths; they're always accessible to 198 * the calling app. Before then, 199 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 200 * write. Write access outside of these paths on secondary external storage 201 * devices is not available. To request external storage access in a 202 * backwards compatible way, consider using {@code android:maxSdkVersion} 203 * like this: 204 * 205 * <pre class="prettyprint"><uses-permission 206 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 207 * android:maxSdkVersion="18" /></pre> 208 * <p> 209 * The first path returned is the same as 210 * {@link Context#getExternalFilesDir(String)}. Returned paths may be 211 * {@code null} if a storage device is unavailable. 212 * 213 * @see Context#getExternalFilesDir(String) 214 * @see EnvironmentCompat#getStorageState(File) 215 */ 216 public static File[] getExternalFilesDirs(Context context, String type) { 217 final int version = Build.VERSION.SDK_INT; 218 if (version >= 19) { 219 return ContextCompatKitKat.getExternalFilesDirs(context, type); 220 } else { 221 final File single; 222 if (version >= 8) { 223 single = ContextCompatFroyo.getExternalFilesDir(context, type); 224 } else { 225 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 226 context.getPackageName(), DIR_FILES, type); 227 } 228 return new File[] { single }; 229 } 230 } 231 232 /** 233 * Returns absolute paths to application-specific directories on all 234 * external storage devices where the application can place cache files it 235 * owns. These files are internal to the application, and not typically 236 * visible to the user as media. 237 * <p> 238 * This is like {@link Context#getCacheDir()} in that these files will be 239 * deleted when the application is uninstalled, however there are some 240 * important differences: 241 * <ul> 242 * <li>External files are not always available: they will disappear if the 243 * user mounts the external storage on a computer or removes it. 244 * <li>There is no security enforced with these files. 245 * </ul> 246 * <p> 247 * External storage devices returned here are considered a permanent part of 248 * the device, including both emulated external storage and physical media 249 * slots, such as SD cards in a battery compartment. The returned paths do 250 * not include transient devices, such as USB flash drives. 251 * <p> 252 * An application may store data on any or all of the returned devices. For 253 * example, an app may choose to store large files on the device with the 254 * most available space, as measured by {@link StatFs}. 255 * <p> 256 * Starting in {@link android.os.Build.VERSION_CODES#KITKAT}, no permissions 257 * are required to write to the returned paths; they're always accessible to 258 * the calling app. Before then, 259 * {@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE} is required to 260 * write. Write access outside of these paths on secondary external storage 261 * devices is not available. To request external storage access in a 262 * backwards compatible way, consider using {@code android:maxSdkVersion} 263 * like this: 264 * 265 * <pre class="prettyprint"><uses-permission 266 * android:name="android.permission.WRITE_EXTERNAL_STORAGE" 267 * android:maxSdkVersion="18" /></pre> 268 * <p> 269 * The first path returned is the same as 270 * {@link Context#getExternalCacheDir()}. Returned paths may be {@code null} 271 * if a storage device is unavailable. 272 * 273 * @see Context#getExternalCacheDir() 274 * @see EnvironmentCompat#getStorageState(File) 275 */ 276 public static File[] getExternalCacheDirs(Context context) { 277 final int version = Build.VERSION.SDK_INT; 278 if (version >= 19) { 279 return ContextCompatKitKat.getExternalCacheDirs(context); 280 } else { 281 final File single; 282 if (version >= 8) { 283 single = ContextCompatFroyo.getExternalCacheDir(context); 284 } else { 285 single = buildPath(Environment.getExternalStorageDirectory(), DIR_ANDROID, DIR_DATA, 286 context.getPackageName(), DIR_CACHE); 287 } 288 return new File[] { single }; 289 } 290 } 291 292 private static File buildPath(File base, String... segments) { 293 File cur = base; 294 for (String segment : segments) { 295 if (cur == null) { 296 cur = new File(segment); 297 } else if (segment != null) { 298 cur = new File(cur, segment); 299 } 300 } 301 return cur; 302 } 303 304 /** 305 * Return a drawable object associated with a particular resource ID. 306 * <p> 307 * Starting in {@link android.os.Build.VERSION_CODES#L}, the returned 308 * drawable will be styled for the specified Context's theme. 309 * 310 * @param id The desired resource identifier, as generated by the aapt tool. 311 * This integer encodes the package, type, and resource entry. 312 * The value 0 is an invalid identifier. 313 * @return Drawable An object that can be used to draw this resource. 314 */ 315 public final Drawable getDrawable(Context context, int id) { 316 final int version = Build.VERSION.SDK_INT; 317 if (version >= 21) { 318 return ContextCompatApi21.getDrawable(context, id); 319 } else { 320 return context.getResources().getDrawable(id); 321 } 322 } 323 324 /** 325 * Returns the absolute path to the directory on the filesystem similar to 326 * {@link Context#getFilesDir()}. The difference is that files placed under this 327 * directory will be excluded from automatic backup to remote storage on 328 * devices running {@link android.os.Build.VERSION_CODES#L} or later. See 329 * {@link android.app.backup.BackupAgent BackupAgent} for a full discussion 330 * of the automatic backup mechanism in Android. 331 * 332 * <p>No permissions are required to read or write to the returned path, since this 333 * path is internal storage. 334 * 335 * @return The path of the directory holding application files that will not be 336 * automatically backed up to remote storage. 337 * 338 * @see android.content.Context.getFilesDir 339 */ 340 public final File getNoBackupFilesDir(Context context) { 341 final int version = Build.VERSION.SDK_INT; 342 if (version >= 21) { 343 return ContextCompatApi21.getNoBackupFilesDir(context); 344 } else { 345 ApplicationInfo appInfo = context.getApplicationInfo(); 346 return new File(appInfo.dataDir, "no_backup"); 347 } 348 } 349} 350