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">&lt;uses-permission
147     *     android:name="android.permission.WRITE_EXTERNAL_STORAGE"
148     *     android:maxSdkVersion="18" /&gt;</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">&lt;uses-permission
206     *     android:name="android.permission.WRITE_EXTERNAL_STORAGE"
207     *     android:maxSdkVersion="18" /&gt;</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">&lt;uses-permission
266     *     android:name="android.permission.WRITE_EXTERNAL_STORAGE"
267     *     android:maxSdkVersion="18" /&gt;</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