blob: ab60cf016ba9c5c01702db4edafba366460561cc [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}
48 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -070049public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070050 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070051 * Representation of an entry on the fragment back stack, as created
52 * with {@link FragmentTransaction#addToBackStack(String)
53 * FragmentTransaction.addToBackStack()}. Entries can later be
Dianne Hackborn327fbd22011-01-17 14:38:50 -080054 * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070055 * FragmentManager.getBackStackEntry()}.
56 *
57 * <p>Note that you should never hold on to a BackStackEntry object;
58 * the identifier as returned by {@link #getId} is the only thing that
59 * will be persisted across activity instances.
60 */
61 public interface BackStackEntry {
62 /**
63 * Return the unique identifier for the entry. This is the only
64 * representation of the entry that will persist across activity
65 * instances.
66 */
67 public int getId();
68
69 /**
Dianne Hackborn327fbd22011-01-17 14:38:50 -080070 * Return the full bread crumb title resource identifier for the entry,
71 * or 0 if it does not have one.
72 */
73 public int getBreadCrumbTitleRes();
74
75 /**
76 * Return the short bread crumb title resource identifier for the entry,
77 * or 0 if it does not have one.
78 */
79 public int getBreadCrumbShortTitleRes();
80
81 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070082 * Return the full bread crumb title for the entry, or null if it
83 * does not have one.
84 */
85 public CharSequence getBreadCrumbTitle();
86
87 /**
88 * Return the short bread crumb title for the entry, or null if it
89 * does not have one.
90 */
91 public CharSequence getBreadCrumbShortTitle();
92 }
93
94 /**
95 * Interface to watch for changes to the back stack.
96 */
97 public interface OnBackStackChangedListener {
98 /**
99 * Called whenever the contents of the back stack change.
100 */
101 public void onBackStackChanged();
102 }
103
104 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700105 * Start a series of edit operations on the Fragments associated with
106 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700107 *
108 * <p>Note: A fragment transaction can only be created/committed prior
109 * to an activity saving its state. If you try to commit a transaction
110 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
111 * (and prior to a following {@link Activity#onStart Activity.onStart}
112 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
113 * This is because the framework takes care of saving your current fragments
114 * in the state, and if changes are made after the state is saved then they
115 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700116 */
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800117 public abstract FragmentTransaction beginTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700118
Dianne Hackborn17b9b812011-01-17 17:16:02 -0800119 /** @hide -- remove once prebuilts are in. */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800120 @Deprecated
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800121 public FragmentTransaction openTransaction() {
122 return beginTransaction();
123 }
124
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700125 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800126 * After a {@link FragmentTransaction} is committed with
127 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
128 * is scheduled to be executed asynchronously on the process's main thread.
129 * If you want to immediately executing any such pending operations, you
130 * can call this function (only from the main thread) to do so. Note that
131 * all callbacks and other related behavior will be done from within this
132 * call, so be careful about where this is called from.
133 *
134 * @return Returns true if there were any pending transactions to be
135 * executed.
136 */
137 public abstract boolean executePendingTransactions();
138
139 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700140 * Finds a fragment that was identified by the given id either when inflated
141 * from XML or as the container ID when added in a transaction. This first
142 * searches through fragments that are currently added to the manager's
143 * activity; if no such fragment is found, then all fragments currently
144 * on the back stack associated with this ID are searched.
145 * @return The fragment if found or null otherwise.
146 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700147 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700148
149 /**
150 * Finds a fragment that was identified by the given tag either when inflated
151 * from XML or as supplied when added in a transaction. This first
152 * searches through fragments that are currently added to the manager's
153 * activity; if no such fragment is found, then all fragments currently
154 * on the back stack are searched.
155 * @return The fragment if found or null otherwise.
156 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700157 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700158
159 /**
160 * Flag for {@link #popBackStack(String, int)}
161 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
162 * a back stack entry has been supplied, then all matching entries will
163 * be consumed until one that doesn't match is found or the bottom of
164 * the stack is reached. Otherwise, all entries up to but not including that entry
165 * will be removed.
166 */
167 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
168
169 /**
Ben Komalo87ffa202011-02-28 12:41:42 -0800170 * Pop the top state off the back stack. This function is asynchronous -- it
171 * enqueues the request to pop, but the action will not be performed until the
172 * application returns to its event loop.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700173 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800174 public abstract void popBackStack();
175
176 /**
177 * Like {@link #popBackStack()}, but performs the operation immediately
178 * inside of the call. This is like calling {@link #executePendingTransactions()}
179 * afterwards.
180 * @return Returns true if there was something popped, else false.
181 */
182 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700183
184 /**
185 * Pop the last fragment transition from the manager's fragment
186 * back stack. If there is nothing to pop, false is returned.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800187 * This function is asynchronous -- it enqueues the
188 * request to pop, but the action will not be performed until the application
189 * returns to its event loop.
190 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700191 * @param name If non-null, this is the name of a previous back state
192 * to look for; if found, all states up to that state will be popped. The
193 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
194 * the named state itself is popped. If null, only the top state is popped.
195 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
196 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800197 public abstract void popBackStack(String name, int flags);
198
199 /**
200 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
201 * inside of the call. This is like calling {@link #executePendingTransactions()}
202 * afterwards.
203 * @return Returns true if there was something popped, else false.
204 */
205 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700206
207 /**
208 * Pop all back stack states up to the one with the given identifier.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800209 * This function is asynchronous -- it enqueues the
210 * request to pop, but the action will not be performed until the application
211 * returns to its event loop.
212 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700213 * @param id Identifier of the stated to be popped. If no identifier exists,
214 * false is returned.
215 * The identifier is the number returned by
216 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
217 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
218 * the named state itself is popped.
219 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
220 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800221 public abstract void popBackStack(int id, int flags);
222
223 /**
224 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
225 * inside of the call. This is like calling {@link #executePendingTransactions()}
226 * afterwards.
227 * @return Returns true if there was something popped, else false.
228 */
229 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700230
231 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700232 * Return the number of entries currently in the back stack.
233 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800234 public abstract int getBackStackEntryCount();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700235
236 /**
237 * Return the BackStackEntry at index <var>index</var> in the back stack;
238 * entries start index 0 being the bottom of the stack.
239 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800240 public abstract BackStackEntry getBackStackEntryAt(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700241
242 /**
243 * Add a new listener for changes to the fragment back stack.
244 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700245 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700246
247 /**
248 * Remove a listener that was previously added with
249 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
250 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700251 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700252
253 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700254 * Put a reference to a fragment in a Bundle. This Bundle can be
255 * persisted as saved state, and when later restoring
256 * {@link #getFragment(Bundle, String)} will return the current
257 * instance of the same fragment.
258 *
259 * @param bundle The bundle in which to put the fragment reference.
260 * @param key The name of the entry in the bundle.
261 * @param fragment The Fragment whose reference is to be stored.
262 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700263 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700264
265 /**
266 * Retrieve the current Fragment instance for a reference previously
267 * placed with {@link #putFragment(Bundle, String, Fragment)}.
268 *
269 * @param bundle The bundle from which to retrieve the fragment reference.
270 * @param key The name of the entry in the bundle.
271 * @return Returns the current Fragment instance that is associated with
272 * the given reference.
273 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700274 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700275
276 /**
277 * Print the FragmentManager's state into the given stream.
278 *
279 * @param prefix Text to print at the front of each line.
280 * @param fd The raw file descriptor that the dump is being sent to.
281 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800282 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700283 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700284 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800285
286 /**
287 * Control whether the framework's internal fragment manager debugging
288 * logs are turned on. If enabled, you will see output in logcat as
289 * the framework performs fragment operations.
290 */
291 public static void enableDebugLogging(boolean enabled) {
292 FragmentManagerImpl.DEBUG = enabled;
293 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700294}
295
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700296final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700297 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700298 int[] mAdded;
299 BackStackState[] mBackStack;
300
301 public FragmentManagerState() {
302 }
303
304 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700305 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700306 mAdded = in.createIntArray();
307 mBackStack = in.createTypedArray(BackStackState.CREATOR);
308 }
309
310 public int describeContents() {
311 return 0;
312 }
313
314 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700315 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700316 dest.writeIntArray(mAdded);
317 dest.writeTypedArray(mBackStack, flags);
318 }
319
320 public static final Parcelable.Creator<FragmentManagerState> CREATOR
321 = new Parcelable.Creator<FragmentManagerState>() {
322 public FragmentManagerState createFromParcel(Parcel in) {
323 return new FragmentManagerState(in);
324 }
325
326 public FragmentManagerState[] newArray(int size) {
327 return new FragmentManagerState[size];
328 }
329 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700330}
331
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700332/**
333 * Container for fragments associated with an activity.
334 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700335final class FragmentManagerImpl extends FragmentManager {
Dianne Hackbornec541e12011-01-21 16:44:04 -0800336 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700337 static final String TAG = "FragmentManager";
338
Dianne Hackborndef15372010-08-15 12:43:52 -0700339 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
340 static final String TARGET_STATE_TAG = "android:target_state";
341 static final String VIEW_STATE_TAG = "android:view_state";
342
Dianne Hackborn445646c2010-06-25 15:52:59 -0700343 ArrayList<Runnable> mPendingActions;
344 Runnable[] mTmpActions;
345 boolean mExecutingActions;
346
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700347 ArrayList<Fragment> mActive;
348 ArrayList<Fragment> mAdded;
349 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700350 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700351 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700352
Dianne Hackborndd913a52010-07-22 12:17:04 -0700353 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700354 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700355 ArrayList<Integer> mAvailBackStackIndices;
356
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700357 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
358
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700359 int mCurState = Fragment.INITIALIZING;
360 Activity mActivity;
361
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700362 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700363 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800364 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700365 String mNoTransactionsBecause;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700366
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700367 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700368 Bundle mStateBundle = null;
369 SparseArray<Parcelable> mStateArray = null;
370
Dianne Hackborn445646c2010-06-25 15:52:59 -0700371 Runnable mExecCommit = new Runnable() {
372 @Override
373 public void run() {
374 execPendingActions();
375 }
376 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700377
378 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800379 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700380 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700381 }
382
Dianne Hackborn625ac272010-09-17 18:29:22 -0700383 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800384 public boolean executePendingTransactions() {
385 return execPendingActions();
386 }
387
388 @Override
389 public void popBackStack() {
390 enqueueAction(new Runnable() {
391 @Override public void run() {
392 popBackStackState(mActivity.mHandler, null, -1, 0);
393 }
394 }, false);
395 }
396
397 @Override
398 public boolean popBackStackImmediate() {
399 checkStateLoss();
400 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700401 return popBackStackState(mActivity.mHandler, null, -1, 0);
402 }
403
Dianne Hackborn625ac272010-09-17 18:29:22 -0700404 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800405 public void popBackStack(final String name, final int flags) {
406 enqueueAction(new Runnable() {
407 @Override public void run() {
408 popBackStackState(mActivity.mHandler, name, -1, flags);
409 }
410 }, false);
411 }
412
413 @Override
414 public boolean popBackStackImmediate(String name, int flags) {
415 checkStateLoss();
416 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700417 return popBackStackState(mActivity.mHandler, name, -1, flags);
418 }
419
Dianne Hackborn625ac272010-09-17 18:29:22 -0700420 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800421 public void popBackStack(final int id, final int flags) {
422 if (id < 0) {
423 throw new IllegalArgumentException("Bad id: " + id);
424 }
425 enqueueAction(new Runnable() {
426 @Override public void run() {
427 popBackStackState(mActivity.mHandler, null, id, flags);
428 }
429 }, false);
430 }
431
432 @Override
433 public boolean popBackStackImmediate(int id, int flags) {
434 checkStateLoss();
435 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700436 if (id < 0) {
437 throw new IllegalArgumentException("Bad id: " + id);
438 }
439 return popBackStackState(mActivity.mHandler, null, id, flags);
440 }
441
Dianne Hackborn625ac272010-09-17 18:29:22 -0700442 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800443 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700444 return mBackStack != null ? mBackStack.size() : 0;
445 }
446
Dianne Hackborn625ac272010-09-17 18:29:22 -0700447 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800448 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700449 return mBackStack.get(index);
450 }
451
Dianne Hackborn625ac272010-09-17 18:29:22 -0700452 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700453 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
454 if (mBackStackChangeListeners == null) {
455 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
456 }
457 mBackStackChangeListeners.add(listener);
458 }
459
Dianne Hackborn625ac272010-09-17 18:29:22 -0700460 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700461 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
462 if (mBackStackChangeListeners != null) {
463 mBackStackChangeListeners.remove(listener);
464 }
465 }
466
Dianne Hackborn625ac272010-09-17 18:29:22 -0700467 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700468 public void putFragment(Bundle bundle, String key, Fragment fragment) {
469 if (fragment.mIndex < 0) {
470 throw new IllegalStateException("Fragment " + fragment
471 + " is not currently in the FragmentManager");
472 }
473 bundle.putInt(key, fragment.mIndex);
474 }
475
Dianne Hackborn625ac272010-09-17 18:29:22 -0700476 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700477 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700478 int index = bundle.getInt(key, -1);
479 if (index == -1) {
480 return null;
481 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700482 if (index >= mActive.size()) {
483 throw new IllegalStateException("Fragement no longer exists for key "
484 + key + ": index " + index);
485 }
486 Fragment f = mActive.get(index);
487 if (f == null) {
488 throw new IllegalStateException("Fragement no longer exists for key "
489 + key + ": index " + index);
490 }
491 return f;
492 }
493
Dianne Hackborn625ac272010-09-17 18:29:22 -0700494 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800495 public String toString() {
496 StringBuilder sb = new StringBuilder(128);
497 sb.append("FragmentManager{");
498 sb.append(Integer.toHexString(System.identityHashCode(this)));
499 sb.append(" in ");
500 DebugUtils.buildShortClassTag(mActivity, sb);
501 sb.append("}}");
502 return sb.toString();
503 }
504
505 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700506 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700507 String innerPrefix = prefix + " ";
508
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800509 int N;
510 if (mActive != null) {
511 N = mActive.size();
512 if (N > 0) {
513 writer.print(prefix); writer.print("Active Fragments in ");
514 writer.print(Integer.toHexString(System.identityHashCode(this)));
515 writer.println(":");
516 for (int i=0; i<N; i++) {
517 Fragment f = mActive.get(i);
518 writer.print(prefix); writer.print(" #"); writer.print(i);
519 writer.print(": "); writer.println(f);
520 if (f != null) {
521 f.dump(innerPrefix, fd, writer, args);
522 }
523 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700524 }
525 }
526
527 if (mAdded != null) {
528 N = mAdded.size();
529 if (N > 0) {
530 writer.print(prefix); writer.println("Added Fragments:");
531 for (int i=0; i<N; i++) {
532 Fragment f = mAdded.get(i);
533 writer.print(prefix); writer.print(" #"); writer.print(i);
534 writer.print(": "); writer.println(f.toString());
535 }
536 }
537 }
538
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800539 if (mCreatedMenus != null) {
540 N = mCreatedMenus.size();
541 if (N > 0) {
542 writer.print(prefix); writer.println("Fragments Created Menus:");
543 for (int i=0; i<N; i++) {
544 Fragment f = mCreatedMenus.get(i);
545 writer.print(prefix); writer.print(" #"); writer.print(i);
546 writer.print(": "); writer.println(f.toString());
547 }
548 }
549 }
550
Dianne Hackborn625ac272010-09-17 18:29:22 -0700551 if (mBackStack != null) {
552 N = mBackStack.size();
553 if (N > 0) {
554 writer.print(prefix); writer.println("Back Stack:");
555 for (int i=0; i<N; i++) {
556 BackStackRecord bs = mBackStack.get(i);
557 writer.print(prefix); writer.print(" #"); writer.print(i);
558 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800559 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700560 }
561 }
562 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800563
564 synchronized (this) {
565 if (mBackStackIndices != null) {
566 N = mBackStackIndices.size();
567 if (N > 0) {
568 writer.print(prefix); writer.println("Back Stack Indices:");
569 for (int i=0; i<N; i++) {
570 BackStackRecord bs = mBackStackIndices.get(i);
571 writer.print(prefix); writer.print(" #"); writer.print(i);
572 writer.print(": "); writer.println(bs);
573 }
574 }
575 }
576
577 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
578 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
579 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
580 }
581 }
582
583 if (mPendingActions != null) {
584 N = mPendingActions.size();
585 if (N > 0) {
586 writer.print(prefix); writer.println("Pending Actions:");
587 for (int i=0; i<N; i++) {
588 Runnable r = mPendingActions.get(i);
589 writer.print(prefix); writer.print(" #"); writer.print(i);
590 writer.print(": "); writer.println(r);
591 }
592 }
593 }
594
595 writer.print(prefix); writer.println("FragmentManager misc state:");
596 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
597 writer.print(" mStateSaved="); writer.print(mStateSaved);
598 writer.print(" mDestroyed="); writer.println(mDestroyed);
599 if (mNeedMenuInvalidate) {
600 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
601 writer.println(mNeedMenuInvalidate);
602 }
603 if (mNoTransactionsBecause != null) {
604 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
605 writer.println(mNoTransactionsBecause);
606 }
607 if (mAvailIndices != null && mAvailIndices.size() > 0) {
608 writer.print(prefix); writer.print(" mAvailIndices: ");
609 writer.println(Arrays.toString(mAvailIndices.toArray()));
610 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700611 }
612
Chet Haasea18a86b2010-09-07 13:20:00 -0700613 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700614 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700615 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700616 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700617 if (animObj != null) {
618 return animObj;
619 }
620
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700621 if (fragment.mNextAnim != 0) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700622 Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700623 if (anim != null) {
624 return anim;
625 }
626 }
627
Dianne Hackbornf121be72010-05-06 14:10:32 -0700628 if (transit == 0) {
629 return null;
630 }
631
632 int styleIndex = transitToStyleIndex(transit, enter);
633 if (styleIndex < 0) {
634 return null;
635 }
636
637 if (transitionStyle == 0 && mActivity.getWindow() != null) {
638 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
639 }
640 if (transitionStyle == 0) {
641 return null;
642 }
643
644 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700645 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700646 int anim = attrs.getResourceId(styleIndex, 0);
647 attrs.recycle();
648
649 if (anim == 0) {
650 return null;
651 }
652
Chet Haasea18a86b2010-09-07 13:20:00 -0700653 return AnimatorInflater.loadAnimator(mActivity, anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700654 }
655
656 void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700657 // Fragments that are not currently added will sit in the onCreate() state.
658 if (!f.mAdded && newState > Fragment.CREATED) {
659 newState = Fragment.CREATED;
660 }
661
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700662 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800663 // For fragments that are created from a layout, when restoring from
664 // state we don't want to allow them to be created until they are
665 // being reloaded from the layout.
666 if (f.mFromLayout && !f.mInLayout) {
667 return;
668 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800669 if (f.mAnimatingAway != null) {
670 // The fragment is currently being animated... but! Now we
671 // want to move our state back up. Give up on waiting for the
672 // animation, move to whatever the final state should be once
673 // the animation is done, and then we can proceed from there.
674 f.mAnimatingAway = null;
675 moveToState(f, f.mStateAfterAnimating, 0, 0);
676 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700677 switch (f.mState) {
678 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700679 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700680 if (f.mSavedFragmentState != null) {
681 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
682 FragmentManagerImpl.VIEW_STATE_TAG);
683 f.mTarget = getFragment(f.mSavedFragmentState,
684 FragmentManagerImpl.TARGET_STATE_TAG);
685 if (f.mTarget != null) {
686 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
687 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
688 }
689 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700690 f.mActivity = mActivity;
Dianne Hackbornd2835932010-12-13 16:28:46 -0800691 f.mFragmentManager = mActivity.mFragments;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700692 f.mCalled = false;
693 f.onAttach(mActivity);
694 if (!f.mCalled) {
695 throw new SuperNotCalledException("Fragment " + f
696 + " did not call through to super.onAttach()");
697 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700698 mActivity.onAttachFragment(f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700699
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700700 if (!f.mRetaining) {
701 f.mCalled = false;
702 f.onCreate(f.mSavedFragmentState);
703 if (!f.mCalled) {
704 throw new SuperNotCalledException("Fragment " + f
705 + " did not call through to super.onCreate()");
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700706 }
707 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700708 f.mRetaining = false;
709 if (f.mFromLayout) {
710 // For fragments that are part of the content view
711 // layout, we need to instantiate the view immediately
712 // and the inflater will take care of adding it.
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800713 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700714 null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700715 if (f.mView != null) {
716 f.mView.setSaveFromParentEnabled(false);
717 f.restoreViewState();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700718 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700719 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700720 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700721 case Fragment.CREATED:
722 if (newState > Fragment.CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700723 if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700724 if (!f.mFromLayout) {
725 ViewGroup container = null;
726 if (f.mContainerId != 0) {
727 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800728 if (container == null && !f.mRestored) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700729 throw new IllegalArgumentException("No view found for id 0x"
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700730 + Integer.toHexString(f.mContainerId)
731 + " for fragment " + f);
732 }
733 }
734 f.mContainer = container;
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800735 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700736 container, f.mSavedFragmentState);
737 if (f.mView != null) {
738 f.mView.setSaveFromParentEnabled(false);
739 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700740 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700741 transitionStyle);
742 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700743 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700744 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700745 }
746 container.addView(f.mView);
747 f.restoreViewState();
748 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700749 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700750 }
751 }
752
753 f.mCalled = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -0700754 f.onActivityCreated(f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700755 if (!f.mCalled) {
756 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800757 + " did not call through to super.onActivityCreated()");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700758 }
759 f.mSavedFragmentState = null;
760 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700761 case Fragment.ACTIVITY_CREATED:
762 if (newState > Fragment.ACTIVITY_CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700763 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700764 f.mCalled = false;
765 f.onStart();
766 if (!f.mCalled) {
767 throw new SuperNotCalledException("Fragment " + f
768 + " did not call through to super.onStart()");
769 }
770 }
771 case Fragment.STARTED:
772 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700773 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700774 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700775 f.mResumed = true;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700776 f.onResume();
777 if (!f.mCalled) {
778 throw new SuperNotCalledException("Fragment " + f
779 + " did not call through to super.onResume()");
780 }
781 }
782 }
783 } else if (f.mState > newState) {
784 switch (f.mState) {
785 case Fragment.RESUMED:
786 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700787 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700788 f.mCalled = false;
789 f.onPause();
790 if (!f.mCalled) {
791 throw new SuperNotCalledException("Fragment " + f
792 + " did not call through to super.onPause()");
793 }
Dianne Hackborn2707d602010-07-09 18:01:20 -0700794 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700795 }
796 case Fragment.STARTED:
797 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700798 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700799 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700800 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700801 if (!f.mCalled) {
802 throw new SuperNotCalledException("Fragment " + f
803 + " did not call through to super.onStop()");
804 }
805 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700806 case Fragment.ACTIVITY_CREATED:
807 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700808 if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700809 if (f.mView != null) {
810 // Need to save the current view state if not
811 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700812 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700813 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700814 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700815 }
816 f.mCalled = false;
817 f.onDestroyView();
818 if (!f.mCalled) {
819 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800820 + " did not call through to super.onDestroyView()");
Dianne Hackborndef15372010-08-15 12:43:52 -0700821 }
822 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700823 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800824 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700825 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700826 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700827 }
828 if (anim != null) {
829 final ViewGroup container = f.mContainer;
830 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800831 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700832 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800833 f.mAnimatingAway = anim;
834 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700835 anim.addListener(new AnimatorListenerAdapter() {
836 @Override
837 public void onAnimationEnd(Animator anim) {
838 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800839 if (fragment.mAnimatingAway != null) {
840 fragment.mAnimatingAway = null;
841 moveToState(fragment, fragment.mStateAfterAnimating,
842 0, 0);
843 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700844 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700845 });
846 anim.setTarget(f.mView);
847 anim.start();
848
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700849 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700850 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700851 }
852 f.mContainer = null;
853 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700854 }
855 case Fragment.CREATED:
856 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800857 if (mDestroyed) {
858 if (f.mAnimatingAway != null) {
859 // The fragment's containing activity is
860 // being destroyed, but this fragment is
861 // currently animating away. Stop the
862 // animation right now -- it is not needed,
863 // and we can't wait any more on destroying
864 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800865 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800866 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800867 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700868 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700869 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800870 if (f.mAnimatingAway != null) {
871 // We are waiting for the fragment's view to finish
872 // animating away. Just make a note of the state
873 // the fragment now should move to once the animation
874 // is done.
875 f.mStateAfterAnimating = newState;
876 } else {
877 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
878 if (!f.mRetaining) {
879 f.mCalled = false;
880 f.onDestroy();
881 if (!f.mCalled) {
882 throw new SuperNotCalledException("Fragment " + f
883 + " did not call through to super.onDestroy()");
884 }
885 }
886
887 f.mCalled = false;
888 f.onDetach();
889 if (!f.mCalled) {
890 throw new SuperNotCalledException("Fragment " + f
891 + " did not call through to super.onDetach()");
892 }
893 f.mImmediateActivity = null;
894 f.mActivity = null;
895 f.mFragmentManager = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700896 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700897 }
898 }
899 }
900
901 f.mState = newState;
902 }
903
Dianne Hackborn625ac272010-09-17 18:29:22 -0700904 void moveToState(Fragment f) {
905 moveToState(f, mCurState, 0, 0);
906 }
907
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700908 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -0700909 moveToState(newState, 0, 0, always);
910 }
911
912 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700913 if (mActivity == null && newState != Fragment.INITIALIZING) {
914 throw new IllegalStateException("No activity");
915 }
916
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700917 if (!always && mCurState == newState) {
918 return;
919 }
920
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700921 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700922 if (mActive != null) {
923 for (int i=0; i<mActive.size(); i++) {
924 Fragment f = mActive.get(i);
925 if (f != null) {
926 moveToState(f, newState, transit, transitStyle);
927 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700928 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -0700929
930 if (mNeedMenuInvalidate && mActivity != null) {
931 mActivity.invalidateOptionsMenu();
932 mNeedMenuInvalidate = false;
933 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700934 }
935 }
936
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700937 void makeActive(Fragment f) {
938 if (f.mIndex >= 0) {
939 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700940 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700941
942 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
943 if (mActive == null) {
944 mActive = new ArrayList<Fragment>();
945 }
946 f.setIndex(mActive.size());
947 mActive.add(f);
948
949 } else {
950 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
951 mActive.set(f.mIndex, f);
952 }
953 }
954
955 void makeInactive(Fragment f) {
956 if (f.mIndex < 0) {
957 return;
958 }
959
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700960 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700961 mActive.set(f.mIndex, null);
962 if (mAvailIndices == null) {
963 mAvailIndices = new ArrayList<Integer>();
964 }
965 mAvailIndices.add(f.mIndex);
Dianne Hackborn9e14e9f32010-07-14 11:07:38 -0700966 mActivity.invalidateFragmentIndex(f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700967 f.clearIndex();
968 }
969
970 public void addFragment(Fragment fragment, boolean moveToStateNow) {
971 if (mAdded == null) {
972 mAdded = new ArrayList<Fragment>();
973 }
974 mAdded.add(fragment);
975 makeActive(fragment);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700976 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700977 fragment.mAdded = true;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -0800978 fragment.mRemoving = false;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700979 if (fragment.mHasMenu) {
980 mNeedMenuInvalidate = true;
981 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700982 if (moveToStateNow) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700983 moveToState(fragment);
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700984 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700985 }
986
Dianne Hackbornf121be72010-05-06 14:10:32 -0700987 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700988 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700989 mAdded.remove(fragment);
990 final boolean inactive = fragment.mBackStackNesting <= 0;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700991 if (fragment.mHasMenu) {
992 mNeedMenuInvalidate = true;
993 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700994 fragment.mAdded = false;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -0800995 fragment.mRemoving = true;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700996 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
997 transition, transitionStyle);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700998 if (inactive) {
999 makeInactive(fragment);
1000 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001001 }
1002
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001003 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1004 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1005 if (!fragment.mHidden) {
1006 fragment.mHidden = true;
1007 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001008 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001009 transitionStyle);
1010 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001011 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001012 // Delay the actual hide operation until the animation finishes, otherwise
1013 // the fragment will just immediately disappear
1014 final Fragment finalFragment = fragment;
1015 anim.addListener(new AnimatorListenerAdapter() {
1016 @Override
1017 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001018 if (finalFragment.mView != null) {
1019 finalFragment.mView.setVisibility(View.GONE);
1020 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001021 }
1022 });
Chet Haase811ed1062010-08-06 10:38:15 -07001023 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001024 } else {
1025 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001026 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001027 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001028 if (fragment.mAdded && fragment.mHasMenu) {
1029 mNeedMenuInvalidate = true;
1030 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001031 fragment.onHiddenChanged(true);
1032 }
1033 }
1034
1035 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1036 if (DEBUG) Log.v(TAG, "show: " + fragment);
1037 if (fragment.mHidden) {
1038 fragment.mHidden = false;
1039 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001040 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001041 transitionStyle);
1042 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001043 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -07001044 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001045 }
1046 fragment.mView.setVisibility(View.VISIBLE);
1047 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001048 if (fragment.mAdded && fragment.mHasMenu) {
1049 mNeedMenuInvalidate = true;
1050 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001051 fragment.onHiddenChanged(false);
1052 }
1053 }
1054
Dianne Hackbornf121be72010-05-06 14:10:32 -07001055 public Fragment findFragmentById(int id) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001056 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001057 // First look through added fragments.
1058 for (int i=mAdded.size()-1; i>=0; i--) {
1059 Fragment f = mAdded.get(i);
1060 if (f != null && f.mFragmentId == id) {
1061 return f;
1062 }
1063 }
1064 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001065 for (int i=mActive.size()-1; i>=0; i--) {
1066 Fragment f = mActive.get(i);
1067 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001068 return f;
1069 }
1070 }
1071 }
1072 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001073 }
1074
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001075 public Fragment findFragmentByTag(String tag) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001076 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001077 // First look through added fragments.
1078 for (int i=mAdded.size()-1; i>=0; i--) {
1079 Fragment f = mAdded.get(i);
1080 if (f != null && tag.equals(f.mTag)) {
1081 return f;
1082 }
1083 }
1084 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001085 for (int i=mActive.size()-1; i>=0; i--) {
1086 Fragment f = mActive.get(i);
1087 if (f != null && tag.equals(f.mTag)) {
1088 return f;
1089 }
1090 }
1091 }
1092 return null;
1093 }
1094
1095 public Fragment findFragmentByWho(String who) {
1096 if (mActive != null && who != null) {
1097 for (int i=mActive.size()-1; i>=0; i--) {
1098 Fragment f = mActive.get(i);
1099 if (f != null && who.equals(f.mWho)) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001100 return f;
1101 }
1102 }
1103 }
1104 return null;
1105 }
1106
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001107 private void checkStateLoss() {
1108 if (mStateSaved) {
1109 throw new IllegalStateException(
1110 "Can not perform this action after onSaveInstanceState");
1111 }
1112 if (mNoTransactionsBecause != null) {
1113 throw new IllegalStateException(
1114 "Can not perform this action inside of " + mNoTransactionsBecause);
1115 }
1116 }
1117
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001118 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001119 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001120 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001121 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001122 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001123 if (mActivity == null) {
1124 throw new IllegalStateException("Activity has been destroyed");
1125 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001126 if (mPendingActions == null) {
1127 mPendingActions = new ArrayList<Runnable>();
1128 }
1129 mPendingActions.add(action);
1130 if (mPendingActions.size() == 1) {
1131 mActivity.mHandler.removeCallbacks(mExecCommit);
1132 mActivity.mHandler.post(mExecCommit);
1133 }
1134 }
1135 }
1136
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001137 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001138 synchronized (this) {
1139 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1140 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001141 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001142 }
1143 int index = mBackStackIndices.size();
1144 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1145 mBackStackIndices.add(bse);
1146 return index;
1147
1148 } else {
1149 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1150 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1151 mBackStackIndices.set(index, bse);
1152 return index;
1153 }
1154 }
1155 }
1156
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001157 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001158 synchronized (this) {
1159 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001160 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001161 }
1162 int N = mBackStackIndices.size();
1163 if (index < N) {
1164 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1165 mBackStackIndices.set(index, bse);
1166 } else {
1167 while (N < index) {
1168 mBackStackIndices.add(null);
1169 if (mAvailBackStackIndices == null) {
1170 mAvailBackStackIndices = new ArrayList<Integer>();
1171 }
1172 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1173 mAvailBackStackIndices.add(N);
1174 N++;
1175 }
1176 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1177 mBackStackIndices.add(bse);
1178 }
1179 }
1180 }
1181
1182 public void freeBackStackIndex(int index) {
1183 synchronized (this) {
1184 mBackStackIndices.set(index, null);
1185 if (mAvailBackStackIndices == null) {
1186 mAvailBackStackIndices = new ArrayList<Integer>();
1187 }
1188 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1189 mAvailBackStackIndices.add(index);
1190 }
1191 }
1192
Dianne Hackborn445646c2010-06-25 15:52:59 -07001193 /**
1194 * Only call from main thread!
1195 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001196 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001197 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001198 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001199 }
1200
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001201 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001202 throw new IllegalStateException("Must be called from main thread of process");
1203 }
1204
1205 boolean didSomething = false;
1206
Dianne Hackborn445646c2010-06-25 15:52:59 -07001207 while (true) {
1208 int numActions;
1209
1210 synchronized (this) {
1211 if (mPendingActions == null || mPendingActions.size() == 0) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001212 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001213 }
1214
1215 numActions = mPendingActions.size();
1216 if (mTmpActions == null || mTmpActions.length < numActions) {
1217 mTmpActions = new Runnable[numActions];
1218 }
1219 mPendingActions.toArray(mTmpActions);
1220 mPendingActions.clear();
1221 mActivity.mHandler.removeCallbacks(mExecCommit);
1222 }
1223
1224 mExecutingActions = true;
1225 for (int i=0; i<numActions; i++) {
1226 mTmpActions[i].run();
1227 }
1228 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001229 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001230 }
1231 }
1232
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001233 void reportBackStackChanged() {
1234 if (mBackStackChangeListeners != null) {
1235 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1236 mBackStackChangeListeners.get(i).onBackStackChanged();
1237 }
1238 }
1239 }
1240
1241 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001242 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001243 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001244 }
1245 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001246 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001247 }
1248
Dianne Hackborndd913a52010-07-22 12:17:04 -07001249 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001250 if (mBackStack == null) {
1251 return false;
1252 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001253 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001254 int last = mBackStack.size()-1;
1255 if (last < 0) {
1256 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001257 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001258 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001259 bss.popFromBackStack(true);
1260 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001261 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001262 int index = -1;
1263 if (name != null || id >= 0) {
1264 // If a name or ID is specified, look for that place in
1265 // the stack.
1266 index = mBackStack.size()-1;
1267 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001268 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001269 if (name != null && name.equals(bss.getName())) {
1270 break;
1271 }
1272 if (id >= 0 && id == bss.mIndex) {
1273 break;
1274 }
1275 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001276 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001277 if (index < 0) {
1278 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001279 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001280 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001281 index--;
1282 // Consume all following entries that match.
1283 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001284 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001285 if ((name != null && name.equals(bss.getName()))
1286 || (id >= 0 && id == bss.mIndex)) {
1287 index--;
1288 continue;
1289 }
1290 break;
1291 }
1292 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001293 }
1294 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001295 return false;
1296 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001297 final ArrayList<BackStackRecord> states
1298 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001299 for (int i=mBackStack.size()-1; i>index; i--) {
1300 states.add(mBackStack.remove(i));
1301 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001302 final int LAST = states.size()-1;
1303 for (int i=0; i<=LAST; i++) {
1304 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1305 states.get(i).popFromBackStack(i == LAST);
1306 }
1307 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001308 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001309 return true;
1310 }
1311
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001312 ArrayList<Fragment> retainNonConfig() {
1313 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001314 if (mActive != null) {
1315 for (int i=0; i<mActive.size(); i++) {
1316 Fragment f = mActive.get(i);
1317 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001318 if (fragments == null) {
1319 fragments = new ArrayList<Fragment>();
1320 }
1321 fragments.add(f);
1322 f.mRetaining = true;
1323 }
1324 }
1325 }
1326 return fragments;
1327 }
1328
1329 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001330 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001331 return;
1332 }
1333 if (mStateArray == null) {
1334 mStateArray = new SparseArray<Parcelable>();
1335 }
1336 f.mView.saveHierarchyState(mStateArray);
1337 if (mStateArray.size() > 0) {
1338 f.mSavedViewState = mStateArray;
1339 mStateArray = null;
1340 }
1341 }
1342
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001343 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001344 // Make sure all pending operations have now been executed to get
1345 // our state update-to-date.
1346 execPendingActions();
1347
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001348 mStateSaved = true;
1349
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001350 if (mActive == null || mActive.size() <= 0) {
1351 return null;
1352 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001353
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001354 // First collect all active fragments.
1355 int N = mActive.size();
1356 FragmentState[] active = new FragmentState[N];
1357 boolean haveFragments = false;
1358 for (int i=0; i<N; i++) {
1359 Fragment f = mActive.get(i);
1360 if (f != null) {
1361 haveFragments = true;
1362
1363 FragmentState fs = new FragmentState(f);
1364 active[i] = fs;
1365
Dianne Hackborn625ac272010-09-17 18:29:22 -07001366 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
1367 if (mStateBundle == null) {
1368 mStateBundle = new Bundle();
1369 }
1370 f.onSaveInstanceState(mStateBundle);
1371 if (!mStateBundle.isEmpty()) {
1372 fs.mSavedFragmentState = mStateBundle;
1373 mStateBundle = null;
1374 }
1375
1376 if (f.mView != null) {
1377 saveFragmentViewState(f);
1378 if (f.mSavedViewState != null) {
1379 if (fs.mSavedFragmentState == null) {
1380 fs.mSavedFragmentState = new Bundle();
1381 }
1382 fs.mSavedFragmentState.putSparseParcelableArray(
1383 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
1384 }
1385 }
1386
1387 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001388 if (f.mTarget.mIndex < 0) {
1389 String msg = "Failure saving state: " + f
1390 + " has target not in fragment manager: " + f.mTarget;
1391 Slog.e(TAG, msg);
1392 dump(" ", null, new PrintWriter(new LogWriter(
1393 Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
1394 throw new IllegalStateException(msg);
1395 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001396 if (fs.mSavedFragmentState == null) {
1397 fs.mSavedFragmentState = new Bundle();
1398 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001399 putFragment(fs.mSavedFragmentState,
1400 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1401 if (f.mTargetRequestCode != 0) {
1402 fs.mSavedFragmentState.putInt(
1403 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1404 f.mTargetRequestCode);
1405 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001406 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001407
Dianne Hackborn625ac272010-09-17 18:29:22 -07001408 } else {
1409 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001410 }
1411
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001412 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1413 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001414 }
1415 }
1416
1417 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001418 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001419 return null;
1420 }
1421
1422 int[] added = null;
1423 BackStackState[] backStack = null;
1424
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001425 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001426 if (mAdded != null) {
1427 N = mAdded.size();
1428 if (N > 0) {
1429 added = new int[N];
1430 for (int i=0; i<N; i++) {
1431 added[i] = mAdded.get(i).mIndex;
1432 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1433 + ": " + mAdded.get(i));
1434 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001435 }
1436 }
1437
1438 // Now save back stack.
1439 if (mBackStack != null) {
1440 N = mBackStack.size();
1441 if (N > 0) {
1442 backStack = new BackStackState[N];
1443 for (int i=0; i<N; i++) {
1444 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001445 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1446 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001447 }
1448 }
1449 }
1450
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001451 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001452 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001453 fms.mAdded = added;
1454 fms.mBackStack = backStack;
1455 return fms;
1456 }
1457
1458 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1459 // If there is no saved state at all, then there can not be
1460 // any nonConfig fragments either, so that is that.
1461 if (state == null) return;
1462 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001463 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001464
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001465 // First re-attach any non-config instances we are retaining back
1466 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001467 if (nonConfig != null) {
1468 for (int i=0; i<nonConfig.size(); i++) {
1469 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001470 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001471 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001472 fs.mInstance = f;
1473 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001474 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001475 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001476 f.mAdded = false;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001477 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001478 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001479 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001480 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001481 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001482 }
1483 }
1484
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001485 // Build the full list of active fragments, instantiating them from
1486 // their saved state.
1487 mActive = new ArrayList<Fragment>(fms.mActive.length);
1488 if (mAvailIndices != null) {
1489 mAvailIndices.clear();
1490 }
1491 for (int i=0; i<fms.mActive.length; i++) {
1492 FragmentState fs = fms.mActive[i];
1493 if (fs != null) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001494 Fragment f = fs.instantiate(mActivity);
1495 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
1496 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001497 // Now that the fragment is instantiated (or came from being
1498 // retained above), clear mInstance in case we end up re-restoring
1499 // from this FragmentState again.
1500 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001501 } else {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001502 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001503 mActive.add(null);
1504 if (mAvailIndices == null) {
1505 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001506 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001507 if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001508 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001509 }
1510 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001511
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001512 // Update the target of all retained fragments.
1513 if (nonConfig != null) {
1514 for (int i=0; i<nonConfig.size(); i++) {
1515 Fragment f = nonConfig.get(i);
1516 if (f.mTarget != null) {
1517 if (f.mTarget.mIndex < mActive.size()) {
1518 f.mTarget = mActive.get(f.mTarget.mIndex);
1519 } else {
1520 Log.w(TAG, "Re-attaching retained fragment " + f
1521 + " target no longer exists: " + f.mTarget);
1522 f.mTarget = null;
1523 }
1524 }
1525 }
1526 }
1527
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001528 // Build the list of currently added fragments.
1529 if (fms.mAdded != null) {
1530 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1531 for (int i=0; i<fms.mAdded.length; i++) {
1532 Fragment f = mActive.get(fms.mAdded[i]);
1533 if (f == null) {
1534 throw new IllegalStateException(
1535 "No instantiated fragment for index #" + fms.mAdded[i]);
1536 }
1537 f.mAdded = true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001538 f.mImmediateActivity = mActivity;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001539 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001540 mAdded.add(f);
1541 }
1542 } else {
1543 mAdded = null;
1544 }
1545
1546 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001547 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001548 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001549 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001550 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001551 if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
1552 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001553 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001554 if (bse.mIndex >= 0) {
1555 setBackStackIndex(bse.mIndex, bse);
1556 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001557 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001558 } else {
1559 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001560 }
1561 }
1562
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001563 public void attachActivity(Activity activity) {
1564 if (mActivity != null) throw new IllegalStateException();
1565 mActivity = activity;
1566 }
1567
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001568 public void noteStateNotSaved() {
1569 mStateSaved = false;
1570 }
1571
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001572 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001573 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001574 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001575 }
1576
Dianne Hackbornc8017682010-07-06 13:34:38 -07001577 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001578 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001579 moveToState(Fragment.ACTIVITY_CREATED, false);
1580 }
1581
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001582 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001583 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001584 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001585 }
1586
1587 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001588 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001589 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001590 }
1591
1592 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001593 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001594 }
1595
1596 public void dispatchStop() {
Dianne Hackbornc8017682010-07-06 13:34:38 -07001597 moveToState(Fragment.ACTIVITY_CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001598 }
1599
1600 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001601 mDestroyed = true;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001602 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001603 mActivity = null;
1604 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001605
Dianne Hackborn9d071802010-12-08 14:49:15 -08001606 public void dispatchConfigurationChanged(Configuration newConfig) {
1607 if (mActive != null) {
1608 for (int i=0; i<mAdded.size(); i++) {
1609 Fragment f = mAdded.get(i);
1610 if (f != null) {
1611 f.onConfigurationChanged(newConfig);
1612 }
1613 }
1614 }
1615 }
1616
1617 public void dispatchLowMemory() {
1618 if (mActive != null) {
1619 for (int i=0; i<mAdded.size(); i++) {
1620 Fragment f = mAdded.get(i);
1621 if (f != null) {
1622 f.onLowMemory();
1623 }
1624 }
1625 }
1626 }
1627
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001628 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1629 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001630 ArrayList<Fragment> newMenus = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001631 if (mActive != null) {
1632 for (int i=0; i<mAdded.size(); i++) {
1633 Fragment f = mAdded.get(i);
1634 if (f != null && !f.mHidden && f.mHasMenu) {
1635 show = true;
1636 f.onCreateOptionsMenu(menu, inflater);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001637 if (newMenus == null) {
1638 newMenus = new ArrayList<Fragment>();
1639 }
1640 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001641 }
1642 }
1643 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001644
1645 if (mCreatedMenus != null) {
1646 for (int i=0; i<mCreatedMenus.size(); i++) {
1647 Fragment f = mCreatedMenus.get(i);
1648 if (newMenus == null || !newMenus.contains(f)) {
1649 f.onDestroyOptionsMenu();
1650 }
1651 }
1652 }
1653
1654 mCreatedMenus = newMenus;
1655
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001656 return show;
1657 }
1658
1659 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1660 boolean show = false;
1661 if (mActive != null) {
1662 for (int i=0; i<mAdded.size(); i++) {
1663 Fragment f = mAdded.get(i);
1664 if (f != null && !f.mHidden && f.mHasMenu) {
1665 show = true;
1666 f.onPrepareOptionsMenu(menu);
1667 }
1668 }
1669 }
1670 return show;
1671 }
1672
1673 public boolean dispatchOptionsItemSelected(MenuItem item) {
1674 if (mActive != null) {
1675 for (int i=0; i<mAdded.size(); i++) {
1676 Fragment f = mAdded.get(i);
1677 if (f != null && !f.mHidden && f.mHasMenu) {
1678 if (f.onOptionsItemSelected(item)) {
1679 return true;
1680 }
1681 }
1682 }
1683 }
1684 return false;
1685 }
1686
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001687 public boolean dispatchContextItemSelected(MenuItem item) {
1688 if (mActive != null) {
1689 for (int i=0; i<mAdded.size(); i++) {
1690 Fragment f = mAdded.get(i);
1691 if (f != null && !f.mHidden) {
1692 if (f.onContextItemSelected(item)) {
1693 return true;
1694 }
1695 }
1696 }
1697 }
1698 return false;
1699 }
1700
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001701 public void dispatchOptionsMenuClosed(Menu menu) {
1702 if (mActive != null) {
1703 for (int i=0; i<mAdded.size(); i++) {
1704 Fragment f = mAdded.get(i);
1705 if (f != null && !f.mHidden && f.mHasMenu) {
1706 f.onOptionsMenuClosed(menu);
1707 }
1708 }
1709 }
1710 }
1711
Dianne Hackbornf121be72010-05-06 14:10:32 -07001712 public static int reverseTransit(int transit) {
1713 int rev = 0;
1714 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001715 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
1716 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001717 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001718 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
1719 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001720 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001721 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
1722 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001723 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001724 }
1725 return rev;
1726
1727 }
1728
1729 public static int transitToStyleIndex(int transit, boolean enter) {
1730 int animAttr = -1;
1731 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001732 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001733 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001734 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
1735 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001736 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001737 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001738 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001739 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
1740 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001741 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001742 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07001743 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001744 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
1745 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001746 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001747 }
1748 return animAttr;
1749 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001750}