blob: fe2ebedca872b69013bf72ee8dc455475cea0474 [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 Hackbornb4bc78b2010-05-12 18:59:50 -070031import android.util.SparseArray;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -070032import android.view.Menu;
33import android.view.MenuInflater;
34import android.view.MenuItem;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070035import android.view.View;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070036import android.view.ViewGroup;
37
Dianne Hackborn625ac272010-09-17 18:29:22 -070038import java.io.FileDescriptor;
39import java.io.PrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070040import java.util.ArrayList;
41
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070042/**
43 * Interface for interacting with {@link Fragment} objects inside of an
44 * {@link Activity}
45 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -070046public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070047 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070048 * Representation of an entry on the fragment back stack, as created
49 * with {@link FragmentTransaction#addToBackStack(String)
50 * FragmentTransaction.addToBackStack()}. Entries can later be
51 * retrieved with {@link FragmentManager#getBackStackEntry(int)
52 * FragmentManager.getBackStackEntry()}.
53 *
54 * <p>Note that you should never hold on to a BackStackEntry object;
55 * the identifier as returned by {@link #getId} is the only thing that
56 * will be persisted across activity instances.
57 */
58 public interface BackStackEntry {
59 /**
60 * Return the unique identifier for the entry. This is the only
61 * representation of the entry that will persist across activity
62 * instances.
63 */
64 public int getId();
65
66 /**
67 * Return the full bread crumb title for the entry, or null if it
68 * does not have one.
69 */
70 public CharSequence getBreadCrumbTitle();
71
72 /**
73 * Return the short bread crumb title for the entry, or null if it
74 * does not have one.
75 */
76 public CharSequence getBreadCrumbShortTitle();
77 }
78
79 /**
80 * Interface to watch for changes to the back stack.
81 */
82 public interface OnBackStackChangedListener {
83 /**
84 * Called whenever the contents of the back stack change.
85 */
86 public void onBackStackChanged();
87 }
88
89 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070090 * Start a series of edit operations on the Fragments associated with
91 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -070092 *
93 * <p>Note: A fragment transaction can only be created/committed prior
94 * to an activity saving its state. If you try to commit a transaction
95 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
96 * (and prior to a following {@link Activity#onStart Activity.onStart}
97 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
98 * This is because the framework takes care of saving your current fragments
99 * in the state, and if changes are made after the state is saved then they
100 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700101 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700102 public abstract FragmentTransaction openTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700103
104 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800105 * After a {@link FragmentTransaction} is committed with
106 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
107 * is scheduled to be executed asynchronously on the process's main thread.
108 * If you want to immediately executing any such pending operations, you
109 * can call this function (only from the main thread) to do so. Note that
110 * all callbacks and other related behavior will be done from within this
111 * call, so be careful about where this is called from.
112 *
113 * @return Returns true if there were any pending transactions to be
114 * executed.
115 */
116 public abstract boolean executePendingTransactions();
117
118 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700119 * Finds a fragment that was identified by the given id either when inflated
120 * from XML or as the container ID when added in a transaction. This first
121 * searches through fragments that are currently added to the manager's
122 * activity; if no such fragment is found, then all fragments currently
123 * on the back stack associated with this ID are searched.
124 * @return The fragment if found or null otherwise.
125 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700126 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700127
128 /**
129 * Finds a fragment that was identified by the given tag either when inflated
130 * from XML or as supplied when added in a transaction. This first
131 * searches through fragments that are currently added to the manager's
132 * activity; if no such fragment is found, then all fragments currently
133 * on the back stack are searched.
134 * @return The fragment if found or null otherwise.
135 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700136 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700137
138 /**
139 * Flag for {@link #popBackStack(String, int)}
140 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
141 * a back stack entry has been supplied, then all matching entries will
142 * be consumed until one that doesn't match is found or the bottom of
143 * the stack is reached. Otherwise, all entries up to but not including that entry
144 * will be removed.
145 */
146 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
147
148 /**
149 * Pop the top state off the back stack. Returns true if there was one
150 * to pop, else false.
151 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800152 public abstract void popBackStack();
153
154 /**
155 * Like {@link #popBackStack()}, but performs the operation immediately
156 * inside of the call. This is like calling {@link #executePendingTransactions()}
157 * afterwards.
158 * @return Returns true if there was something popped, else false.
159 */
160 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700161
162 /**
163 * Pop the last fragment transition from the manager's fragment
164 * back stack. If there is nothing to pop, false is returned.
165 * @param name If non-null, this is the name of a previous back state
166 * to look for; if found, all states up to that state will be popped. The
167 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
168 * the named state itself is popped. If null, only the top state is popped.
169 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
170 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800171 public abstract void popBackStack(String name, int flags);
172
173 /**
174 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
175 * inside of the call. This is like calling {@link #executePendingTransactions()}
176 * afterwards.
177 * @return Returns true if there was something popped, else false.
178 */
179 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700180
181 /**
182 * Pop all back stack states up to the one with the given identifier.
183 * @param id Identifier of the stated to be popped. If no identifier exists,
184 * false is returned.
185 * The identifier is the number returned by
186 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
187 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
188 * the named state itself is popped.
189 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
190 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800191 public abstract void popBackStack(int id, int flags);
192
193 /**
194 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
195 * inside of the call. This is like calling {@link #executePendingTransactions()}
196 * afterwards.
197 * @return Returns true if there was something popped, else false.
198 */
199 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700200
201 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700202 * Return the number of entries currently in the back stack.
203 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700204 public abstract int countBackStackEntries();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700205
206 /**
207 * Return the BackStackEntry at index <var>index</var> in the back stack;
208 * entries start index 0 being the bottom of the stack.
209 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700210 public abstract BackStackEntry getBackStackEntry(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700211
212 /**
213 * Add a new listener for changes to the fragment back stack.
214 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700215 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700216
217 /**
218 * Remove a listener that was previously added with
219 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
220 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700221 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700222
223 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700224 * Put a reference to a fragment in a Bundle. This Bundle can be
225 * persisted as saved state, and when later restoring
226 * {@link #getFragment(Bundle, String)} will return the current
227 * instance of the same fragment.
228 *
229 * @param bundle The bundle in which to put the fragment reference.
230 * @param key The name of the entry in the bundle.
231 * @param fragment The Fragment whose reference is to be stored.
232 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700233 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700234
235 /**
236 * Retrieve the current Fragment instance for a reference previously
237 * placed with {@link #putFragment(Bundle, String, Fragment)}.
238 *
239 * @param bundle The bundle from which to retrieve the fragment reference.
240 * @param key The name of the entry in the bundle.
241 * @return Returns the current Fragment instance that is associated with
242 * the given reference.
243 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700244 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700245
246 /**
247 * Print the FragmentManager's state into the given stream.
248 *
249 * @param prefix Text to print at the front of each line.
250 * @param fd The raw file descriptor that the dump is being sent to.
251 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800252 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700253 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700254 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800255
256 /**
257 * Control whether the framework's internal fragment manager debugging
258 * logs are turned on. If enabled, you will see output in logcat as
259 * the framework performs fragment operations.
260 */
261 public static void enableDebugLogging(boolean enabled) {
262 FragmentManagerImpl.DEBUG = enabled;
263 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700264}
265
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700266final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700267 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700268 int[] mAdded;
269 BackStackState[] mBackStack;
270
271 public FragmentManagerState() {
272 }
273
274 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700275 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700276 mAdded = in.createIntArray();
277 mBackStack = in.createTypedArray(BackStackState.CREATOR);
278 }
279
280 public int describeContents() {
281 return 0;
282 }
283
284 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700285 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700286 dest.writeIntArray(mAdded);
287 dest.writeTypedArray(mBackStack, flags);
288 }
289
290 public static final Parcelable.Creator<FragmentManagerState> CREATOR
291 = new Parcelable.Creator<FragmentManagerState>() {
292 public FragmentManagerState createFromParcel(Parcel in) {
293 return new FragmentManagerState(in);
294 }
295
296 public FragmentManagerState[] newArray(int size) {
297 return new FragmentManagerState[size];
298 }
299 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700300}
301
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700302/**
303 * Container for fragments associated with an activity.
304 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700305final class FragmentManagerImpl extends FragmentManager {
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800306 static boolean DEBUG = true;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700307 static final String TAG = "FragmentManager";
308
Dianne Hackborndef15372010-08-15 12:43:52 -0700309 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
310 static final String TARGET_STATE_TAG = "android:target_state";
311 static final String VIEW_STATE_TAG = "android:view_state";
312
Dianne Hackborn445646c2010-06-25 15:52:59 -0700313 ArrayList<Runnable> mPendingActions;
314 Runnable[] mTmpActions;
315 boolean mExecutingActions;
316
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700317 ArrayList<Fragment> mActive;
318 ArrayList<Fragment> mAdded;
319 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700320 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700321 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700322
Dianne Hackborndd913a52010-07-22 12:17:04 -0700323 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700324 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700325 ArrayList<Integer> mAvailBackStackIndices;
326
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700327 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
328
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700329 int mCurState = Fragment.INITIALIZING;
330 Activity mActivity;
331
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700332 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700333 boolean mStateSaved;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700334 String mNoTransactionsBecause;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700335
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700336 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700337 Bundle mStateBundle = null;
338 SparseArray<Parcelable> mStateArray = null;
339
Dianne Hackborn445646c2010-06-25 15:52:59 -0700340 Runnable mExecCommit = new Runnable() {
341 @Override
342 public void run() {
343 execPendingActions();
344 }
345 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700346
347 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700348 public FragmentTransaction openTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700349 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700350 }
351
Dianne Hackborn625ac272010-09-17 18:29:22 -0700352 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800353 public boolean executePendingTransactions() {
354 return execPendingActions();
355 }
356
357 @Override
358 public void popBackStack() {
359 enqueueAction(new Runnable() {
360 @Override public void run() {
361 popBackStackState(mActivity.mHandler, null, -1, 0);
362 }
363 }, false);
364 }
365
366 @Override
367 public boolean popBackStackImmediate() {
368 checkStateLoss();
369 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700370 return popBackStackState(mActivity.mHandler, null, -1, 0);
371 }
372
Dianne Hackborn625ac272010-09-17 18:29:22 -0700373 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800374 public void popBackStack(final String name, final int flags) {
375 enqueueAction(new Runnable() {
376 @Override public void run() {
377 popBackStackState(mActivity.mHandler, name, -1, flags);
378 }
379 }, false);
380 }
381
382 @Override
383 public boolean popBackStackImmediate(String name, int flags) {
384 checkStateLoss();
385 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700386 return popBackStackState(mActivity.mHandler, name, -1, flags);
387 }
388
Dianne Hackborn625ac272010-09-17 18:29:22 -0700389 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800390 public void popBackStack(final int id, final int flags) {
391 if (id < 0) {
392 throw new IllegalArgumentException("Bad id: " + id);
393 }
394 enqueueAction(new Runnable() {
395 @Override public void run() {
396 popBackStackState(mActivity.mHandler, null, id, flags);
397 }
398 }, false);
399 }
400
401 @Override
402 public boolean popBackStackImmediate(int id, int flags) {
403 checkStateLoss();
404 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700405 if (id < 0) {
406 throw new IllegalArgumentException("Bad id: " + id);
407 }
408 return popBackStackState(mActivity.mHandler, null, id, flags);
409 }
410
Dianne Hackborn625ac272010-09-17 18:29:22 -0700411 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700412 public int countBackStackEntries() {
413 return mBackStack != null ? mBackStack.size() : 0;
414 }
415
Dianne Hackborn625ac272010-09-17 18:29:22 -0700416 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700417 public BackStackEntry getBackStackEntry(int index) {
418 return mBackStack.get(index);
419 }
420
Dianne Hackborn625ac272010-09-17 18:29:22 -0700421 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700422 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
423 if (mBackStackChangeListeners == null) {
424 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
425 }
426 mBackStackChangeListeners.add(listener);
427 }
428
Dianne Hackborn625ac272010-09-17 18:29:22 -0700429 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700430 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
431 if (mBackStackChangeListeners != null) {
432 mBackStackChangeListeners.remove(listener);
433 }
434 }
435
Dianne Hackborn625ac272010-09-17 18:29:22 -0700436 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700437 public void putFragment(Bundle bundle, String key, Fragment fragment) {
438 if (fragment.mIndex < 0) {
439 throw new IllegalStateException("Fragment " + fragment
440 + " is not currently in the FragmentManager");
441 }
442 bundle.putInt(key, fragment.mIndex);
443 }
444
Dianne Hackborn625ac272010-09-17 18:29:22 -0700445 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700446 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700447 int index = bundle.getInt(key, -1);
448 if (index == -1) {
449 return null;
450 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700451 if (index >= mActive.size()) {
452 throw new IllegalStateException("Fragement no longer exists for key "
453 + key + ": index " + index);
454 }
455 Fragment f = mActive.get(index);
456 if (f == null) {
457 throw new IllegalStateException("Fragement no longer exists for key "
458 + key + ": index " + index);
459 }
460 return f;
461 }
462
Dianne Hackborn625ac272010-09-17 18:29:22 -0700463 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800464 public String toString() {
465 StringBuilder sb = new StringBuilder(128);
466 sb.append("FragmentManager{");
467 sb.append(Integer.toHexString(System.identityHashCode(this)));
468 sb.append(" in ");
469 DebugUtils.buildShortClassTag(mActivity, sb);
470 sb.append("}}");
471 return sb.toString();
472 }
473
474 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700475 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
476 if (mActive == null || mActive.size() <= 0) {
477 return;
478 }
479
Dianne Hackborn30d71892010-12-11 10:37:55 -0800480 writer.print(prefix); writer.print("Active Fragments in ");
481 writer.print(Integer.toHexString(System.identityHashCode(this)));
482 writer.println(":");
Dianne Hackborn625ac272010-09-17 18:29:22 -0700483
484 String innerPrefix = prefix + " ";
485
486 int N = mActive.size();
487 for (int i=0; i<N; i++) {
488 Fragment f = mActive.get(i);
489 if (f != null) {
490 writer.print(prefix); writer.print(" #"); writer.print(i);
491 writer.print(": "); writer.println(f.toString());
492 f.dump(innerPrefix, fd, writer, args);
493 }
494 }
495
496 if (mAdded != null) {
497 N = mAdded.size();
498 if (N > 0) {
499 writer.print(prefix); writer.println("Added Fragments:");
500 for (int i=0; i<N; i++) {
501 Fragment f = mAdded.get(i);
502 writer.print(prefix); writer.print(" #"); writer.print(i);
503 writer.print(": "); writer.println(f.toString());
504 }
505 }
506 }
507
508 if (mBackStack != null) {
509 N = mBackStack.size();
510 if (N > 0) {
511 writer.print(prefix); writer.println("Back Stack:");
512 for (int i=0; i<N; i++) {
513 BackStackRecord bs = mBackStack.get(i);
514 writer.print(prefix); writer.print(" #"); writer.print(i);
515 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800516 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700517 }
518 }
519 }
520 }
521
Chet Haasea18a86b2010-09-07 13:20:00 -0700522 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700523 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700524 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700525 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700526 if (animObj != null) {
527 return animObj;
528 }
529
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700530 if (fragment.mNextAnim != 0) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700531 Animator anim = AnimatorInflater.loadAnimator(mActivity, fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700532 if (anim != null) {
533 return anim;
534 }
535 }
536
Dianne Hackbornf121be72010-05-06 14:10:32 -0700537 if (transit == 0) {
538 return null;
539 }
540
541 int styleIndex = transitToStyleIndex(transit, enter);
542 if (styleIndex < 0) {
543 return null;
544 }
545
546 if (transitionStyle == 0 && mActivity.getWindow() != null) {
547 transitionStyle = mActivity.getWindow().getAttributes().windowAnimations;
548 }
549 if (transitionStyle == 0) {
550 return null;
551 }
552
553 TypedArray attrs = mActivity.obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700554 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700555 int anim = attrs.getResourceId(styleIndex, 0);
556 attrs.recycle();
557
558 if (anim == 0) {
559 return null;
560 }
561
Chet Haasea18a86b2010-09-07 13:20:00 -0700562 return AnimatorInflater.loadAnimator(mActivity, anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700563 }
564
565 void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700566 // Fragments that are not currently added will sit in the onCreate() state.
567 if (!f.mAdded && newState > Fragment.CREATED) {
568 newState = Fragment.CREATED;
569 }
570
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700571 if (f.mState < newState) {
572 switch (f.mState) {
573 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700574 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700575 if (f.mSavedFragmentState != null) {
576 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
577 FragmentManagerImpl.VIEW_STATE_TAG);
578 f.mTarget = getFragment(f.mSavedFragmentState,
579 FragmentManagerImpl.TARGET_STATE_TAG);
580 if (f.mTarget != null) {
581 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
582 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
583 }
584 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700585 f.mActivity = mActivity;
Dianne Hackbornd2835932010-12-13 16:28:46 -0800586 f.mFragmentManager = mActivity.mFragments;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700587 f.mCalled = false;
588 f.onAttach(mActivity);
589 if (!f.mCalled) {
590 throw new SuperNotCalledException("Fragment " + f
591 + " did not call through to super.onAttach()");
592 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700593 mActivity.onAttachFragment(f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700594
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700595 if (!f.mRetaining) {
596 f.mCalled = false;
597 f.onCreate(f.mSavedFragmentState);
598 if (!f.mCalled) {
599 throw new SuperNotCalledException("Fragment " + f
600 + " did not call through to super.onCreate()");
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700601 }
602 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700603 f.mRetaining = false;
604 if (f.mFromLayout) {
605 // For fragments that are part of the content view
606 // layout, we need to instantiate the view immediately
607 // and the inflater will take care of adding it.
608 f.mView = f.onCreateView(mActivity.getLayoutInflater(),
609 null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700610 if (f.mView != null) {
611 f.mView.setSaveFromParentEnabled(false);
612 f.restoreViewState();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700613 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700614 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700615 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700616 case Fragment.CREATED:
617 if (newState > Fragment.CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700618 if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700619 if (!f.mFromLayout) {
620 ViewGroup container = null;
621 if (f.mContainerId != 0) {
622 container = (ViewGroup)mActivity.findViewById(f.mContainerId);
623 if (container == null) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700624 throw new IllegalArgumentException("No view found for id 0x"
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700625 + Integer.toHexString(f.mContainerId)
626 + " for fragment " + f);
627 }
628 }
629 f.mContainer = container;
630 f.mView = f.onCreateView(mActivity.getLayoutInflater(),
631 container, f.mSavedFragmentState);
632 if (f.mView != null) {
633 f.mView.setSaveFromParentEnabled(false);
634 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700635 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700636 transitionStyle);
637 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700638 anim.setTarget(f.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700639 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700640 }
641 container.addView(f.mView);
642 f.restoreViewState();
643 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700644 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700645 }
646 }
647
648 f.mCalled = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -0700649 f.onActivityCreated(f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700650 if (!f.mCalled) {
651 throw new SuperNotCalledException("Fragment " + f
652 + " did not call through to super.onReady()");
653 }
654 f.mSavedFragmentState = null;
655 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700656 case Fragment.ACTIVITY_CREATED:
657 if (newState > Fragment.ACTIVITY_CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700658 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700659 f.mCalled = false;
660 f.onStart();
661 if (!f.mCalled) {
662 throw new SuperNotCalledException("Fragment " + f
663 + " did not call through to super.onStart()");
664 }
665 }
666 case Fragment.STARTED:
667 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700668 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700669 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700670 f.mResumed = true;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700671 f.onResume();
672 if (!f.mCalled) {
673 throw new SuperNotCalledException("Fragment " + f
674 + " did not call through to super.onResume()");
675 }
676 }
677 }
678 } else if (f.mState > newState) {
679 switch (f.mState) {
680 case Fragment.RESUMED:
681 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700682 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700683 f.mCalled = false;
684 f.onPause();
685 if (!f.mCalled) {
686 throw new SuperNotCalledException("Fragment " + f
687 + " did not call through to super.onPause()");
688 }
Dianne Hackborn2707d602010-07-09 18:01:20 -0700689 f.mResumed = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700690 }
691 case Fragment.STARTED:
692 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700693 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700694 f.mCalled = false;
Dianne Hackborn2707d602010-07-09 18:01:20 -0700695 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700696 if (!f.mCalled) {
697 throw new SuperNotCalledException("Fragment " + f
698 + " did not call through to super.onStop()");
699 }
700 }
Dianne Hackbornc8017682010-07-06 13:34:38 -0700701 case Fragment.ACTIVITY_CREATED:
702 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700703 if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700704 if (f.mView != null) {
705 // Need to save the current view state if not
706 // done already.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700707 if (!mActivity.isFinishing() && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700708 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700709 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700710 }
711 f.mCalled = false;
712 f.onDestroyView();
713 if (!f.mCalled) {
714 throw new SuperNotCalledException("Fragment " + f
715 + " did not call through to super.onDestroyedView()");
716 }
717 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700718 Animator anim = null;
Dianne Hackborndef15372010-08-15 12:43:52 -0700719 if (mCurState > Fragment.INITIALIZING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700720 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -0700721 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -0700722 }
723 if (anim != null) {
724 final ViewGroup container = f.mContainer;
725 final View view = f.mView;
726 container.startViewTransition(view);
727 anim.addListener(new AnimatorListenerAdapter() {
728 @Override
729 public void onAnimationEnd(Animator anim) {
730 container.endViewTransition(view);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700731 }
Chet Haaseb20db3e2010-09-10 13:07:30 -0700732 });
733 anim.setTarget(f.mView);
734 anim.start();
735
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700736 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700737 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700738 }
739 f.mContainer = null;
740 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700741 }
742 case Fragment.CREATED:
743 if (newState < Fragment.CREATED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700744 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700745 if (!f.mRetaining) {
746 f.mCalled = false;
747 f.onDestroy();
748 if (!f.mCalled) {
749 throw new SuperNotCalledException("Fragment " + f
750 + " did not call through to super.onDestroy()");
751 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700752 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700753
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700754 f.mCalled = false;
755 f.onDetach();
756 if (!f.mCalled) {
757 throw new SuperNotCalledException("Fragment " + f
758 + " did not call through to super.onDetach()");
759 }
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700760 f.mImmediateActivity = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700761 f.mActivity = null;
Dianne Hackbornd2835932010-12-13 16:28:46 -0800762 f.mFragmentManager = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700763 }
764 }
765 }
766
767 f.mState = newState;
768 }
769
Dianne Hackborn625ac272010-09-17 18:29:22 -0700770 void moveToState(Fragment f) {
771 moveToState(f, mCurState, 0, 0);
772 }
773
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700774 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -0700775 moveToState(newState, 0, 0, always);
776 }
777
778 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700779 if (mActivity == null && newState != Fragment.INITIALIZING) {
780 throw new IllegalStateException("No activity");
781 }
782
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700783 if (!always && mCurState == newState) {
784 return;
785 }
786
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700787 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700788 if (mActive != null) {
789 for (int i=0; i<mActive.size(); i++) {
790 Fragment f = mActive.get(i);
791 if (f != null) {
792 moveToState(f, newState, transit, transitStyle);
793 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700794 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -0700795
796 if (mNeedMenuInvalidate && mActivity != null) {
797 mActivity.invalidateOptionsMenu();
798 mNeedMenuInvalidate = false;
799 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700800 }
801 }
802
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700803 void makeActive(Fragment f) {
804 if (f.mIndex >= 0) {
805 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700806 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700807
808 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
809 if (mActive == null) {
810 mActive = new ArrayList<Fragment>();
811 }
812 f.setIndex(mActive.size());
813 mActive.add(f);
814
815 } else {
816 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
817 mActive.set(f.mIndex, f);
818 }
819 }
820
821 void makeInactive(Fragment f) {
822 if (f.mIndex < 0) {
823 return;
824 }
825
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700826 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700827 mActive.set(f.mIndex, null);
828 if (mAvailIndices == null) {
829 mAvailIndices = new ArrayList<Integer>();
830 }
831 mAvailIndices.add(f.mIndex);
Dianne Hackborn9e14e9f32010-07-14 11:07:38 -0700832 mActivity.invalidateFragmentIndex(f.mIndex);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700833 f.clearIndex();
834 }
835
836 public void addFragment(Fragment fragment, boolean moveToStateNow) {
837 if (mAdded == null) {
838 mAdded = new ArrayList<Fragment>();
839 }
840 mAdded.add(fragment);
841 makeActive(fragment);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700842 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700843 fragment.mAdded = true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700844 if (fragment.mHasMenu) {
845 mNeedMenuInvalidate = true;
846 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700847 if (moveToStateNow) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700848 moveToState(fragment);
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700849 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700850 }
851
Dianne Hackbornf121be72010-05-06 14:10:32 -0700852 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700853 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700854 mAdded.remove(fragment);
855 final boolean inactive = fragment.mBackStackNesting <= 0;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700856 if (fragment.mHasMenu) {
857 mNeedMenuInvalidate = true;
858 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700859 fragment.mAdded = false;
860 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
861 transition, transitionStyle);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -0700862 if (inactive) {
863 makeInactive(fragment);
864 }
Dianne Hackbornf121be72010-05-06 14:10:32 -0700865 }
866
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700867 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
868 if (DEBUG) Log.v(TAG, "hide: " + fragment);
869 if (!fragment.mHidden) {
870 fragment.mHidden = true;
871 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700872 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700873 transitionStyle);
874 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700875 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700876 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700877 }
878 fragment.mView.setVisibility(View.GONE);
879 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700880 if (fragment.mAdded && fragment.mHasMenu) {
881 mNeedMenuInvalidate = true;
882 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700883 fragment.onHiddenChanged(true);
884 }
885 }
886
887 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
888 if (DEBUG) Log.v(TAG, "show: " + fragment);
889 if (fragment.mHidden) {
890 fragment.mHidden = false;
891 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700892 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700893 transitionStyle);
894 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700895 anim.setTarget(fragment.mView);
Chet Haase811ed1062010-08-06 10:38:15 -0700896 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700897 }
898 fragment.mView.setVisibility(View.VISIBLE);
899 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700900 if (fragment.mAdded && fragment.mHasMenu) {
901 mNeedMenuInvalidate = true;
902 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700903 fragment.onHiddenChanged(false);
904 }
905 }
906
Dianne Hackbornf121be72010-05-06 14:10:32 -0700907 public Fragment findFragmentById(int id) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700908 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700909 // First look through added fragments.
910 for (int i=mAdded.size()-1; i>=0; i--) {
911 Fragment f = mAdded.get(i);
912 if (f != null && f.mFragmentId == id) {
913 return f;
914 }
915 }
916 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700917 for (int i=mActive.size()-1; i>=0; i--) {
918 Fragment f = mActive.get(i);
919 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -0700920 return f;
921 }
922 }
923 }
924 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700925 }
926
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700927 public Fragment findFragmentByTag(String tag) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700928 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700929 // First look through added fragments.
930 for (int i=mAdded.size()-1; i>=0; i--) {
931 Fragment f = mAdded.get(i);
932 if (f != null && tag.equals(f.mTag)) {
933 return f;
934 }
935 }
936 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700937 for (int i=mActive.size()-1; i>=0; i--) {
938 Fragment f = mActive.get(i);
939 if (f != null && tag.equals(f.mTag)) {
940 return f;
941 }
942 }
943 }
944 return null;
945 }
946
947 public Fragment findFragmentByWho(String who) {
948 if (mActive != null && who != null) {
949 for (int i=mActive.size()-1; i>=0; i--) {
950 Fragment f = mActive.get(i);
951 if (f != null && who.equals(f.mWho)) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700952 return f;
953 }
954 }
955 }
956 return null;
957 }
958
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800959 private void checkStateLoss() {
960 if (mStateSaved) {
961 throw new IllegalStateException(
962 "Can not perform this action after onSaveInstanceState");
963 }
964 if (mNoTransactionsBecause != null) {
965 throw new IllegalStateException(
966 "Can not perform this action inside of " + mNoTransactionsBecause);
967 }
968 }
969
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700970 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -0800971 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800972 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700973 }
Dianne Hackborn445646c2010-06-25 15:52:59 -0700974 synchronized (this) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -0800975 if (mActivity == null) {
976 throw new IllegalStateException("Activity has been destroyed");
977 }
Dianne Hackborn445646c2010-06-25 15:52:59 -0700978 if (mPendingActions == null) {
979 mPendingActions = new ArrayList<Runnable>();
980 }
981 mPendingActions.add(action);
982 if (mPendingActions.size() == 1) {
983 mActivity.mHandler.removeCallbacks(mExecCommit);
984 mActivity.mHandler.post(mExecCommit);
985 }
986 }
987 }
988
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700989 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -0700990 synchronized (this) {
991 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
992 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700993 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -0700994 }
995 int index = mBackStackIndices.size();
996 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
997 mBackStackIndices.add(bse);
998 return index;
999
1000 } else {
1001 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1002 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1003 mBackStackIndices.set(index, bse);
1004 return index;
1005 }
1006 }
1007 }
1008
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001009 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001010 synchronized (this) {
1011 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001012 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001013 }
1014 int N = mBackStackIndices.size();
1015 if (index < N) {
1016 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1017 mBackStackIndices.set(index, bse);
1018 } else {
1019 while (N < index) {
1020 mBackStackIndices.add(null);
1021 if (mAvailBackStackIndices == null) {
1022 mAvailBackStackIndices = new ArrayList<Integer>();
1023 }
1024 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1025 mAvailBackStackIndices.add(N);
1026 N++;
1027 }
1028 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1029 mBackStackIndices.add(bse);
1030 }
1031 }
1032 }
1033
1034 public void freeBackStackIndex(int index) {
1035 synchronized (this) {
1036 mBackStackIndices.set(index, null);
1037 if (mAvailBackStackIndices == null) {
1038 mAvailBackStackIndices = new ArrayList<Integer>();
1039 }
1040 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1041 mAvailBackStackIndices.add(index);
1042 }
1043 }
1044
Dianne Hackborn445646c2010-06-25 15:52:59 -07001045 /**
1046 * Only call from main thread!
1047 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001048 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001049 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001050 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001051 }
1052
Dianne Hackbornd9b3b7e2010-11-16 18:22:49 -08001053 if (Looper.myLooper() != mActivity.mHandler.getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001054 throw new IllegalStateException("Must be called from main thread of process");
1055 }
1056
1057 boolean didSomething = false;
1058
Dianne Hackborn445646c2010-06-25 15:52:59 -07001059 while (true) {
1060 int numActions;
1061
1062 synchronized (this) {
1063 if (mPendingActions == null || mPendingActions.size() == 0) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001064 return didSomething;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001065 }
1066
1067 numActions = mPendingActions.size();
1068 if (mTmpActions == null || mTmpActions.length < numActions) {
1069 mTmpActions = new Runnable[numActions];
1070 }
1071 mPendingActions.toArray(mTmpActions);
1072 mPendingActions.clear();
1073 mActivity.mHandler.removeCallbacks(mExecCommit);
1074 }
1075
1076 mExecutingActions = true;
1077 for (int i=0; i<numActions; i++) {
1078 mTmpActions[i].run();
1079 }
1080 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001081 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001082 }
1083 }
1084
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001085 void reportBackStackChanged() {
1086 if (mBackStackChangeListeners != null) {
1087 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1088 mBackStackChangeListeners.get(i).onBackStackChanged();
1089 }
1090 }
1091 }
1092
1093 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001094 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001095 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001096 }
1097 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001098 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001099 }
1100
Dianne Hackborndd913a52010-07-22 12:17:04 -07001101 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001102 if (mBackStack == null) {
1103 return false;
1104 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001105 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001106 int last = mBackStack.size()-1;
1107 if (last < 0) {
1108 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001109 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001110 final BackStackRecord bss = mBackStack.remove(last);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001111 bss.popFromBackStack(true);
1112 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001113 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001114 int index = -1;
1115 if (name != null || id >= 0) {
1116 // If a name or ID is specified, look for that place in
1117 // the stack.
1118 index = mBackStack.size()-1;
1119 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001120 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001121 if (name != null && name.equals(bss.getName())) {
1122 break;
1123 }
1124 if (id >= 0 && id == bss.mIndex) {
1125 break;
1126 }
1127 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001128 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001129 if (index < 0) {
1130 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001131 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001132 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001133 index--;
1134 // Consume all following entries that match.
1135 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001136 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001137 if ((name != null && name.equals(bss.getName()))
1138 || (id >= 0 && id == bss.mIndex)) {
1139 index--;
1140 continue;
1141 }
1142 break;
1143 }
1144 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001145 }
1146 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001147 return false;
1148 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001149 final ArrayList<BackStackRecord> states
1150 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001151 for (int i=mBackStack.size()-1; i>index; i--) {
1152 states.add(mBackStack.remove(i));
1153 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001154 final int LAST = states.size()-1;
1155 for (int i=0; i<=LAST; i++) {
1156 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
1157 states.get(i).popFromBackStack(i == LAST);
1158 }
1159 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001160 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001161 return true;
1162 }
1163
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001164 ArrayList<Fragment> retainNonConfig() {
1165 ArrayList<Fragment> fragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001166 if (mActive != null) {
1167 for (int i=0; i<mActive.size(); i++) {
1168 Fragment f = mActive.get(i);
1169 if (f != null && f.mRetainInstance) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001170 if (fragments == null) {
1171 fragments = new ArrayList<Fragment>();
1172 }
1173 fragments.add(f);
1174 f.mRetaining = true;
1175 }
1176 }
1177 }
1178 return fragments;
1179 }
1180
1181 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001182 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001183 return;
1184 }
1185 if (mStateArray == null) {
1186 mStateArray = new SparseArray<Parcelable>();
1187 }
1188 f.mView.saveHierarchyState(mStateArray);
1189 if (mStateArray.size() > 0) {
1190 f.mSavedViewState = mStateArray;
1191 mStateArray = null;
1192 }
1193 }
1194
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001195 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001196 // Make sure all pending operations have now been executed to get
1197 // our state update-to-date.
1198 execPendingActions();
1199
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001200 mStateSaved = true;
1201
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001202 if (mActive == null || mActive.size() <= 0) {
1203 return null;
1204 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001205
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001206 // First collect all active fragments.
1207 int N = mActive.size();
1208 FragmentState[] active = new FragmentState[N];
1209 boolean haveFragments = false;
1210 for (int i=0; i<N; i++) {
1211 Fragment f = mActive.get(i);
1212 if (f != null) {
1213 haveFragments = true;
1214
1215 FragmentState fs = new FragmentState(f);
1216 active[i] = fs;
1217
Dianne Hackborn625ac272010-09-17 18:29:22 -07001218 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
1219 if (mStateBundle == null) {
1220 mStateBundle = new Bundle();
1221 }
1222 f.onSaveInstanceState(mStateBundle);
1223 if (!mStateBundle.isEmpty()) {
1224 fs.mSavedFragmentState = mStateBundle;
1225 mStateBundle = null;
1226 }
1227
1228 if (f.mView != null) {
1229 saveFragmentViewState(f);
1230 if (f.mSavedViewState != null) {
1231 if (fs.mSavedFragmentState == null) {
1232 fs.mSavedFragmentState = new Bundle();
1233 }
1234 fs.mSavedFragmentState.putSparseParcelableArray(
1235 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
1236 }
1237 }
1238
1239 if (f.mTarget != null) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001240 if (fs.mSavedFragmentState == null) {
1241 fs.mSavedFragmentState = new Bundle();
1242 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001243 putFragment(fs.mSavedFragmentState,
1244 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1245 if (f.mTargetRequestCode != 0) {
1246 fs.mSavedFragmentState.putInt(
1247 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1248 f.mTargetRequestCode);
1249 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001250 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001251
Dianne Hackborn625ac272010-09-17 18:29:22 -07001252 } else {
1253 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001254 }
1255
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001256 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1257 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001258 }
1259 }
1260
1261 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001262 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001263 return null;
1264 }
1265
1266 int[] added = null;
1267 BackStackState[] backStack = null;
1268
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001269 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001270 if (mAdded != null) {
1271 N = mAdded.size();
1272 if (N > 0) {
1273 added = new int[N];
1274 for (int i=0; i<N; i++) {
1275 added[i] = mAdded.get(i).mIndex;
1276 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1277 + ": " + mAdded.get(i));
1278 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001279 }
1280 }
1281
1282 // Now save back stack.
1283 if (mBackStack != null) {
1284 N = mBackStack.size();
1285 if (N > 0) {
1286 backStack = new BackStackState[N];
1287 for (int i=0; i<N; i++) {
1288 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001289 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1290 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001291 }
1292 }
1293 }
1294
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001295 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001296 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001297 fms.mAdded = added;
1298 fms.mBackStack = backStack;
1299 return fms;
1300 }
1301
1302 void restoreAllState(Parcelable state, ArrayList<Fragment> nonConfig) {
1303 // If there is no saved state at all, then there can not be
1304 // any nonConfig fragments either, so that is that.
1305 if (state == null) return;
1306 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001307 if (fms.mActive == null) return;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001308
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001309 // First re-attach any non-config instances we are retaining back
1310 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001311 if (nonConfig != null) {
1312 for (int i=0; i<nonConfig.size(); i++) {
1313 Fragment f = nonConfig.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001314 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001315 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001316 fs.mInstance = f;
1317 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001318 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001319 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001320 f.mAdded = false;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001321 if (fs.mSavedFragmentState != null) {
Dianne Hackborn51642462010-10-28 10:32:37 -07001322 fs.mSavedFragmentState.setClassLoader(mActivity.getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001323 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001324 FragmentManagerImpl.VIEW_STATE_TAG);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001325 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001326 }
1327 }
1328
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001329 // Build the full list of active fragments, instantiating them from
1330 // their saved state.
1331 mActive = new ArrayList<Fragment>(fms.mActive.length);
1332 if (mAvailIndices != null) {
1333 mAvailIndices.clear();
1334 }
1335 for (int i=0; i<fms.mActive.length; i++) {
1336 FragmentState fs = fms.mActive[i];
1337 if (fs != null) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001338 Fragment f = fs.instantiate(mActivity);
1339 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
1340 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001341 // Now that the fragment is instantiated (or came from being
1342 // retained above), clear mInstance in case we end up re-restoring
1343 // from this FragmentState again.
1344 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001345 } else {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001346 if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": (null)");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001347 mActive.add(null);
1348 if (mAvailIndices == null) {
1349 mAvailIndices = new ArrayList<Integer>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001350 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001351 if (DEBUG) Log.v(TAG, "restoreAllState: adding avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001352 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001353 }
1354 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001355
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001356 // Update the target of all retained fragments.
1357 if (nonConfig != null) {
1358 for (int i=0; i<nonConfig.size(); i++) {
1359 Fragment f = nonConfig.get(i);
1360 if (f.mTarget != null) {
1361 if (f.mTarget.mIndex < mActive.size()) {
1362 f.mTarget = mActive.get(f.mTarget.mIndex);
1363 } else {
1364 Log.w(TAG, "Re-attaching retained fragment " + f
1365 + " target no longer exists: " + f.mTarget);
1366 f.mTarget = null;
1367 }
1368 }
1369 }
1370 }
1371
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001372 // Build the list of currently added fragments.
1373 if (fms.mAdded != null) {
1374 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1375 for (int i=0; i<fms.mAdded.length; i++) {
1376 Fragment f = mActive.get(fms.mAdded[i]);
1377 if (f == null) {
1378 throw new IllegalStateException(
1379 "No instantiated fragment for index #" + fms.mAdded[i]);
1380 }
1381 f.mAdded = true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001382 f.mImmediateActivity = mActivity;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001383 if (DEBUG) Log.v(TAG, "restoreAllState: making added #" + i + ": " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001384 mAdded.add(f);
1385 }
1386 } else {
1387 mAdded = null;
1388 }
1389
1390 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001391 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001392 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001393 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001394 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001395 if (DEBUG) Log.v(TAG, "restoreAllState: adding bse #" + i
1396 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001397 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07001398 if (bse.mIndex >= 0) {
1399 setBackStackIndex(bse.mIndex, bse);
1400 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001401 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001402 } else {
1403 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001404 }
1405 }
1406
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001407 public void attachActivity(Activity activity) {
1408 if (mActivity != null) throw new IllegalStateException();
1409 mActivity = activity;
1410 }
1411
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001412 public void noteStateNotSaved() {
1413 mStateSaved = false;
1414 }
1415
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001416 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001417 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001418 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001419 }
1420
Dianne Hackbornc8017682010-07-06 13:34:38 -07001421 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001422 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07001423 moveToState(Fragment.ACTIVITY_CREATED, false);
1424 }
1425
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001426 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001427 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001428 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001429 }
1430
1431 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001432 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001433 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001434 }
1435
1436 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001437 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001438 }
1439
1440 public void dispatchStop() {
Dianne Hackbornc8017682010-07-06 13:34:38 -07001441 moveToState(Fragment.ACTIVITY_CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001442 }
1443
1444 public void dispatchDestroy() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001445 moveToState(Fragment.INITIALIZING, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001446 mActivity = null;
1447 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001448
Dianne Hackborn9d071802010-12-08 14:49:15 -08001449 public void dispatchConfigurationChanged(Configuration newConfig) {
1450 if (mActive != null) {
1451 for (int i=0; i<mAdded.size(); i++) {
1452 Fragment f = mAdded.get(i);
1453 if (f != null) {
1454 f.onConfigurationChanged(newConfig);
1455 }
1456 }
1457 }
1458 }
1459
1460 public void dispatchLowMemory() {
1461 if (mActive != null) {
1462 for (int i=0; i<mAdded.size(); i++) {
1463 Fragment f = mAdded.get(i);
1464 if (f != null) {
1465 f.onLowMemory();
1466 }
1467 }
1468 }
1469 }
1470
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001471 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
1472 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001473 ArrayList<Fragment> newMenus = null;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001474 if (mActive != null) {
1475 for (int i=0; i<mAdded.size(); i++) {
1476 Fragment f = mAdded.get(i);
1477 if (f != null && !f.mHidden && f.mHasMenu) {
1478 show = true;
1479 f.onCreateOptionsMenu(menu, inflater);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001480 if (newMenus == null) {
1481 newMenus = new ArrayList<Fragment>();
1482 }
1483 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001484 }
1485 }
1486 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07001487
1488 if (mCreatedMenus != null) {
1489 for (int i=0; i<mCreatedMenus.size(); i++) {
1490 Fragment f = mCreatedMenus.get(i);
1491 if (newMenus == null || !newMenus.contains(f)) {
1492 f.onDestroyOptionsMenu();
1493 }
1494 }
1495 }
1496
1497 mCreatedMenus = newMenus;
1498
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001499 return show;
1500 }
1501
1502 public boolean dispatchPrepareOptionsMenu(Menu menu) {
1503 boolean show = false;
1504 if (mActive != null) {
1505 for (int i=0; i<mAdded.size(); i++) {
1506 Fragment f = mAdded.get(i);
1507 if (f != null && !f.mHidden && f.mHasMenu) {
1508 show = true;
1509 f.onPrepareOptionsMenu(menu);
1510 }
1511 }
1512 }
1513 return show;
1514 }
1515
1516 public boolean dispatchOptionsItemSelected(MenuItem item) {
1517 if (mActive != null) {
1518 for (int i=0; i<mAdded.size(); i++) {
1519 Fragment f = mAdded.get(i);
1520 if (f != null && !f.mHidden && f.mHasMenu) {
1521 if (f.onOptionsItemSelected(item)) {
1522 return true;
1523 }
1524 }
1525 }
1526 }
1527 return false;
1528 }
1529
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07001530 public boolean dispatchContextItemSelected(MenuItem item) {
1531 if (mActive != null) {
1532 for (int i=0; i<mAdded.size(); i++) {
1533 Fragment f = mAdded.get(i);
1534 if (f != null && !f.mHidden) {
1535 if (f.onContextItemSelected(item)) {
1536 return true;
1537 }
1538 }
1539 }
1540 }
1541 return false;
1542 }
1543
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001544 public void dispatchOptionsMenuClosed(Menu menu) {
1545 if (mActive != null) {
1546 for (int i=0; i<mAdded.size(); i++) {
1547 Fragment f = mAdded.get(i);
1548 if (f != null && !f.mHidden && f.mHasMenu) {
1549 f.onOptionsMenuClosed(menu);
1550 }
1551 }
1552 }
1553 }
1554
Dianne Hackbornf121be72010-05-06 14:10:32 -07001555 public static int reverseTransit(int transit) {
1556 int rev = 0;
1557 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001558 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
1559 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001560 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001561 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
1562 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001563 break;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001564 case FragmentTransaction.TRANSIT_FRAGMENT_NEXT:
1565 rev = FragmentTransaction.TRANSIT_FRAGMENT_PREV;
1566 break;
1567 case FragmentTransaction.TRANSIT_FRAGMENT_PREV:
1568 rev = FragmentTransaction.TRANSIT_FRAGMENT_NEXT;
1569 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001570 }
1571 return rev;
1572
1573 }
1574
1575 public static int transitToStyleIndex(int transit, boolean enter) {
1576 int animAttr = -1;
1577 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07001578 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001579 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001580 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
1581 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001582 break;
Chet Haase811ed1062010-08-06 10:38:15 -07001583 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07001584 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07001585 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
1586 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001587 break;
Chet Haase9ff82bf2010-10-05 14:30:51 -07001588 case FragmentTransaction.TRANSIT_FRAGMENT_NEXT:
1589 animAttr = enter
1590 ? com.android.internal.R.styleable.FragmentAnimation_fragmentNextEnterAnimation
1591 : com.android.internal.R.styleable.FragmentAnimation_fragmentNextExitAnimation;
1592 break;
1593 case FragmentTransaction.TRANSIT_FRAGMENT_PREV:
1594 animAttr = enter
1595 ? com.android.internal.R.styleable.FragmentAnimation_fragmentPrevEnterAnimation
1596 : com.android.internal.R.styleable.FragmentAnimation_fragmentPrevExitAnimation;
1597 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001598 }
1599 return animAttr;
1600 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001601}