blob: 1abb7dea99496546ca120e076e033a50fc4cf523 [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 Hackbornba51c3d2010-05-05 18:49:48 -070025import android.os.Handler;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -080026import android.os.Looper;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070027import android.os.Parcel;
28import android.os.Parcelable;
Dianne Hackborna2ea7472010-12-20 12:10:01 -080029import android.util.DebugUtils;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070030import android.util.Log;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -080031import android.util.LogWriter;
32import android.util.Slog;
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 Hackborn625ac272010-09-17 18:29:22 -0700321 * Print the FragmentManager's state into the given stream.
322 *
323 * @param prefix Text to print at the front of each line.
324 * @param fd The raw file descriptor that the dump is being sent to.
325 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800326 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700327 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700328 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800329
330 /**
331 * Control whether the framework's internal fragment manager debugging
332 * logs are turned on. If enabled, you will see output in logcat as
333 * the framework performs fragment operations.
334 */
335 public static void enableDebugLogging(boolean enabled) {
336 FragmentManagerImpl.DEBUG = enabled;
337 }
Adam Powellf0f5fff2011-08-01 13:42:50 -0700338
339 /**
340 * Invalidate the attached activity's options menu as necessary.
341 * This may end up being deferred until we move to the resumed state.
342 */
343 public void invalidateOptionsMenu() { }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700344}
345
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700346final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700347 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700348 int[] mAdded;
349 BackStackState[] mBackStack;
350
351 public FragmentManagerState() {
352 }
353
354 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700355 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700356 mAdded = in.createIntArray();
357 mBackStack = in.createTypedArray(BackStackState.CREATOR);
358 }
359
360 public int describeContents() {
361 return 0;
362 }
363
364 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700365 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700366 dest.writeIntArray(mAdded);
367 dest.writeTypedArray(mBackStack, flags);
368 }
369
370 public static final Parcelable.Creator<FragmentManagerState> CREATOR
371 = new Parcelable.Creator<FragmentManagerState>() {
372 public FragmentManagerState createFromParcel(Parcel in) {
373 return new FragmentManagerState(in);
374 }
375
376 public FragmentManagerState[] newArray(int size) {
377 return new FragmentManagerState[size];
378 }
379 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700380}
381
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700382/**
383 * Container for fragments associated with an activity.
384 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700385final class FragmentManagerImpl extends FragmentManager {
Dianne Hackbornec541e12011-01-21 16:44:04 -0800386 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700387 static final String TAG = "FragmentManager";
388
Dianne Hackborndef15372010-08-15 12:43:52 -0700389 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
390 static final String TARGET_STATE_TAG = "android:target_state";
391 static final String VIEW_STATE_TAG = "android:view_state";
Adam Powell78fed9b2011-11-07 10:45:34 -0800392 static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
Dianne Hackborndef15372010-08-15 12:43:52 -0700393
Dianne Hackborn445646c2010-06-25 15:52:59 -0700394 ArrayList<Runnable> mPendingActions;
395 Runnable[] mTmpActions;
396 boolean mExecutingActions;
397
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700398 ArrayList<Fragment> mActive;
399 ArrayList<Fragment> mAdded;
400 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700401 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700402 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700403
Dianne Hackborndd913a52010-07-22 12:17:04 -0700404 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700405 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700406 ArrayList<Integer> mAvailBackStackIndices;
407
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700408 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
409
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700410 int mCurState = Fragment.INITIALIZING;
411 Activity mActivity;
412
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700413 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700414 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800415 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700416 String mNoTransactionsBecause;
Adam Powell78fed9b2011-11-07 10:45:34 -0800417 boolean mHavePendingDeferredStart;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700418
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700419 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700420 Bundle mStateBundle = null;
421 SparseArray<Parcelable> mStateArray = null;
422
Dianne Hackborn445646c2010-06-25 15:52:59 -0700423 Runnable mExecCommit = new Runnable() {
424 @Override
425 public void run() {
426 execPendingActions();
427 }
428 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700429
430 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800431 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700432 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700433 }
434
Dianne Hackborn625ac272010-09-17 18:29:22 -0700435 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800436 public boolean executePendingTransactions() {
437 return execPendingActions();
438 }
439
440 @Override
441 public void popBackStack() {
442 enqueueAction(new Runnable() {
443 @Override public void run() {
444 popBackStackState(mActivity.mHandler, null, -1, 0);
445 }
446 }, false);
447 }
448
449 @Override
450 public boolean popBackStackImmediate() {
451 checkStateLoss();
452 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700453 return popBackStackState(mActivity.mHandler, null, -1, 0);
454 }
455
Dianne Hackborn625ac272010-09-17 18:29:22 -0700456 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800457 public void popBackStack(final String name, final int flags) {
458 enqueueAction(new Runnable() {
459 @Override public void run() {
460 popBackStackState(mActivity.mHandler, name, -1, flags);
461 }
462 }, false);
463 }
464
465 @Override
466 public boolean popBackStackImmediate(String name, int flags) {
467 checkStateLoss();
468 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700469 return popBackStackState(mActivity.mHandler, name, -1, flags);
470 }
471
Dianne Hackborn625ac272010-09-17 18:29:22 -0700472 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800473 public void popBackStack(final int id, final int flags) {
474 if (id < 0) {
475 throw new IllegalArgumentException("Bad id: " + id);
476 }
477 enqueueAction(new Runnable() {
478 @Override public void run() {
479 popBackStackState(mActivity.mHandler, null, id, flags);
480 }
481 }, false);
482 }
483
484 @Override
485 public boolean popBackStackImmediate(int id, int flags) {
486 checkStateLoss();
487 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700488 if (id < 0) {
489 throw new IllegalArgumentException("Bad id: " + id);
490 }
491 return popBackStackState(mActivity.mHandler, null, id, flags);
492 }
493
Dianne Hackborn625ac272010-09-17 18:29:22 -0700494 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800495 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700496 return mBackStack != null ? mBackStack.size() : 0;
497 }
498
Dianne Hackborn625ac272010-09-17 18:29:22 -0700499 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800500 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700501 return mBackStack.get(index);
502 }
503
Dianne Hackborn625ac272010-09-17 18:29:22 -0700504 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700505 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
506 if (mBackStackChangeListeners == null) {
507 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
508 }
509 mBackStackChangeListeners.add(listener);
510 }
511
Dianne Hackborn625ac272010-09-17 18:29:22 -0700512 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700513 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
514 if (mBackStackChangeListeners != null) {
515 mBackStackChangeListeners.remove(listener);
516 }
517 }
518
Dianne Hackborn625ac272010-09-17 18:29:22 -0700519 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700520 public void putFragment(Bundle bundle, String key, Fragment fragment) {
521 if (fragment.mIndex < 0) {
522 throw new IllegalStateException("Fragment " + fragment
523 + " is not currently in the FragmentManager");
524 }
525 bundle.putInt(key, fragment.mIndex);
526 }
527
Dianne Hackborn625ac272010-09-17 18:29:22 -0700528 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700529 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700530 int index = bundle.getInt(key, -1);
531 if (index == -1) {
532 return null;
533 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700534 if (index >= mActive.size()) {
535 throw new IllegalStateException("Fragement no longer exists for key "
536 + key + ": index " + index);
537 }
538 Fragment f = mActive.get(index);
539 if (f == null) {
540 throw new IllegalStateException("Fragement no longer exists for key "
541 + key + ": index " + index);
542 }
543 return f;
544 }
545
Dianne Hackborn625ac272010-09-17 18:29:22 -0700546 @Override
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700547 public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
548 if (fragment.mIndex < 0) {
549 throw new IllegalStateException("Fragment " + fragment
550 + " is not currently in the FragmentManager");
551 }
552 if (fragment.mState > Fragment.INITIALIZING) {
553 Bundle result = saveFragmentBasicState(fragment);
554 return result != null ? new Fragment.SavedState(result) : null;
555 }
556 return null;
557 }
558
559 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800560 public String toString() {
561 StringBuilder sb = new StringBuilder(128);
562 sb.append("FragmentManager{");
563 sb.append(Integer.toHexString(System.identityHashCode(this)));
564 sb.append(" in ");
565 DebugUtils.buildShortClassTag(mActivity, sb);
566 sb.append("}}");
567 return sb.toString();
568 }
569
570 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700571 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700572 String innerPrefix = prefix + " ";
573
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800574 int N;
575 if (mActive != null) {
576 N = mActive.size();
577 if (N > 0) {
578 writer.print(prefix); writer.print("Active Fragments in ");
579 writer.print(Integer.toHexString(System.identityHashCode(this)));
580 writer.println(":");
581 for (int i=0; i<N; i++) {
582 Fragment f = mActive.get(i);
583 writer.print(prefix); writer.print(" #"); writer.print(i);
584 writer.print(": "); writer.println(f);
585 if (f != null) {
586 f.dump(innerPrefix, fd, writer, args);
587 }
588 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700589 }
590 }
591
592 if (mAdded != null) {
593 N = mAdded.size();
594 if (N > 0) {
595 writer.print(prefix); writer.println("Added Fragments:");
596 for (int i=0; i<N; i++) {
597 Fragment f = mAdded.get(i);
598 writer.print(prefix); writer.print(" #"); writer.print(i);
599 writer.print(": "); writer.println(f.toString());
600 }
601 }
602 }
603
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800604 if (mCreatedMenus != null) {
605 N = mCreatedMenus.size();
606 if (N > 0) {
607 writer.print(prefix); writer.println("Fragments Created Menus:");
608 for (int i=0; i<N; i++) {
609 Fragment f = mCreatedMenus.get(i);
610 writer.print(prefix); writer.print(" #"); writer.print(i);
611 writer.print(": "); writer.println(f.toString());
612 }
613 }
614 }
615
Dianne Hackborn625ac272010-09-17 18:29:22 -0700616 if (mBackStack != null) {
617 N = mBackStack.size();
618 if (N > 0) {
619 writer.print(prefix); writer.println("Back Stack:");
620 for (int i=0; i<N; i++) {
621 BackStackRecord bs = mBackStack.get(i);
622 writer.print(prefix); writer.print(" #"); writer.print(i);
623 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800624 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700625 }
626 }
627 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800628
629 synchronized (this) {
630 if (mBackStackIndices != null) {
631 N = mBackStackIndices.size();
632 if (N > 0) {
633 writer.print(prefix); writer.println("Back Stack Indices:");
634 for (int i=0; i<N; i++) {
635 BackStackRecord bs = mBackStackIndices.get(i);
636 writer.print(prefix); writer.print(" #"); writer.print(i);
637 writer.print(": "); writer.println(bs);
638 }
639 }
640 }
641
642 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
643 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
644 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
645 }
646 }
647
648 if (mPendingActions != null) {
649 N = mPendingActions.size();
650 if (N > 0) {
651 writer.print(prefix); writer.println("Pending Actions:");
652 for (int i=0; i<N; i++) {
653 Runnable r = mPendingActions.get(i);
654 writer.print(prefix); writer.print(" #"); writer.print(i);
655 writer.print(": "); writer.println(r);
656 }
657 }
658 }
659
660 writer.print(prefix); writer.println("FragmentManager misc state:");
661 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
662 writer.print(" mStateSaved="); writer.print(mStateSaved);
663 writer.print(" mDestroyed="); writer.println(mDestroyed);
664 if (mNeedMenuInvalidate) {
665 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
666 writer.println(mNeedMenuInvalidate);
667 }
668 if (mNoTransactionsBecause != null) {
669 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
670 writer.println(mNoTransactionsBecause);
671 }
672 if (mAvailIndices != null && mAvailIndices.size() > 0) {
673 writer.print(prefix); writer.print(" mAvailIndices: ");
674 writer.println(Arrays.toString(mAvailIndices.toArray()));
675 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700676 }
677
Chet Haasea18a86b2010-09-07 13:20:00 -0700678 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700679 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700680 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700681 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700682 if (animObj != null) {
683 return animObj;
684 }
685
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700686 if (fragment.mNextAnim != 0) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700687 Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700688 if (anim != null) {
689 return anim;
690 }
691 }
692
Dianne Hackbornf121be72010-05-06 14:10:32 -0700693 if (transit == 0) {
694 return null;
695 }
696
697 int styleIndex = transitToStyleIndex(transit, enter);
698 if (styleIndex < 0) {
699 return null;
700 }
701
702 if (transitionStyle == 0 && mActivity.getWindow() != null) {
703 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
704 }
705 if (transitionStyle == 0) {
706 return null;
707 }
708
709 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700710 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700711 int anim = attrs.getResourceId(styleIndex, 0);
712 attrs.recycle();
713
714 if (anim == 0) {
715 return null;
716 }
717
Chet Haasea18a86b2010-09-07 13:20:00 -0700718 return AnimatorInflater.loadAnimator(mActivity, anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700719 }
720
Adam Powell635c60a2011-10-26 10:22:16 -0700721 public void performPendingDeferredStart(Fragment f) {
722 if (f.mDeferStart) {
Adam Powell78fed9b2011-11-07 10:45:34 -0800723 if (mExecutingActions) {
724 // Wait until we're done executing our pending transactions
725 mHavePendingDeferredStart = true;
726 return;
727 }
Adam Powell635c60a2011-10-26 10:22:16 -0700728 f.mDeferStart = false;
729 moveToState(f, mCurState, 0, 0);
730 }
731 }
732
Dianne Hackbornf121be72010-05-06 14:10:32 -0700733 void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700734 // Fragments that are not currently added will sit in the onCreate() state.
735 if (!f.mAdded && newState > Fragment.CREATED) {
736 newState = Fragment.CREATED;
737 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700738 if (f.mRemoving && newState > f.mState) {
739 // While removing a fragment, we can't change it to a higher state.
740 newState = f.mState;
741 }
Adam Powell2db4e4b2011-11-02 14:30:47 -0700742 // Defer start if requested; don't allow it to move to STARTED or higher
743 // if it's not already started.
744 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -0700745 newState = Fragment.STOPPED;
746 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700747 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800748 // For fragments that are created from a layout, when restoring from
749 // state we don't want to allow them to be created until they are
750 // being reloaded from the layout.
751 if (f.mFromLayout && !f.mInLayout) {
752 return;
753 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800754 if (f.mAnimatingAway != null) {
755 // The fragment is currently being animated... but! Now we
756 // want to move our state back up. Give up on waiting for the
757 // animation, move to whatever the final state should be once
758 // the animation is done, and then we can proceed from there.
759 f.mAnimatingAway = null;
760 moveToState(f, f.mStateAfterAnimating, 0, 0);
761 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700762 switch (f.mState) {
763 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700764 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700765 if (f.mSavedFragmentState != null) {
766 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
767 FragmentManagerImpl.VIEW_STATE_TAG);
768 f.mTarget = getFragment(f.mSavedFragmentState,
769 FragmentManagerImpl.TARGET_STATE_TAG);
770 if (f.mTarget != null) {
771 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
772 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
773 }
Adam Powell78fed9b2011-11-07 10:45:34 -0800774 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
775 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
776 if (!f.mUserVisibleHint) {
777 f.mDeferStart = true;
778 if (newState > Fragment.STOPPED) {
779 newState = Fragment.STOPPED;
780 }
781 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700782 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700783 f.mActivity = mActivity;
Dianne Hackbornd2835932010-12-13 16:28:46 -0800784 f.mFragmentManager = mActivity.mFragments;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700785 f.mCalled = false;
786 f.onAttach(mActivity);
787 if (!f.mCalled) {
788 throw new SuperNotCalledException("Fragment " + f
789 + " did not call through to super.onAttach()");
790 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700791 mActivity.onAttachFragment(f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700792
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700793 if (!f.mRetaining) {
794 f.mCalled = false;
795 f.onCreate(f.mSavedFragmentState);
796 if (!f.mCalled) {
797 throw new SuperNotCalledException("Fragment " + f
798 + " did not call through to super.onCreate()");
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700799 }
800 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700801 f.mRetaining = false;
802 if (f.mFromLayout) {
803 // For fragments that are part of the content view
804 // layout, we need to instantiate the view immediately
805 // and the inflater will take care of adding it.
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800806 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700807 null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700808 if (f.mView != null) {
809 f.mView.setSaveFromParentEnabled(false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700810 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700811 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700812 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700813 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700814 case Fragment.CREATED:
815 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700816 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700817 if (!f.mFromLayout) {
818 ViewGroup container = null;
819 if (f.mContainerId != 0) {
820 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800821 if (container == null && !f.mRestored) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700822 throw new IllegalArgumentException("No view found for id 0x"
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700823 + Integer.toHexString(f.mContainerId)
824 + " for fragment " + f);
825 }
826 }
827 f.mContainer = container;
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800828 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700829 container, f.mSavedFragmentState);
830 if (f.mView != null) {
831 f.mView.setSaveFromParentEnabled(false);
832 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700833 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700834 transitionStyle);
835 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700836 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700837 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700838 }
839 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700840 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700841 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700842 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700843 }
844 }
845
846 f.mCalled = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -0700847 f.onActivityCreated(f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700848 if (!f.mCalled) {
849 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800850 + " did not call through to super.onActivityCreated()");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700851 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700852 if (f.mView != null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700853 f.restoreViewState();
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700854 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700855 f.mSavedFragmentState = null;
856 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700857 case Fragment.ACTIVITY_CREATED:
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700858 case Fragment.STOPPED:
859 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700860 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700861 f.mCalled = false;
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700862 f.performStart();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700863 if (!f.mCalled) {
864 throw new SuperNotCalledException("Fragment " + f
865 + " did not call through to super.onStart()");
866 }
867 }
868 case Fragment.STARTED:
869 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700870 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700871 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700872 f.mResumed = true;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700873 f.onResume();
874 if (!f.mCalled) {
875 throw new SuperNotCalledException("Fragment " + f
876 + " did not call through to super.onResume()");
877 }
Adam Powell95202512011-08-07 17:20:17 -0700878 // Get rid of this in case we saved it and never needed it.
879 f.mSavedFragmentState = null;
880 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700881 }
882 }
883 } else if (f.mState > newState) {
884 switch (f.mState) {
885 case Fragment.RESUMED:
886 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700887 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700888 f.mCalled = false;
889 f.onPause();
890 if (!f.mCalled) {
891 throw new SuperNotCalledException("Fragment " + f
892 + " did not call through to super.onPause()");
893 }
Dianne Hackborn2707d602010-07-09 18:01:20 -0700894 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700895 }
896 case Fragment.STARTED:
897 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700898 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700899 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700900 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700901 if (!f.mCalled) {
902 throw new SuperNotCalledException("Fragment " + f
903 + " did not call through to super.onStop()");
904 }
905 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700906 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -0700907 case Fragment.ACTIVITY_CREATED:
908 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700909 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700910 if (f.mView != null) {
911 // Need to save the current view state if not
912 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700913 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700914 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700915 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700916 }
917 f.mCalled = false;
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700918 f.performDestroyView();
Dianne Hackborndef15372010-08-15 12:43:52 -0700919 if (!f.mCalled) {
920 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800921 + " did not call through to super.onDestroyView()");
Dianne Hackborndef15372010-08-15 12:43:52 -0700922 }
923 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700924 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800925 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700926 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700927 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700928 }
929 if (anim != null) {
930 final ViewGroup container = f.mContainer;
931 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800932 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700933 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800934 f.mAnimatingAway = anim;
935 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700936 anim.addListener(new AnimatorListenerAdapter() {
937 @Override
938 public void onAnimationEnd(Animator anim) {
939 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800940 if (fragment.mAnimatingAway != null) {
941 fragment.mAnimatingAway = null;
942 moveToState(fragment, fragment.mStateAfterAnimating,
943 0, 0);
944 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700945 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700946 });
947 anim.setTarget(f.mView);
948 anim.start();
949
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700950 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700951 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700952 }
953 f.mContainer = null;
954 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700955 }
956 case Fragment.CREATED:
957 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800958 if (mDestroyed) {
959 if (f.mAnimatingAway != null) {
960 // The fragment's containing activity is
961 // being destroyed, but this fragment is
962 // currently animating away. Stop the
963 // animation right now -- it is not needed,
964 // and we can't wait any more on destroying
965 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800966 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800967 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800968 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700969 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700970 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800971 if (f.mAnimatingAway != null) {
972 // We are waiting for the fragment's view to finish
973 // animating away. Just make a note of the state
974 // the fragment now should move to once the animation
975 // is done.
976 f.mStateAfterAnimating = newState;
Dianne Hackbornf9302322011-06-14 18:36:14 -0700977 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800978 } else {
979 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
980 if (!f.mRetaining) {
981 f.mCalled = false;
982 f.onDestroy();
983 if (!f.mCalled) {
984 throw new SuperNotCalledException("Fragment " + f
985 + " did not call through to super.onDestroy()");
986 }
987 }
988
989 f.mCalled = false;
990 f.onDetach();
991 if (!f.mCalled) {
992 throw new SuperNotCalledException("Fragment " + f
993 + " did not call through to super.onDetach()");
994 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700995 if (!f.mRetaining) {
996 makeInactive(f);
997 } else {
Dianne Hackbornf9302322011-06-14 18:36:14 -0700998 f.mActivity = null;
999 f.mFragmentManager = null;
1000 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001001 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001002 }
1003 }
1004 }
1005
1006 f.mState = newState;
1007 }
1008
Dianne Hackborn625ac272010-09-17 18:29:22 -07001009 void moveToState(Fragment f) {
1010 moveToState(f, mCurState, 0, 0);
1011 }
1012
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001013 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001014 moveToState(newState, 0, 0, always);
1015 }
1016
1017 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001018 if (mActivity == null && newState != Fragment.INITIALIZING) {
1019 throw new IllegalStateException("No activity");
1020 }
1021
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001022 if (!always && mCurState == newState) {
1023 return;
1024 }
1025
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001026 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001027 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001028 boolean loadersRunning = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001029 for (int i=0; i<mActive.size(); i++) {
1030 Fragment f = mActive.get(i);
1031 if (f != null) {
1032 moveToState(f, newState, transit, transitStyle);
Adam Powell635c60a2011-10-26 10:22:16 -07001033 if (f.mLoaderManager != null) {
1034 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1035 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001036 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001037 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001038
Adam Powell635c60a2011-10-26 10:22:16 -07001039 if (!loadersRunning) {
1040 startPendingDeferredFragments();
1041 }
1042
Adam Powell89b09da2011-07-27 11:55:29 -07001043 if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001044 mActivity.invalidateOptionsMenu();
1045 mNeedMenuInvalidate = false;
1046 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001047 }
1048 }
1049
Adam Powell635c60a2011-10-26 10:22:16 -07001050 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001051 if (mActive == null) return;
1052
Adam Powell635c60a2011-10-26 10:22:16 -07001053 for (int i=0; i<mActive.size(); i++) {
1054 Fragment f = mActive.get(i);
1055 if (f != null) {
1056 performPendingDeferredStart(f);
1057 }
1058 }
1059 }
1060
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001061 void makeActive(Fragment f) {
1062 if (f.mIndex >= 0) {
1063 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001064 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001065
1066 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
1067 if (mActive == null) {
1068 mActive = new ArrayList<Fragment>();
1069 }
1070 f.setIndex(mActive.size());
1071 mActive.add(f);
1072
1073 } else {
1074 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
1075 mActive.set(f.mIndex, f);
1076 }
1077 }
1078
1079 void makeInactive(Fragment f) {
1080 if (f.mIndex < 0) {
1081 return;
1082 }
1083
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001084 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001085 mActive.set(f.mIndex, null);
1086 if (mAvailIndices == null) {
1087 mAvailIndices = new ArrayList<Integer>();
1088 }
1089 mAvailIndices.add(f.mIndex);
Dianne Hackborn9e14e9f32010-07-14 11:07:38 -07001090 mActivity.invalidateFragmentIndex(f.mIndex);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001091 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001092 }
1093
1094 public void addFragment(Fragment fragment, boolean moveToStateNow) {
1095 if (mAdded == null) {
1096 mAdded = new ArrayList<Fragment>();
1097 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001098 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001099 makeActive(fragment);
1100 if (!fragment.mDetached) {
1101 mAdded.add(fragment);
1102 fragment.mAdded = true;
1103 fragment.mRemoving = false;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001104 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001105 mNeedMenuInvalidate = true;
1106 }
1107 if (moveToStateNow) {
1108 moveToState(fragment);
1109 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001110 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001111 }
1112
Dianne Hackbornf121be72010-05-06 14:10:32 -07001113 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001114 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001115 final boolean inactive = !fragment.isInBackStack();
1116 if (!fragment.mDetached || inactive) {
1117 mAdded.remove(fragment);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001118 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001119 mNeedMenuInvalidate = true;
1120 }
1121 fragment.mAdded = false;
1122 fragment.mRemoving = true;
1123 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
1124 transition, transitionStyle);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001125 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001126 }
1127
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001128 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1129 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1130 if (!fragment.mHidden) {
1131 fragment.mHidden = true;
1132 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001133 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001134 transitionStyle);
1135 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001136 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001137 // Delay the actual hide operation until the animation finishes, otherwise
1138 // the fragment will just immediately disappear
1139 final Fragment finalFragment = fragment;
1140 anim.addListener(new AnimatorListenerAdapter() {
1141 @Override
1142 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001143 if (finalFragment.mView != null) {
1144 finalFragment.mView.setVisibility(View.GONE);
1145 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001146 }
1147 });
Chet Haase811ed1062010-08-06 10:38:15 -07001148 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001149 } else {
1150 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001151 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001152 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001153 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001154 mNeedMenuInvalidate = true;
1155 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001156 fragment.onHiddenChanged(true);
1157 }
1158 }
1159
1160 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1161 if (DEBUG) Log.v(TAG, "show: " + fragment);
1162 if (fragment.mHidden) {
1163 fragment.mHidden = false;
1164 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001165 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001166 transitionStyle);
1167 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001168 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -07001169 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001170 }
1171 fragment.mView.setVisibility(View.VISIBLE);
1172 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001173 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001174 mNeedMenuInvalidate = true;
1175 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001176 fragment.onHiddenChanged(false);
1177 }
1178 }
1179
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001180 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1181 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1182 if (!fragment.mDetached) {
1183 fragment.mDetached = true;
1184 if (fragment.mAdded) {
1185 // We are not already in back stack, so need to remove the fragment.
1186 mAdded.remove(fragment);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001187 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001188 mNeedMenuInvalidate = true;
1189 }
1190 fragment.mAdded = false;
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001191 moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
1192 }
1193 }
1194 }
1195
1196 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1197 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1198 if (fragment.mDetached) {
1199 fragment.mDetached = false;
1200 if (!fragment.mAdded) {
1201 mAdded.add(fragment);
1202 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001203 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001204 mNeedMenuInvalidate = true;
1205 }
1206 moveToState(fragment, mCurState, transition, transitionStyle);
1207 }
1208 }
1209 }
1210
Dianne Hackbornf121be72010-05-06 14:10:32 -07001211 public Fragment findFragmentById(int id) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001212 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001213 // First look through added fragments.
1214 for (int i=mAdded.size()-1; i>=0; i--) {
1215 Fragment f = mAdded.get(i);
1216 if (f != null && f.mFragmentId == id) {
1217 return f;
1218 }
1219 }
1220 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001221 for (int i=mActive.size()-1; i>=0; i--) {
1222 Fragment f = mActive.get(i);
1223 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001224 return f;
1225 }
1226 }
1227 }
1228 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001229 }
1230
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001231 public Fragment findFragmentByTag(String tag) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001232 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001233 // First look through added fragments.
1234 for (int i=mAdded.size()-1; i>=0; i--) {
1235 Fragment f = mAdded.get(i);
1236 if (f != null && tag.equals(f.mTag)) {
1237 return f;
1238 }
1239 }
1240 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001241 for (int i=mActive.size()-1; i>=0; i--) {
1242 Fragment f = mActive.get(i);
1243 if (f != null && tag.equals(f.mTag)) {
1244 return f;
1245 }
1246 }
1247 }
1248 return null;
1249 }
1250
1251 public Fragment findFragmentByWho(String who) {
1252 if (mActive != null && who != null) {
1253 for (int i=mActive.size()-1; i>=0; i--) {
1254 Fragment f = mActive.get(i);
1255 if (f != null && who.equals(f.mWho)) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001256 return f;
1257 }
1258 }
1259 }
1260 return null;
1261 }
1262
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001263 private void checkStateLoss() {
1264 if (mStateSaved) {
1265 throw new IllegalStateException(
1266 "Can not perform this action after onSaveInstanceState");
1267 }
1268 if (mNoTransactionsBecause != null) {
1269 throw new IllegalStateException(
1270 "Can not perform this action inside of " + mNoTransactionsBecause);
1271 }
1272 }
1273
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001274 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001275 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001276 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001277 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001278 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001279 if (mActivity == null) {
1280 throw new IllegalStateException("Activity has been destroyed");
1281 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001282 if (mPendingActions == null) {
1283 mPendingActions = new ArrayList<Runnable>();
1284 }
1285 mPendingActions.add(action);
1286 if (mPendingActions.size() == 1) {
1287 mActivity.mHandler.removeCallbacks(mExecCommit);
1288 mActivity.mHandler.post(mExecCommit);
1289 }
1290 }
1291 }
1292
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001293 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001294 synchronized (this) {
1295 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1296 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001297 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001298 }
1299 int index = mBackStackIndices.size();
1300 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1301 mBackStackIndices.add(bse);
1302 return index;
1303
1304 } else {
1305 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1306 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1307 mBackStackIndices.set(index, bse);
1308 return index;
1309 }
1310 }
1311 }
1312
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001313 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001314 synchronized (this) {
1315 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001316 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001317 }
1318 int N = mBackStackIndices.size();
1319 if (index < N) {
1320 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1321 mBackStackIndices.set(index, bse);
1322 } else {
1323 while (N < index) {
1324 mBackStackIndices.add(null);
1325 if (mAvailBackStackIndices == null) {
1326 mAvailBackStackIndices = new ArrayList<Integer>();
1327 }
1328 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1329 mAvailBackStackIndices.add(N);
1330 N++;
1331 }
1332 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1333 mBackStackIndices.add(bse);
1334 }
1335 }
1336 }
1337
1338 public void freeBackStackIndex(int index) {
1339 synchronized (this) {
1340 mBackStackIndices.set(index, null);
1341 if (mAvailBackStackIndices == null) {
1342 mAvailBackStackIndices = new ArrayList<Integer>();
1343 }
1344 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1345 mAvailBackStackIndices.add(index);
1346 }
1347 }
1348
Dianne Hackborn445646c2010-06-25 15:52:59 -07001349 /**
1350 * Only call from main thread!
1351 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001352 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001353 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001354 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001355 }
1356
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001357 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001358 throw new IllegalStateException("Must be called from main thread of process");
1359 }
1360
1361 boolean didSomething = false;
1362
Dianne Hackborn445646c2010-06-25 15:52:59 -07001363 while (true) {
1364 int numActions;
1365
1366 synchronized (this) {
1367 if (mPendingActions == null || mPendingActions.size() == 0) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001368 break;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001369 }
1370
1371 numActions = mPendingActions.size();
1372 if (mTmpActions == null || mTmpActions.length < numActions) {
1373 mTmpActions = new Runnable[numActions];
1374 }
1375 mPendingActions.toArray(mTmpActions);
1376 mPendingActions.clear();
1377 mActivity.mHandler.removeCallbacks(mExecCommit);
1378 }
1379
1380 mExecutingActions = true;
1381 for (int i=0; i<numActions; i++) {
1382 mTmpActions[i].run();
Jeff Sharkey0d325282011-07-13 09:36:27 -07001383 mTmpActions[i] = null;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001384 }
1385 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001386 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001387 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001388
1389 if (mHavePendingDeferredStart) {
1390 boolean loadersRunning = false;
1391 for (int i=0; i<mActive.size(); i++) {
1392 Fragment f = mActive.get(i);
1393 if (f != null && f.mLoaderManager != null) {
1394 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1395 }
1396 }
1397 if (!loadersRunning) {
1398 mHavePendingDeferredStart = false;
1399 startPendingDeferredFragments();
1400 }
1401 }
1402 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001403 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001404
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001405 void reportBackStackChanged() {
1406 if (mBackStackChangeListeners != null) {
1407 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1408 mBackStackChangeListeners.get(i).onBackStackChanged();
1409 }
1410 }
1411 }
1412
1413 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001414 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001415 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001416 }
1417 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001418 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001419 }
1420
Dianne Hackborndd913a52010-07-22 12:17:04 -07001421 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001422 if (mBackStack == null) {
1423 return false;
1424 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001425 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001426 int last = mBackStack.size()-1;
1427 if (last < 0) {
1428 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001429 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001430 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001431 bss.popFromBackStack(true);
1432 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001433 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001434 int index = -1;
1435 if (name != null || id >= 0) {
1436 // If a name or ID is specified, look for that place in
1437 // the stack.
1438 index = mBackStack.size()-1;
1439 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001440 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001441 if (name != null && name.equals(bss.getName())) {
1442 break;
1443 }
1444 if (id >= 0 && id == bss.mIndex) {
1445 break;
1446 }
1447 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001448 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001449 if (index < 0) {
1450 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001451 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001452 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001453 index--;
1454 // Consume all following entries that match.
1455 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001456 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001457 if ((name != null && name.equals(bss.getName()))
1458 || (id >= 0 && id == bss.mIndex)) {
1459 index--;
1460 continue;
1461 }
1462 break;
1463 }
1464 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001465 }
1466 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001467 return false;
1468 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001469 final ArrayList<BackStackRecord> states
1470 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001471 for (int i=mBackStack.size()-1; i>index; i--) {
1472 states.add(mBackStack.remove(i));
1473 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001474 final int LAST = states.size()-1;
1475 for (int i=0; i<=LAST; i++) {
1476 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1477 states.get(i).popFromBackStack(i == LAST);
1478 }
1479 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001480 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001481 return true;
1482 }
1483
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001484 ArrayList<Fragment> retainNonConfig() {
1485 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001486 if (mActive != null) {
1487 for (int i=0; i<mActive.size(); i++) {
1488 Fragment f = mActive.get(i);
1489 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001490 if (fragments == null) {
1491 fragments = new ArrayList<Fragment>();
1492 }
1493 fragments.add(f);
1494 f.mRetaining = true;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001495 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001496 }
1497 }
1498 }
1499 return fragments;
1500 }
1501
1502 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001503 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001504 return;
1505 }
1506 if (mStateArray == null) {
1507 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001508 } else {
1509 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001510 }
1511 f.mView.saveHierarchyState(mStateArray);
1512 if (mStateArray.size() > 0) {
1513 f.mSavedViewState = mStateArray;
1514 mStateArray = null;
1515 }
1516 }
1517
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001518 Bundle saveFragmentBasicState(Fragment f) {
1519 Bundle result = null;
1520
1521 if (mStateBundle == null) {
1522 mStateBundle = new Bundle();
1523 }
1524 f.onSaveInstanceState(mStateBundle);
1525 if (!mStateBundle.isEmpty()) {
1526 result = mStateBundle;
1527 mStateBundle = null;
1528 }
1529
1530 if (f.mView != null) {
1531 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07001532 }
1533 if (f.mSavedViewState != null) {
1534 if (result == null) {
1535 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001536 }
Dianne Hackborn13332762011-06-03 17:34:45 -07001537 result.putSparseParcelableArray(
1538 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001539 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001540 if (!f.mUserVisibleHint) {
1541 // Only add this if it's not the default value
1542 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
1543 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001544
1545 return result;
1546 }
1547
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001548 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001549 // Make sure all pending operations have now been executed to get
1550 // our state update-to-date.
1551 execPendingActions();
1552
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001553 mStateSaved = true;
1554
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001555 if (mActive == null || mActive.size() <= 0) {
1556 return null;
1557 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001558
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001559 // First collect all active fragments.
1560 int N = mActive.size();
1561 FragmentState[] active = new FragmentState[N];
1562 boolean haveFragments = false;
1563 for (int i=0; i<N; i++) {
1564 Fragment f = mActive.get(i);
1565 if (f != null) {
1566 haveFragments = true;
1567
1568 FragmentState fs = new FragmentState(f);
1569 active[i] = fs;
1570
Dianne Hackborn625ac272010-09-17 18:29:22 -07001571 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001572 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001573
1574 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001575 if (f.mTarget.mIndex < 0) {
1576 String msg = "Failure saving state: " + f
1577 + " has target not in fragment manager: " + f.mTarget;
1578 Slog.e(TAG, msg);
1579 dump(" ", null, new PrintWriter(new LogWriter(
1580 Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
1581 throw new IllegalStateException(msg);
1582 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001583 if (fs.mSavedFragmentState == null) {
1584 fs.mSavedFragmentState = new Bundle();
1585 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001586 putFragment(fs.mSavedFragmentState,
1587 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1588 if (f.mTargetRequestCode != 0) {
1589 fs.mSavedFragmentState.putInt(
1590 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1591 f.mTargetRequestCode);
1592 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001593 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001594
Dianne Hackborn625ac272010-09-17 18:29:22 -07001595 } else {
1596 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001597 }
1598
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001599 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1600 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001601 }
1602 }
1603
1604 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001605 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001606 return null;
1607 }
1608
1609 int[] added = null;
1610 BackStackState[] backStack = null;
1611
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001612 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001613 if (mAdded != null) {
1614 N = mAdded.size();
1615 if (N > 0) {
1616 added = new int[N];
1617 for (int i=0; i<N; i++) {
1618 added[i] = mAdded.get(i).mIndex;
1619 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1620 + ": " + mAdded.get(i));
1621 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001622 }
1623 }
1624
1625 // Now save back stack.
1626 if (mBackStack != null) {
1627 N = mBackStack.size();
1628 if (N > 0) {
1629 backStack = new BackStackState[N];
1630 for (int i=0; i<N; i++) {
1631 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001632 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1633 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001634 }
1635 }
1636 }
1637
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001638 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001639 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001640 fms.mAdded = added;
1641 fms.mBackStack = backStack;
1642 return fms;
1643 }
1644
1645 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1646 // If there is no saved state at all, then there can not be
1647 // any nonConfig fragments either, so that is that.
1648 if (state == null) return;
1649 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001650 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001651
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001652 // First re-attach any non-config instances we are retaining back
1653 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001654 if (nonConfig != null) {
1655 for (int i=0; i<nonConfig.size(); i++) {
1656 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001657 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001658 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001659 fs.mInstance = f;
1660 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001661 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001662 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001663 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001664 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001665 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001666 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001667 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001668 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001669 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001670 }
1671 }
1672
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001673 // Build the full list of active fragments, instantiating them from
1674 // their saved state.
1675 mActive = new ArrayList<Fragment>(fms.mActive.length);
1676 if (mAvailIndices != null) {
1677 mAvailIndices.clear();
1678 }
1679 for (int i=0; i<fms.mActive.length; i++) {
1680 FragmentState fs = fms.mActive[i];
1681 if (fs != null) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001682 Fragment f = fs.instantiate(mActivity);
1683 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
1684 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001685 // Now that the fragment is instantiated (or came from being
1686 // retained above), clear mInstance in case we end up re-restoring
1687 // from this FragmentState again.
1688 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001689 } else {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001690 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001691 mActive.add(null);
1692 if (mAvailIndices == null) {
1693 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001694 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001695 if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001696 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001697 }
1698 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001699
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001700 // Update the target of all retained fragments.
1701 if (nonConfig != null) {
1702 for (int i=0; i<nonConfig.size(); i++) {
1703 Fragment f = nonConfig.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001704 if (f.mTargetIndex >= 0) {
1705 if (f.mTargetIndex < mActive.size()) {
1706 f.mTarget = mActive.get(f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001707 } else {
1708 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07001709 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001710 f.mTarget = null;
1711 }
1712 }
1713 }
1714 }
1715
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001716 // Build the list of currently added fragments.
1717 if (fms.mAdded != null) {
1718 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1719 for (int i=0; i<fms.mAdded.length; i++) {
1720 Fragment f = mActive.get(fms.mAdded[i]);
1721 if (f == null) {
1722 throw new IllegalStateException(
1723 "No instantiated fragment for index #" + fms.mAdded[i]);
1724 }
1725 f.mAdded = true;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001726 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001727 mAdded.add(f);
1728 }
1729 } else {
1730 mAdded = null;
1731 }
1732
1733 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001734 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001735 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001736 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001737 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001738 if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
1739 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001740 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001741 if (bse.mIndex >= 0) {
1742 setBackStackIndex(bse.mIndex, bse);
1743 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001744 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001745 } else {
1746 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001747 }
1748 }
1749
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001750 public void attachActivity(Activity activity) {
1751 if (mActivity != null) throw new IllegalStateException();
1752 mActivity = activity;
1753 }
1754
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001755 public void noteStateNotSaved() {
1756 mStateSaved = false;
1757 }
1758
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001759 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001760 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001761 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001762 }
1763
Dianne Hackbornc8017682010-07-06 13:34:38 -07001764 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001765 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001766 moveToState(Fragment.ACTIVITY_CREATED, false);
1767 }
1768
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001769 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001770 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001771 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001772 }
1773
1774 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001775 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001776 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001777 }
1778
1779 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001780 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001781 }
1782
1783 public void dispatchStop() {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001784 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001785 }
1786
1787 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001788 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07001789 execPendingActions();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001790 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001791 mActivity = null;
1792 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001793
Dianne Hackborn9d071802010-12-08 14:49:15 -08001794 public void dispatchConfigurationChanged(Configuration newConfig) {
1795 if (mActive != null) {
1796 for (int i=0; i<mAdded.size(); i++) {
1797 Fragment f = mAdded.get(i);
1798 if (f != null) {
1799 f.onConfigurationChanged(newConfig);
1800 }
1801 }
1802 }
1803 }
1804
1805 public void dispatchLowMemory() {
1806 if (mActive != null) {
1807 for (int i=0; i<mAdded.size(); i++) {
1808 Fragment f = mAdded.get(i);
1809 if (f != null) {
1810 f.onLowMemory();
1811 }
1812 }
1813 }
1814 }
1815
Dianne Hackbornc68c9132011-07-29 01:25:18 -07001816 public void dispatchTrimMemory(int level) {
1817 if (mActive != null) {
1818 for (int i=0; i<mAdded.size(); i++) {
1819 Fragment f = mAdded.get(i);
1820 if (f != null) {
1821 f.onTrimMemory(level);
1822 }
1823 }
1824 }
1825 }
1826
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001827 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1828 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001829 ArrayList<Fragment> newMenus = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001830 if (mActive != null) {
1831 for (int i=0; i<mAdded.size(); i++) {
1832 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001833 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001834 show = true;
1835 f.onCreateOptionsMenu(menu, inflater);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001836 if (newMenus == null) {
1837 newMenus = new ArrayList<Fragment>();
1838 }
1839 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001840 }
1841 }
1842 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001843
1844 if (mCreatedMenus != null) {
1845 for (int i=0; i<mCreatedMenus.size(); i++) {
1846 Fragment f = mCreatedMenus.get(i);
1847 if (newMenus == null || !newMenus.contains(f)) {
1848 f.onDestroyOptionsMenu();
1849 }
1850 }
1851 }
1852
1853 mCreatedMenus = newMenus;
1854
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001855 return show;
1856 }
1857
1858 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1859 boolean show = false;
1860 if (mActive != null) {
1861 for (int i=0; i<mAdded.size(); i++) {
1862 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001863 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001864 show = true;
1865 f.onPrepareOptionsMenu(menu);
1866 }
1867 }
1868 }
1869 return show;
1870 }
1871
1872 public boolean dispatchOptionsItemSelected(MenuItem item) {
1873 if (mActive != null) {
1874 for (int i=0; i<mAdded.size(); i++) {
1875 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001876 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001877 if (f.onOptionsItemSelected(item)) {
1878 return true;
1879 }
1880 }
1881 }
1882 }
1883 return false;
1884 }
1885
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001886 public boolean dispatchContextItemSelected(MenuItem item) {
1887 if (mActive != null) {
1888 for (int i=0; i<mAdded.size(); i++) {
1889 Fragment f = mAdded.get(i);
1890 if (f != null && !f.mHidden) {
1891 if (f.onContextItemSelected(item)) {
1892 return true;
1893 }
1894 }
1895 }
1896 }
1897 return false;
1898 }
1899
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001900 public void dispatchOptionsMenuClosed(Menu menu) {
1901 if (mActive != null) {
1902 for (int i=0; i<mAdded.size(); i++) {
1903 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001904 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001905 f.onOptionsMenuClosed(menu);
1906 }
1907 }
1908 }
1909 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07001910
1911 @Override
1912 public void invalidateOptionsMenu() {
1913 if (mActivity != null && mCurState == Fragment.RESUMED) {
1914 mActivity.invalidateOptionsMenu();
1915 } else {
1916 mNeedMenuInvalidate = true;
1917 }
1918 }
1919
Dianne Hackbornf121be72010-05-06 14:10:32 -07001920 public static int reverseTransit(int transit) {
1921 int rev = 0;
1922 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001923 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
1924 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001925 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001926 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
1927 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001928 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001929 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
1930 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001931 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001932 }
1933 return rev;
1934
1935 }
1936
1937 public static int transitToStyleIndex(int transit, boolean enter) {
1938 int animAttr = -1;
1939 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001940 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001941 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001942 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
1943 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001944 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001945 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001946 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001947 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
1948 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001949 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001950 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07001951 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001952 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
1953 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001954 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001955 }
1956 return animAttr;
1957 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001958}