1/*
2 * Copyright (C) 2011 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.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.os.Build;
23
24/**
25 * Helper for accessing features in {@link android.content.Intent}
26 * introduced after API level 4 in a backwards compatible fashion.
27 */
28public class IntentCompat {
29
30    interface IntentCompatImpl {
31        Intent makeMainActivity(ComponentName componentName);
32        Intent makeMainSelectorActivity(String selectorAction, String selectorCategory);
33        Intent makeRestartActivityTask(ComponentName mainActivity);
34    }
35
36    static class IntentCompatImplBase implements IntentCompatImpl {
37        @Override
38        public Intent makeMainActivity(ComponentName componentName) {
39            Intent intent = new Intent(Intent.ACTION_MAIN);
40            intent.setComponent(componentName);
41            intent.addCategory(Intent.CATEGORY_LAUNCHER);
42            return intent;
43        }
44
45        @Override
46        public Intent makeMainSelectorActivity(String selectorAction,
47                String selectorCategory) {
48            // Before api 15 you couldn't set a selector intent.
49            // Fall back and just return an intent with the requested action/category,
50            // even though it won't be a proper "main" intent.
51            Intent intent = new Intent(selectorAction);
52            intent.addCategory(selectorCategory);
53            return intent;
54        }
55
56        @Override
57        public Intent makeRestartActivityTask(ComponentName mainActivity) {
58            Intent intent = makeMainActivity(mainActivity);
59            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
60                    | IntentCompat.FLAG_ACTIVITY_CLEAR_TASK);
61            return intent;
62        }
63    }
64
65    static class IntentCompatImplHC extends IntentCompatImplBase {
66        @Override
67        public Intent makeMainActivity(ComponentName componentName) {
68            return IntentCompatHoneycomb.makeMainActivity(componentName);
69        }
70        @Override
71        public Intent makeRestartActivityTask(ComponentName componentName) {
72            return IntentCompatHoneycomb.makeRestartActivityTask(componentName);
73        }
74    }
75
76    static class IntentCompatImplIcsMr1 extends IntentCompatImplHC {
77        @Override
78        public Intent makeMainSelectorActivity(String selectorAction, String selectorCategory) {
79            return IntentCompatIcsMr1.makeMainSelectorActivity(selectorAction, selectorCategory);
80        }
81    }
82
83    private static final IntentCompatImpl IMPL;
84    static {
85        final int version = Build.VERSION.SDK_INT;
86        if (version >= 15) {
87            IMPL = new IntentCompatImplIcsMr1();
88        } else if (version >= 11) {
89            IMPL = new IntentCompatImplHC();
90        } else {
91            IMPL = new IntentCompatImplBase();
92        }
93    }
94
95    private IntentCompat() {
96        /* Hide constructor */
97    }
98
99    /**
100     * Broadcast Action: Resources for a set of packages (which were
101     * previously unavailable) are currently
102     * available since the media on which they exist is available.
103     * The extra data {@link #EXTRA_CHANGED_PACKAGE_LIST} contains a
104     * list of packages whose availability changed.
105     * The extra data {@link #EXTRA_CHANGED_UID_LIST} contains a
106     * list of uids of packages whose availability changed.
107     * Note that the
108     * packages in this list do <em>not</em> receive this broadcast.
109     * The specified set of packages are now available on the system.
110     * <p>Includes the following extras:
111     * <ul>
112     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages
113     * whose resources(were previously unavailable) are currently available.
114     * {@link #EXTRA_CHANGED_UID_LIST} is the set of uids of the
115     * packages whose resources(were previously unavailable)
116     * are  currently available.
117     * </ul>
118     *
119     * <p class="note">This is a protected intent that can only be sent
120     * by the system.
121     */
122    public static final String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE =
123        "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE";
124
125    /**
126     * Broadcast Action: Resources for a set of packages are currently
127     * unavailable since the media on which they exist is unavailable.
128     * The extra data {@link #EXTRA_CHANGED_PACKAGE_LIST} contains a
129     * list of packages whose availability changed.
130     * The extra data {@link #EXTRA_CHANGED_UID_LIST} contains a
131     * list of uids of packages whose availability changed.
132     * The specified set of packages can no longer be
133     * launched and are practically unavailable on the system.
134     * <p>Inclues the following extras:
135     * <ul>
136     * <li> {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages
137     * whose resources are no longer available.
138     * {@link #EXTRA_CHANGED_UID_LIST} is the set of packages
139     * whose resources are no longer available.
140     * </ul>
141     *
142     * <p class="note">This is a protected intent that can only be sent
143     * by the system.
144     */
145    public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE =
146        "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABLE";
147
148    /**
149     * This field is part of
150     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
151     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
152     * and contains a string array of all of the components that have changed.
153     */
154    public static final String EXTRA_CHANGED_PACKAGE_LIST =
155            "android.intent.extra.changed_package_list";
156
157    /**
158     * This field is part of
159     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE},
160     * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE}
161     * and contains an integer array of uids of all of the components
162     * that have changed.
163     */
164    public static final String EXTRA_CHANGED_UID_LIST =
165            "android.intent.extra.changed_uid_list";
166
167    /**
168     * A constant String that is associated with the Intent, used with
169     * {@link android.content.Intent#ACTION_SEND} to supply an alternative to
170     * {@link android.content.Intent#EXTRA_TEXT}
171     * as HTML formatted text.  Note that you <em>must</em> also supply
172     * {@link android.content.Intent#EXTRA_TEXT}.
173     */
174    public static final String EXTRA_HTML_TEXT = "android.intent.extra.HTML_TEXT";
175
176    /**
177     * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
178     * this flag will cause a newly launching task to be placed on top of the current
179     * home activity task (if there is one). That is, pressing back from the task
180     * will always return the user to home even if that was not the last activity they
181     * saw. This can only be used in conjunction with
182     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}.
183     */
184    public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0x00004000;
185
186    /**
187     * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
188     * this flag will cause any existing task that would be associated with the
189     * activity to be cleared before the activity is started.  That is, the activity
190     * becomes the new root of an otherwise empty task, and any old activities
191     * are finished.  This can only be used in conjunction with
192     * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK}.
193     *
194     * <p>This flag will only be obeyed on devices supporting API 11 or higher.</p>
195     */
196    public static final int FLAG_ACTIVITY_CLEAR_TASK = 0x00008000;
197
198    /**
199     * Create an intent to launch the main (root) activity of a task.  This
200     * is the Intent that is started when the application's is launched from
201     * Home.  For anything else that wants to launch an application in the
202     * same way, it is important that they use an Intent structured the same
203     * way, and can use this function to ensure this is the case.
204     *
205     * <p>The returned Intent has the given Activity component as its explicit
206     * component, {@link Intent#ACTION_MAIN ACTION_MAIN} as its action, and includes the
207     * category {@link Intent#CATEGORY_LAUNCHER CATEGORY_LAUNCHER}.  This does <em>not</em> have
208     * {@link Intent#FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_NEW_TASK} set,
209     * though typically you will want to do that through {@link Intent#addFlags(int) addFlags(int)}
210     * on the returned Intent.
211     *
212     * @param mainActivity The main activity component that this Intent will
213     * launch.
214     * @return Returns a newly created Intent that can be used to launch the
215     * activity as a main application entry.
216     *
217     * @see Intent#setClass
218     * @see Intent#setComponent
219     */
220    public static Intent makeMainActivity(ComponentName mainActivity) {
221        return IMPL.makeMainActivity(mainActivity);
222    }
223
224
225    /**
226     * Make an Intent for the main activity of an application, without
227     * specifying a specific activity to run but giving a selector to find
228     * the activity.  This results in a final Intent that is structured
229     * the same as when the application is launched from
230     * Home.  For anything else that wants to launch an application in the
231     * same way, it is important that they use an Intent structured the same
232     * way, and can use this function to ensure this is the case.
233     *
234     * <p>The returned Intent has {@link Intent#ACTION_MAIN} as its action, and includes the
235     * category {@link Intent#CATEGORY_LAUNCHER}.  This does <em>not</em> have
236     * {@link Intent#FLAG_ACTIVITY_NEW_TASK} set, though typically you will want
237     * to do that through {@link Intent#addFlags(int)} on the returned Intent.
238     *
239     * @param selectorAction The action name of the Intent's selector.
240     * @param selectorCategory The name of a category to add to the Intent's
241     * selector.
242     * @return Returns a newly created Intent that can be used to launch the
243     * activity as a main application entry.
244     *
245     * @see #setSelector(Intent)
246     */
247    public static Intent makeMainSelectorActivity(String selectorAction,
248            String selectorCategory) {
249        return IMPL.makeMainSelectorActivity(selectorAction, selectorCategory);
250    }
251
252    /**
253     * Make an Intent that can be used to re-launch an application's task
254     * in its base state.  This is like {@link #makeMainActivity(ComponentName)},
255     * but also sets the flags {@link Intent#FLAG_ACTIVITY_NEW_TASK} and
256     * {@link IntentCompat#FLAG_ACTIVITY_CLEAR_TASK}.
257     *
258     * @param mainActivity The activity component that is the root of the
259     * task; this is the activity that has been published in the application's
260     * manifest as the main launcher icon.
261     *
262     * @return Returns a newly created Intent that can be used to relaunch the
263     * activity's task in its root state.
264     */
265    public static Intent makeRestartActivityTask(ComponentName mainActivity) {
266        return IMPL.makeRestartActivityTask(mainActivity);
267    }
268}
269