NavUtils.java revision c9cf2eb0a9b6694d0fda3dbc313844955db60820
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.app;
18
19import android.app.Activity;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.ActivityInfo;
24import android.content.pm.PackageManager;
25import android.content.pm.PackageManager.NameNotFoundException;
26
27/**
28 * NavUtils provides helper functionality for applications implementing
29 * recommended Android UI navigation patterns. For information about recommended
30 * navigation patterns see
31 * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
32 * from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
33 * from the design guide.
34 */
35public class NavUtils {
36    private static final String TAG = "NavUtils";
37    public static final String PARENT_ACTIVITY = "android.support.PARENT_ACTIVITY";
38
39    /**
40     * Returns true if sourceActivity should recreate the task when navigating 'up'
41     * by using targetIntent.
42     *
43     * <p>If this method returns false the app can trivially call
44     * {@link #navigateUpTo(Activity, Intent)} using the same parameters to correctly perform
45     * up navigation. If this method returns false, the app should synthesize a new task stack
46     * by using {@link TaskStackBuilder} or another similar mechanism to perform up navigation.</p>
47     *
48     * @param sourceActivity The current activity from which the user is attempting to navigate up
49     * @param targetIntent An intent representing the target destination for up navigation
50     * @return true if navigating up should recreate a new task stack, false if the same task
51     *         should be used for the destination
52     */
53    public static boolean shouldUpRecreateTask(Activity sourceActivity, Intent targetIntent) {
54        String action = sourceActivity.getIntent().getAction();
55        return action != null && !action.equals(Intent.ACTION_MAIN);
56    }
57
58    /**
59     * Convenience method that is equivalent to calling
60     * <code>{@link #navigateUpTo(Activity, Intent) navigateUpTo}(sourceActivity,
61     * {@link #getParentActivityIntent(Activity) getParentActivityIntent} (sourceActivity))</code>.
62     * sourceActivity will be finished by this call.
63     *
64     * <p><em>Note:</em> This method should only be used when sourceActivity and the corresponding
65     * parent are within the same task. If up navigation should cross tasks in some cases, see
66     * {@link #shouldUpRecreateTask(Activity, Intent)}.</p>
67     *
68     * @param sourceActivity The current activity from which the user is attempting to navigate up
69     */
70    public static void navigateUpFromSameTask(Activity sourceActivity) {
71        Intent upIntent = getParentActivityIntent(sourceActivity);
72
73        if (upIntent == null) {
74            throw new IllegalArgumentException("Activity " +
75                    sourceActivity.getClass().getSimpleName() +
76                    " does not have a parent activity name specified." +
77                    " (Did you forget to add the android.support.PARENT_ACTIVITY <meta-data> " +
78                    " element in your manifest?)");
79        }
80
81        navigateUpTo(sourceActivity, upIntent);
82    }
83
84    /**
85     * Navigate from sourceActivity to the activity specified by upIntent, finishing sourceActivity
86     * in the process. upIntent will have the flag {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} set
87     * by this method, along with any others required for proper up navigation as outlined
88     * in the Android Design Guide.
89     *
90     * <p>This method should be used when performing up navigation from within the same task
91     * as the destination. If up navigation should cross tasks in some cases, see
92     * {@link #shouldUpRecreateTask(Activity, Intent)}.</p>
93     *
94     * @param sourceActivity The current activity from which the user is attempting to navigate up
95     * @param upIntent An intent representing the target destination for up navigation
96     */
97    public static void navigateUpTo(Activity sourceActivity, Intent upIntent) {
98        upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
99        sourceActivity.startActivity(upIntent);
100        sourceActivity.finish();
101    }
102
103    /**
104     * Obtain an {@link Intent} that will launch {@link Intent#ACTION_MAIN} with an explicit
105     * target activity specified by sourceActivity's {@link #PARENT_ACTIVITY} &lt;meta-data&gt;
106     * element in the application's manifest.
107     *
108     * @param sourceActivity Activity to fetch a parent intent for
109     * @return a new Intent targeting the defined parent activity of sourceActivity
110     */
111    public static Intent getParentActivityIntent(Activity sourceActivity) {
112        String parentActivity = getParentActivityName(sourceActivity);
113        if (parentActivity == null) return null;
114        return new Intent(Intent.ACTION_MAIN).setClassName(sourceActivity, parentActivity);
115    }
116
117    /**
118     * Obtain an {@link Intent} that will launch {@link Intent#ACTION_MAIN} with an explicit
119     * target activity specified by sourceActivityClass's {@link #PARENT_ACTIVITY} &lt;meta-data&gt;
120     * element in the application's manifest.
121     *
122     * @param context Context for looking up the activity component for sourceActivityClass
123     * @param sourceActivityClass {@link java.lang.Class} object for an Activity class
124     * @return a new Intent targeting the defined parent activity of sourceActivity
125     * @throws NameNotFoundException if the ComponentName for sourceActivityClass is invalid
126     */
127    public static Intent getParentActivityIntent(Context context, Class<?> sourceActivityClass)
128            throws NameNotFoundException {
129        String parentActivity = getParentActivityName(context,
130                new ComponentName(context, sourceActivityClass));
131        if (parentActivity == null) return null;
132        return new Intent(Intent.ACTION_MAIN).setClassName(context, parentActivity);
133    }
134
135    /**
136     * Obtain an {@link Intent} that will launch {@link Intent#ACTION_MAIN} with an explicit
137     * target activity specified by sourceActivityClass's {@link #PARENT_ACTIVITY} &lt;meta-data&gt;
138     * element in the application's manifest.
139     *
140     * @param context Context for looking up the activity component for the source activity
141     * @param componentName ComponentName for the source Activity
142     * @return a new Intent targeting the defined parent activity of sourceActivity
143     * @throws NameNotFoundException if the ComponentName for sourceActivityClass is invalid
144     */
145    public static Intent getParentActivityIntent(Context context, ComponentName componentName)
146            throws NameNotFoundException {
147        String parentActivity = getParentActivityName(context, componentName);
148        if (parentActivity == null) return null;
149        if (parentActivity.charAt(0) == '.') {
150            parentActivity = context.getPackageName() + parentActivity;
151        }
152        return new Intent(Intent.ACTION_MAIN).setClassName(context, parentActivity);
153    }
154
155    /**
156     * Return the fully qualified class name of sourceActivity's parent activity as specified by
157     * a {@link #PARENT_ACTIVITY} &lt;meta-data&gt; element within the activity element in
158     * the application's manifest.
159     *
160     * @param sourceActivity Activity to fetch a parent class name for
161     * @return The fully qualified class name of sourceActivity's parent activity or null if
162     *         it was not specified
163     */
164    public static String getParentActivityName(Activity sourceActivity) {
165        try {
166            return getParentActivityName(sourceActivity, sourceActivity.getComponentName());
167        } catch (NameNotFoundException e) {
168            // Component name of supplied activity does not exist...?
169            throw new IllegalArgumentException(e);
170        }
171    }
172    /**
173     * Return the fully qualified class name of a source activity's parent activity as specified by
174     * a {@link #PARENT_ACTIVITY} &lt;meta-data&gt; element within the activity element in
175     * the application's manifest. The source activity is provided by componentName.
176     *
177     * @param context Context for looking up the activity component for the source activity
178     * @param componentName ComponentName for the source Activity
179     * @return The fully qualified class name of sourceActivity's parent activity or null if
180     *         it was not specified
181     */
182    public static String getParentActivityName(Context context, ComponentName componentName)
183            throws NameNotFoundException {
184        PackageManager pm = context.getPackageManager();
185        ActivityInfo info = pm.getActivityInfo(componentName, PackageManager.GET_META_DATA);
186        if (info.metaData == null) return null;
187        String parentActivity = info.metaData.getString(PARENT_ACTIVITY);
188        if (parentActivity == null) return null;
189        if (parentActivity.charAt(0) == '.') {
190            parentActivity = context.getPackageName() + parentActivity;
191        }
192        return parentActivity;
193    }
194
195    /** No instances! */
196    private NavUtils() {
197    }
198}
199