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