blob: 0da656fb64196199be18725589e4487edff772ef [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);
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700717 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700718 f.restoreViewState();
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700719 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700720 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700721 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700722 case Fragment.CREATED:
723 if (newState > Fragment.CREATED) {
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700724 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700725 if (!f.mFromLayout) {
726 ViewGroup container = null;
727 if (f.mContainerId != 0) {
728 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800729 if (container == null && !f.mRestored) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700730 throw new IllegalArgumentException("No view found for id 0x"
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700731 + Integer.toHexString(f.mContainerId)
732 + " for fragment " + f);
733 }
734 }
735 f.mContainer = container;
Dianne Hackborn7187ccb2011-01-24 23:58:13 -0800736 f.mView = f.onCreateView(f.getLayoutInflater(f.mSavedFragmentState),
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700737 container, f.mSavedFragmentState);
738 if (f.mView != null) {
739 f.mView.setSaveFromParentEnabled(false);
740 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700741 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700742 transitionStyle);
743 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700744 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700745 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700746 }
747 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700748 }
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700749 if (f.mHidden) f.mView.setVisibility(View.GONE);
750 f.restoreViewState();
751 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700752 }
753 }
754
755 f.mCalled = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -0700756 f.onActivityCreated(f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700757 if (!f.mCalled) {
758 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800759 + " did not call through to super.onActivityCreated()");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700760 }
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700761 if (f.mView != null) {
762 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700763 f.mSavedFragmentState = null;
764 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700765 case Fragment.ACTIVITY_CREATED:
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700766 case Fragment.STOPPED:
767 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700768 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700769 f.mCalled = false;
770 f.onStart();
771 if (!f.mCalled) {
772 throw new SuperNotCalledException("Fragment " + f
773 + " did not call through to super.onStart()");
774 }
775 }
776 case Fragment.STARTED:
777 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700778 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700779 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700780 f.mResumed = true;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700781 f.onResume();
782 if (!f.mCalled) {
783 throw new SuperNotCalledException("Fragment " + f
784 + " did not call through to super.onResume()");
785 }
786 }
787 }
788 } else if (f.mState > newState) {
789 switch (f.mState) {
790 case Fragment.RESUMED:
791 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700792 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700793 f.mCalled = false;
794 f.onPause();
795 if (!f.mCalled) {
796 throw new SuperNotCalledException("Fragment " + f
797 + " did not call through to super.onPause()");
798 }
Dianne Hackborn2707d602010-07-09 18:01:20 -0700799 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700800 }
801 case Fragment.STARTED:
802 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700803 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700804 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700805 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700806 if (!f.mCalled) {
807 throw new SuperNotCalledException("Fragment " + f
808 + " did not call through to super.onStop()");
809 }
810 }
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700811 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -0700812 case Fragment.ACTIVITY_CREATED:
813 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackbornd071ec22011-04-18 14:08:33 -0700814 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700815 if (f.mView != null) {
816 // Need to save the current view state if not
817 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700818 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700819 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700820 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700821 }
822 f.mCalled = false;
823 f.onDestroyView();
824 if (!f.mCalled) {
825 throw new SuperNotCalledException("Fragment " + f
Dianne Hackbornec541e12011-01-21 16:44:04 -0800826 + " did not call through to super.onDestroyView()");
Dianne Hackborndef15372010-08-15 12:43:52 -0700827 }
828 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700829 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800830 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700831 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700832 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700833 }
834 if (anim != null) {
835 final ViewGroup container = f.mContainer;
836 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800837 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700838 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800839 f.mAnimatingAway = anim;
840 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -0700841 anim.addListener(new AnimatorListenerAdapter() {
842 @Override
843 public void onAnimationEnd(Animator anim) {
844 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800845 if (fragment.mAnimatingAway != null) {
846 fragment.mAnimatingAway = null;
847 moveToState(fragment, fragment.mStateAfterAnimating,
848 0, 0);
849 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700850 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700851 });
852 anim.setTarget(f.mView);
853 anim.start();
854
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700855 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700856 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700857 }
858 f.mContainer = null;
859 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700860 }
861 case Fragment.CREATED:
862 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800863 if (mDestroyed) {
864 if (f.mAnimatingAway != null) {
865 // The fragment's containing activity is
866 // being destroyed, but this fragment is
867 // currently animating away. Stop the
868 // animation right now -- it is not needed,
869 // and we can't wait any more on destroying
870 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800871 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800872 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -0800873 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700874 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700875 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800876 if (f.mAnimatingAway != null) {
877 // We are waiting for the fragment's view to finish
878 // animating away. Just make a note of the state
879 // the fragment now should move to once the animation
880 // is done.
881 f.mStateAfterAnimating = newState;
882 } else {
883 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
884 if (!f.mRetaining) {
885 f.mCalled = false;
886 f.onDestroy();
887 if (!f.mCalled) {
888 throw new SuperNotCalledException("Fragment " + f
889 + " did not call through to super.onDestroy()");
890 }
891 }
892
893 f.mCalled = false;
894 f.onDetach();
895 if (!f.mCalled) {
896 throw new SuperNotCalledException("Fragment " + f
897 + " did not call through to super.onDetach()");
898 }
899 f.mImmediateActivity = null;
900 f.mActivity = null;
901 f.mFragmentManager = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700902 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700903 }
904 }
905 }
906
907 f.mState = newState;
908 }
909
Dianne Hackborn625ac272010-09-17 18:29:22 -0700910 void moveToState(Fragment f) {
911 moveToState(f, mCurState, 0, 0);
912 }
913
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700914 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -0700915 moveToState(newState, 0, 0, always);
916 }
917
918 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700919 if (mActivity == null && newState != Fragment.INITIALIZING) {
920 throw new IllegalStateException("No activity");
921 }
922
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700923 if (!always && mCurState == newState) {
924 return;
925 }
926
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700927 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700928 if (mActive != null) {
929 for (int i=0; i<mActive.size(); i++) {
930 Fragment f = mActive.get(i);
931 if (f != null) {
932 moveToState(f, newState, transit, transitStyle);
933 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700934 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -0700935
936 if (mNeedMenuInvalidate && mActivity != null) {
937 mActivity.invalidateOptionsMenu();
938 mNeedMenuInvalidate = false;
939 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700940 }
941 }
942
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700943 void makeActive(Fragment f) {
944 if (f.mIndex >= 0) {
945 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700946 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700947
948 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
949 if (mActive == null) {
950 mActive = new ArrayList<Fragment>();
951 }
952 f.setIndex(mActive.size());
953 mActive.add(f);
954
955 } else {
956 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
957 mActive.set(f.mIndex, f);
958 }
959 }
960
961 void makeInactive(Fragment f) {
962 if (f.mIndex < 0) {
963 return;
964 }
965
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700966 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700967 mActive.set(f.mIndex, null);
968 if (mAvailIndices == null) {
969 mAvailIndices = new ArrayList<Integer>();
970 }
971 mAvailIndices.add(f.mIndex);
Dianne Hackborn9e14e9f32010-07-14 11:07:38 -0700972 mActivity.invalidateFragmentIndex(f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700973 f.clearIndex();
974 }
975
976 public void addFragment(Fragment fragment, boolean moveToStateNow) {
977 if (mAdded == null) {
978 mAdded = new ArrayList<Fragment>();
979 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700980 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn47c41562011-04-15 19:00:20 -0700981 makeActive(fragment);
982 if (!fragment.mDetached) {
983 mAdded.add(fragment);
984 fragment.mAdded = true;
985 fragment.mRemoving = false;
986 if (fragment.mHasMenu) {
987 mNeedMenuInvalidate = true;
988 }
989 if (moveToStateNow) {
990 moveToState(fragment);
991 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700992 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700993 }
994
Dianne Hackbornf121be72010-05-06 14:10:32 -0700995 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700996 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn47c41562011-04-15 19:00:20 -0700997 final boolean inactive = !fragment.isInBackStack();
998 if (!fragment.mDetached || inactive) {
999 mAdded.remove(fragment);
1000 if (fragment.mHasMenu) {
1001 mNeedMenuInvalidate = true;
1002 }
1003 fragment.mAdded = false;
1004 fragment.mRemoving = true;
1005 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
1006 transition, transitionStyle);
1007 if (inactive) {
1008 makeInactive(fragment);
1009 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001010 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001011 }
1012
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001013 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1014 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1015 if (!fragment.mHidden) {
1016 fragment.mHidden = true;
1017 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001018 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001019 transitionStyle);
1020 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001021 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001022 // Delay the actual hide operation until the animation finishes, otherwise
1023 // the fragment will just immediately disappear
1024 final Fragment finalFragment = fragment;
1025 anim.addListener(new AnimatorListenerAdapter() {
1026 @Override
1027 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001028 if (finalFragment.mView != null) {
1029 finalFragment.mView.setVisibility(View.GONE);
1030 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001031 }
1032 });
Chet Haase811ed1062010-08-06 10:38:15 -07001033 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001034 } else {
1035 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001036 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001037 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001038 if (fragment.mAdded && fragment.mHasMenu) {
1039 mNeedMenuInvalidate = true;
1040 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001041 fragment.onHiddenChanged(true);
1042 }
1043 }
1044
1045 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1046 if (DEBUG) Log.v(TAG, "show: " + fragment);
1047 if (fragment.mHidden) {
1048 fragment.mHidden = false;
1049 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001050 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001051 transitionStyle);
1052 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001053 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -07001054 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001055 }
1056 fragment.mView.setVisibility(View.VISIBLE);
1057 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001058 if (fragment.mAdded && fragment.mHasMenu) {
1059 mNeedMenuInvalidate = true;
1060 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001061 fragment.onHiddenChanged(false);
1062 }
1063 }
1064
Dianne Hackborn47c41562011-04-15 19:00:20 -07001065 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1066 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1067 if (!fragment.mDetached) {
1068 fragment.mDetached = true;
1069 if (fragment.mAdded) {
1070 // We are not already in back stack, so need to remove the fragment.
1071 mAdded.remove(fragment);
1072 if (fragment.mHasMenu) {
1073 mNeedMenuInvalidate = true;
1074 }
1075 fragment.mAdded = false;
1076 fragment.mRemoving = true;
1077 moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
1078 }
1079 }
1080 }
1081
1082 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1083 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1084 if (fragment.mDetached) {
1085 fragment.mDetached = false;
1086 if (!fragment.mAdded) {
1087 mAdded.add(fragment);
1088 fragment.mAdded = true;
1089 fragment.mRemoving = false;
1090 if (fragment.mHasMenu) {
1091 mNeedMenuInvalidate = true;
1092 }
1093 moveToState(fragment, mCurState, transition, transitionStyle);
1094 }
1095 }
1096 }
1097
Dianne Hackbornf121be72010-05-06 14:10:32 -07001098 public Fragment findFragmentById(int id) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001099 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001100 // First look through added fragments.
1101 for (int i=mAdded.size()-1; i>=0; i--) {
1102 Fragment f = mAdded.get(i);
1103 if (f != null && f.mFragmentId == id) {
1104 return f;
1105 }
1106 }
1107 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001108 for (int i=mActive.size()-1; i>=0; i--) {
1109 Fragment f = mActive.get(i);
1110 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001111 return f;
1112 }
1113 }
1114 }
1115 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001116 }
1117
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001118 public Fragment findFragmentByTag(String tag) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001119 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001120 // First look through added fragments.
1121 for (int i=mAdded.size()-1; i>=0; i--) {
1122 Fragment f = mAdded.get(i);
1123 if (f != null && tag.equals(f.mTag)) {
1124 return f;
1125 }
1126 }
1127 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001128 for (int i=mActive.size()-1; i>=0; i--) {
1129 Fragment f = mActive.get(i);
1130 if (f != null && tag.equals(f.mTag)) {
1131 return f;
1132 }
1133 }
1134 }
1135 return null;
1136 }
1137
1138 public Fragment findFragmentByWho(String who) {
1139 if (mActive != null && who != null) {
1140 for (int i=mActive.size()-1; i>=0; i--) {
1141 Fragment f = mActive.get(i);
1142 if (f != null && who.equals(f.mWho)) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001143 return f;
1144 }
1145 }
1146 }
1147 return null;
1148 }
1149
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001150 private void checkStateLoss() {
1151 if (mStateSaved) {
1152 throw new IllegalStateException(
1153 "Can not perform this action after onSaveInstanceState");
1154 }
1155 if (mNoTransactionsBecause != null) {
1156 throw new IllegalStateException(
1157 "Can not perform this action inside of " + mNoTransactionsBecause);
1158 }
1159 }
1160
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001161 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001162 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001163 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001164 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001165 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001166 if (mActivity == null) {
1167 throw new IllegalStateException("Activity has been destroyed");
1168 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001169 if (mPendingActions == null) {
1170 mPendingActions = new ArrayList<Runnable>();
1171 }
1172 mPendingActions.add(action);
1173 if (mPendingActions.size() == 1) {
1174 mActivity.mHandler.removeCallbacks(mExecCommit);
1175 mActivity.mHandler.post(mExecCommit);
1176 }
1177 }
1178 }
1179
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001180 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001181 synchronized (this) {
1182 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1183 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001184 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001185 }
1186 int index = mBackStackIndices.size();
1187 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1188 mBackStackIndices.add(bse);
1189 return index;
1190
1191 } else {
1192 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1193 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1194 mBackStackIndices.set(index, bse);
1195 return index;
1196 }
1197 }
1198 }
1199
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001200 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001201 synchronized (this) {
1202 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001203 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001204 }
1205 int N = mBackStackIndices.size();
1206 if (index < N) {
1207 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1208 mBackStackIndices.set(index, bse);
1209 } else {
1210 while (N < index) {
1211 mBackStackIndices.add(null);
1212 if (mAvailBackStackIndices == null) {
1213 mAvailBackStackIndices = new ArrayList<Integer>();
1214 }
1215 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1216 mAvailBackStackIndices.add(N);
1217 N++;
1218 }
1219 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1220 mBackStackIndices.add(bse);
1221 }
1222 }
1223 }
1224
1225 public void freeBackStackIndex(int index) {
1226 synchronized (this) {
1227 mBackStackIndices.set(index, null);
1228 if (mAvailBackStackIndices == null) {
1229 mAvailBackStackIndices = new ArrayList<Integer>();
1230 }
1231 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1232 mAvailBackStackIndices.add(index);
1233 }
1234 }
1235
Dianne Hackborn445646c2010-06-25 15:52:59 -07001236 /**
1237 * Only call from main thread!
1238 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001239 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001240 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001241 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001242 }
1243
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001244 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001245 throw new IllegalStateException("Must be called from main thread of process");
1246 }
1247
1248 boolean didSomething = false;
1249
Dianne Hackborn445646c2010-06-25 15:52:59 -07001250 while (true) {
1251 int numActions;
1252
1253 synchronized (this) {
1254 if (mPendingActions == null || mPendingActions.size() == 0) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001255 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001256 }
1257
1258 numActions = mPendingActions.size();
1259 if (mTmpActions == null || mTmpActions.length < numActions) {
1260 mTmpActions = new Runnable[numActions];
1261 }
1262 mPendingActions.toArray(mTmpActions);
1263 mPendingActions.clear();
1264 mActivity.mHandler.removeCallbacks(mExecCommit);
1265 }
1266
1267 mExecutingActions = true;
1268 for (int i=0; i<numActions; i++) {
1269 mTmpActions[i].run();
1270 }
1271 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001272 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001273 }
1274 }
1275
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001276 void reportBackStackChanged() {
1277 if (mBackStackChangeListeners != null) {
1278 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1279 mBackStackChangeListeners.get(i).onBackStackChanged();
1280 }
1281 }
1282 }
1283
1284 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001285 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001286 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001287 }
1288 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001289 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001290 }
1291
Dianne Hackborndd913a52010-07-22 12:17:04 -07001292 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001293 if (mBackStack == null) {
1294 return false;
1295 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001296 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001297 int last = mBackStack.size()-1;
1298 if (last < 0) {
1299 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001300 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001301 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001302 bss.popFromBackStack(true);
1303 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001304 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001305 int index = -1;
1306 if (name != null || id >= 0) {
1307 // If a name or ID is specified, look for that place in
1308 // the stack.
1309 index = mBackStack.size()-1;
1310 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001311 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001312 if (name != null && name.equals(bss.getName())) {
1313 break;
1314 }
1315 if (id >= 0 && id == bss.mIndex) {
1316 break;
1317 }
1318 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001319 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001320 if (index < 0) {
1321 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001322 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001323 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001324 index--;
1325 // Consume all following entries that match.
1326 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001327 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001328 if ((name != null && name.equals(bss.getName()))
1329 || (id >= 0 && id == bss.mIndex)) {
1330 index--;
1331 continue;
1332 }
1333 break;
1334 }
1335 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001336 }
1337 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001338 return false;
1339 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001340 final ArrayList<BackStackRecord> states
1341 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001342 for (int i=mBackStack.size()-1; i>index; i--) {
1343 states.add(mBackStack.remove(i));
1344 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001345 final int LAST = states.size()-1;
1346 for (int i=0; i<=LAST; i++) {
1347 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1348 states.get(i).popFromBackStack(i == LAST);
1349 }
1350 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001351 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001352 return true;
1353 }
1354
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001355 ArrayList<Fragment> retainNonConfig() {
1356 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001357 if (mActive != null) {
1358 for (int i=0; i<mActive.size(); i++) {
1359 Fragment f = mActive.get(i);
1360 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001361 if (fragments == null) {
1362 fragments = new ArrayList<Fragment>();
1363 }
1364 fragments.add(f);
1365 f.mRetaining = true;
1366 }
1367 }
1368 }
1369 return fragments;
1370 }
1371
1372 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001373 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001374 return;
1375 }
1376 if (mStateArray == null) {
1377 mStateArray = new SparseArray<Parcelable>();
1378 }
1379 f.mView.saveHierarchyState(mStateArray);
1380 if (mStateArray.size() > 0) {
1381 f.mSavedViewState = mStateArray;
1382 mStateArray = null;
1383 }
1384 }
1385
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001386 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001387 // Make sure all pending operations have now been executed to get
1388 // our state update-to-date.
1389 execPendingActions();
1390
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001391 mStateSaved = true;
1392
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001393 if (mActive == null || mActive.size() <= 0) {
1394 return null;
1395 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001396
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001397 // First collect all active fragments.
1398 int N = mActive.size();
1399 FragmentState[] active = new FragmentState[N];
1400 boolean haveFragments = false;
1401 for (int i=0; i<N; i++) {
1402 Fragment f = mActive.get(i);
1403 if (f != null) {
1404 haveFragments = true;
1405
1406 FragmentState fs = new FragmentState(f);
1407 active[i] = fs;
1408
Dianne Hackborn625ac272010-09-17 18:29:22 -07001409 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
1410 if (mStateBundle == null) {
1411 mStateBundle = new Bundle();
1412 }
1413 f.onSaveInstanceState(mStateBundle);
1414 if (!mStateBundle.isEmpty()) {
1415 fs.mSavedFragmentState = mStateBundle;
1416 mStateBundle = null;
1417 }
1418
1419 if (f.mView != null) {
1420 saveFragmentViewState(f);
1421 if (f.mSavedViewState != null) {
1422 if (fs.mSavedFragmentState == null) {
1423 fs.mSavedFragmentState = new Bundle();
1424 }
1425 fs.mSavedFragmentState.putSparseParcelableArray(
1426 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
1427 }
1428 }
1429
1430 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001431 if (f.mTarget.mIndex < 0) {
1432 String msg = "Failure saving state: " + f
1433 + " has target not in fragment manager: " + f.mTarget;
1434 Slog.e(TAG, msg);
1435 dump(" ", null, new PrintWriter(new LogWriter(
1436 Log.ERROR, TAG, Log.LOG_ID_SYSTEM)), new String[] { });
1437 throw new IllegalStateException(msg);
1438 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001439 if (fs.mSavedFragmentState == null) {
1440 fs.mSavedFragmentState = new Bundle();
1441 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001442 putFragment(fs.mSavedFragmentState,
1443 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1444 if (f.mTargetRequestCode != 0) {
1445 fs.mSavedFragmentState.putInt(
1446 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1447 f.mTargetRequestCode);
1448 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001449 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001450
Dianne Hackborn625ac272010-09-17 18:29:22 -07001451 } else {
1452 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001453 }
1454
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001455 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1456 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001457 }
1458 }
1459
1460 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001461 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001462 return null;
1463 }
1464
1465 int[] added = null;
1466 BackStackState[] backStack = null;
1467
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001468 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001469 if (mAdded != null) {
1470 N = mAdded.size();
1471 if (N > 0) {
1472 added = new int[N];
1473 for (int i=0; i<N; i++) {
1474 added[i] = mAdded.get(i).mIndex;
1475 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1476 + ": " + mAdded.get(i));
1477 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001478 }
1479 }
1480
1481 // Now save back stack.
1482 if (mBackStack != null) {
1483 N = mBackStack.size();
1484 if (N > 0) {
1485 backStack = new BackStackState[N];
1486 for (int i=0; i<N; i++) {
1487 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001488 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1489 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001490 }
1491 }
1492 }
1493
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001494 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001495 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001496 fms.mAdded = added;
1497 fms.mBackStack = backStack;
1498 return fms;
1499 }
1500
1501 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1502 // If there is no saved state at all, then there can not be
1503 // any nonConfig fragments either, so that is that.
1504 if (state == null) return;
1505 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001506 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001507
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001508 // First re-attach any non-config instances we are retaining back
1509 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001510 if (nonConfig != null) {
1511 for (int i=0; i<nonConfig.size(); i++) {
1512 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001513 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001514 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001515 fs.mInstance = f;
1516 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001517 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001518 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001519 f.mAdded = false;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001520 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001521 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001522 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001523 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001524 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001525 }
1526 }
1527
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001528 // Build the full list of active fragments, instantiating them from
1529 // their saved state.
1530 mActive = new ArrayList<Fragment>(fms.mActive.length);
1531 if (mAvailIndices != null) {
1532 mAvailIndices.clear();
1533 }
1534 for (int i=0; i<fms.mActive.length; i++) {
1535 FragmentState fs = fms.mActive[i];
1536 if (fs != null) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001537 Fragment f = fs.instantiate(mActivity);
1538 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
1539 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001540 // Now that the fragment is instantiated (or came from being
1541 // retained above), clear mInstance in case we end up re-restoring
1542 // from this FragmentState again.
1543 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001544 } else {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001545 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001546 mActive.add(null);
1547 if (mAvailIndices == null) {
1548 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001549 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001550 if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001551 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001552 }
1553 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001554
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001555 // Update the target of all retained fragments.
1556 if (nonConfig != null) {
1557 for (int i=0; i<nonConfig.size(); i++) {
1558 Fragment f = nonConfig.get(i);
1559 if (f.mTarget != null) {
1560 if (f.mTarget.mIndex < mActive.size()) {
1561 f.mTarget = mActive.get(f.mTarget.mIndex);
1562 } else {
1563 Log.w(TAG, "Re-attaching retained fragment " + f
1564 + " target no longer exists: " + f.mTarget);
1565 f.mTarget = null;
1566 }
1567 }
1568 }
1569 }
1570
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001571 // Build the list of currently added fragments.
1572 if (fms.mAdded != null) {
1573 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1574 for (int i=0; i<fms.mAdded.length; i++) {
1575 Fragment f = mActive.get(fms.mAdded[i]);
1576 if (f == null) {
1577 throw new IllegalStateException(
1578 "No instantiated fragment for index #" + fms.mAdded[i]);
1579 }
1580 f.mAdded = true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001581 f.mImmediateActivity = mActivity;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001582 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001583 mAdded.add(f);
1584 }
1585 } else {
1586 mAdded = null;
1587 }
1588
1589 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001590 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001591 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001592 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001593 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001594 if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
1595 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001596 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001597 if (bse.mIndex >= 0) {
1598 setBackStackIndex(bse.mIndex, bse);
1599 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001600 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001601 } else {
1602 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001603 }
1604 }
1605
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001606 public void attachActivity(Activity activity) {
1607 if (mActivity != null) throw new IllegalStateException();
1608 mActivity = activity;
1609 }
1610
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001611 public void noteStateNotSaved() {
1612 mStateSaved = false;
1613 }
1614
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001615 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001616 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001617 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001618 }
1619
Dianne Hackbornc8017682010-07-06 13:34:38 -07001620 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001621 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001622 moveToState(Fragment.ACTIVITY_CREATED, false);
1623 }
1624
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001625 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001626 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001627 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001628 }
1629
1630 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001631 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001632 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001633 }
1634
1635 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001636 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001637 }
1638
1639 public void dispatchStop() {
Dianne Hackbornd071ec22011-04-18 14:08:33 -07001640 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001641 }
1642
1643 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001644 mDestroyed = true;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001645 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001646 mActivity = null;
1647 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001648
Dianne Hackborn9d071802010-12-08 14:49:15 -08001649 public void dispatchConfigurationChanged(Configuration newConfig) {
1650 if (mActive != null) {
1651 for (int i=0; i<mAdded.size(); i++) {
1652 Fragment f = mAdded.get(i);
1653 if (f != null) {
1654 f.onConfigurationChanged(newConfig);
1655 }
1656 }
1657 }
1658 }
1659
1660 public void dispatchLowMemory() {
1661 if (mActive != null) {
1662 for (int i=0; i<mAdded.size(); i++) {
1663 Fragment f = mAdded.get(i);
1664 if (f != null) {
1665 f.onLowMemory();
1666 }
1667 }
1668 }
1669 }
1670
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001671 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1672 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001673 ArrayList<Fragment> newMenus = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001674 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 show = true;
1679 f.onCreateOptionsMenu(menu, inflater);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001680 if (newMenus == null) {
1681 newMenus = new ArrayList<Fragment>();
1682 }
1683 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001684 }
1685 }
1686 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001687
1688 if (mCreatedMenus != null) {
1689 for (int i=0; i<mCreatedMenus.size(); i++) {
1690 Fragment f = mCreatedMenus.get(i);
1691 if (newMenus == null || !newMenus.contains(f)) {
1692 f.onDestroyOptionsMenu();
1693 }
1694 }
1695 }
1696
1697 mCreatedMenus = newMenus;
1698
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001699 return show;
1700 }
1701
1702 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1703 boolean show = false;
1704 if (mActive != null) {
1705 for (int i=0; i<mAdded.size(); i++) {
1706 Fragment f = mAdded.get(i);
1707 if (f != null && !f.mHidden && f.mHasMenu) {
1708 show = true;
1709 f.onPrepareOptionsMenu(menu);
1710 }
1711 }
1712 }
1713 return show;
1714 }
1715
1716 public boolean dispatchOptionsItemSelected(MenuItem item) {
1717 if (mActive != null) {
1718 for (int i=0; i<mAdded.size(); i++) {
1719 Fragment f = mAdded.get(i);
1720 if (f != null && !f.mHidden && f.mHasMenu) {
1721 if (f.onOptionsItemSelected(item)) {
1722 return true;
1723 }
1724 }
1725 }
1726 }
1727 return false;
1728 }
1729
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001730 public boolean dispatchContextItemSelected(MenuItem item) {
1731 if (mActive != null) {
1732 for (int i=0; i<mAdded.size(); i++) {
1733 Fragment f = mAdded.get(i);
1734 if (f != null && !f.mHidden) {
1735 if (f.onContextItemSelected(item)) {
1736 return true;
1737 }
1738 }
1739 }
1740 }
1741 return false;
1742 }
1743
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001744 public void dispatchOptionsMenuClosed(Menu menu) {
1745 if (mActive != null) {
1746 for (int i=0; i<mAdded.size(); i++) {
1747 Fragment f = mAdded.get(i);
1748 if (f != null && !f.mHidden && f.mHasMenu) {
1749 f.onOptionsMenuClosed(menu);
1750 }
1751 }
1752 }
1753 }
1754
Dianne Hackbornf121be72010-05-06 14:10:32 -07001755 public static int reverseTransit(int transit) {
1756 int rev = 0;
1757 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001758 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
1759 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001760 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001761 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
1762 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001763 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001764 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
1765 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001766 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001767 }
1768 return rev;
1769
1770 }
1771
1772 public static int transitToStyleIndex(int transit, boolean enter) {
1773 int animAttr = -1;
1774 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001775 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001776 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001777 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
1778 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001779 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001780 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001781 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001782 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
1783 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001784 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001785 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07001786 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08001787 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
1788 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001789 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001790 }
1791 return animAttr;
1792 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001793}