blob: a8c9cbab2095458ac6c08f1d9d55c8008d7e89dc [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 Hackbornb7a2e472010-08-12 16:20:42 -070054 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -070055public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070056 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070057 * Representation of an entry on the fragment back stack, as created
58 * with {@link FragmentTransaction#addToBackStack(String)
59 * FragmentTransaction.addToBackStack()}. Entries can later be
Dianne Hackborn327fbd22011-01-17 14:38:50 -080060 * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070061 * FragmentManager.getBackStackEntry()}.
62 *
63 * <p>Note that you should never hold on to a BackStackEntry object;
64 * the identifier as returned by {@link #getId} is the only thing that
65 * will be persisted across activity instances.
66 */
67 public interface BackStackEntry {
68 /**
69 * Return the unique identifier for the entry. This is the only
70 * representation of the entry that will persist across activity
71 * instances.
72 */
73 public int getId();
74
75 /**
Dianne Hackborn6c285972011-08-29 16:53:49 -070076 * Get the name that was supplied to
77 * {@link FragmentTransaction#addToBackStack(String)
78 * FragmentTransaction.addToBackStack(String)} when creating this entry.
79 */
80 public String getName();
81
82 /**
Dianne Hackborn327fbd22011-01-17 14:38:50 -080083 * Return the full bread crumb title resource identifier for the entry,
84 * or 0 if it does not have one.
85 */
86 public int getBreadCrumbTitleRes();
87
88 /**
89 * Return the short bread crumb title resource identifier for the entry,
90 * or 0 if it does not have one.
91 */
92 public int getBreadCrumbShortTitleRes();
93
94 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070095 * Return the full bread crumb title for the entry, or null if it
96 * does not have one.
97 */
98 public CharSequence getBreadCrumbTitle();
99
100 /**
101 * Return the short bread crumb title for the entry, or null if it
102 * does not have one.
103 */
104 public CharSequence getBreadCrumbShortTitle();
105 }
106
107 /**
108 * Interface to watch for changes to the back stack.
109 */
110 public interface OnBackStackChangedListener {
111 /**
112 * Called whenever the contents of the back stack change.
113 */
114 public void onBackStackChanged();
115 }
116
117 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700118 * Start a series of edit operations on the Fragments associated with
119 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700120 *
121 * <p>Note: A fragment transaction can only be created/committed prior
122 * to an activity saving its state. If you try to commit a transaction
123 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
124 * (and prior to a following {@link Activity#onStart Activity.onStart}
125 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
126 * This is because the framework takes care of saving your current fragments
127 * in the state, and if changes are made after the state is saved then they
128 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700129 */
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800130 public abstract FragmentTransaction beginTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700131
Dianne Hackborn17b9b812011-01-17 17:16:02 -0800132 /** @hide -- remove once prebuilts are in. */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800133 @Deprecated
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800134 public FragmentTransaction openTransaction() {
135 return beginTransaction();
136 }
137
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700138 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800139 * After a {@link FragmentTransaction} is committed with
140 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
141 * is scheduled to be executed asynchronously on the process's main thread.
142 * If you want to immediately executing any such pending operations, you
143 * can call this function (only from the main thread) to do so. Note that
144 * all callbacks and other related behavior will be done from within this
145 * call, so be careful about where this is called from.
146 *
147 * @return Returns true if there were any pending transactions to be
148 * executed.
149 */
150 public abstract boolean executePendingTransactions();
151
152 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700153 * Finds a fragment that was identified by the given id either when inflated
154 * from XML or as the container ID when added in a transaction. This first
155 * searches through fragments that are currently added to the manager's
156 * activity; if no such fragment is found, then all fragments currently
157 * on the back stack associated with this ID are searched.
158 * @return The fragment if found or null otherwise.
159 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700160 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700161
162 /**
163 * Finds a fragment that was identified by the given tag either when inflated
164 * from XML or as supplied when added in a transaction. This first
165 * searches through fragments that are currently added to the manager's
166 * activity; if no such fragment is found, then all fragments currently
167 * on the back stack are searched.
168 * @return The fragment if found or null otherwise.
169 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700170 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700171
172 /**
173 * Flag for {@link #popBackStack(String, int)}
174 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
175 * a back stack entry has been supplied, then all matching entries will
176 * be consumed until one that doesn't match is found or the bottom of
177 * the stack is reached. Otherwise, all entries up to but not including that entry
178 * will be removed.
179 */
180 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
181
182 /**
Ben Komalo87ffa202011-02-28 12:41:42 -0800183 * Pop the top state off the back stack. This function is asynchronous -- it
184 * enqueues the request to pop, but the action will not be performed until the
185 * application returns to its event loop.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700186 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800187 public abstract void popBackStack();
188
189 /**
190 * Like {@link #popBackStack()}, but performs the operation immediately
191 * inside of the call. This is like calling {@link #executePendingTransactions()}
192 * afterwards.
193 * @return Returns true if there was something popped, else false.
194 */
195 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700196
197 /**
198 * Pop the last fragment transition from the manager's fragment
199 * back stack. If there is nothing to pop, false is returned.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800200 * This function is asynchronous -- it enqueues the
201 * request to pop, but the action will not be performed until the application
202 * returns to its event loop.
203 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700204 * @param name If non-null, this is the name of a previous back state
205 * to look for; if found, all states up to that state will be popped. The
206 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
207 * the named state itself is popped. If null, only the top state is popped.
208 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
209 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800210 public abstract void popBackStack(String name, int flags);
211
212 /**
213 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
214 * inside of the call. This is like calling {@link #executePendingTransactions()}
215 * afterwards.
216 * @return Returns true if there was something popped, else false.
217 */
218 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700219
220 /**
221 * Pop all back stack states up to the one with the given identifier.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800222 * This function is asynchronous -- it enqueues the
223 * request to pop, but the action will not be performed until the application
224 * returns to its event loop.
225 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700226 * @param id Identifier of the stated to be popped. If no identifier exists,
227 * false is returned.
228 * The identifier is the number returned by
229 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
230 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
231 * the named state itself is popped.
232 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
233 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800234 public abstract void popBackStack(int id, int flags);
235
236 /**
237 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
238 * inside of the call. This is like calling {@link #executePendingTransactions()}
239 * afterwards.
240 * @return Returns true if there was something popped, else false.
241 */
242 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700243
244 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700245 * Return the number of entries currently in the back stack.
246 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800247 public abstract int getBackStackEntryCount();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700248
249 /**
250 * Return the BackStackEntry at index <var>index</var> in the back stack;
251 * entries start index 0 being the bottom of the stack.
252 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800253 public abstract BackStackEntry getBackStackEntryAt(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700254
255 /**
256 * Add a new listener for changes to the fragment back stack.
257 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700258 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700259
260 /**
261 * Remove a listener that was previously added with
262 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
263 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700264 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700265
266 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700267 * Put a reference to a fragment in a Bundle. This Bundle can be
268 * persisted as saved state, and when later restoring
269 * {@link #getFragment(Bundle, String)} will return the current
270 * instance of the same fragment.
271 *
272 * @param bundle The bundle in which to put the fragment reference.
273 * @param key The name of the entry in the bundle.
274 * @param fragment The Fragment whose reference is to be stored.
275 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700276 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700277
278 /**
279 * Retrieve the current Fragment instance for a reference previously
280 * placed with {@link #putFragment(Bundle, String, Fragment)}.
281 *
282 * @param bundle The bundle from which to retrieve the fragment reference.
283 * @param key The name of the entry in the bundle.
284 * @return Returns the current Fragment instance that is associated with
285 * the given reference.
286 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700287 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700288
289 /**
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700290 * Save the current instance state of the given Fragment. This can be
291 * used later when creating a new instance of the Fragment and adding
292 * it to the fragment manager, to have it create itself to match the
293 * current state returned here. Note that there are limits on how
294 * this can be used:
295 *
296 * <ul>
297 * <li>The Fragment must currently be attached to the FragmentManager.
298 * <li>A new Fragment created using this saved state must be the same class
299 * type as the Fragment it was created from.
300 * <li>The saved state can not contain dependencies on other fragments --
301 * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
302 * store a fragment reference because that reference may not be valid when
303 * this saved state is later used. Likewise the Fragment's target and
304 * result code are not included in this state.
305 * </ul>
306 *
307 * @param f The Fragment whose state is to be saved.
308 * @return The generated state. This will be null if there was no
309 * interesting state created by the fragment.
310 */
311 public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
312
313 /**
Dianne Hackborn625ac272010-09-17 18:29:22 -0700314 * Print the FragmentManager's state into the given stream.
315 *
316 * @param prefix Text to print at the front of each line.
317 * @param fd The raw file descriptor that the dump is being sent to.
318 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800319 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700320 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700321 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800322
323 /**
324 * Control whether the framework's internal fragment manager debugging
325 * logs are turned on. If enabled, you will see output in logcat as
326 * the framework performs fragment operations.
327 */
328 public static void enableDebugLogging(boolean enabled) {
329 FragmentManagerImpl.DEBUG = enabled;
330 }
Adam Powellf0f5fff2011-08-01 13:42:50 -0700331
332 /**
333 * Invalidate the attached activity's options menu as necessary.
334 * This may end up being deferred until we move to the resumed state.
335 */
336 public void invalidateOptionsMenu() { }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700337}
338
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700339final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700340 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700341 int[] mAdded;
342 BackStackState[] mBackStack;
343
344 public FragmentManagerState() {
345 }
346
347 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700348 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700349 mAdded = in.createIntArray();
350 mBackStack = in.createTypedArray(BackStackState.CREATOR);
351 }
352
353 public int describeContents() {
354 return 0;
355 }
356
357 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700358 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700359 dest.writeIntArray(mAdded);
360 dest.writeTypedArray(mBackStack, flags);
361 }
362
363 public static final Parcelable.Creator<FragmentManagerState> CREATOR
364 = new Parcelable.Creator<FragmentManagerState>() {
365 public FragmentManagerState createFromParcel(Parcel in) {
366 return new FragmentManagerState(in);
367 }
368
369 public FragmentManagerState[] newArray(int size) {
370 return new FragmentManagerState[size];
371 }
372 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700373}
374
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700375/**
376 * Container for fragments associated with an activity.
377 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700378final class FragmentManagerImpl extends FragmentManager {
Dianne Hackbornec541e12011-01-21 16:44:04 -0800379 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700380 static final String TAG = "FragmentManager";
381
Dianne Hackborndef15372010-08-15 12:43:52 -0700382 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
383 static final String TARGET_STATE_TAG = "android:target_state";
384 static final String VIEW_STATE_TAG = "android:view_state";
Adam Powell78fed9b2011-11-07 10:45:34 -0800385 static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
Dianne Hackborndef15372010-08-15 12:43:52 -0700386
Dianne Hackborn445646c2010-06-25 15:52:59 -0700387 ArrayList<Runnable> mPendingActions;
388 Runnable[] mTmpActions;
389 boolean mExecutingActions;
390
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700391 ArrayList<Fragment> mActive;
392 ArrayList<Fragment> mAdded;
393 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700394 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700395 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700396
Dianne Hackborndd913a52010-07-22 12:17:04 -0700397 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700398 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700399 ArrayList<Integer> mAvailBackStackIndices;
400
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700401 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
402
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700403 int mCurState = Fragment.INITIALIZING;
404 Activity mActivity;
405
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700406 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700407 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800408 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700409 String mNoTransactionsBecause;
Adam Powell78fed9b2011-11-07 10:45:34 -0800410 boolean mHavePendingDeferredStart;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700411
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700412 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700413 Bundle mStateBundle = null;
414 SparseArray<Parcelable> mStateArray = null;
415
Dianne Hackborn445646c2010-06-25 15:52:59 -0700416 Runnable mExecCommit = new Runnable() {
417 @Override
418 public void run() {
419 execPendingActions();
420 }
421 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700422
423 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800424 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700425 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700426 }
427
Dianne Hackborn625ac272010-09-17 18:29:22 -0700428 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800429 public boolean executePendingTransactions() {
430 return execPendingActions();
431 }
432
433 @Override
434 public void popBackStack() {
435 enqueueAction(new Runnable() {
436 @Override public void run() {
437 popBackStackState(mActivity.mHandler, null, -1, 0);
438 }
439 }, false);
440 }
441
442 @Override
443 public boolean popBackStackImmediate() {
444 checkStateLoss();
445 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700446 return popBackStackState(mActivity.mHandler, null, -1, 0);
447 }
448
Dianne Hackborn625ac272010-09-17 18:29:22 -0700449 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800450 public void popBackStack(final String name, final int flags) {
451 enqueueAction(new Runnable() {
452 @Override public void run() {
453 popBackStackState(mActivity.mHandler, name, -1, flags);
454 }
455 }, false);
456 }
457
458 @Override
459 public boolean popBackStackImmediate(String name, int flags) {
460 checkStateLoss();
461 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700462 return popBackStackState(mActivity.mHandler, name, -1, flags);
463 }
464
Dianne Hackborn625ac272010-09-17 18:29:22 -0700465 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800466 public void popBackStack(final int id, final int flags) {
467 if (id < 0) {
468 throw new IllegalArgumentException("Bad id: " + id);
469 }
470 enqueueAction(new Runnable() {
471 @Override public void run() {
472 popBackStackState(mActivity.mHandler, null, id, flags);
473 }
474 }, false);
475 }
476
477 @Override
478 public boolean popBackStackImmediate(int id, int flags) {
479 checkStateLoss();
480 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700481 if (id < 0) {
482 throw new IllegalArgumentException("Bad id: " + id);
483 }
484 return popBackStackState(mActivity.mHandler, null, id, flags);
485 }
486
Dianne Hackborn625ac272010-09-17 18:29:22 -0700487 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800488 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700489 return mBackStack != null ? mBackStack.size() : 0;
490 }
491
Dianne Hackborn625ac272010-09-17 18:29:22 -0700492 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800493 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700494 return mBackStack.get(index);
495 }
496
Dianne Hackborn625ac272010-09-17 18:29:22 -0700497 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700498 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
499 if (mBackStackChangeListeners == null) {
500 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
501 }
502 mBackStackChangeListeners.add(listener);
503 }
504
Dianne Hackborn625ac272010-09-17 18:29:22 -0700505 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700506 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
507 if (mBackStackChangeListeners != null) {
508 mBackStackChangeListeners.remove(listener);
509 }
510 }
511
Dianne Hackborn625ac272010-09-17 18:29:22 -0700512 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700513 public void putFragment(Bundle bundle, String key, Fragment fragment) {
514 if (fragment.mIndex < 0) {
515 throw new IllegalStateException("Fragment " + fragment
516 + " is not currently in the FragmentManager");
517 }
518 bundle.putInt(key, fragment.mIndex);
519 }
520
Dianne Hackborn625ac272010-09-17 18:29:22 -0700521 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700522 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700523 int index = bundle.getInt(key, -1);
524 if (index == -1) {
525 return null;
526 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700527 if (index >= mActive.size()) {
528 throw new IllegalStateException("Fragement no longer exists for key "
529 + key + ": index " + index);
530 }
531 Fragment f = mActive.get(index);
532 if (f == null) {
533 throw new IllegalStateException("Fragement no longer exists for key "
534 + key + ": index " + index);
535 }
536 return f;
537 }
538
Dianne Hackborn625ac272010-09-17 18:29:22 -0700539 @Override
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700540 public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
541 if (fragment.mIndex < 0) {
542 throw new IllegalStateException("Fragment " + fragment
543 + " is not currently in the FragmentManager");
544 }
545 if (fragment.mState > Fragment.INITIALIZING) {
546 Bundle result = saveFragmentBasicState(fragment);
547 return result != null ? new Fragment.SavedState(result) : null;
548 }
549 return null;
550 }
551
552 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800553 public String toString() {
554 StringBuilder sb = new StringBuilder(128);
555 sb.append("FragmentManager{");
556 sb.append(Integer.toHexString(System.identityHashCode(this)));
557 sb.append(" in ");
558 DebugUtils.buildShortClassTag(mActivity, sb);
559 sb.append("}}");
560 return sb.toString();
561 }
562
563 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700564 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700565 String innerPrefix = prefix + " ";
566
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800567 int N;
568 if (mActive != null) {
569 N = mActive.size();
570 if (N > 0) {
571 writer.print(prefix); writer.print("Active Fragments in ");
572 writer.print(Integer.toHexString(System.identityHashCode(this)));
573 writer.println(":");
574 for (int i=0; i<N; i++) {
575 Fragment f = mActive.get(i);
576 writer.print(prefix); writer.print(" #"); writer.print(i);
577 writer.print(": "); writer.println(f);
578 if (f != null) {
579 f.dump(innerPrefix, fd, writer, args);
580 }
581 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700582 }
583 }
584
585 if (mAdded != null) {
586 N = mAdded.size();
587 if (N > 0) {
588 writer.print(prefix); writer.println("Added Fragments:");
589 for (int i=0; i<N; i++) {
590 Fragment f = mAdded.get(i);
591 writer.print(prefix); writer.print(" #"); writer.print(i);
592 writer.print(": "); writer.println(f.toString());
593 }
594 }
595 }
596
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800597 if (mCreatedMenus != null) {
598 N = mCreatedMenus.size();
599 if (N > 0) {
600 writer.print(prefix); writer.println("Fragments Created Menus:");
601 for (int i=0; i<N; i++) {
602 Fragment f = mCreatedMenus.get(i);
603 writer.print(prefix); writer.print(" #"); writer.print(i);
604 writer.print(": "); writer.println(f.toString());
605 }
606 }
607 }
608
Dianne Hackborn625ac272010-09-17 18:29:22 -0700609 if (mBackStack != null) {
610 N = mBackStack.size();
611 if (N > 0) {
612 writer.print(prefix); writer.println("Back Stack:");
613 for (int i=0; i<N; i++) {
614 BackStackRecord bs = mBackStack.get(i);
615 writer.print(prefix); writer.print(" #"); writer.print(i);
616 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800617 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700618 }
619 }
620 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800621
622 synchronized (this) {
623 if (mBackStackIndices != null) {
624 N = mBackStackIndices.size();
625 if (N > 0) {
626 writer.print(prefix); writer.println("Back Stack Indices:");
627 for (int i=0; i<N; i++) {
628 BackStackRecord bs = mBackStackIndices.get(i);
629 writer.print(prefix); writer.print(" #"); writer.print(i);
630 writer.print(": "); writer.println(bs);
631 }
632 }
633 }
634
635 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
636 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
637 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
638 }
639 }
640
641 if (mPendingActions != null) {
642 N = mPendingActions.size();
643 if (N > 0) {
644 writer.print(prefix); writer.println("Pending Actions:");
645 for (int i=0; i<N; i++) {
646 Runnable r = mPendingActions.get(i);
647 writer.print(prefix); writer.print(" #"); writer.print(i);
648 writer.print(": "); writer.println(r);
649 }
650 }
651 }
652
653 writer.print(prefix); writer.println("FragmentManager misc state:");
654 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
655 writer.print(" mStateSaved="); writer.print(mStateSaved);
656 writer.print(" mDestroyed="); writer.println(mDestroyed);
657 if (mNeedMenuInvalidate) {
658 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
659 writer.println(mNeedMenuInvalidate);
660 }
661 if (mNoTransactionsBecause != null) {
662 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
663 writer.println(mNoTransactionsBecause);
664 }
665 if (mAvailIndices != null && mAvailIndices.size() > 0) {
666 writer.print(prefix); writer.print(" mAvailIndices: ");
667 writer.println(Arrays.toString(mAvailIndices.toArray()));
668 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700669 }
670
Chet Haasea18a86b2010-09-07 13:20:00 -0700671 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700672 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700673 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700674 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700675 if (animObj != null) {
676 return animObj;
677 }
678
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700679 if (fragment.mNextAnim != 0) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700680 Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700681 if (anim != null) {
682 return anim;
683 }
684 }
685
Dianne Hackbornf121be72010-05-06 14:10:32 -0700686 if (transit == 0) {
687 return null;
688 }
689
690 int styleIndex = transitToStyleIndex(transit, enter);
691 if (styleIndex < 0) {
692 return null;
693 }
694
695 if (transitionStyle == 0 && mActivity.getWindow() != null) {
696 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
697 }
698 if (transitionStyle == 0) {
699 return null;
700 }
701
702 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700703 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700704 int anim = attrs.getResourceId(styleIndex, 0);
705 attrs.recycle();
706
707 if (anim == 0) {
708 return null;
709 }
710
Chet Haasea18a86b2010-09-07 13:20:00 -0700711 return AnimatorInflater.loadAnimator(mActivity, anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700712 }
713
Adam Powell635c60a2011-10-26 10:22:16 -0700714 public void performPendingDeferredStart(Fragment f) {
715 if (f.mDeferStart) {
Adam Powell78fed9b2011-11-07 10:45:34 -0800716 if (mExecutingActions) {
717 // Wait until we're done executing our pending transactions
718 mHavePendingDeferredStart = true;
719 return;
720 }
Adam Powell635c60a2011-10-26 10:22:16 -0700721 f.mDeferStart = false;
722 moveToState(f, mCurState, 0, 0);
723 }
724 }
725
Dianne Hackbornf121be72010-05-06 14:10:32 -0700726 void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700727 // Fragments that are not currently added will sit in the onCreate() state.
728 if (!f.mAdded && newState > Fragment.CREATED) {
729 newState = Fragment.CREATED;
730 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700731 if (f.mRemoving && newState > f.mState) {
732 // While removing a fragment, we can't change it to a higher state.
733 newState = f.mState;
734 }
Adam Powell2db4e4b2011-11-02 14:30:47 -0700735 // Defer start if requested; don't allow it to move to STARTED or higher
736 // if it's not already started.
737 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -0700738 newState = Fragment.STOPPED;
739 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700740 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800741 // For fragments that are created from a layout, when restoring from
742 // state we don't want to allow them to be created until they are
743 // being reloaded from the layout.
744 if (f.mFromLayout && !f.mInLayout) {
745 return;
746 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800747 if (f.mAnimatingAway != null) {
748 // The fragment is currently being animated... but! Now we
749 // want to move our state back up. Give up on waiting for the
750 // animation, move to whatever the final state should be once
751 // the animation is done, and then we can proceed from there.
752 f.mAnimatingAway = null;
753 moveToState(f, f.mStateAfterAnimating, 0, 0);
754 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700755 switch (f.mState) {
756 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700757 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700758 if (f.mSavedFragmentState != null) {
759 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
760 FragmentManagerImpl.VIEW_STATE_TAG);
761 f.mTarget = getFragment(f.mSavedFragmentState,
762 FragmentManagerImpl.TARGET_STATE_TAG);
763 if (f.mTarget != null) {
764 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
765 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
766 }
Adam Powell78fed9b2011-11-07 10:45:34 -0800767 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
768 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
769 if (!f.mUserVisibleHint) {
770 f.mDeferStart = true;
771 if (newState > Fragment.STOPPED) {
772 newState = Fragment.STOPPED;
773 }
774 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700775 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700776 f.mActivity = mActivity;
Dianne Hackbornd2835932010-12-13 16:28:46 -0800777 f.mFragmentManager = mActivity.mFragments;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700778 f.mCalled = false;
779 f.onAttach(mActivity);
780 if (!f.mCalled) {
781 throw new SuperNotCalledException("Fragment " + f
782 + " did not call through to super.onAttach()");
783 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700784 mActivity.onAttachFragment(f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700785
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700786 if (!f.mRetaining) {
787 f.mCalled = false;
788 f.onCreate(f.mSavedFragmentState);
789 if (!f.mCalled) {
790 throw new SuperNotCalledException("Fragment " + f
791 + " did not call through to super.onCreate()");
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700792 }
793 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700794 f.mRetaining = false;
795 if (f.mFromLayout) {
796 // For fragments that are part of the content view
797 // layout, we need to instantiate the view immediately
798 // and the inflater will take care of adding it.
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800799 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700800 null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700801 if (f.mView != null) {
802 f.mView.setSaveFromParentEnabled(false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700803 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700804 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700805 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700806 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700807 case Fragment.CREATED:
808 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700809 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700810 if (!f.mFromLayout) {
811 ViewGroup container = null;
812 if (f.mContainerId != 0) {
813 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800814 if (container == null && !f.mRestored) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700815 throw new IllegalArgumentException("No view found for id 0x"
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700816 + Integer.toHexString(f.mContainerId)
817 + " for fragment " + f);
818 }
819 }
820 f.mContainer = container;
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800821 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700822 container, f.mSavedFragmentState);
823 if (f.mView != null) {
824 f.mView.setSaveFromParentEnabled(false);
825 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700826 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700827 transitionStyle);
828 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700829 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700830 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700831 }
832 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700833 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700834 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700835 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700836 }
837 }
838
839 f.mCalled = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -0700840 f.onActivityCreated(f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700841 if (!f.mCalled) {
842 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800843 + " did not call through to super.onActivityCreated()");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700844 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700845 if (f.mView != null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700846 f.restoreViewState();
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700847 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700848 f.mSavedFragmentState = null;
849 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700850 case Fragment.ACTIVITY_CREATED:
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700851 case Fragment.STOPPED:
852 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700853 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700854 f.mCalled = false;
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700855 f.performStart();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700856 if (!f.mCalled) {
857 throw new SuperNotCalledException("Fragment " + f
858 + " did not call through to super.onStart()");
859 }
860 }
861 case Fragment.STARTED:
862 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700863 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700864 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700865 f.mResumed = true;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700866 f.onResume();
867 if (!f.mCalled) {
868 throw new SuperNotCalledException("Fragment " + f
869 + " did not call through to super.onResume()");
870 }
Adam Powell95202512011-08-07 17:20:17 -0700871 // Get rid of this in case we saved it and never needed it.
872 f.mSavedFragmentState = null;
873 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700874 }
875 }
876 } else if (f.mState > newState) {
877 switch (f.mState) {
878 case Fragment.RESUMED:
879 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700880 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700881 f.mCalled = false;
882 f.onPause();
883 if (!f.mCalled) {
884 throw new SuperNotCalledException("Fragment " + f
885 + " did not call through to super.onPause()");
886 }
Dianne Hackborn2707d602010-07-09 18:01:20 -0700887 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700888 }
889 case Fragment.STARTED:
890 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700891 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700892 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700893 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700894 if (!f.mCalled) {
895 throw new SuperNotCalledException("Fragment " + f
896 + " did not call through to super.onStop()");
897 }
898 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700899 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -0700900 case Fragment.ACTIVITY_CREATED:
901 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700902 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700903 if (f.mView != null) {
904 // Need to save the current view state if not
905 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700906 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700907 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700908 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700909 }
910 f.mCalled = false;
Dianne Hackbornafc4b282011-06-10 17:03:42 -0700911 f.performDestroyView();
Dianne Hackborndef15372010-08-15 12:43:52 -0700912 if (!f.mCalled) {
913 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800914 + " did not call through to super.onDestroyView()");
Dianne Hackborndef15372010-08-15 12:43:52 -0700915 }
916 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700917 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800918 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700919 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700920 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700921 }
922 if (anim != null) {
923 final ViewGroup container = f.mContainer;
924 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800925 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700926 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800927 f.mAnimatingAway = anim;
928 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700929 anim.addListener(new AnimatorListenerAdapter() {
930 @Override
931 public void onAnimationEnd(Animator anim) {
932 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800933 if (fragment.mAnimatingAway != null) {
934 fragment.mAnimatingAway = null;
935 moveToState(fragment, fragment.mStateAfterAnimating,
936 0, 0);
937 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700938 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700939 });
940 anim.setTarget(f.mView);
941 anim.start();
942
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700943 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700944 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700945 }
946 f.mContainer = null;
947 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700948 }
949 case Fragment.CREATED:
950 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800951 if (mDestroyed) {
952 if (f.mAnimatingAway != null) {
953 // The fragment's containing activity is
954 // being destroyed, but this fragment is
955 // currently animating away. Stop the
956 // animation right now -- it is not needed,
957 // and we can't wait any more on destroying
958 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800959 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800960 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800961 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700962 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700963 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800964 if (f.mAnimatingAway != null) {
965 // We are waiting for the fragment's view to finish
966 // animating away. Just make a note of the state
967 // the fragment now should move to once the animation
968 // is done.
969 f.mStateAfterAnimating = newState;
Dianne Hackbornf9302322011-06-14 18:36:14 -0700970 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800971 } else {
972 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
973 if (!f.mRetaining) {
974 f.mCalled = false;
975 f.onDestroy();
976 if (!f.mCalled) {
977 throw new SuperNotCalledException("Fragment " + f
978 + " did not call through to super.onDestroy()");
979 }
980 }
981
982 f.mCalled = false;
983 f.onDetach();
984 if (!f.mCalled) {
985 throw new SuperNotCalledException("Fragment " + f
986 + " did not call through to super.onDetach()");
987 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700988 if (!f.mRetaining) {
989 makeInactive(f);
990 } else {
Dianne Hackbornf9302322011-06-14 18:36:14 -0700991 f.mActivity = null;
992 f.mFragmentManager = null;
993 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700994 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700995 }
996 }
997 }
998
999 f.mState = newState;
1000 }
1001
Dianne Hackborn625ac272010-09-17 18:29:22 -07001002 void moveToState(Fragment f) {
1003 moveToState(f, mCurState, 0, 0);
1004 }
1005
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001006 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001007 moveToState(newState, 0, 0, always);
1008 }
1009
1010 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001011 if (mActivity == null && newState != Fragment.INITIALIZING) {
1012 throw new IllegalStateException("No activity");
1013 }
1014
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001015 if (!always && mCurState == newState) {
1016 return;
1017 }
1018
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001019 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001020 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001021 boolean loadersRunning = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001022 for (int i=0; i<mActive.size(); i++) {
1023 Fragment f = mActive.get(i);
1024 if (f != null) {
1025 moveToState(f, newState, transit, transitStyle);
Adam Powell635c60a2011-10-26 10:22:16 -07001026 if (f.mLoaderManager != null) {
1027 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1028 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001029 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001030 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001031
Adam Powell635c60a2011-10-26 10:22:16 -07001032 if (!loadersRunning) {
1033 startPendingDeferredFragments();
1034 }
1035
Adam Powell89b09da2011-07-27 11:55:29 -07001036 if (mNeedMenuInvalidate && mActivity != null && mCurState == Fragment.RESUMED) {
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001037 mActivity.invalidateOptionsMenu();
1038 mNeedMenuInvalidate = false;
1039 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001040 }
1041 }
1042
Adam Powell635c60a2011-10-26 10:22:16 -07001043 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001044 if (mActive == null) return;
1045
Adam Powell635c60a2011-10-26 10:22:16 -07001046 for (int i=0; i<mActive.size(); i++) {
1047 Fragment f = mActive.get(i);
1048 if (f != null) {
1049 performPendingDeferredStart(f);
1050 }
1051 }
1052 }
1053
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001054 void makeActive(Fragment f) {
1055 if (f.mIndex >= 0) {
1056 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001057 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001058
1059 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
1060 if (mActive == null) {
1061 mActive = new ArrayList<Fragment>();
1062 }
1063 f.setIndex(mActive.size());
1064 mActive.add(f);
1065
1066 } else {
1067 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
1068 mActive.set(f.mIndex, f);
1069 }
1070 }
1071
1072 void makeInactive(Fragment f) {
1073 if (f.mIndex < 0) {
1074 return;
1075 }
1076
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001077 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001078 mActive.set(f.mIndex, null);
1079 if (mAvailIndices == null) {
1080 mAvailIndices = new ArrayList<Integer>();
1081 }
1082 mAvailIndices.add(f.mIndex);
Dianne Hackborn9e14e9f32010-07-14 11:07:38 -07001083 mActivity.invalidateFragmentIndex(f.mIndex);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001084 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001085 }
1086
1087 public void addFragment(Fragment fragment, boolean moveToStateNow) {
1088 if (mAdded == null) {
1089 mAdded = new ArrayList<Fragment>();
1090 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001091 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001092 makeActive(fragment);
1093 if (!fragment.mDetached) {
1094 mAdded.add(fragment);
1095 fragment.mAdded = true;
1096 fragment.mRemoving = false;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001097 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001098 mNeedMenuInvalidate = true;
1099 }
1100 if (moveToStateNow) {
1101 moveToState(fragment);
1102 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001103 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001104 }
1105
Dianne Hackbornf121be72010-05-06 14:10:32 -07001106 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001107 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001108 final boolean inactive = !fragment.isInBackStack();
1109 if (!fragment.mDetached || inactive) {
1110 mAdded.remove(fragment);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001111 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001112 mNeedMenuInvalidate = true;
1113 }
1114 fragment.mAdded = false;
1115 fragment.mRemoving = true;
1116 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
1117 transition, transitionStyle);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001118 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001119 }
1120
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001121 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1122 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1123 if (!fragment.mHidden) {
1124 fragment.mHidden = true;
1125 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001126 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001127 transitionStyle);
1128 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001129 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001130 // Delay the actual hide operation until the animation finishes, otherwise
1131 // the fragment will just immediately disappear
1132 final Fragment finalFragment = fragment;
1133 anim.addListener(new AnimatorListenerAdapter() {
1134 @Override
1135 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001136 if (finalFragment.mView != null) {
1137 finalFragment.mView.setVisibility(View.GONE);
1138 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001139 }
1140 });
Chet Haase811ed1062010-08-06 10:38:15 -07001141 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001142 } else {
1143 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001144 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001145 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001146 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001147 mNeedMenuInvalidate = true;
1148 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001149 fragment.onHiddenChanged(true);
1150 }
1151 }
1152
1153 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1154 if (DEBUG) Log.v(TAG, "show: " + fragment);
1155 if (fragment.mHidden) {
1156 fragment.mHidden = false;
1157 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001158 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001159 transitionStyle);
1160 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001161 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -07001162 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001163 }
1164 fragment.mView.setVisibility(View.VISIBLE);
1165 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001166 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001167 mNeedMenuInvalidate = true;
1168 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001169 fragment.onHiddenChanged(false);
1170 }
1171 }
1172
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001173 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1174 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1175 if (!fragment.mDetached) {
1176 fragment.mDetached = true;
1177 if (fragment.mAdded) {
1178 // We are not already in back stack, so need to remove the fragment.
1179 mAdded.remove(fragment);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001180 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001181 mNeedMenuInvalidate = true;
1182 }
1183 fragment.mAdded = false;
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001184 moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
1185 }
1186 }
1187 }
1188
1189 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1190 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1191 if (fragment.mDetached) {
1192 fragment.mDetached = false;
1193 if (!fragment.mAdded) {
1194 mAdded.add(fragment);
1195 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001196 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001197 mNeedMenuInvalidate = true;
1198 }
1199 moveToState(fragment, mCurState, transition, transitionStyle);
1200 }
1201 }
1202 }
1203
Dianne Hackbornf121be72010-05-06 14:10:32 -07001204 public Fragment findFragmentById(int id) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001205 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001206 // First look through added fragments.
1207 for (int i=mAdded.size()-1; i>=0; i--) {
1208 Fragment f = mAdded.get(i);
1209 if (f != null && f.mFragmentId == id) {
1210 return f;
1211 }
1212 }
1213 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001214 for (int i=mActive.size()-1; i>=0; i--) {
1215 Fragment f = mActive.get(i);
1216 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001217 return f;
1218 }
1219 }
1220 }
1221 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001222 }
1223
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001224 public Fragment findFragmentByTag(String tag) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001225 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001226 // First look through added fragments.
1227 for (int i=mAdded.size()-1; i>=0; i--) {
1228 Fragment f = mAdded.get(i);
1229 if (f != null && tag.equals(f.mTag)) {
1230 return f;
1231 }
1232 }
1233 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001234 for (int i=mActive.size()-1; i>=0; i--) {
1235 Fragment f = mActive.get(i);
1236 if (f != null && tag.equals(f.mTag)) {
1237 return f;
1238 }
1239 }
1240 }
1241 return null;
1242 }
1243
1244 public Fragment findFragmentByWho(String who) {
1245 if (mActive != null && who != null) {
1246 for (int i=mActive.size()-1; i>=0; i--) {
1247 Fragment f = mActive.get(i);
1248 if (f != null && who.equals(f.mWho)) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001249 return f;
1250 }
1251 }
1252 }
1253 return null;
1254 }
1255
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001256 private void checkStateLoss() {
1257 if (mStateSaved) {
1258 throw new IllegalStateException(
1259 "Can not perform this action after onSaveInstanceState");
1260 }
1261 if (mNoTransactionsBecause != null) {
1262 throw new IllegalStateException(
1263 "Can not perform this action inside of " + mNoTransactionsBecause);
1264 }
1265 }
1266
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001267 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001268 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001269 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001270 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001271 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001272 if (mActivity == null) {
1273 throw new IllegalStateException("Activity has been destroyed");
1274 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001275 if (mPendingActions == null) {
1276 mPendingActions = new ArrayList<Runnable>();
1277 }
1278 mPendingActions.add(action);
1279 if (mPendingActions.size() == 1) {
1280 mActivity.mHandler.removeCallbacks(mExecCommit);
1281 mActivity.mHandler.post(mExecCommit);
1282 }
1283 }
1284 }
1285
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001286 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001287 synchronized (this) {
1288 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1289 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001290 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001291 }
1292 int index = mBackStackIndices.size();
1293 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1294 mBackStackIndices.add(bse);
1295 return index;
1296
1297 } else {
1298 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1299 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1300 mBackStackIndices.set(index, bse);
1301 return index;
1302 }
1303 }
1304 }
1305
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001306 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001307 synchronized (this) {
1308 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001309 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001310 }
1311 int N = mBackStackIndices.size();
1312 if (index < N) {
1313 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1314 mBackStackIndices.set(index, bse);
1315 } else {
1316 while (N < index) {
1317 mBackStackIndices.add(null);
1318 if (mAvailBackStackIndices == null) {
1319 mAvailBackStackIndices = new ArrayList<Integer>();
1320 }
1321 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1322 mAvailBackStackIndices.add(N);
1323 N++;
1324 }
1325 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1326 mBackStackIndices.add(bse);
1327 }
1328 }
1329 }
1330
1331 public void freeBackStackIndex(int index) {
1332 synchronized (this) {
1333 mBackStackIndices.set(index, null);
1334 if (mAvailBackStackIndices == null) {
1335 mAvailBackStackIndices = new ArrayList<Integer>();
1336 }
1337 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1338 mAvailBackStackIndices.add(index);
1339 }
1340 }
1341
Dianne Hackborn445646c2010-06-25 15:52:59 -07001342 /**
1343 * Only call from main thread!
1344 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001345 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001346 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001347 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001348 }
1349
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001350 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001351 throw new IllegalStateException("Must be called from main thread of process");
1352 }
1353
1354 boolean didSomething = false;
1355
Dianne Hackborn445646c2010-06-25 15:52:59 -07001356 while (true) {
1357 int numActions;
1358
1359 synchronized (this) {
1360 if (mPendingActions == null || mPendingActions.size() == 0) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001361 break;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001362 }
1363
1364 numActions = mPendingActions.size();
1365 if (mTmpActions == null || mTmpActions.length < numActions) {
1366 mTmpActions = new Runnable[numActions];
1367 }
1368 mPendingActions.toArray(mTmpActions);
1369 mPendingActions.clear();
1370 mActivity.mHandler.removeCallbacks(mExecCommit);
1371 }
1372
1373 mExecutingActions = true;
1374 for (int i=0; i<numActions; i++) {
1375 mTmpActions[i].run();
Jeff Sharkey0d325282011-07-13 09:36:27 -07001376 mTmpActions[i] = null;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001377 }
1378 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001379 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001380 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001381
1382 if (mHavePendingDeferredStart) {
1383 boolean loadersRunning = false;
1384 for (int i=0; i<mActive.size(); i++) {
1385 Fragment f = mActive.get(i);
1386 if (f != null && f.mLoaderManager != null) {
1387 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1388 }
1389 }
1390 if (!loadersRunning) {
1391 mHavePendingDeferredStart = false;
1392 startPendingDeferredFragments();
1393 }
1394 }
1395 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001396 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001397
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001398 void reportBackStackChanged() {
1399 if (mBackStackChangeListeners != null) {
1400 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1401 mBackStackChangeListeners.get(i).onBackStackChanged();
1402 }
1403 }
1404 }
1405
1406 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001407 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001408 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001409 }
1410 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001411 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001412 }
1413
Dianne Hackborndd913a52010-07-22 12:17:04 -07001414 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001415 if (mBackStack == null) {
1416 return false;
1417 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001418 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001419 int last = mBackStack.size()-1;
1420 if (last < 0) {
1421 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001422 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001423 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001424 bss.popFromBackStack(true);
1425 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001426 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001427 int index = -1;
1428 if (name != null || id >= 0) {
1429 // If a name or ID is specified, look for that place in
1430 // the stack.
1431 index = mBackStack.size()-1;
1432 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001433 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001434 if (name != null && name.equals(bss.getName())) {
1435 break;
1436 }
1437 if (id >= 0 && id == bss.mIndex) {
1438 break;
1439 }
1440 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001441 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001442 if (index < 0) {
1443 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001444 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001445 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001446 index--;
1447 // Consume all following entries that match.
1448 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001449 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001450 if ((name != null && name.equals(bss.getName()))
1451 || (id >= 0 && id == bss.mIndex)) {
1452 index--;
1453 continue;
1454 }
1455 break;
1456 }
1457 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001458 }
1459 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001460 return false;
1461 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001462 final ArrayList<BackStackRecord> states
1463 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001464 for (int i=mBackStack.size()-1; i>index; i--) {
1465 states.add(mBackStack.remove(i));
1466 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001467 final int LAST = states.size()-1;
1468 for (int i=0; i<=LAST; i++) {
1469 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1470 states.get(i).popFromBackStack(i == LAST);
1471 }
1472 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001473 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001474 return true;
1475 }
1476
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001477 ArrayList<Fragment> retainNonConfig() {
1478 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001479 if (mActive != null) {
1480 for (int i=0; i<mActive.size(); i++) {
1481 Fragment f = mActive.get(i);
1482 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001483 if (fragments == null) {
1484 fragments = new ArrayList<Fragment>();
1485 }
1486 fragments.add(f);
1487 f.mRetaining = true;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001488 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001489 }
1490 }
1491 }
1492 return fragments;
1493 }
1494
1495 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001496 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001497 return;
1498 }
1499 if (mStateArray == null) {
1500 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001501 } else {
1502 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001503 }
1504 f.mView.saveHierarchyState(mStateArray);
1505 if (mStateArray.size() > 0) {
1506 f.mSavedViewState = mStateArray;
1507 mStateArray = null;
1508 }
1509 }
1510
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001511 Bundle saveFragmentBasicState(Fragment f) {
1512 Bundle result = null;
1513
1514 if (mStateBundle == null) {
1515 mStateBundle = new Bundle();
1516 }
1517 f.onSaveInstanceState(mStateBundle);
1518 if (!mStateBundle.isEmpty()) {
1519 result = mStateBundle;
1520 mStateBundle = null;
1521 }
1522
1523 if (f.mView != null) {
1524 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07001525 }
1526 if (f.mSavedViewState != null) {
1527 if (result == null) {
1528 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001529 }
Dianne Hackborn13332762011-06-03 17:34:45 -07001530 result.putSparseParcelableArray(
1531 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001532 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001533 if (!f.mUserVisibleHint) {
1534 // Only add this if it's not the default value
1535 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
1536 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001537
1538 return result;
1539 }
1540
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001541 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001542 // Make sure all pending operations have now been executed to get
1543 // our state update-to-date.
1544 execPendingActions();
1545
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001546 mStateSaved = true;
1547
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001548 if (mActive == null || mActive.size() <= 0) {
1549 return null;
1550 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001551
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001552 // First collect all active fragments.
1553 int N = mActive.size();
1554 FragmentState[] active = new FragmentState[N];
1555 boolean haveFragments = false;
1556 for (int i=0; i<N; i++) {
1557 Fragment f = mActive.get(i);
1558 if (f != null) {
1559 haveFragments = true;
1560
1561 FragmentState fs = new FragmentState(f);
1562 active[i] = fs;
1563
Dianne Hackborn625ac272010-09-17 18:29:22 -07001564 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001565 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001566
1567 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001568 if (f.mTarget.mIndex < 0) {
1569 String msg = "Failure saving state: " + f
1570 + " has target not in fragment manager: " + f.mTarget;
1571 Slog.e(TAG, msg);
1572 dump(" ", null, new PrintWriter(new LogWriter(
1573 Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
1574 throw new IllegalStateException(msg);
1575 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001576 if (fs.mSavedFragmentState == null) {
1577 fs.mSavedFragmentState = new Bundle();
1578 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001579 putFragment(fs.mSavedFragmentState,
1580 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1581 if (f.mTargetRequestCode != 0) {
1582 fs.mSavedFragmentState.putInt(
1583 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1584 f.mTargetRequestCode);
1585 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001586 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001587
Dianne Hackborn625ac272010-09-17 18:29:22 -07001588 } else {
1589 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001590 }
1591
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001592 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1593 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001594 }
1595 }
1596
1597 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001598 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001599 return null;
1600 }
1601
1602 int[] added = null;
1603 BackStackState[] backStack = null;
1604
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001605 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001606 if (mAdded != null) {
1607 N = mAdded.size();
1608 if (N > 0) {
1609 added = new int[N];
1610 for (int i=0; i<N; i++) {
1611 added[i] = mAdded.get(i).mIndex;
1612 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1613 + ": " + mAdded.get(i));
1614 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001615 }
1616 }
1617
1618 // Now save back stack.
1619 if (mBackStack != null) {
1620 N = mBackStack.size();
1621 if (N > 0) {
1622 backStack = new BackStackState[N];
1623 for (int i=0; i<N; i++) {
1624 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001625 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1626 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001627 }
1628 }
1629 }
1630
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001631 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001632 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001633 fms.mAdded = added;
1634 fms.mBackStack = backStack;
1635 return fms;
1636 }
1637
1638 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1639 // If there is no saved state at all, then there can not be
1640 // any nonConfig fragments either, so that is that.
1641 if (state == null) return;
1642 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001643 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001644
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001645 // First re-attach any non-config instances we are retaining back
1646 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001647 if (nonConfig != null) {
1648 for (int i=0; i<nonConfig.size(); i++) {
1649 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001650 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001651 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001652 fs.mInstance = f;
1653 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001654 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001655 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001656 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001657 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001658 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001659 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001660 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001661 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001662 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001663 }
1664 }
1665
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001666 // Build the full list of active fragments, instantiating them from
1667 // their saved state.
1668 mActive = new ArrayList<Fragment>(fms.mActive.length);
1669 if (mAvailIndices != null) {
1670 mAvailIndices.clear();
1671 }
1672 for (int i=0; i<fms.mActive.length; i++) {
1673 FragmentState fs = fms.mActive[i];
1674 if (fs != null) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001675 Fragment f = fs.instantiate(mActivity);
1676 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
1677 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001678 // Now that the fragment is instantiated (or came from being
1679 // retained above), clear mInstance in case we end up re-restoring
1680 // from this FragmentState again.
1681 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001682 } else {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001683 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001684 mActive.add(null);
1685 if (mAvailIndices == null) {
1686 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001687 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001688 if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001689 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001690 }
1691 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001692
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001693 // Update the target of all retained fragments.
1694 if (nonConfig != null) {
1695 for (int i=0; i<nonConfig.size(); i++) {
1696 Fragment f = nonConfig.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001697 if (f.mTargetIndex >= 0) {
1698 if (f.mTargetIndex < mActive.size()) {
1699 f.mTarget = mActive.get(f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001700 } else {
1701 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07001702 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001703 f.mTarget = null;
1704 }
1705 }
1706 }
1707 }
1708
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001709 // Build the list of currently added fragments.
1710 if (fms.mAdded != null) {
1711 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1712 for (int i=0; i<fms.mAdded.length; i++) {
1713 Fragment f = mActive.get(fms.mAdded[i]);
1714 if (f == null) {
1715 throw new IllegalStateException(
1716 "No instantiated fragment for index #" + fms.mAdded[i]);
1717 }
1718 f.mAdded = true;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001719 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001720 mAdded.add(f);
1721 }
1722 } else {
1723 mAdded = null;
1724 }
1725
1726 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001727 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001728 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001729 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001730 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001731 if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
1732 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001733 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001734 if (bse.mIndex >= 0) {
1735 setBackStackIndex(bse.mIndex, bse);
1736 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001737 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001738 } else {
1739 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001740 }
1741 }
1742
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001743 public void attachActivity(Activity activity) {
1744 if (mActivity != null) throw new IllegalStateException();
1745 mActivity = activity;
1746 }
1747
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001748 public void noteStateNotSaved() {
1749 mStateSaved = false;
1750 }
1751
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001752 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001753 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001754 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001755 }
1756
Dianne Hackbornc8017682010-07-06 13:34:38 -07001757 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001758 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001759 moveToState(Fragment.ACTIVITY_CREATED, false);
1760 }
1761
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001762 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001763 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001764 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001765 }
1766
1767 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001768 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001769 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001770 }
1771
1772 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001773 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001774 }
1775
1776 public void dispatchStop() {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001777 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001778 }
1779
1780 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001781 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07001782 execPendingActions();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001783 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001784 mActivity = null;
1785 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001786
Dianne Hackborn9d071802010-12-08 14:49:15 -08001787 public void dispatchConfigurationChanged(Configuration newConfig) {
1788 if (mActive != null) {
1789 for (int i=0; i<mAdded.size(); i++) {
1790 Fragment f = mAdded.get(i);
1791 if (f != null) {
1792 f.onConfigurationChanged(newConfig);
1793 }
1794 }
1795 }
1796 }
1797
1798 public void dispatchLowMemory() {
1799 if (mActive != null) {
1800 for (int i=0; i<mAdded.size(); i++) {
1801 Fragment f = mAdded.get(i);
1802 if (f != null) {
1803 f.onLowMemory();
1804 }
1805 }
1806 }
1807 }
1808
Dianne Hackbornc68c9132011-07-29 01:25:18 -07001809 public void dispatchTrimMemory(int level) {
1810 if (mActive != null) {
1811 for (int i=0; i<mAdded.size(); i++) {
1812 Fragment f = mAdded.get(i);
1813 if (f != null) {
1814 f.onTrimMemory(level);
1815 }
1816 }
1817 }
1818 }
1819
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001820 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1821 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001822 ArrayList<Fragment> newMenus = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001823 if (mActive != null) {
1824 for (int i=0; i<mAdded.size(); i++) {
1825 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001826 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001827 show = true;
1828 f.onCreateOptionsMenu(menu, inflater);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001829 if (newMenus == null) {
1830 newMenus = new ArrayList<Fragment>();
1831 }
1832 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001833 }
1834 }
1835 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001836
1837 if (mCreatedMenus != null) {
1838 for (int i=0; i<mCreatedMenus.size(); i++) {
1839 Fragment f = mCreatedMenus.get(i);
1840 if (newMenus == null || !newMenus.contains(f)) {
1841 f.onDestroyOptionsMenu();
1842 }
1843 }
1844 }
1845
1846 mCreatedMenus = newMenus;
1847
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001848 return show;
1849 }
1850
1851 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1852 boolean show = false;
1853 if (mActive != null) {
1854 for (int i=0; i<mAdded.size(); i++) {
1855 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001856 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001857 show = true;
1858 f.onPrepareOptionsMenu(menu);
1859 }
1860 }
1861 }
1862 return show;
1863 }
1864
1865 public boolean dispatchOptionsItemSelected(MenuItem item) {
1866 if (mActive != null) {
1867 for (int i=0; i<mAdded.size(); i++) {
1868 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001869 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001870 if (f.onOptionsItemSelected(item)) {
1871 return true;
1872 }
1873 }
1874 }
1875 }
1876 return false;
1877 }
1878
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001879 public boolean dispatchContextItemSelected(MenuItem item) {
1880 if (mActive != null) {
1881 for (int i=0; i<mAdded.size(); i++) {
1882 Fragment f = mAdded.get(i);
1883 if (f != null && !f.mHidden) {
1884 if (f.onContextItemSelected(item)) {
1885 return true;
1886 }
1887 }
1888 }
1889 }
1890 return false;
1891 }
1892
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001893 public void dispatchOptionsMenuClosed(Menu menu) {
1894 if (mActive != null) {
1895 for (int i=0; i<mAdded.size(); i++) {
1896 Fragment f = mAdded.get(i);
Dianne Hackborn6c285972011-08-29 16:53:49 -07001897 if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001898 f.onOptionsMenuClosed(menu);
1899 }
1900 }
1901 }
1902 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07001903
1904 @Override
1905 public void invalidateOptionsMenu() {
1906 if (mActivity != null && mCurState == Fragment.RESUMED) {
1907 mActivity.invalidateOptionsMenu();
1908 } else {
1909 mNeedMenuInvalidate = true;
1910 }
1911 }
1912
Dianne Hackbornf121be72010-05-06 14:10:32 -07001913 public static int reverseTransit(int transit) {
1914 int rev = 0;
1915 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001916 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
1917 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001918 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001919 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
1920 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001921 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001922 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
1923 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001924 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001925 }
1926 return rev;
1927
1928 }
1929
1930 public static int transitToStyleIndex(int transit, boolean enter) {
1931 int animAttr = -1;
1932 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001933 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001934 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001935 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
1936 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001937 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001938 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001939 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001940 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
1941 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001942 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001943 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07001944 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001945 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
1946 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001947 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001948 }
1949 return animAttr;
1950 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001951}