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} <meta-data> 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} <meta-data> 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} <meta-data> 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} <meta-data> 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} <meta-data> 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