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.app.PendingIntent;
21f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powellimport android.content.ComponentName;
22c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.content.Context;
23c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.content.Intent;
24c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.content.pm.PackageManager.NameNotFoundException;
25c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.os.Build;
260306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powellimport android.os.Bundle;
27575e098da5bc16ff8b95ca080284253fd206fe12Adam Powellimport android.support.v4.content.ContextCompat;
28c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.support.v4.content.IntentCompat;
29c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport android.util.Log;
30c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
31c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport java.util.ArrayList;
32c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powellimport java.util.Iterator;
33c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
34c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell/**
35c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * Utility class for constructing synthetic back stacks for cross-task navigation
36c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * on Android 3.0 and newer.
37c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell *
38c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <p>In API level 11 (Android 3.0/Honeycomb) the recommended conventions for
39c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * app navigation using the back key changed. The back key's behavior is local
40c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * to the current task and does not capture navigation across different tasks.
41c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * Navigating across tasks and easily reaching the previous task is accomplished
42c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * through the "recents" UI, accessible through the software-provided Recents key
43c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * on the navigation or system bar. On devices with the older hardware button configuration
44c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * the recents UI can be accessed with a long press on the Home key.</p>
45c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell *
46c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <p>When crossing from one task stack to another post-Android 3.0,
47c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * the application should synthesize a back stack/history for the new task so that
48c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * the user may navigate out of the new task and back to the Launcher by repeated
49c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * presses of the back key. Back key presses should not navigate across task stacks.</p>
50c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell *
51c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <p>TaskStackBuilder provides a backward-compatible way to obey the correct conventions
52c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * around cross-task navigation on the device's version of the platform. On devices running
53c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * Android 3.0 or newer, calls to the {@link #startActivities()} method or sending the
54c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * {@link PendingIntent} generated by {@link #getPendingIntent(int, int)} will construct
55c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * the synthetic back stack as prescribed. On devices running older versions of the platform,
56c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * these same calls will invoke the topmost activity in the supplied stack, ignoring
57c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * the rest of the synthetic stack and allowing the back key to navigate back to the previous
58c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * task.</p>
59c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell *
60c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <div class="special reference">
61c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <h3>About Navigation</h3>
62c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * For more detailed information about tasks, the back stack, and navigation design guidelines,
63c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * please read
64c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back Stack</a>
65c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * from the developer guide and <a href="{@docRoot}design/patterns/navigation.html">Navigation</a>
66c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * from the design guide.
67c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell * </div>
68c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell */
69c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banespublic final class TaskStackBuilder implements Iterable<Intent> {
70c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    private static final String TAG = "TaskStackBuilder";
71c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
726f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes    public interface SupportParentable {
736f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        Intent getSupportParentActivityIntent();
746f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes    }
756f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes
76c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    interface TaskStackBuilderImpl {
77c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
780306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell                int flags, Bundle options);
79c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
80c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
81c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    static class TaskStackBuilderImplBase implements TaskStackBuilderImpl {
82c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
830306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell                int flags, Bundle options) {
84f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            Intent topIntent = new Intent(intents[intents.length - 1]);
85c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            topIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
86c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            return PendingIntent.getActivity(context, requestCode, topIntent, flags);
87c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
88c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
89c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
90c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    static class TaskStackBuilderImplHoneycomb implements TaskStackBuilderImpl {
91c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
920306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell                int flags, Bundle options) {
93f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
94f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                    IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
95f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                    IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
96c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            return TaskStackBuilderHoneycomb.getActivitiesPendingIntent(context, requestCode,
97c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                    intents, flags);
98c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
99c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
100c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
1010306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    static class TaskStackBuilderImplJellybean implements TaskStackBuilderImpl {
1020306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        public PendingIntent getPendingIntent(Context context, Intent[] intents, int requestCode,
1030306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell                int flags, Bundle options) {
104f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
105f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                    IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
106f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                    IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
1070306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell            return TaskStackBuilderJellybean.getActivitiesPendingIntent(context, requestCode,
1080306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell                    intents, flags, options);
1090306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        }
1100306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
1110306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
112c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    private static final TaskStackBuilderImpl IMPL;
113c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
114c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    static {
115c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        if (Build.VERSION.SDK_INT >= 11) {
116c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            IMPL = new TaskStackBuilderImplHoneycomb();
117c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        } else {
118c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            IMPL = new TaskStackBuilderImplBase();
119c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
120c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
121c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
122c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    private final ArrayList<Intent> mIntents = new ArrayList<Intent>();
123c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    private final Context mSourceContext;
124c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
125c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    private TaskStackBuilder(Context a) {
126c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        mSourceContext = a;
127c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
128c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
129c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
130c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Return a new TaskStackBuilder for launching a fresh task stack consisting
131c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * of a series of activities.
132c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
133c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param context The context that will launch the new task stack or generate a PendingIntent
134c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return A new TaskStackBuilder
135c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
1360306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public static TaskStackBuilder create(Context context) {
137c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return new TaskStackBuilder(context);
138c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
139c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
140c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
1410306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Return a new TaskStackBuilder for launching a fresh task stack consisting
1420306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * of a series of activities.
1430306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
1440306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param context The context that will launch the new task stack or generate a PendingIntent
1450306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @return A new TaskStackBuilder
1460306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
1470306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @deprecated use {@link #create(Context)} instead
1480306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
149d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    @Deprecated
1500306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public static TaskStackBuilder from(Context context) {
1510306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        return create(context);
1520306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
1530306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
1540306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
155c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Add a new Intent to the task stack. The most recently added Intent will invoke
156c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * the Activity at the top of the final task stack.
157c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
158c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param nextIntent Intent for the next Activity in the synthesized task stack
159c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return This TaskStackBuilder for method chaining
160c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
161c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public TaskStackBuilder addNextIntent(Intent nextIntent) {
162c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        mIntents.add(nextIntent);
163c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return this;
164c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
165c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
166c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
167f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * Add a new Intent with the resolved chain of parents for the target activity to
168f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * the task stack.
169f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     *
170f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * <p>This is equivalent to calling {@link #addParentStack(ComponentName) addParentStack}
171f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * with the resolved ComponentName of nextIntent (if it can be resolved), followed by
172f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * {@link #addNextIntent(Intent) addNextIntent} with nextIntent.</p>
173f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     *
174f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * @param nextIntent Intent for the topmost Activity in the synthesized task stack.
175f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     *                   Its chain of parents as specified in the manifest will be added.
176f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * @return This TaskStackBuilder for method chaining.
177f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     */
178f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    public TaskStackBuilder addNextIntentWithParentStack(Intent nextIntent) {
179f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        ComponentName target = nextIntent.getComponent();
180f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        if (target == null) {
181f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            target = nextIntent.resolveActivity(mSourceContext.getPackageManager());
182f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        }
183f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        if (target != null) {
184f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            addParentStack(target);
185f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        }
186f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        addNextIntent(nextIntent);
187f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        return this;
188f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    }
189f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell
190f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    /**
191c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Add the activity parent chain as specified by manifest &lt;meta-data&gt; elements
192c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * to the task stack builder.
193c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
194c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param sourceActivity All parents of this activity will be added
195c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return This TaskStackBuilder for method chaining
196c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
197c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public TaskStackBuilder addParentStack(Activity sourceActivity) {
1986f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        Intent parent = null;
1996f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        if (sourceActivity instanceof SupportParentable) {
2006f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes            parent = ((SupportParentable) sourceActivity).getSupportParentActivityIntent();
2016f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        }
2026f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        if (parent == null) {
2036f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes            parent = NavUtils.getParentActivityIntent(sourceActivity);
2046f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes        }
2056f9952fd5a1dc66c584b26b9062ba6efd69ebcc7Chris Banes
206f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        if (parent != null) {
207f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            // We have the actual parent intent, build the rest from static metadata
208f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            // then add the direct parent intent to the end.
209f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            ComponentName target = parent.getComponent();
210f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            if (target == null) {
211f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                target = parent.resolveActivity(mSourceContext.getPackageManager());
212c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            }
213f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            addParentStack(target);
214f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            addNextIntent(parent);
215c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
216c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return this;
217c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
218c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
219c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
220c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Add the activity parent chain as specified by manifest &lt;meta-data&gt; elements
221c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * to the task stack builder.
222c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
223c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param sourceActivityClass All parents of this activity will be added
224c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return This TaskStackBuilder for method chaining
225c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
226c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public TaskStackBuilder addParentStack(Class<?> sourceActivityClass) {
227f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        return addParentStack(new ComponentName(mSourceContext, sourceActivityClass));
228f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    }
229f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell
230f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    /**
231f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * Add the activity parent chain as specified by manifest &lt;meta-data&gt; elements
232f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * to the task stack builder.
233f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     *
234f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * @param sourceActivityName Must specify an Activity component. All parents of
235f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     *                           this activity will be added
236f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     * @return This TaskStackBuilder for method chaining
237f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell     */
238f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell    public TaskStackBuilder addParentStack(ComponentName sourceActivityName) {
239c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        final int insertAt = mIntents.size();
240c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        try {
241f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            Intent parent = NavUtils.getParentActivityIntent(mSourceContext, sourceActivityName);
242c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            while (parent != null) {
243c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                mIntents.add(insertAt, parent);
244c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                parent = NavUtils.getParentActivityIntent(mSourceContext, parent.getComponent());
245c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            }
246c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        } catch (NameNotFoundException e) {
247c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            Log.e(TAG, "Bad ComponentName while traversing activity parent metadata");
248c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            throw new IllegalArgumentException(e);
249c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
250c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return this;
251c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
252c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
253c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
254c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return the number of intents added so far.
255c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
256c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public int getIntentCount() {
257c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return mIntents.size();
258c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
259c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
260c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
261c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Get the intent at the specified index.
262c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Useful if you need to modify the flags or extras of an intent that was previously added,
263c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * for example with {@link #addParentStack(Activity)}.
264c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
265c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param index Index from 0-getIntentCount()
266c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return the intent at position index
2670306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
2680306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @deprecated Renamed to editIntentAt to better reflect intended usage
269c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
270d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    @Deprecated
271c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public Intent getIntent(int index) {
2720306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        return editIntentAt(index);
2730306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
2740306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
2750306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
2760306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Return the intent at the specified index for modification.
2770306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Useful if you need to modify the flags or extras of an intent that was previously added,
2780306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * for example with {@link #addParentStack(Activity)}.
2790306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
2800306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param index Index from 0-getIntentCount()
2810306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @return the intent at position index
2820306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
2830306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public Intent editIntentAt(int index) {
284c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return mIntents.get(index);
285c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
286c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
2870306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
2880306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @deprecated Use editIntentAt instead
2890306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
290d805095048f6be52cddbd572ee343c4639ba8187Alan Viverette    @Deprecated
291c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public Iterator<Intent> iterator() {
292c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        return mIntents.iterator();
293c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
294c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
295c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
296c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Start the task stack constructed by this builder. The Context used to obtain
297c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * this builder must be an Activity.
298c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
299c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * <p>On devices that do not support API level 11 or higher the topmost activity
300c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * will be started as a new task. On devices that do support API level 11 or higher
301c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * the new task stack will be created in its entirety.</p>
302c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
303c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public void startActivities() {
3040306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        startActivities(null);
3050306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
3060306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
3070306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
3080306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Start the task stack constructed by this builder. The Context used to obtain
3090306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * this builder must be an Activity.
3100306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
3110306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * <p>On devices that do not support API level 11 or higher the topmost activity
3120306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * will be started as a new task. On devices that do support API level 11 or higher
3130306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * the new task stack will be created in its entirety.</p>
3140306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
3150306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param options Additional options for how the Activity should be started.
3160306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * See {@link android.content.Context#startActivity(Intent, Bundle)
3170306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
3180306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public void startActivities(Bundle options) {
319c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        if (mIntents.isEmpty()) {
320c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            throw new IllegalStateException(
321c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                    "No intents added to TaskStackBuilder; cannot startActivities");
322c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
323c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
324c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
325f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
326c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
327c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
328575e098da5bc16ff8b95ca080284253fd206fe12Adam Powell        if (!ContextCompat.startActivities(mSourceContext, intents, options)) {
329f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            Intent topIntent = new Intent(intents[intents.length - 1]);
330c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            topIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
331c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell            mSourceContext.startActivity(topIntent);
332c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        }
333c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
334c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell
335c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    /**
336c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * Obtain a {@link PendingIntent} for launching the task constructed by this builder so far.
337c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *
338c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param requestCode Private request code for the sender
339c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT},
340c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *              {@link PendingIntent#FLAG_NO_CREATE}, {@link PendingIntent#FLAG_CANCEL_CURRENT},
341c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *              {@link PendingIntent#FLAG_UPDATE_CURRENT}, or any of the flags supported by
342c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *              {@link Intent#fillIn(Intent, int)} to control which unspecified parts of the
343c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     *              intent that can be supplied when the actual send happens.
344c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     * @return The obtained PendingIntent
345c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell     */
346c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    public PendingIntent getPendingIntent(int requestCode, int flags) {
3470306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        return getPendingIntent(requestCode, flags, null);
3480306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
3490306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
3500306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
3510306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Obtain a {@link PendingIntent} for launching the task constructed by this builder so far.
3520306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
3530306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param requestCode Private request code for the sender
3540306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param flags May be {@link PendingIntent#FLAG_ONE_SHOT},
3550306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *              {@link PendingIntent#FLAG_NO_CREATE}, {@link PendingIntent#FLAG_CANCEL_CURRENT},
3560306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *              {@link PendingIntent#FLAG_UPDATE_CURRENT}, or any of the flags supported by
3570306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *              {@link Intent#fillIn(Intent, int)} to control which unspecified parts of the
3580306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *              intent that can be supplied when the actual send happens.
3590306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @param options Additional options for how the Activity should be started.
3600306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * See {@link android.content.Context#startActivity(Intent, Bundle)
3610306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @return The obtained PendingIntent
3620306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
3630306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public PendingIntent getPendingIntent(int requestCode, int flags, Bundle options) {
36456a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell        if (mIntents.isEmpty()) {
36556a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell            throw new IllegalStateException(
36656a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell                    "No intents added to TaskStackBuilder; cannot getPendingIntent");
36756a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell        }
36856a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell
369c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell        Intent[] intents = mIntents.toArray(new Intent[mIntents.size()]);
370f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        intents[0] = new Intent(intents[0]).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
37156a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
37256a1f598b89d0e65dbd2a2678b66a43f5b7638c2Adam Powell                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
373f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        // Appropriate flags will be added by the call below.
3740306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell        return IMPL.getPendingIntent(mSourceContext, intents, requestCode, flags, options);
3750306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    }
3760306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell
3770306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    /**
3780306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * Return an array containing the intents added to this builder. The intent at the
3790306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * root of the task stack will appear as the first item in the array and the
3800306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * intent at the top of the stack will appear as the last item.
3810306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     *
3820306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     * @return An array containing the intents added to this builder.
3830306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell     */
3840306ebc908d5dcf148aa319a9734b419eacb23b5Adam Powell    public Intent[] getIntents() {
385f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        Intent[] intents = new Intent[mIntents.size()];
386f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        if (intents.length == 0) return intents;
387f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell
388f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        intents[0] = new Intent(mIntents.get(0)).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
389f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                IntentCompat.FLAG_ACTIVITY_CLEAR_TASK |
390f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell                IntentCompat.FLAG_ACTIVITY_TASK_ON_HOME);
391f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        for (int i = 1; i < intents.length; i++) {
392f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell            intents[i] = new Intent(mIntents.get(i));
393f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        }
394f19cb1f3facdb9f90ef1b26537ff303eaa3db77dAdam Powell        return intents;
395c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell    }
396c9cf2eb0a9b6694d0fda3dbc313844955db60820Adam Powell}
397