blob: 72c91562d647ba5fe2f581e079b9560422b4be78 [file] [log] [blame]
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001/*
2 * Copyright (C) 2010 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.app;
18
Chet Haasea18a86b2010-09-07 13:20:00 -070019import android.animation.Animator;
20import android.animation.AnimatorInflater;
Chet Haaseb20db3e2010-09-10 13:07:30 -070021import android.animation.AnimatorListenerAdapter;
Dianne Hackborn9d071802010-12-08 14:49:15 -080022import android.content.res.Configuration;
Dianne Hackbornf121be72010-05-06 14:10:32 -070023import android.content.res.TypedArray;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070024import android.os.Bundle;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -070025import android.os.Debug;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -070026import android.os.Handler;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -080027import android.os.Looper;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070028import android.os.Parcel;
29import android.os.Parcelable;
Dianne Hackborna2ea7472010-12-20 12:10:01 -080030import android.util.DebugUtils;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070031import android.util.Log;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -080032import android.util.LogWriter;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070033import android.util.SparseArray;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -070034import android.view.Menu;
35import android.view.MenuInflater;
36import android.view.MenuItem;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070037import android.view.View;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070038import android.view.ViewGroup;
39
Dianne Hackborn625ac272010-09-17 18:29:22 -070040import java.io.FileDescriptor;
41import java.io.PrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070042import java.util.ArrayList;
Dianne Hackbornd173fa32010-12-23 13:58:22 -080043import java.util.Arrays;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070044
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070045/**
46 * Interface for interacting with {@link Fragment} objects inside of an
47 * {@link Activity}
Joe Fernandezb54e7a32011-10-03 15:09:50 -070048 *
49 * <div class="special reference">
50 * <h3>Developer Guides</h3>
51 * <p>For more information about using fragments, read the
52 * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
53 * </div>
Dianne Hackborn7871bad2011-12-12 15:19:26 -080054 *
55 * While the FragmentManager API was introduced in
56 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
57 * at is also available for use on older platforms through
58 * {@link android.support.v4.app.FragmentActivity}. See the blog post
59 * <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
60 * Fragments For All</a> for more details.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070061 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -070062public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070063 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070064 * Representation of an entry on the fragment back stack, as created
65 * with {@link FragmentTransaction#addToBackStack(String)
66 * FragmentTransaction.addToBackStack()}. Entries can later be
Dianne Hackborn327fbd22011-01-17 14:38:50 -080067 * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070068 * FragmentManager.getBackStackEntry()}.
69 *
70 * <p>Note that you should never hold on to a BackStackEntry object;
71 * the identifier as returned by {@link #getId} is the only thing that
72 * will be persisted across activity instances.
73 */
74 public interface BackStackEntry {
75 /**
76 * Return the unique identifier for the entry. This is the only
77 * representation of the entry that will persist across activity
78 * instances.
79 */
80 public int getId();
81
82 /**
Dianne Hackborn6c285972011-08-29 16:53:49 -070083 * Get the name that was supplied to
84 * {@link FragmentTransaction#addToBackStack(String)
85 * FragmentTransaction.addToBackStack(String)} when creating this entry.
86 */
87 public String getName();
88
89 /**
Dianne Hackborn327fbd22011-01-17 14:38:50 -080090 * Return the full bread crumb title resource identifier for the entry,
91 * or 0 if it does not have one.
92 */
93 public int getBreadCrumbTitleRes();
94
95 /**
96 * Return the short bread crumb title resource identifier for the entry,
97 * or 0 if it does not have one.
98 */
99 public int getBreadCrumbShortTitleRes();
100
101 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700102 * Return the full bread crumb title for the entry, or null if it
103 * does not have one.
104 */
105 public CharSequence getBreadCrumbTitle();
106
107 /**
108 * Return the short bread crumb title for the entry, or null if it
109 * does not have one.
110 */
111 public CharSequence getBreadCrumbShortTitle();
112 }
113
114 /**
115 * Interface to watch for changes to the back stack.
116 */
117 public interface OnBackStackChangedListener {
118 /**
119 * Called whenever the contents of the back stack change.
120 */
121 public void onBackStackChanged();
122 }
123
124 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700125 * Start a series of edit operations on the Fragments associated with
126 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700127 *
128 * <p>Note: A fragment transaction can only be created/committed prior
129 * to an activity saving its state. If you try to commit a transaction
130 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
131 * (and prior to a following {@link Activity#onStart Activity.onStart}
132 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
133 * This is because the framework takes care of saving your current fragments
134 * in the state, and if changes are made after the state is saved then they
135 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700136 */
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800137 public abstract FragmentTransaction beginTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700138
Dianne Hackborn17b9b812011-01-17 17:16:02 -0800139 /** @hide -- remove once prebuilts are in. */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800140 @Deprecated
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800141 public FragmentTransaction openTransaction() {
142 return beginTransaction();
143 }
144
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700145 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800146 * After a {@link FragmentTransaction} is committed with
147 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
148 * is scheduled to be executed asynchronously on the process's main thread.
149 * If you want to immediately executing any such pending operations, you
150 * can call this function (only from the main thread) to do so. Note that
151 * all callbacks and other related behavior will be done from within this
152 * call, so be careful about where this is called from.
153 *
154 * @return Returns true if there were any pending transactions to be
155 * executed.
156 */
157 public abstract boolean executePendingTransactions();
158
159 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700160 * Finds a fragment that was identified by the given id either when inflated
161 * from XML or as the container ID when added in a transaction. This first
162 * searches through fragments that are currently added to the manager's
163 * activity; if no such fragment is found, then all fragments currently
164 * on the back stack associated with this ID are searched.
165 * @return The fragment if found or null otherwise.
166 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700167 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700168
169 /**
170 * Finds a fragment that was identified by the given tag either when inflated
171 * from XML or as supplied when added in a transaction. This first
172 * searches through fragments that are currently added to the manager's
173 * activity; if no such fragment is found, then all fragments currently
174 * on the back stack are searched.
175 * @return The fragment if found or null otherwise.
176 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700177 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700178
179 /**
180 * Flag for {@link #popBackStack(String, int)}
181 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
182 * a back stack entry has been supplied, then all matching entries will
183 * be consumed until one that doesn't match is found or the bottom of
184 * the stack is reached. Otherwise, all entries up to but not including that entry
185 * will be removed.
186 */
187 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
188
189 /**
Ben Komalo87ffa202011-02-28 12:41:42 -0800190 * Pop the top state off the back stack. This function is asynchronous -- it
191 * enqueues the request to pop, but the action will not be performed until the
192 * application returns to its event loop.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700193 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800194 public abstract void popBackStack();
195
196 /**
197 * Like {@link #popBackStack()}, but performs the operation immediately
198 * inside of the call. This is like calling {@link #executePendingTransactions()}
199 * afterwards.
200 * @return Returns true if there was something popped, else false.
201 */
202 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700203
204 /**
205 * Pop the last fragment transition from the manager's fragment
206 * back stack. If there is nothing to pop, false is returned.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800207 * This function is asynchronous -- it enqueues the
208 * request to pop, but the action will not be performed until the application
209 * returns to its event loop.
210 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700211 * @param name If non-null, this is the name of a previous back state
212 * to look for; if found, all states up to that state will be popped. The
213 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
214 * the named state itself is popped. If null, only the top state is popped.
215 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
216 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800217 public abstract void popBackStack(String name, int flags);
218
219 /**
220 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
221 * inside of the call. This is like calling {@link #executePendingTransactions()}
222 * afterwards.
223 * @return Returns true if there was something popped, else false.
224 */
225 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700226
227 /**
228 * Pop all back stack states up to the one with the given identifier.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800229 * This function is asynchronous -- it enqueues the
230 * request to pop, but the action will not be performed until the application
231 * returns to its event loop.
232 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700233 * @param id Identifier of the stated to be popped. If no identifier exists,
234 * false is returned.
235 * The identifier is the number returned by
236 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
237 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
238 * the named state itself is popped.
239 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
240 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800241 public abstract void popBackStack(int id, int flags);
242
243 /**
244 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
245 * inside of the call. This is like calling {@link #executePendingTransactions()}
246 * afterwards.
247 * @return Returns true if there was something popped, else false.
248 */
249 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700250
251 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700252 * Return the number of entries currently in the back stack.
253 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800254 public abstract int getBackStackEntryCount();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700255
256 /**
257 * Return the BackStackEntry at index <var>index</var> in the back stack;
258 * entries start index 0 being the bottom of the stack.
259 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800260 public abstract BackStackEntry getBackStackEntryAt(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700261
262 /**
263 * Add a new listener for changes to the fragment back stack.
264 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700265 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700266
267 /**
268 * Remove a listener that was previously added with
269 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
270 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700271 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700272
273 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700274 * Put a reference to a fragment in a Bundle. This Bundle can be
275 * persisted as saved state, and when later restoring
276 * {@link #getFragment(Bundle, String)} will return the current
277 * instance of the same fragment.
278 *
279 * @param bundle The bundle in which to put the fragment reference.
280 * @param key The name of the entry in the bundle.
281 * @param fragment The Fragment whose reference is to be stored.
282 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700283 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700284
285 /**
286 * Retrieve the current Fragment instance for a reference previously
287 * placed with {@link #putFragment(Bundle, String, Fragment)}.
288 *
289 * @param bundle The bundle from which to retrieve the fragment reference.
290 * @param key The name of the entry in the bundle.
291 * @return Returns the current Fragment instance that is associated with
292 * the given reference.
293 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700294 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700295
296 /**
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700297 * Save the current instance state of the given Fragment. This can be
298 * used later when creating a new instance of the Fragment and adding
299 * it to the fragment manager, to have it create itself to match the
300 * current state returned here. Note that there are limits on how
301 * this can be used:
302 *
303 * <ul>
304 * <li>The Fragment must currently be attached to the FragmentManager.
305 * <li>A new Fragment created using this saved state must be the same class
306 * type as the Fragment it was created from.
307 * <li>The saved state can not contain dependencies on other fragments --
308 * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
309 * store a fragment reference because that reference may not be valid when
310 * this saved state is later used. Likewise the Fragment's target and
311 * result code are not included in this state.
312 * </ul>
313 *
314 * @param f The Fragment whose state is to be saved.
315 * @return The generated state. This will be null if there was no
316 * interesting state created by the fragment.
317 */
318 public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
319
320 /**
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700321 * Returns true if the final {@link Activity#onDestroy() Activity.onDestroy()}
322 * call has been made on the FragmentManager's Activity, so this instance is now dead.
323 */
324 public abstract boolean isDestroyed();
325
326 /**
Dianne Hackborn625ac272010-09-17 18:29:22 -0700327 * Print the FragmentManager's state into the given stream.
328 *
329 * @param prefix Text to print at the front of each line.
330 * @param fd The raw file descriptor that the dump is being sent to.
331 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800332 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700333 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700334 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800335
336 /**
337 * Control whether the framework's internal fragment manager debugging
338 * logs are turned on. If enabled, you will see output in logcat as
339 * the framework performs fragment operations.
340 */
341 public static void enableDebugLogging(boolean enabled) {
342 FragmentManagerImpl.DEBUG = enabled;
343 }
Adam Powellf0f5fff2011-08-01 13:42:50 -0700344
345 /**
346 * Invalidate the attached activity's options menu as necessary.
347 * This may end up being deferred until we move to the resumed state.
348 */
349 public void invalidateOptionsMenu() { }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700350}
351
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700352final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700353 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700354 int[] mAdded;
355 BackStackState[] mBackStack;
356
357 public FragmentManagerState() {
358 }
359
360 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700361 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700362 mAdded = in.createIntArray();
363 mBackStack = in.createTypedArray(BackStackState.CREATOR);
364 }
365
366 public int describeContents() {
367 return 0;
368 }
369
370 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700371 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700372 dest.writeIntArray(mAdded);
373 dest.writeTypedArray(mBackStack, flags);
374 }
375
376 public static final Parcelable.Creator<FragmentManagerState> CREATOR
377 = new Parcelable.Creator<FragmentManagerState>() {
378 public FragmentManagerState createFromParcel(Parcel in) {
379 return new FragmentManagerState(in);
380 }
381
382 public FragmentManagerState[] newArray(int size) {
383 return new FragmentManagerState[size];
384 }
385 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700386}
387
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700388/**
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700389 * Callbacks from FragmentManagerImpl to its container.
390 */
391interface FragmentContainer {
392 public View findViewById(int id);
393}
394
395/**
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700396 * Container for fragments associated with an activity.
397 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700398final class FragmentManagerImpl extends FragmentManager {
Craig Mautner1c437192012-08-01 10:01:16 -0700399 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700400 static final String TAG = "FragmentManager";
401
Dianne Hackborndef15372010-08-15 12:43:52 -0700402 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
403 static final String TARGET_STATE_TAG = "android:target_state";
404 static final String VIEW_STATE_TAG = "android:view_state";
Adam Powell78fed9b2011-11-07 10:45:34 -0800405 static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
Dianne Hackborndef15372010-08-15 12:43:52 -0700406
Dianne Hackborn445646c2010-06-25 15:52:59 -0700407 ArrayList<Runnable> mPendingActions;
408 Runnable[] mTmpActions;
409 boolean mExecutingActions;
410
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700411 ArrayList<Fragment> mActive;
412 ArrayList<Fragment> mAdded;
413 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700414 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700415 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700416
Dianne Hackborndd913a52010-07-22 12:17:04 -0700417 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700418 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700419 ArrayList<Integer> mAvailBackStackIndices;
420
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700421 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
422
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700423 int mCurState = Fragment.INITIALIZING;
424 Activity mActivity;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700425 FragmentContainer mContainer;
426 Fragment mParent;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700427
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700428 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700429 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800430 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700431 String mNoTransactionsBecause;
Adam Powell78fed9b2011-11-07 10:45:34 -0800432 boolean mHavePendingDeferredStart;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700433
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700434 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700435 Bundle mStateBundle = null;
436 SparseArray<Parcelable> mStateArray = null;
437
Dianne Hackborn445646c2010-06-25 15:52:59 -0700438 Runnable mExecCommit = new Runnable() {
439 @Override
440 public void run() {
441 execPendingActions();
442 }
443 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700444
Dianne Hackborn4702a852012-08-17 15:18:29 -0700445 private void throwException(RuntimeException ex) {
446 Log.e(TAG, ex.getMessage());
447 LogWriter logw = new LogWriter(Log.ERROR, TAG);
448 PrintWriter pw = new PrintWriter(logw);
449 if (mActivity != null) {
450 Log.e(TAG, "Activity state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700451 try {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700452 mActivity.dump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700453 } catch (Exception e) {
454 Log.e(TAG, "Failed dumping state", e);
455 }
456 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700457 Log.e(TAG, "Fragment manager state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700458 try {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700459 dump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700460 } catch (Exception e) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700461 Log.e(TAG, "Failed dumping state", e);
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700462 }
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700463 }
Dianne Hackborn4702a852012-08-17 15:18:29 -0700464 throw ex;
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700465 }
466
Dianne Hackborn625ac272010-09-17 18:29:22 -0700467 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800468 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700469 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700470 }
471
Dianne Hackborn625ac272010-09-17 18:29:22 -0700472 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800473 public boolean executePendingTransactions() {
474 return execPendingActions();
475 }
476
477 @Override
478 public void popBackStack() {
479 enqueueAction(new Runnable() {
480 @Override public void run() {
481 popBackStackState(mActivity.mHandler, null, -1, 0);
482 }
483 }, false);
484 }
485
486 @Override
487 public boolean popBackStackImmediate() {
488 checkStateLoss();
489 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700490 return popBackStackState(mActivity.mHandler, null, -1, 0);
491 }
492
Dianne Hackborn625ac272010-09-17 18:29:22 -0700493 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800494 public void popBackStack(final String name, final int flags) {
495 enqueueAction(new Runnable() {
496 @Override public void run() {
497 popBackStackState(mActivity.mHandler, name, -1, flags);
498 }
499 }, false);
500 }
501
502 @Override
503 public boolean popBackStackImmediate(String name, int flags) {
504 checkStateLoss();
505 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700506 return popBackStackState(mActivity.mHandler, name, -1, flags);
507 }
508
Dianne Hackborn625ac272010-09-17 18:29:22 -0700509 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800510 public void popBackStack(final int id, final int flags) {
511 if (id < 0) {
512 throw new IllegalArgumentException("Bad id: " + id);
513 }
514 enqueueAction(new Runnable() {
515 @Override public void run() {
516 popBackStackState(mActivity.mHandler, null, id, flags);
517 }
518 }, false);
519 }
520
521 @Override
522 public boolean popBackStackImmediate(int id, int flags) {
523 checkStateLoss();
524 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700525 if (id < 0) {
526 throw new IllegalArgumentException("Bad id: " + id);
527 }
528 return popBackStackState(mActivity.mHandler, null, id, flags);
529 }
530
Dianne Hackborn625ac272010-09-17 18:29:22 -0700531 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800532 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700533 return mBackStack != null ? mBackStack.size() : 0;
534 }
535
Dianne Hackborn625ac272010-09-17 18:29:22 -0700536 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800537 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700538 return mBackStack.get(index);
539 }
540
Dianne Hackborn625ac272010-09-17 18:29:22 -0700541 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700542 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
543 if (mBackStackChangeListeners == null) {
544 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
545 }
546 mBackStackChangeListeners.add(listener);
547 }
548
Dianne Hackborn625ac272010-09-17 18:29:22 -0700549 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700550 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
551 if (mBackStackChangeListeners != null) {
552 mBackStackChangeListeners.remove(listener);
553 }
554 }
555
Dianne Hackborn625ac272010-09-17 18:29:22 -0700556 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700557 public void putFragment(Bundle bundle, String key, Fragment fragment) {
558 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700559 throwException(new IllegalStateException("Fragment " + fragment
560 + " is not currently in the FragmentManager"));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700561 }
562 bundle.putInt(key, fragment.mIndex);
563 }
564
Dianne Hackborn625ac272010-09-17 18:29:22 -0700565 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700566 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700567 int index = bundle.getInt(key, -1);
568 if (index == -1) {
569 return null;
570 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700571 if (index >= mActive.size()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700572 throwException(new IllegalStateException("Fragement no longer exists for key "
573 + key + ": index " + index));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700574 }
575 Fragment f = mActive.get(index);
576 if (f == null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700577 throwException(new IllegalStateException("Fragement no longer exists for key "
578 + key + ": index " + index));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700579 }
580 return f;
581 }
582
Dianne Hackborn625ac272010-09-17 18:29:22 -0700583 @Override
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700584 public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
585 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700586 throwException(new IllegalStateException("Fragment " + fragment
587 + " is not currently in the FragmentManager"));
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700588 }
589 if (fragment.mState > Fragment.INITIALIZING) {
590 Bundle result = saveFragmentBasicState(fragment);
591 return result != null ? new Fragment.SavedState(result) : null;
592 }
593 return null;
594 }
595
596 @Override
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700597 public boolean isDestroyed() {
598 return mDestroyed;
599 }
600
601 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800602 public String toString() {
603 StringBuilder sb = new StringBuilder(128);
604 sb.append("FragmentManager{");
605 sb.append(Integer.toHexString(System.identityHashCode(this)));
606 sb.append(" in ");
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700607 if (mParent != null) {
608 DebugUtils.buildShortClassTag(mParent, sb);
609 } else {
610 DebugUtils.buildShortClassTag(mActivity, sb);
611 }
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800612 sb.append("}}");
613 return sb.toString();
614 }
615
616 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700617 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700618 String innerPrefix = prefix + " ";
619
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800620 int N;
621 if (mActive != null) {
622 N = mActive.size();
623 if (N > 0) {
624 writer.print(prefix); writer.print("Active Fragments in ");
625 writer.print(Integer.toHexString(System.identityHashCode(this)));
626 writer.println(":");
627 for (int i=0; i<N; i++) {
628 Fragment f = mActive.get(i);
629 writer.print(prefix); writer.print(" #"); writer.print(i);
630 writer.print(": "); writer.println(f);
631 if (f != null) {
632 f.dump(innerPrefix, fd, writer, args);
633 }
634 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700635 }
636 }
637
638 if (mAdded != null) {
639 N = mAdded.size();
640 if (N > 0) {
641 writer.print(prefix); writer.println("Added Fragments:");
642 for (int i=0; i<N; i++) {
643 Fragment f = mAdded.get(i);
644 writer.print(prefix); writer.print(" #"); writer.print(i);
645 writer.print(": "); writer.println(f.toString());
646 }
647 }
648 }
649
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800650 if (mCreatedMenus != null) {
651 N = mCreatedMenus.size();
652 if (N > 0) {
653 writer.print(prefix); writer.println("Fragments Created Menus:");
654 for (int i=0; i<N; i++) {
655 Fragment f = mCreatedMenus.get(i);
656 writer.print(prefix); writer.print(" #"); writer.print(i);
657 writer.print(": "); writer.println(f.toString());
658 }
659 }
660 }
661
Dianne Hackborn625ac272010-09-17 18:29:22 -0700662 if (mBackStack != null) {
663 N = mBackStack.size();
664 if (N > 0) {
665 writer.print(prefix); writer.println("Back Stack:");
666 for (int i=0; i<N; i++) {
667 BackStackRecord bs = mBackStack.get(i);
668 writer.print(prefix); writer.print(" #"); writer.print(i);
669 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800670 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700671 }
672 }
673 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800674
675 synchronized (this) {
676 if (mBackStackIndices != null) {
677 N = mBackStackIndices.size();
678 if (N > 0) {
679 writer.print(prefix); writer.println("Back Stack Indices:");
680 for (int i=0; i<N; i++) {
681 BackStackRecord bs = mBackStackIndices.get(i);
682 writer.print(prefix); writer.print(" #"); writer.print(i);
683 writer.print(": "); writer.println(bs);
684 }
685 }
686 }
687
688 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
689 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
690 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
691 }
692 }
693
694 if (mPendingActions != null) {
695 N = mPendingActions.size();
696 if (N > 0) {
697 writer.print(prefix); writer.println("Pending Actions:");
698 for (int i=0; i<N; i++) {
699 Runnable r = mPendingActions.get(i);
700 writer.print(prefix); writer.print(" #"); writer.print(i);
701 writer.print(": "); writer.println(r);
702 }
703 }
704 }
705
706 writer.print(prefix); writer.println("FragmentManager misc state:");
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700707 writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
708 writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
709 if (mParent != null) {
710 writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
711 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800712 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
713 writer.print(" mStateSaved="); writer.print(mStateSaved);
714 writer.print(" mDestroyed="); writer.println(mDestroyed);
715 if (mNeedMenuInvalidate) {
716 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
717 writer.println(mNeedMenuInvalidate);
718 }
719 if (mNoTransactionsBecause != null) {
720 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
721 writer.println(mNoTransactionsBecause);
722 }
723 if (mAvailIndices != null && mAvailIndices.size() > 0) {
724 writer.print(prefix); writer.print(" mAvailIndices: ");
725 writer.println(Arrays.toString(mAvailIndices.toArray()));
726 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700727 }
728
Chet Haasea18a86b2010-09-07 13:20:00 -0700729 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700730 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700731 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700732 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700733 if (animObj != null) {
734 return animObj;
735 }
736
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700737 if (fragment.mNextAnim != 0) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700738 Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700739 if (anim != null) {
740 return anim;
741 }
742 }
743
Dianne Hackbornf121be72010-05-06 14:10:32 -0700744 if (transit == 0) {
745 return null;
746 }
747
748 int styleIndex = transitToStyleIndex(transit, enter);
749 if (styleIndex < 0) {
750 return null;
751 }
752
753 if (transitionStyle == 0 && mActivity.getWindow() != null) {
754 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
755 }
756 if (transitionStyle == 0) {
757 return null;
758 }
759
760 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700761 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700762 int anim = attrs.getResourceId(styleIndex, 0);
763 attrs.recycle();
764
765 if (anim == 0) {
766 return null;
767 }
768
Chet Haasea18a86b2010-09-07 13:20:00 -0700769 return AnimatorInflater.loadAnimator(mActivity, anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700770 }
771
Adam Powell635c60a2011-10-26 10:22:16 -0700772 public void performPendingDeferredStart(Fragment f) {
773 if (f.mDeferStart) {
Adam Powell78fed9b2011-11-07 10:45:34 -0800774 if (mExecutingActions) {
775 // Wait until we're done executing our pending transactions
776 mHavePendingDeferredStart = true;
777 return;
778 }
Adam Powell635c60a2011-10-26 10:22:16 -0700779 f.mDeferStart = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700780 moveToState(f, mCurState, 0, 0, false);
Adam Powell635c60a2011-10-26 10:22:16 -0700781 }
782 }
783
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700784 void moveToState(Fragment f, int newState, int transit, int transitionStyle,
785 boolean keepActive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -0700786 if (DEBUG && false) Log.v(TAG, "moveToState: " + f
787 + " oldState=" + f.mState + " newState=" + newState
788 + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
Craig Mautner1c437192012-08-01 10:01:16 -0700789
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700790 // Fragments that are not currently added will sit in the onCreate() state.
Dianne Hackborne181bd92012-09-25 14:15:15 -0700791 if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700792 newState = Fragment.CREATED;
793 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700794 if (f.mRemoving && newState > f.mState) {
795 // While removing a fragment, we can't change it to a higher state.
796 newState = f.mState;
797 }
Adam Powell2db4e4b2011-11-02 14:30:47 -0700798 // Defer start if requested; don't allow it to move to STARTED or higher
799 // if it's not already started.
800 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -0700801 newState = Fragment.STOPPED;
802 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700803 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800804 // For fragments that are created from a layout, when restoring from
805 // state we don't want to allow them to be created until they are
806 // being reloaded from the layout.
807 if (f.mFromLayout && !f.mInLayout) {
808 return;
809 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800810 if (f.mAnimatingAway != null) {
811 // The fragment is currently being animated... but! Now we
812 // want to move our state back up. Give up on waiting for the
813 // animation, move to whatever the final state should be once
814 // the animation is done, and then we can proceed from there.
815 f.mAnimatingAway = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700816 moveToState(f, f.mStateAfterAnimating, 0, 0, true);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800817 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700818 switch (f.mState) {
819 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700820 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700821 if (f.mSavedFragmentState != null) {
822 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
823 FragmentManagerImpl.VIEW_STATE_TAG);
824 f.mTarget = getFragment(f.mSavedFragmentState,
825 FragmentManagerImpl.TARGET_STATE_TAG);
826 if (f.mTarget != null) {
827 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
828 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
829 }
Adam Powell78fed9b2011-11-07 10:45:34 -0800830 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
831 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
832 if (!f.mUserVisibleHint) {
833 f.mDeferStart = true;
834 if (newState > Fragment.STOPPED) {
835 newState = Fragment.STOPPED;
836 }
837 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700838 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700839 f.mActivity = mActivity;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700840 f.mParentFragment = mParent;
841 f.mFragmentManager = mParent != null
842 ? mParent.mChildFragmentManager : mActivity.mFragments;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700843 f.mCalled = false;
844 f.onAttach(mActivity);
845 if (!f.mCalled) {
846 throw new SuperNotCalledException("Fragment " + f
847 + " did not call through to super.onAttach()");
848 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700849 if (f.mParentFragment == null) {
850 mActivity.onAttachFragment(f);
851 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700852
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700853 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700854 f.performCreate(f.mSavedFragmentState);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700855 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700856 f.mRetaining = false;
857 if (f.mFromLayout) {
858 // For fragments that are part of the content view
859 // layout, we need to instantiate the view immediately
860 // and the inflater will take care of adding it.
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700861 f.mView = f.performCreateView(f.getLayoutInflater(
862 f.mSavedFragmentState), null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700863 if (f.mView != null) {
864 f.mView.setSaveFromParentEnabled(false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700865 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700866 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700867 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700868 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700869 case Fragment.CREATED:
870 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700871 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700872 if (!f.mFromLayout) {
873 ViewGroup container = null;
874 if (f.mContainerId != 0) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700875 container = (ViewGroup)mContainer.findViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800876 if (container == null && !f.mRestored) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700877 throwException(new IllegalArgumentException(
878 "No view found for id 0x"
879 + Integer.toHexString(f.mContainerId) + " ("
880 + f.getResources().getResourceName(f.mContainerId)
881 + ") for fragment " + f));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700882 }
883 }
884 f.mContainer = container;
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700885 f.mView = f.performCreateView(f.getLayoutInflater(
886 f.mSavedFragmentState), container, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700887 if (f.mView != null) {
888 f.mView.setSaveFromParentEnabled(false);
889 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700890 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700891 transitionStyle);
892 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700893 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700894 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700895 }
896 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700897 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700898 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700899 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700900 }
901 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700902
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700903 f.performActivityCreated(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700904 if (f.mView != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700905 f.restoreViewState(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700906 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700907 f.mSavedFragmentState = null;
908 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700909 case Fragment.ACTIVITY_CREATED:
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700910 case Fragment.STOPPED:
911 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700912 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700913 f.performStart();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700914 }
915 case Fragment.STARTED:
916 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700917 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2707d602010-07-09 18:01:20 -0700918 f.mResumed = true;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700919 f.performResume();
Adam Powell95202512011-08-07 17:20:17 -0700920 // Get rid of this in case we saved it and never needed it.
921 f.mSavedFragmentState = null;
922 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700923 }
924 }
925 } else if (f.mState > newState) {
926 switch (f.mState) {
927 case Fragment.RESUMED:
928 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700929 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700930 f.performPause();
Dianne Hackborn2707d602010-07-09 18:01:20 -0700931 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700932 }
933 case Fragment.STARTED:
934 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700935 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2707d602010-07-09 18:01:20 -0700936 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700937 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700938 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -0700939 case Fragment.ACTIVITY_CREATED:
940 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700941 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700942 if (f.mView != null) {
943 // Need to save the current view state if not
944 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700945 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700946 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700947 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700948 }
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700949 f.performDestroyView();
Dianne Hackborndef15372010-08-15 12:43:52 -0700950 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700951 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800952 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700953 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700954 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700955 }
956 if (anim != null) {
957 final ViewGroup container = f.mContainer;
958 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800959 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700960 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800961 f.mAnimatingAway = anim;
962 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700963 anim.addListener(new AnimatorListenerAdapter() {
964 @Override
965 public void onAnimationEnd(Animator anim) {
966 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800967 if (fragment.mAnimatingAway != null) {
968 fragment.mAnimatingAway = null;
969 moveToState(fragment, fragment.mStateAfterAnimating,
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700970 0, 0, false);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800971 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700972 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700973 });
974 anim.setTarget(f.mView);
975 anim.start();
976
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700977 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700978 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700979 }
980 f.mContainer = null;
981 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700982 }
983 case Fragment.CREATED:
984 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800985 if (mDestroyed) {
986 if (f.mAnimatingAway != null) {
987 // The fragment's containing activity is
988 // being destroyed, but this fragment is
989 // currently animating away. Stop the
990 // animation right now -- it is not needed,
991 // and we can't wait any more on destroying
992 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800993 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800994 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800995 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700996 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700997 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800998 if (f.mAnimatingAway != null) {
999 // We are waiting for the fragment's view to finish
1000 // animating away. Just make a note of the state
1001 // the fragment now should move to once the animation
1002 // is done.
1003 f.mStateAfterAnimating = newState;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001004 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001005 } else {
1006 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
1007 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001008 f.performDestroy();
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001009 }
1010
1011 f.mCalled = false;
1012 f.onDetach();
1013 if (!f.mCalled) {
1014 throw new SuperNotCalledException("Fragment " + f
1015 + " did not call through to super.onDetach()");
1016 }
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001017 if (!keepActive) {
1018 if (!f.mRetaining) {
1019 makeInactive(f);
1020 } else {
1021 f.mActivity = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001022 f.mParentFragment = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001023 f.mFragmentManager = null;
1024 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001025 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001026 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001027 }
1028 }
1029 }
1030
1031 f.mState = newState;
1032 }
1033
Dianne Hackborn625ac272010-09-17 18:29:22 -07001034 void moveToState(Fragment f) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001035 moveToState(f, mCurState, 0, 0, false);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001036 }
1037
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001038 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001039 moveToState(newState, 0, 0, always);
1040 }
1041
1042 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001043 if (mActivity == null && newState != Fragment.INITIALIZING) {
1044 throw new IllegalStateException("No activity");
1045 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001046
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001047 if (!always && mCurState == newState) {
1048 return;
1049 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001050
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001051 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001052 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001053 boolean loadersRunning = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001054 for (int i=0; i<mActive.size(); i++) {
1055 Fragment f = mActive.get(i);
1056 if (f != null) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001057 moveToState(f, newState, transit, transitStyle, false);
Adam Powell635c60a2011-10-26 10:22:16 -07001058 if (f.mLoaderManager != null) {
1059 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1060 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001061 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001062 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001063
Adam Powell635c60a2011-10-26 10:22:16 -07001064 if (!loadersRunning) {
1065 startPendingDeferredFragments();
1066 }
1067
Adam Powell89b09da2011-07-27 11:55:29 -07001068 if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001069 mActivity.invalidateOptionsMenu();
1070 mNeedMenuInvalidate = false;
1071 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001072 }
1073 }
1074
Adam Powell635c60a2011-10-26 10:22:16 -07001075 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001076 if (mActive == null) return;
1077
Adam Powell635c60a2011-10-26 10:22:16 -07001078 for (int i=0; i<mActive.size(); i++) {
1079 Fragment f = mActive.get(i);
1080 if (f != null) {
1081 performPendingDeferredStart(f);
1082 }
1083 }
1084 }
1085
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001086 void makeActive(Fragment f) {
1087 if (f.mIndex >= 0) {
1088 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001089 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001090
1091 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
1092 if (mActive == null) {
1093 mActive = new ArrayList<Fragment>();
1094 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001095 f.setIndex(mActive.size(), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001096 mActive.add(f);
1097
1098 } else {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001099 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001100 mActive.set(f.mIndex, f);
1101 }
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001102 if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001103 }
1104
1105 void makeInactive(Fragment f) {
1106 if (f.mIndex < 0) {
1107 return;
1108 }
1109
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001110 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001111 mActive.set(f.mIndex, null);
1112 if (mAvailIndices == null) {
1113 mAvailIndices = new ArrayList<Integer>();
1114 }
1115 mAvailIndices.add(f.mIndex);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001116 mActivity.invalidateFragment(f.mWho);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001117 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001118 }
1119
1120 public void addFragment(Fragment fragment, boolean moveToStateNow) {
1121 if (mAdded == null) {
1122 mAdded = new ArrayList<Fragment>();
1123 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001124 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001125 makeActive(fragment);
1126 if (!fragment.mDetached) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001127 if (mAdded.contains(fragment)) {
1128 throw new IllegalStateException("Fragment already added: " + fragment);
1129 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001130 mAdded.add(fragment);
1131 fragment.mAdded = true;
1132 fragment.mRemoving = false;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001133 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001134 mNeedMenuInvalidate = true;
1135 }
1136 if (moveToStateNow) {
1137 moveToState(fragment);
1138 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001139 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001140 }
1141
Dianne Hackbornf121be72010-05-06 14:10:32 -07001142 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001143 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001144 final boolean inactive = !fragment.isInBackStack();
1145 if (!fragment.mDetached || inactive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001146 if (false) {
1147 // Would be nice to catch a bad remove here, but we need
1148 // time to test this to make sure we aren't crashes cases
1149 // where it is not a problem.
1150 if (!mAdded.contains(fragment)) {
1151 throw new IllegalStateException("Fragment not added: " + fragment);
1152 }
1153 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001154 if (mAdded != null) {
1155 mAdded.remove(fragment);
1156 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001157 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001158 mNeedMenuInvalidate = true;
1159 }
1160 fragment.mAdded = false;
1161 fragment.mRemoving = true;
1162 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001163 transition, transitionStyle, false);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001164 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001165 }
1166
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001167 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1168 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1169 if (!fragment.mHidden) {
1170 fragment.mHidden = true;
1171 if (fragment.mView != null) {
Adam Powell27562932013-06-07 10:16:08 -07001172 Animator anim = loadAnimator(fragment, transition, false,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001173 transitionStyle);
1174 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001175 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001176 // Delay the actual hide operation until the animation finishes, otherwise
1177 // the fragment will just immediately disappear
1178 final Fragment finalFragment = fragment;
1179 anim.addListener(new AnimatorListenerAdapter() {
1180 @Override
1181 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001182 if (finalFragment.mView != null) {
1183 finalFragment.mView.setVisibility(View.GONE);
1184 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001185 }
1186 });
Chet Haase811ed1062010-08-06 10:38:15 -07001187 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001188 } else {
1189 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001190 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001191 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001192 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001193 mNeedMenuInvalidate = true;
1194 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001195 fragment.onHiddenChanged(true);
1196 }
1197 }
1198
1199 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1200 if (DEBUG) Log.v(TAG, "show: " + fragment);
1201 if (fragment.mHidden) {
1202 fragment.mHidden = false;
1203 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001204 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001205 transitionStyle);
1206 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001207 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -07001208 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001209 }
1210 fragment.mView.setVisibility(View.VISIBLE);
1211 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001212 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001213 mNeedMenuInvalidate = true;
1214 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001215 fragment.onHiddenChanged(false);
1216 }
1217 }
1218
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001219 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1220 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1221 if (!fragment.mDetached) {
1222 fragment.mDetached = true;
1223 if (fragment.mAdded) {
1224 // We are not already in back stack, so need to remove the fragment.
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001225 if (mAdded != null) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001226 if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001227 mAdded.remove(fragment);
1228 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001229 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001230 mNeedMenuInvalidate = true;
1231 }
1232 fragment.mAdded = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001233 moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001234 }
1235 }
1236 }
1237
1238 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1239 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1240 if (fragment.mDetached) {
1241 fragment.mDetached = false;
1242 if (!fragment.mAdded) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001243 if (mAdded == null) {
1244 mAdded = new ArrayList<Fragment>();
1245 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001246 if (mAdded.contains(fragment)) {
1247 throw new IllegalStateException("Fragment already added: " + fragment);
1248 }
1249 if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001250 mAdded.add(fragment);
1251 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001252 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001253 mNeedMenuInvalidate = true;
1254 }
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001255 moveToState(fragment, mCurState, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001256 }
1257 }
1258 }
1259
Dianne Hackbornf121be72010-05-06 14:10:32 -07001260 public Fragment findFragmentById(int id) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001261 if (mAdded != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001262 // First look through added fragments.
1263 for (int i=mAdded.size()-1; i>=0; i--) {
1264 Fragment f = mAdded.get(i);
1265 if (f != null && f.mFragmentId == id) {
1266 return f;
1267 }
1268 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001269 }
1270 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001271 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001272 for (int i=mActive.size()-1; i>=0; i--) {
1273 Fragment f = mActive.get(i);
1274 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001275 return f;
1276 }
1277 }
1278 }
1279 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001280 }
1281
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001282 public Fragment findFragmentByTag(String tag) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001283 if (mAdded != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001284 // First look through added fragments.
1285 for (int i=mAdded.size()-1; i>=0; i--) {
1286 Fragment f = mAdded.get(i);
1287 if (f != null && tag.equals(f.mTag)) {
1288 return f;
1289 }
1290 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001291 }
1292 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001293 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001294 for (int i=mActive.size()-1; i>=0; i--) {
1295 Fragment f = mActive.get(i);
1296 if (f != null && tag.equals(f.mTag)) {
1297 return f;
1298 }
1299 }
1300 }
1301 return null;
1302 }
1303
1304 public Fragment findFragmentByWho(String who) {
1305 if (mActive != null && who != null) {
1306 for (int i=mActive.size()-1; i>=0; i--) {
1307 Fragment f = mActive.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001308 if (f != null && (f=f.findFragmentByWho(who)) != null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001309 return f;
1310 }
1311 }
1312 }
1313 return null;
1314 }
1315
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001316 private void checkStateLoss() {
1317 if (mStateSaved) {
1318 throw new IllegalStateException(
1319 "Can not perform this action after onSaveInstanceState");
1320 }
1321 if (mNoTransactionsBecause != null) {
1322 throw new IllegalStateException(
1323 "Can not perform this action inside of " + mNoTransactionsBecause);
1324 }
1325 }
1326
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001327 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001328 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001329 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001330 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001331 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001332 if (mActivity == null) {
1333 throw new IllegalStateException("Activity has been destroyed");
1334 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001335 if (mPendingActions == null) {
1336 mPendingActions = new ArrayList<Runnable>();
1337 }
1338 mPendingActions.add(action);
1339 if (mPendingActions.size() == 1) {
1340 mActivity.mHandler.removeCallbacks(mExecCommit);
1341 mActivity.mHandler.post(mExecCommit);
1342 }
1343 }
1344 }
1345
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001346 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001347 synchronized (this) {
1348 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1349 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001350 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001351 }
1352 int index = mBackStackIndices.size();
1353 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1354 mBackStackIndices.add(bse);
1355 return index;
1356
1357 } else {
1358 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1359 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1360 mBackStackIndices.set(index, bse);
1361 return index;
1362 }
1363 }
1364 }
1365
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001366 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001367 synchronized (this) {
1368 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001369 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001370 }
1371 int N = mBackStackIndices.size();
1372 if (index < N) {
1373 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1374 mBackStackIndices.set(index, bse);
1375 } else {
1376 while (N < index) {
1377 mBackStackIndices.add(null);
1378 if (mAvailBackStackIndices == null) {
1379 mAvailBackStackIndices = new ArrayList<Integer>();
1380 }
1381 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1382 mAvailBackStackIndices.add(N);
1383 N++;
1384 }
1385 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1386 mBackStackIndices.add(bse);
1387 }
1388 }
1389 }
1390
1391 public void freeBackStackIndex(int index) {
1392 synchronized (this) {
1393 mBackStackIndices.set(index, null);
1394 if (mAvailBackStackIndices == null) {
1395 mAvailBackStackIndices = new ArrayList<Integer>();
1396 }
1397 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1398 mAvailBackStackIndices.add(index);
1399 }
1400 }
1401
Dianne Hackborn445646c2010-06-25 15:52:59 -07001402 /**
1403 * Only call from main thread!
1404 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001405 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001406 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001407 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001408 }
1409
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001410 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001411 throw new IllegalStateException("Must be called from main thread of process");
1412 }
1413
1414 boolean didSomething = false;
1415
Dianne Hackborn445646c2010-06-25 15:52:59 -07001416 while (true) {
1417 int numActions;
1418
1419 synchronized (this) {
1420 if (mPendingActions == null || mPendingActions.size() == 0) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001421 break;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001422 }
1423
1424 numActions = mPendingActions.size();
1425 if (mTmpActions == null || mTmpActions.length < numActions) {
1426 mTmpActions = new Runnable[numActions];
1427 }
1428 mPendingActions.toArray(mTmpActions);
1429 mPendingActions.clear();
1430 mActivity.mHandler.removeCallbacks(mExecCommit);
1431 }
1432
1433 mExecutingActions = true;
1434 for (int i=0; i<numActions; i++) {
1435 mTmpActions[i].run();
Jeff Sharkey0d325282011-07-13 09:36:27 -07001436 mTmpActions[i] = null;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001437 }
1438 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001439 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001440 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001441
1442 if (mHavePendingDeferredStart) {
1443 boolean loadersRunning = false;
1444 for (int i=0; i<mActive.size(); i++) {
1445 Fragment f = mActive.get(i);
1446 if (f != null && f.mLoaderManager != null) {
1447 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1448 }
1449 }
1450 if (!loadersRunning) {
1451 mHavePendingDeferredStart = false;
1452 startPendingDeferredFragments();
1453 }
1454 }
1455 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001456 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001457
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001458 void reportBackStackChanged() {
1459 if (mBackStackChangeListeners != null) {
1460 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1461 mBackStackChangeListeners.get(i).onBackStackChanged();
1462 }
1463 }
1464 }
1465
1466 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001467 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001468 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001469 }
1470 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001471 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001472 }
1473
Dianne Hackborndd913a52010-07-22 12:17:04 -07001474 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001475 if (mBackStack == null) {
1476 return false;
1477 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001478 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001479 int last = mBackStack.size()-1;
1480 if (last < 0) {
1481 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001482 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001483 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001484 bss.popFromBackStack(true);
1485 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001486 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001487 int index = -1;
1488 if (name != null || id >= 0) {
1489 // If a name or ID is specified, look for that place in
1490 // the stack.
1491 index = mBackStack.size()-1;
1492 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001493 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001494 if (name != null && name.equals(bss.getName())) {
1495 break;
1496 }
1497 if (id >= 0 && id == bss.mIndex) {
1498 break;
1499 }
1500 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001501 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001502 if (index < 0) {
1503 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001504 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001505 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001506 index--;
1507 // Consume all following entries that match.
1508 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001509 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001510 if ((name != null && name.equals(bss.getName()))
1511 || (id >= 0 && id == bss.mIndex)) {
1512 index--;
1513 continue;
1514 }
1515 break;
1516 }
1517 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001518 }
1519 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001520 return false;
1521 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001522 final ArrayList<BackStackRecord> states
1523 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001524 for (int i=mBackStack.size()-1; i>index; i--) {
1525 states.add(mBackStack.remove(i));
1526 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001527 final int LAST = states.size()-1;
1528 for (int i=0; i<=LAST; i++) {
1529 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1530 states.get(i).popFromBackStack(i == LAST);
1531 }
1532 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001533 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001534 return true;
1535 }
1536
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001537 ArrayList<Fragment> retainNonConfig() {
1538 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001539 if (mActive != null) {
1540 for (int i=0; i<mActive.size(); i++) {
1541 Fragment f = mActive.get(i);
1542 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001543 if (fragments == null) {
1544 fragments = new ArrayList<Fragment>();
1545 }
1546 fragments.add(f);
1547 f.mRetaining = true;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001548 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001549 if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001550 }
1551 }
1552 }
1553 return fragments;
1554 }
1555
1556 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001557 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001558 return;
1559 }
1560 if (mStateArray == null) {
1561 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001562 } else {
1563 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001564 }
1565 f.mView.saveHierarchyState(mStateArray);
1566 if (mStateArray.size() > 0) {
1567 f.mSavedViewState = mStateArray;
1568 mStateArray = null;
1569 }
1570 }
1571
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001572 Bundle saveFragmentBasicState(Fragment f) {
1573 Bundle result = null;
1574
1575 if (mStateBundle == null) {
1576 mStateBundle = new Bundle();
1577 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001578 f.performSaveInstanceState(mStateBundle);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001579 if (!mStateBundle.isEmpty()) {
1580 result = mStateBundle;
1581 mStateBundle = null;
1582 }
1583
1584 if (f.mView != null) {
1585 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07001586 }
1587 if (f.mSavedViewState != null) {
1588 if (result == null) {
1589 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001590 }
Dianne Hackborn13332762011-06-03 17:34:45 -07001591 result.putSparseParcelableArray(
1592 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001593 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001594 if (!f.mUserVisibleHint) {
Jake Wharton258029e2012-04-22 17:17:01 -04001595 if (result == null) {
1596 result = new Bundle();
1597 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001598 // Only add this if it's not the default value
1599 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
1600 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001601
1602 return result;
1603 }
1604
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001605 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001606 // Make sure all pending operations have now been executed to get
1607 // our state update-to-date.
1608 execPendingActions();
1609
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001610 mStateSaved = true;
1611
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001612 if (mActive == null || mActive.size() <= 0) {
1613 return null;
1614 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001615
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001616 // First collect all active fragments.
1617 int N = mActive.size();
1618 FragmentState[] active = new FragmentState[N];
1619 boolean haveFragments = false;
1620 for (int i=0; i<N; i++) {
1621 Fragment f = mActive.get(i);
1622 if (f != null) {
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001623 if (f.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001624 throwException(new IllegalStateException(
1625 "Failure saving state: active " + f
1626 + " has cleared index: " + f.mIndex));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001627 }
1628
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001629 haveFragments = true;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001630
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001631 FragmentState fs = new FragmentState(f);
1632 active[i] = fs;
1633
Dianne Hackborn625ac272010-09-17 18:29:22 -07001634 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001635 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001636
1637 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001638 if (f.mTarget.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001639 throwException(new IllegalStateException(
1640 "Failure saving state: " + f
1641 + " has target not in fragment manager: " + f.mTarget));
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001642 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001643 if (fs.mSavedFragmentState == null) {
1644 fs.mSavedFragmentState = new Bundle();
1645 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001646 putFragment(fs.mSavedFragmentState,
1647 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1648 if (f.mTargetRequestCode != 0) {
1649 fs.mSavedFragmentState.putInt(
1650 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1651 f.mTargetRequestCode);
1652 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001653 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001654
Dianne Hackborn625ac272010-09-17 18:29:22 -07001655 } else {
1656 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001657 }
1658
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001659 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1660 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001661 }
1662 }
1663
1664 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001665 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001666 return null;
1667 }
1668
1669 int[] added = null;
1670 BackStackState[] backStack = null;
1671
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001672 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001673 if (mAdded != null) {
1674 N = mAdded.size();
1675 if (N > 0) {
1676 added = new int[N];
1677 for (int i=0; i<N; i++) {
1678 added[i] = mAdded.get(i).mIndex;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001679 if (added[i] < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001680 throwException(new IllegalStateException(
1681 "Failure saving state: active " + mAdded.get(i)
1682 + " has cleared index: " + added[i]));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001683 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001684 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1685 + ": " + mAdded.get(i));
1686 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001687 }
1688 }
1689
1690 // Now save back stack.
1691 if (mBackStack != null) {
1692 N = mBackStack.size();
1693 if (N > 0) {
1694 backStack = new BackStackState[N];
1695 for (int i=0; i<N; i++) {
1696 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001697 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1698 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001699 }
1700 }
1701 }
1702
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001703 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001704 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001705 fms.mAdded = added;
1706 fms.mBackStack = backStack;
1707 return fms;
1708 }
1709
1710 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1711 // If there is no saved state at all, then there can not be
1712 // any nonConfig fragments either, so that is that.
1713 if (state == null) return;
1714 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001715 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001716
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001717 // First re-attach any non-config instances we are retaining back
1718 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001719 if (nonConfig != null) {
1720 for (int i=0; i<nonConfig.size(); i++) {
1721 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001722 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001723 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001724 fs.mInstance = f;
1725 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001726 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001727 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001728 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001729 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001730 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001731 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001732 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001733 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001734 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001735 }
1736 }
1737
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001738 // Build the full list of active fragments, instantiating them from
1739 // their saved state.
1740 mActive = new ArrayList<Fragment>(fms.mActive.length);
1741 if (mAvailIndices != null) {
1742 mAvailIndices.clear();
1743 }
1744 for (int i=0; i<fms.mActive.length; i++) {
1745 FragmentState fs = fms.mActive[i];
1746 if (fs != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001747 Fragment f = fs.instantiate(mActivity, mParent);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001748 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001749 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001750 // Now that the fragment is instantiated (or came from being
1751 // retained above), clear mInstance in case we end up re-restoring
1752 // from this FragmentState again.
1753 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001754 } else {
1755 mActive.add(null);
1756 if (mAvailIndices == null) {
1757 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001758 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001759 if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001760 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001761 }
1762 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001763
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001764 // Update the target of all retained fragments.
1765 if (nonConfig != null) {
1766 for (int i=0; i<nonConfig.size(); i++) {
1767 Fragment f = nonConfig.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001768 if (f.mTargetIndex >= 0) {
1769 if (f.mTargetIndex < mActive.size()) {
1770 f.mTarget = mActive.get(f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001771 } else {
1772 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07001773 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001774 f.mTarget = null;
1775 }
1776 }
1777 }
1778 }
1779
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001780 // Build the list of currently added fragments.
1781 if (fms.mAdded != null) {
1782 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1783 for (int i=0; i<fms.mAdded.length; i++) {
1784 Fragment f = mActive.get(fms.mAdded[i]);
1785 if (f == null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001786 throwException(new IllegalStateException(
1787 "No instantiated fragment for index #" + fms.mAdded[i]));
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001788 }
1789 f.mAdded = true;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001790 if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
1791 if (mAdded.contains(f)) {
1792 throw new IllegalStateException("Already added!");
1793 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001794 mAdded.add(f);
1795 }
1796 } else {
1797 mAdded = null;
1798 }
1799
1800 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001801 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001802 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001803 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001804 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001805 if (DEBUG) {
1806 Log.v(TAG, "restoreAllState: back stack #" + i
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001807 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001808 LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
1809 PrintWriter pw = new PrintWriter(logw);
1810 bse.dump(" ", pw, false);
1811 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001812 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001813 if (bse.mIndex >= 0) {
1814 setBackStackIndex(bse.mIndex, bse);
1815 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001816 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001817 } else {
1818 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001819 }
1820 }
1821
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001822 public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001823 if (mActivity != null) throw new IllegalStateException("Already attached");
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001824 mActivity = activity;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001825 mContainer = container;
1826 mParent = parent;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001827 }
1828
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001829 public void noteStateNotSaved() {
1830 mStateSaved = false;
1831 }
1832
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001833 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001834 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001835 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001836 }
1837
Dianne Hackbornc8017682010-07-06 13:34:38 -07001838 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001839 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001840 moveToState(Fragment.ACTIVITY_CREATED, false);
1841 }
1842
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001843 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001844 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001845 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001846 }
1847
1848 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001849 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001850 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001851 }
1852
1853 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001854 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001855 }
1856
1857 public void dispatchStop() {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001858 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001859 }
1860
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001861 public void dispatchDestroyView() {
1862 moveToState(Fragment.CREATED, false);
1863 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07001864
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001865 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001866 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07001867 execPendingActions();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001868 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001869 mActivity = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001870 mContainer = null;
1871 mParent = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001872 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001873
Dianne Hackborn9d071802010-12-08 14:49:15 -08001874 public void dispatchConfigurationChanged(Configuration newConfig) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001875 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08001876 for (int i=0; i<mAdded.size(); i++) {
1877 Fragment f = mAdded.get(i);
1878 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001879 f.performConfigurationChanged(newConfig);
Dianne Hackborn9d071802010-12-08 14:49:15 -08001880 }
1881 }
1882 }
1883 }
1884
1885 public void dispatchLowMemory() {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001886 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08001887 for (int i=0; i<mAdded.size(); i++) {
1888 Fragment f = mAdded.get(i);
1889 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001890 f.performLowMemory();
Dianne Hackborn9d071802010-12-08 14:49:15 -08001891 }
1892 }
1893 }
1894 }
1895
Dianne Hackbornc68c9132011-07-29 01:25:18 -07001896 public void dispatchTrimMemory(int level) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001897 if (mAdded != null) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -07001898 for (int i=0; i<mAdded.size(); i++) {
1899 Fragment f = mAdded.get(i);
1900 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001901 f.performTrimMemory(level);
Dianne Hackbornc68c9132011-07-29 01:25:18 -07001902 }
1903 }
1904 }
1905 }
1906
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001907 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1908 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001909 ArrayList<Fragment> newMenus = null;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001910 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001911 for (int i=0; i<mAdded.size(); i++) {
1912 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001913 if (f != null) {
1914 if (f.performCreateOptionsMenu(menu, inflater)) {
1915 show = true;
1916 if (newMenus == null) {
1917 newMenus = new ArrayList<Fragment>();
1918 }
1919 newMenus.add(f);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001920 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001921 }
1922 }
1923 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001924
1925 if (mCreatedMenus != null) {
1926 for (int i=0; i<mCreatedMenus.size(); i++) {
1927 Fragment f = mCreatedMenus.get(i);
1928 if (newMenus == null || !newMenus.contains(f)) {
1929 f.onDestroyOptionsMenu();
1930 }
1931 }
1932 }
1933
1934 mCreatedMenus = newMenus;
1935
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001936 return show;
1937 }
1938
1939 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1940 boolean show = false;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001941 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001942 for (int i=0; i<mAdded.size(); i++) {
1943 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001944 if (f != null) {
1945 if (f.performPrepareOptionsMenu(menu)) {
1946 show = true;
1947 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001948 }
1949 }
1950 }
1951 return show;
1952 }
1953
1954 public boolean dispatchOptionsItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001955 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001956 for (int i=0; i<mAdded.size(); i++) {
1957 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001958 if (f != null) {
1959 if (f.performOptionsItemSelected(item)) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001960 return true;
1961 }
1962 }
1963 }
1964 }
1965 return false;
1966 }
1967
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001968 public boolean dispatchContextItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001969 if (mAdded != null) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001970 for (int i=0; i<mAdded.size(); i++) {
1971 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001972 if (f != null) {
1973 if (f.performContextItemSelected(item)) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001974 return true;
1975 }
1976 }
1977 }
1978 }
1979 return false;
1980 }
1981
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001982 public void dispatchOptionsMenuClosed(Menu menu) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001983 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001984 for (int i=0; i<mAdded.size(); i++) {
1985 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001986 if (f != null) {
1987 f.performOptionsMenuClosed(menu);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001988 }
1989 }
1990 }
1991 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07001992
1993 @Override
1994 public void invalidateOptionsMenu() {
1995 if (mActivity != null && mCurState == Fragment.RESUMED) {
1996 mActivity.invalidateOptionsMenu();
1997 } else {
1998 mNeedMenuInvalidate = true;
1999 }
2000 }
2001
Dianne Hackbornf121be72010-05-06 14:10:32 -07002002 public static int reverseTransit(int transit) {
2003 int rev = 0;
2004 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002005 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
2006 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002007 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002008 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
2009 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002010 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002011 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
2012 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002013 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002014 }
2015 return rev;
2016
2017 }
2018
2019 public static int transitToStyleIndex(int transit, boolean enter) {
2020 int animAttr = -1;
2021 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002022 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002023 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002024 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
2025 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002026 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002027 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002028 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002029 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
2030 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002031 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002032 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07002033 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002034 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
2035 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002036 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002037 }
2038 return animAttr;
2039 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002040}