blob: 8369f17c877f183fce94262f26fc77a63bed0519 [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;
Doris Liude9284d2015-05-22 15:41:46 -070022import android.animation.AnimatorSet;
23import android.animation.PropertyValuesHolder;
24import android.animation.ValueAnimator;
Adam Powell371a8092014-06-20 12:51:12 -070025import android.content.Context;
Dianne Hackborn9d071802010-12-08 14:49:15 -080026import android.content.res.Configuration;
Adam Powelle01f5952016-02-23 15:25:42 -080027import android.content.res.Resources.NotFoundException;
Dianne Hackbornf121be72010-05-06 14:10:32 -070028import android.content.res.TypedArray;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070029import android.os.Bundle;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -070030import android.os.Debug;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -070031import android.os.Handler;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -080032import android.os.Looper;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070033import android.os.Parcel;
34import android.os.Parcelable;
Adam Powell371a8092014-06-20 12:51:12 -070035import android.util.AttributeSet;
Dianne Hackborna2ea7472010-12-20 12:10:01 -080036import android.util.DebugUtils;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070037import android.util.Log;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -080038import android.util.LogWriter;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070039import android.util.SparseArray;
Adam Powell14874662013-07-18 19:42:41 -070040import android.util.SuperNotCalledException;
Adam Powell371a8092014-06-20 12:51:12 -070041import android.view.LayoutInflater;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -070042import android.view.Menu;
43import android.view.MenuInflater;
44import android.view.MenuItem;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070045import android.view.View;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070046import android.view.ViewGroup;
Dianne Hackborn8c841092013-06-24 13:46:13 -070047import com.android.internal.util.FastPrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070048
Dianne Hackborn625ac272010-09-17 18:29:22 -070049import java.io.FileDescriptor;
50import java.io.PrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070051import java.util.ArrayList;
Dianne Hackbornd173fa32010-12-23 13:58:22 -080052import java.util.Arrays;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070053import java.util.List;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070054
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070055/**
56 * Interface for interacting with {@link Fragment} objects inside of an
57 * {@link Activity}
Joe Fernandezb54e7a32011-10-03 15:09:50 -070058 *
59 * <div class="special reference">
60 * <h3>Developer Guides</h3>
61 * <p>For more information about using fragments, read the
62 * <a href="{@docRoot}guide/topics/fundamentals/fragments.html">Fragments</a> developer guide.</p>
63 * </div>
Dianne Hackborn7871bad2011-12-12 15:19:26 -080064 *
65 * While the FragmentManager API was introduced in
66 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
67 * at is also available for use on older platforms through
68 * {@link android.support.v4.app.FragmentActivity}. See the blog post
69 * <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
70 * Fragments For All</a> for more details.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070071 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -070072public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070073 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070074 * Representation of an entry on the fragment back stack, as created
75 * with {@link FragmentTransaction#addToBackStack(String)
76 * FragmentTransaction.addToBackStack()}. Entries can later be
Dianne Hackborn327fbd22011-01-17 14:38:50 -080077 * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
Mark Dolinerd0646dc2014-08-27 16:04:02 -070078 * FragmentManager.getBackStackEntryAt()}.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070079 *
80 * <p>Note that you should never hold on to a BackStackEntry object;
81 * the identifier as returned by {@link #getId} is the only thing that
82 * will be persisted across activity instances.
83 */
84 public interface BackStackEntry {
85 /**
86 * Return the unique identifier for the entry. This is the only
87 * representation of the entry that will persist across activity
88 * instances.
89 */
90 public int getId();
91
92 /**
Dianne Hackborn6c285972011-08-29 16:53:49 -070093 * Get the name that was supplied to
94 * {@link FragmentTransaction#addToBackStack(String)
95 * FragmentTransaction.addToBackStack(String)} when creating this entry.
96 */
97 public String getName();
98
99 /**
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800100 * Return the full bread crumb title resource identifier for the entry,
101 * or 0 if it does not have one.
102 */
103 public int getBreadCrumbTitleRes();
104
105 /**
106 * Return the short bread crumb title resource identifier for the entry,
107 * or 0 if it does not have one.
108 */
109 public int getBreadCrumbShortTitleRes();
110
111 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700112 * Return the full bread crumb title for the entry, or null if it
113 * does not have one.
114 */
115 public CharSequence getBreadCrumbTitle();
116
117 /**
118 * Return the short bread crumb title for the entry, or null if it
119 * does not have one.
120 */
121 public CharSequence getBreadCrumbShortTitle();
122 }
123
124 /**
125 * Interface to watch for changes to the back stack.
126 */
127 public interface OnBackStackChangedListener {
128 /**
129 * Called whenever the contents of the back stack change.
130 */
131 public void onBackStackChanged();
132 }
133
134 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700135 * Start a series of edit operations on the Fragments associated with
136 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700137 *
138 * <p>Note: A fragment transaction can only be created/committed prior
139 * to an activity saving its state. If you try to commit a transaction
140 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
141 * (and prior to a following {@link Activity#onStart Activity.onStart}
142 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
143 * This is because the framework takes care of saving your current fragments
144 * in the state, and if changes are made after the state is saved then they
145 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700146 */
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800147 public abstract FragmentTransaction beginTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700148
Dianne Hackborn17b9b812011-01-17 17:16:02 -0800149 /** @hide -- remove once prebuilts are in. */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800150 @Deprecated
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800151 public FragmentTransaction openTransaction() {
152 return beginTransaction();
153 }
154
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700155 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800156 * After a {@link FragmentTransaction} is committed with
157 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
158 * is scheduled to be executed asynchronously on the process's main thread.
159 * If you want to immediately executing any such pending operations, you
160 * can call this function (only from the main thread) to do so. Note that
161 * all callbacks and other related behavior will be done from within this
162 * call, so be careful about where this is called from.
163 *
164 * @return Returns true if there were any pending transactions to be
165 * executed.
166 */
167 public abstract boolean executePendingTransactions();
168
169 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700170 * Finds a fragment that was identified by the given id either when inflated
171 * from XML or as the container ID when added in a transaction. This first
172 * searches through fragments that are currently added to the manager's
173 * activity; if no such fragment is found, then all fragments currently
174 * on the back stack associated with this ID are searched.
175 * @return The fragment if found or null otherwise.
176 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700177 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700178
179 /**
180 * Finds a fragment that was identified by the given tag either when inflated
181 * from XML or as supplied when added in a transaction. This first
182 * searches through fragments that are currently added to the manager's
183 * activity; if no such fragment is found, then all fragments currently
184 * on the back stack are searched.
185 * @return The fragment if found or null otherwise.
186 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700187 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700188
189 /**
190 * Flag for {@link #popBackStack(String, int)}
191 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
192 * a back stack entry has been supplied, then all matching entries will
193 * be consumed until one that doesn't match is found or the bottom of
194 * the stack is reached. Otherwise, all entries up to but not including that entry
195 * will be removed.
196 */
197 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
198
199 /**
Ben Komalo87ffa202011-02-28 12:41:42 -0800200 * Pop the top state off the back stack. This function is asynchronous -- it
201 * enqueues the request to pop, but the action will not be performed until the
202 * application returns to its event loop.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700203 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800204 public abstract void popBackStack();
205
206 /**
207 * Like {@link #popBackStack()}, but performs the operation immediately
208 * inside of the call. This is like calling {@link #executePendingTransactions()}
209 * afterwards.
210 * @return Returns true if there was something popped, else false.
211 */
212 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700213
214 /**
215 * Pop the last fragment transition from the manager's fragment
216 * back stack. If there is nothing to pop, false is returned.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800217 * This function is asynchronous -- it enqueues the
218 * request to pop, but the action will not be performed until the application
219 * returns to its event loop.
220 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700221 * @param name If non-null, this is the name of a previous back state
222 * to look for; if found, all states up to that state will be popped. The
223 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
224 * the named state itself is popped. If null, only the top state is popped.
225 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
226 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800227 public abstract void popBackStack(String name, int flags);
228
229 /**
230 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
231 * inside of the call. This is like calling {@link #executePendingTransactions()}
232 * afterwards.
233 * @return Returns true if there was something popped, else false.
234 */
235 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700236
237 /**
238 * Pop all back stack states up to the one with the given identifier.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800239 * This function is asynchronous -- it enqueues the
240 * request to pop, but the action will not be performed until the application
241 * returns to its event loop.
242 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700243 * @param id Identifier of the stated to be popped. If no identifier exists,
244 * false is returned.
245 * The identifier is the number returned by
246 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
247 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
248 * the named state itself is popped.
249 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
250 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800251 public abstract void popBackStack(int id, int flags);
252
253 /**
254 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
255 * inside of the call. This is like calling {@link #executePendingTransactions()}
256 * afterwards.
257 * @return Returns true if there was something popped, else false.
258 */
259 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700260
261 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700262 * Return the number of entries currently in the back stack.
263 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800264 public abstract int getBackStackEntryCount();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700265
266 /**
267 * Return the BackStackEntry at index <var>index</var> in the back stack;
Mark Dolinerd0646dc2014-08-27 16:04:02 -0700268 * where the item on the bottom of the stack has index 0.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700269 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800270 public abstract BackStackEntry getBackStackEntryAt(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700271
272 /**
273 * Add a new listener for changes to the fragment back stack.
274 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700275 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700276
277 /**
278 * Remove a listener that was previously added with
279 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
280 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700281 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700282
283 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700284 * Put a reference to a fragment in a Bundle. This Bundle can be
285 * persisted as saved state, and when later restoring
286 * {@link #getFragment(Bundle, String)} will return the current
287 * instance of the same fragment.
288 *
289 * @param bundle The bundle in which to put the fragment reference.
290 * @param key The name of the entry in the bundle.
291 * @param fragment The Fragment whose reference is to be stored.
292 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700293 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700294
295 /**
296 * Retrieve the current Fragment instance for a reference previously
297 * placed with {@link #putFragment(Bundle, String, Fragment)}.
298 *
299 * @param bundle The bundle from which to retrieve the fragment reference.
300 * @param key The name of the entry in the bundle.
301 * @return Returns the current Fragment instance that is associated with
302 * the given reference.
303 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700304 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700305
306 /**
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700307 * Save the current instance state of the given Fragment. This can be
308 * used later when creating a new instance of the Fragment and adding
309 * it to the fragment manager, to have it create itself to match the
310 * current state returned here. Note that there are limits on how
311 * this can be used:
312 *
313 * <ul>
314 * <li>The Fragment must currently be attached to the FragmentManager.
315 * <li>A new Fragment created using this saved state must be the same class
316 * type as the Fragment it was created from.
317 * <li>The saved state can not contain dependencies on other fragments --
318 * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
319 * store a fragment reference because that reference may not be valid when
320 * this saved state is later used. Likewise the Fragment's target and
321 * result code are not included in this state.
322 * </ul>
323 *
324 * @param f The Fragment whose state is to be saved.
325 * @return The generated state. This will be null if there was no
326 * interesting state created by the fragment.
327 */
328 public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
329
330 /**
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700331 * Returns true if the final {@link Activity#onDestroy() Activity.onDestroy()}
332 * call has been made on the FragmentManager's Activity, so this instance is now dead.
333 */
334 public abstract boolean isDestroyed();
335
336 /**
Dianne Hackborn625ac272010-09-17 18:29:22 -0700337 * Print the FragmentManager's state into the given stream.
338 *
339 * @param prefix Text to print at the front of each line.
340 * @param fd The raw file descriptor that the dump is being sent to.
341 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800342 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700343 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700344 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800345
346 /**
347 * Control whether the framework's internal fragment manager debugging
348 * logs are turned on. If enabled, you will see output in logcat as
349 * the framework performs fragment operations.
350 */
351 public static void enableDebugLogging(boolean enabled) {
352 FragmentManagerImpl.DEBUG = enabled;
353 }
Adam Powellf0f5fff2011-08-01 13:42:50 -0700354
355 /**
356 * Invalidate the attached activity's options menu as necessary.
357 * This may end up being deferred until we move to the resumed state.
358 */
359 public void invalidateOptionsMenu() { }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700360}
361
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700362final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700363 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700364 int[] mAdded;
365 BackStackState[] mBackStack;
366
367 public FragmentManagerState() {
368 }
369
370 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700371 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700372 mAdded = in.createIntArray();
373 mBackStack = in.createTypedArray(BackStackState.CREATOR);
374 }
375
376 public int describeContents() {
377 return 0;
378 }
379
380 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700381 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700382 dest.writeIntArray(mAdded);
383 dest.writeTypedArray(mBackStack, flags);
384 }
385
386 public static final Parcelable.Creator<FragmentManagerState> CREATOR
387 = new Parcelable.Creator<FragmentManagerState>() {
388 public FragmentManagerState createFromParcel(Parcel in) {
389 return new FragmentManagerState(in);
390 }
391
392 public FragmentManagerState[] newArray(int size) {
393 return new FragmentManagerState[size];
394 }
395 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700396}
397
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700398/**
399 * Container for fragments associated with an activity.
400 */
Adam Powell371a8092014-06-20 12:51:12 -0700401final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
Craig Mautner1c437192012-08-01 10:01:16 -0700402 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700403 static final String TAG = "FragmentManager";
404
Dianne Hackborndef15372010-08-15 12:43:52 -0700405 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
406 static final String TARGET_STATE_TAG = "android:target_state";
407 static final String VIEW_STATE_TAG = "android:view_state";
Adam Powell78fed9b2011-11-07 10:45:34 -0800408 static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
Dianne Hackborndef15372010-08-15 12:43:52 -0700409
Doris Liude9284d2015-05-22 15:41:46 -0700410 static class AnimateOnHWLayerIfNeededListener implements Animator.AnimatorListener {
411 private boolean mShouldRunOnHWLayer = false;
412 private View mView;
413 public AnimateOnHWLayerIfNeededListener(final View v) {
414 if (v == null) {
415 return;
416 }
417 mView = v;
418 }
419
420 @Override
421 public void onAnimationStart(Animator animation) {
422 mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
423 if (mShouldRunOnHWLayer) {
424 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
425 }
426 }
427
428 @Override
429 public void onAnimationEnd(Animator animation) {
430 if (mShouldRunOnHWLayer) {
431 mView.setLayerType(View.LAYER_TYPE_NONE, null);
432 }
433 mView = null;
434 animation.removeListener(this);
435 }
436
437 @Override
438 public void onAnimationCancel(Animator animation) {
439
440 }
441
442 @Override
443 public void onAnimationRepeat(Animator animation) {
444
445 }
446 }
447
Dianne Hackborn445646c2010-06-25 15:52:59 -0700448 ArrayList<Runnable> mPendingActions;
449 Runnable[] mTmpActions;
450 boolean mExecutingActions;
451
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700452 ArrayList<Fragment> mActive;
453 ArrayList<Fragment> mAdded;
454 ArrayList<Integer> mAvailIndices;
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700455 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700456 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700457
Dianne Hackborndd913a52010-07-22 12:17:04 -0700458 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700459 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700460 ArrayList<Integer> mAvailBackStackIndices;
461
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700462 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
463
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700464 int mCurState = Fragment.INITIALIZING;
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700465 FragmentHostCallback<?> mHost;
466 FragmentController mController;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700467 FragmentContainer mContainer;
468 Fragment mParent;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700469
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700470 boolean mNeedMenuInvalidate;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700471 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800472 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700473 String mNoTransactionsBecause;
Adam Powell78fed9b2011-11-07 10:45:34 -0800474 boolean mHavePendingDeferredStart;
Adam Powell371a8092014-06-20 12:51:12 -0700475
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700476 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700477 Bundle mStateBundle = null;
478 SparseArray<Parcelable> mStateArray = null;
479
Dianne Hackborn445646c2010-06-25 15:52:59 -0700480 Runnable mExecCommit = new Runnable() {
481 @Override
482 public void run() {
483 execPendingActions();
484 }
485 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700486
Dianne Hackborn4702a852012-08-17 15:18:29 -0700487 private void throwException(RuntimeException ex) {
488 Log.e(TAG, ex.getMessage());
489 LogWriter logw = new LogWriter(Log.ERROR, TAG);
Dianne Hackborn8c841092013-06-24 13:46:13 -0700490 PrintWriter pw = new FastPrintWriter(logw, false, 1024);
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700491 if (mHost != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700492 Log.e(TAG, "Activity state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700493 try {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700494 mHost.onDump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700495 } catch (Exception e) {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700496 pw.flush();
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700497 Log.e(TAG, "Failed dumping state", e);
498 }
499 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700500 Log.e(TAG, "Fragment manager state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700501 try {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700502 dump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700503 } catch (Exception e) {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700504 pw.flush();
Dianne Hackborn4702a852012-08-17 15:18:29 -0700505 Log.e(TAG, "Failed dumping state", e);
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700506 }
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700507 }
Dianne Hackborn8c841092013-06-24 13:46:13 -0700508 pw.flush();
Dianne Hackborn4702a852012-08-17 15:18:29 -0700509 throw ex;
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700510 }
511
Doris Liude9284d2015-05-22 15:41:46 -0700512 static boolean modifiesAlpha(Animator anim) {
513 if (anim == null) {
514 return false;
515 }
516 if (anim instanceof ValueAnimator) {
517 ValueAnimator valueAnim = (ValueAnimator) anim;
518 PropertyValuesHolder[] values = valueAnim.getValues();
519 for (int i = 0; i < values.length; i++) {
520 if (("alpha").equals(values[i].getPropertyName())) {
521 return true;
522 }
523 }
524 } else if (anim instanceof AnimatorSet) {
525 List<Animator> animList = ((AnimatorSet) anim).getChildAnimations();
526 for (int i = 0; i < animList.size(); i++) {
527 if (modifiesAlpha(animList.get(i))) {
528 return true;
529 }
530 }
531 }
532 return false;
533 }
534
535 static boolean shouldRunOnHWLayer(View v, Animator anim) {
536 if (v == null || anim == null) {
537 return false;
538 }
539 return v.getLayerType() == View.LAYER_TYPE_NONE
540 && v.hasOverlappingRendering()
541 && modifiesAlpha(anim);
542 }
543
544 /**
545 * Sets the to be animated view on hardware layer during the animation.
546 */
547 private void setHWLayerAnimListenerIfAlpha(final View v, Animator anim) {
548 if (v == null || anim == null) {
549 return;
550 }
551 if (shouldRunOnHWLayer(v, anim)) {
552 anim.addListener(new AnimateOnHWLayerIfNeededListener(v));
553 }
554 }
555
Dianne Hackborn625ac272010-09-17 18:29:22 -0700556 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800557 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700558 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700559 }
560
Dianne Hackborn625ac272010-09-17 18:29:22 -0700561 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800562 public boolean executePendingTransactions() {
563 return execPendingActions();
564 }
565
566 @Override
567 public void popBackStack() {
568 enqueueAction(new Runnable() {
569 @Override public void run() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700570 popBackStackState(mHost.getHandler(), null, -1, 0);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800571 }
572 }, false);
573 }
574
575 @Override
576 public boolean popBackStackImmediate() {
577 checkStateLoss();
578 executePendingTransactions();
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700579 return popBackStackState(mHost.getHandler(), null, -1, 0);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700580 }
581
Dianne Hackborn625ac272010-09-17 18:29:22 -0700582 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800583 public void popBackStack(final String name, final int flags) {
584 enqueueAction(new Runnable() {
585 @Override public void run() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700586 popBackStackState(mHost.getHandler(), name, -1, flags);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800587 }
588 }, false);
589 }
590
591 @Override
592 public boolean popBackStackImmediate(String name, int flags) {
593 checkStateLoss();
594 executePendingTransactions();
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700595 return popBackStackState(mHost.getHandler(), name, -1, flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700596 }
597
Dianne Hackborn625ac272010-09-17 18:29:22 -0700598 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800599 public void popBackStack(final int id, final int flags) {
600 if (id < 0) {
601 throw new IllegalArgumentException("Bad id: " + id);
602 }
603 enqueueAction(new Runnable() {
604 @Override public void run() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700605 popBackStackState(mHost.getHandler(), null, id, flags);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800606 }
607 }, false);
608 }
609
610 @Override
611 public boolean popBackStackImmediate(int id, int flags) {
612 checkStateLoss();
613 executePendingTransactions();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700614 if (id < 0) {
615 throw new IllegalArgumentException("Bad id: " + id);
616 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700617 return popBackStackState(mHost.getHandler(), null, id, flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700618 }
619
Dianne Hackborn625ac272010-09-17 18:29:22 -0700620 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800621 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700622 return mBackStack != null ? mBackStack.size() : 0;
623 }
624
Dianne Hackborn625ac272010-09-17 18:29:22 -0700625 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800626 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700627 return mBackStack.get(index);
628 }
629
Dianne Hackborn625ac272010-09-17 18:29:22 -0700630 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700631 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
632 if (mBackStackChangeListeners == null) {
633 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
634 }
635 mBackStackChangeListeners.add(listener);
636 }
637
Dianne Hackborn625ac272010-09-17 18:29:22 -0700638 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700639 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
640 if (mBackStackChangeListeners != null) {
641 mBackStackChangeListeners.remove(listener);
642 }
643 }
644
Dianne Hackborn625ac272010-09-17 18:29:22 -0700645 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700646 public void putFragment(Bundle bundle, String key, Fragment fragment) {
647 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700648 throwException(new IllegalStateException("Fragment " + fragment
649 + " is not currently in the FragmentManager"));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700650 }
651 bundle.putInt(key, fragment.mIndex);
652 }
653
Dianne Hackborn625ac272010-09-17 18:29:22 -0700654 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700655 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700656 int index = bundle.getInt(key, -1);
657 if (index == -1) {
658 return null;
659 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700660 if (index >= mActive.size()) {
Cyril Mottier2de50822013-09-30 22:42:26 +0200661 throwException(new IllegalStateException("Fragment no longer exists for key "
Dianne Hackborn4702a852012-08-17 15:18:29 -0700662 + key + ": index " + index));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700663 }
664 Fragment f = mActive.get(index);
665 if (f == null) {
Cyril Mottier2de50822013-09-30 22:42:26 +0200666 throwException(new IllegalStateException("Fragment no longer exists for key "
Dianne Hackborn4702a852012-08-17 15:18:29 -0700667 + key + ": index " + index));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700668 }
669 return f;
670 }
671
Dianne Hackborn625ac272010-09-17 18:29:22 -0700672 @Override
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700673 public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
674 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700675 throwException(new IllegalStateException("Fragment " + fragment
676 + " is not currently in the FragmentManager"));
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700677 }
678 if (fragment.mState > Fragment.INITIALIZING) {
679 Bundle result = saveFragmentBasicState(fragment);
680 return result != null ? new Fragment.SavedState(result) : null;
681 }
682 return null;
683 }
684
685 @Override
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700686 public boolean isDestroyed() {
687 return mDestroyed;
688 }
689
690 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800691 public String toString() {
692 StringBuilder sb = new StringBuilder(128);
693 sb.append("FragmentManager{");
694 sb.append(Integer.toHexString(System.identityHashCode(this)));
695 sb.append(" in ");
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700696 if (mParent != null) {
697 DebugUtils.buildShortClassTag(mParent, sb);
698 } else {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700699 DebugUtils.buildShortClassTag(mHost, sb);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700700 }
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800701 sb.append("}}");
702 return sb.toString();
703 }
704
705 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700706 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700707 String innerPrefix = prefix + " ";
708
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800709 int N;
710 if (mActive != null) {
711 N = mActive.size();
712 if (N > 0) {
713 writer.print(prefix); writer.print("Active Fragments in ");
714 writer.print(Integer.toHexString(System.identityHashCode(this)));
715 writer.println(":");
716 for (int i=0; i<N; i++) {
717 Fragment f = mActive.get(i);
718 writer.print(prefix); writer.print(" #"); writer.print(i);
719 writer.print(": "); writer.println(f);
720 if (f != null) {
721 f.dump(innerPrefix, fd, writer, args);
722 }
723 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700724 }
725 }
726
727 if (mAdded != null) {
728 N = mAdded.size();
729 if (N > 0) {
730 writer.print(prefix); writer.println("Added Fragments:");
731 for (int i=0; i<N; i++) {
732 Fragment f = mAdded.get(i);
733 writer.print(prefix); writer.print(" #"); writer.print(i);
734 writer.print(": "); writer.println(f.toString());
735 }
736 }
737 }
738
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800739 if (mCreatedMenus != null) {
740 N = mCreatedMenus.size();
741 if (N > 0) {
742 writer.print(prefix); writer.println("Fragments Created Menus:");
743 for (int i=0; i<N; i++) {
744 Fragment f = mCreatedMenus.get(i);
745 writer.print(prefix); writer.print(" #"); writer.print(i);
746 writer.print(": "); writer.println(f.toString());
747 }
748 }
749 }
750
Dianne Hackborn625ac272010-09-17 18:29:22 -0700751 if (mBackStack != null) {
752 N = mBackStack.size();
753 if (N > 0) {
754 writer.print(prefix); writer.println("Back Stack:");
755 for (int i=0; i<N; i++) {
756 BackStackRecord bs = mBackStack.get(i);
757 writer.print(prefix); writer.print(" #"); writer.print(i);
758 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -0800759 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700760 }
761 }
762 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800763
764 synchronized (this) {
765 if (mBackStackIndices != null) {
766 N = mBackStackIndices.size();
767 if (N > 0) {
768 writer.print(prefix); writer.println("Back Stack Indices:");
769 for (int i=0; i<N; i++) {
770 BackStackRecord bs = mBackStackIndices.get(i);
771 writer.print(prefix); writer.print(" #"); writer.print(i);
772 writer.print(": "); writer.println(bs);
773 }
774 }
775 }
776
777 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
778 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
779 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
780 }
781 }
782
783 if (mPendingActions != null) {
784 N = mPendingActions.size();
785 if (N > 0) {
786 writer.print(prefix); writer.println("Pending Actions:");
787 for (int i=0; i<N; i++) {
788 Runnable r = mPendingActions.get(i);
789 writer.print(prefix); writer.print(" #"); writer.print(i);
790 writer.print(": "); writer.println(r);
791 }
792 }
793 }
794
795 writer.print(prefix); writer.println("FragmentManager misc state:");
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700796 writer.print(prefix); writer.print(" mHost="); writer.println(mHost);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700797 writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
798 if (mParent != null) {
799 writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
800 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800801 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
802 writer.print(" mStateSaved="); writer.print(mStateSaved);
803 writer.print(" mDestroyed="); writer.println(mDestroyed);
804 if (mNeedMenuInvalidate) {
805 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
806 writer.println(mNeedMenuInvalidate);
807 }
808 if (mNoTransactionsBecause != null) {
809 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
810 writer.println(mNoTransactionsBecause);
811 }
812 if (mAvailIndices != null && mAvailIndices.size() > 0) {
813 writer.print(prefix); writer.print(" mAvailIndices: ");
814 writer.println(Arrays.toString(mAvailIndices.toArray()));
815 }
Dianne Hackborn625ac272010-09-17 18:29:22 -0700816 }
817
Chet Haasea18a86b2010-09-07 13:20:00 -0700818 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -0700819 int transitionStyle) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700820 Animator animObj = fragment.onCreateAnimator(transit, enter,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700821 fragment.mNextAnim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700822 if (animObj != null) {
823 return animObj;
824 }
825
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700826 if (fragment.mNextAnim != 0) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700827 Animator anim = AnimatorInflater.loadAnimator(mHost.getContext(), fragment.mNextAnim);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700828 if (anim != null) {
829 return anim;
830 }
831 }
832
Dianne Hackbornf121be72010-05-06 14:10:32 -0700833 if (transit == 0) {
834 return null;
835 }
836
837 int styleIndex = transitToStyleIndex(transit, enter);
838 if (styleIndex < 0) {
839 return null;
840 }
841
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700842 if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
843 transitionStyle = mHost.onGetWindowAnimations();
Dianne Hackbornf121be72010-05-06 14:10:32 -0700844 }
845 if (transitionStyle == 0) {
846 return null;
847 }
848
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700849 TypedArray attrs = mHost.getContext().obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -0700850 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700851 int anim = attrs.getResourceId(styleIndex, 0);
852 attrs.recycle();
853
854 if (anim == 0) {
855 return null;
856 }
857
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700858 return AnimatorInflater.loadAnimator(mHost.getContext(), anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -0700859 }
860
Adam Powell635c60a2011-10-26 10:22:16 -0700861 public void performPendingDeferredStart(Fragment f) {
862 if (f.mDeferStart) {
Adam Powell78fed9b2011-11-07 10:45:34 -0800863 if (mExecutingActions) {
864 // Wait until we're done executing our pending transactions
865 mHavePendingDeferredStart = true;
866 return;
867 }
Adam Powell635c60a2011-10-26 10:22:16 -0700868 f.mDeferStart = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700869 moveToState(f, mCurState, 0, 0, false);
Adam Powell635c60a2011-10-26 10:22:16 -0700870 }
871 }
872
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700873 void moveToState(Fragment f, int newState, int transit, int transitionStyle,
874 boolean keepActive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -0700875 if (DEBUG && false) Log.v(TAG, "moveToState: " + f
876 + " oldState=" + f.mState + " newState=" + newState
877 + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
Craig Mautner1c437192012-08-01 10:01:16 -0700878
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700879 // Fragments that are not currently added will sit in the onCreate() state.
Dianne Hackborne181bd92012-09-25 14:15:15 -0700880 if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700881 newState = Fragment.CREATED;
882 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700883 if (f.mRemoving && newState > f.mState) {
884 // While removing a fragment, we can't change it to a higher state.
885 newState = f.mState;
886 }
Adam Powell2db4e4b2011-11-02 14:30:47 -0700887 // Defer start if requested; don't allow it to move to STARTED or higher
888 // if it's not already started.
889 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -0700890 newState = Fragment.STOPPED;
891 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700892 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800893 // For fragments that are created from a layout, when restoring from
894 // state we don't want to allow them to be created until they are
895 // being reloaded from the layout.
896 if (f.mFromLayout && !f.mInLayout) {
897 return;
898 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800899 if (f.mAnimatingAway != null) {
900 // The fragment is currently being animated... but! Now we
901 // want to move our state back up. Give up on waiting for the
902 // animation, move to whatever the final state should be once
903 // the animation is done, and then we can proceed from there.
904 f.mAnimatingAway = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700905 moveToState(f, f.mStateAfterAnimating, 0, 0, true);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800906 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700907 switch (f.mState) {
908 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700909 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700910 if (f.mSavedFragmentState != null) {
911 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
912 FragmentManagerImpl.VIEW_STATE_TAG);
913 f.mTarget = getFragment(f.mSavedFragmentState,
914 FragmentManagerImpl.TARGET_STATE_TAG);
915 if (f.mTarget != null) {
916 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
917 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
918 }
Adam Powell78fed9b2011-11-07 10:45:34 -0800919 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
920 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
921 if (!f.mUserVisibleHint) {
922 f.mDeferStart = true;
923 if (newState > Fragment.STOPPED) {
924 newState = Fragment.STOPPED;
925 }
926 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700927 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700928 f.mHost = mHost;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700929 f.mParentFragment = mParent;
930 f.mFragmentManager = mParent != null
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700931 ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700932 f.mCalled = false;
Todd Kennedy434bd652015-05-04 12:29:50 -0700933 f.onAttach(mHost.getContext());
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700934 if (!f.mCalled) {
935 throw new SuperNotCalledException("Fragment " + f
936 + " did not call through to super.onAttach()");
937 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700938 if (f.mParentFragment == null) {
Todd Kennedy434bd652015-05-04 12:29:50 -0700939 mHost.onAttachFragment(f);
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700940 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700941
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700942 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700943 f.performCreate(f.mSavedFragmentState);
Adam Powelleacacb52016-03-23 13:07:27 -0700944 } else {
945 f.restoreChildFragmentState(f.mSavedFragmentState, true);
946 f.mState = Fragment.CREATED;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700947 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700948 f.mRetaining = false;
949 if (f.mFromLayout) {
950 // For fragments that are part of the content view
951 // layout, we need to instantiate the view immediately
952 // and the inflater will take care of adding it.
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700953 f.mView = f.performCreateView(f.getLayoutInflater(
954 f.mSavedFragmentState), null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700955 if (f.mView != null) {
956 f.mView.setSaveFromParentEnabled(false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700957 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700958 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700959 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700960 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700961 case Fragment.CREATED:
962 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700963 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700964 if (!f.mFromLayout) {
965 ViewGroup container = null;
966 if (f.mContainerId != 0) {
Adam Powelle01f5952016-02-23 15:25:42 -0800967 if (f.mContainerId == View.NO_ID) {
968 throwException(new IllegalArgumentException(
969 "Cannot create fragment "
970 + f
971 + " for a container view with no id"));
972 }
973 container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800974 if (container == null && !f.mRestored) {
Adam Powelle01f5952016-02-23 15:25:42 -0800975 String resName;
976 try {
977 resName = f.getResources().getResourceName(f.mContainerId);
978 } catch (NotFoundException e) {
979 resName = "unknown";
980 }
Dianne Hackborn4702a852012-08-17 15:18:29 -0700981 throwException(new IllegalArgumentException(
982 "No view found for id 0x"
983 + Integer.toHexString(f.mContainerId) + " ("
Adam Powelle01f5952016-02-23 15:25:42 -0800984 + resName
Dianne Hackborn4702a852012-08-17 15:18:29 -0700985 + ") for fragment " + f));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700986 }
987 }
988 f.mContainer = container;
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700989 f.mView = f.performCreateView(f.getLayoutInflater(
990 f.mSavedFragmentState), container, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700991 if (f.mView != null) {
992 f.mView.setSaveFromParentEnabled(false);
993 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -0700994 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700995 transitionStyle);
996 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -0700997 anim.setTarget(f.mView);
Doris Liude9284d2015-05-22 15:41:46 -0700998 setHWLayerAnimListenerIfAlpha(f.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -0700999 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001000 }
1001 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001002 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001003 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001004 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001005 }
1006 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07001007
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001008 f.performActivityCreated(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001009 if (f.mView != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001010 f.restoreViewState(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001011 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001012 f.mSavedFragmentState = null;
1013 }
Dianne Hackbornc8017682010-07-06 13:34:38 -07001014 case Fragment.ACTIVITY_CREATED:
Adam Powelleacacb52016-03-23 13:07:27 -07001015 if (newState > Fragment.ACTIVITY_CREATED) {
1016 f.mState = Fragment.STOPPED;
1017 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001018 case Fragment.STOPPED:
1019 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001020 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001021 f.performStart();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001022 }
1023 case Fragment.STARTED:
1024 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001025 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001026 f.performResume();
Adam Powell95202512011-08-07 17:20:17 -07001027 // Get rid of this in case we saved it and never needed it.
1028 f.mSavedFragmentState = null;
1029 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001030 }
1031 }
1032 } else if (f.mState > newState) {
1033 switch (f.mState) {
1034 case Fragment.RESUMED:
1035 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001036 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001037 f.performPause();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001038 }
1039 case Fragment.STARTED:
1040 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001041 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2707d602010-07-09 18:01:20 -07001042 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001043 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001044 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -07001045 case Fragment.ACTIVITY_CREATED:
1046 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001047 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001048 if (f.mView != null) {
1049 // Need to save the current view state if not
1050 // done already.
Todd Kennedy46d168f2015-05-13 11:13:58 -07001051 if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001052 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001053 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001054 }
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001055 f.performDestroyView();
Dianne Hackborndef15372010-08-15 12:43:52 -07001056 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001057 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001058 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001059 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -07001060 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001061 }
1062 if (anim != null) {
1063 final ViewGroup container = f.mContainer;
1064 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001065 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -07001066 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001067 f.mAnimatingAway = anim;
1068 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -07001069 anim.addListener(new AnimatorListenerAdapter() {
1070 @Override
1071 public void onAnimationEnd(Animator anim) {
1072 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001073 if (fragment.mAnimatingAway != null) {
1074 fragment.mAnimatingAway = null;
1075 moveToState(fragment, fragment.mStateAfterAnimating,
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001076 0, 0, false);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001077 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001078 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07001079 });
1080 anim.setTarget(f.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001081 setHWLayerAnimListenerIfAlpha(f.mView, anim);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001082 anim.start();
1083
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001084 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001085 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001086 }
1087 f.mContainer = null;
1088 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001089 }
1090 case Fragment.CREATED:
1091 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001092 if (mDestroyed) {
1093 if (f.mAnimatingAway != null) {
1094 // The fragment's containing activity is
1095 // being destroyed, but this fragment is
1096 // currently animating away. Stop the
1097 // animation right now -- it is not needed,
1098 // and we can't wait any more on destroying
1099 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -08001100 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001101 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -08001102 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001103 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001104 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001105 if (f.mAnimatingAway != null) {
1106 // We are waiting for the fragment's view to finish
1107 // animating away. Just make a note of the state
1108 // the fragment now should move to once the animation
1109 // is done.
1110 f.mStateAfterAnimating = newState;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001111 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001112 } else {
1113 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
1114 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001115 f.performDestroy();
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001116 } else {
Adam Powelleacacb52016-03-23 13:07:27 -07001117 f.mState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001118 }
1119
1120 f.mCalled = false;
1121 f.onDetach();
1122 if (!f.mCalled) {
1123 throw new SuperNotCalledException("Fragment " + f
1124 + " did not call through to super.onDetach()");
1125 }
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001126 if (!keepActive) {
1127 if (!f.mRetaining) {
1128 makeInactive(f);
1129 } else {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001130 f.mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001131 f.mParentFragment = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001132 f.mFragmentManager = null;
1133 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001134 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001135 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001136 }
1137 }
1138 }
1139
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001140 if (f.mState != newState) {
1141 Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
1142 + "expected state " + newState + " found " + f.mState);
1143 f.mState = newState;
1144 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001145 }
1146
Dianne Hackborn625ac272010-09-17 18:29:22 -07001147 void moveToState(Fragment f) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001148 moveToState(f, mCurState, 0, 0, false);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001149 }
1150
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001151 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001152 moveToState(newState, 0, 0, always);
1153 }
1154
1155 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001156 if (mHost == null && newState != Fragment.INITIALIZING) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001157 throw new IllegalStateException("No activity");
1158 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001159
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001160 if (!always && mCurState == newState) {
1161 return;
1162 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001163
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001164 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001165 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001166 boolean loadersRunning = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001167 for (int i=0; i<mActive.size(); i++) {
1168 Fragment f = mActive.get(i);
1169 if (f != null) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001170 moveToState(f, newState, transit, transitStyle, false);
Adam Powell635c60a2011-10-26 10:22:16 -07001171 if (f.mLoaderManager != null) {
1172 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1173 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001174 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001175 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001176
Adam Powell635c60a2011-10-26 10:22:16 -07001177 if (!loadersRunning) {
1178 startPendingDeferredFragments();
1179 }
1180
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001181 if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
1182 mHost.onInvalidateOptionsMenu();
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001183 mNeedMenuInvalidate = false;
1184 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001185 }
1186 }
1187
Adam Powell635c60a2011-10-26 10:22:16 -07001188 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001189 if (mActive == null) return;
1190
Adam Powell635c60a2011-10-26 10:22:16 -07001191 for (int i=0; i<mActive.size(); i++) {
1192 Fragment f = mActive.get(i);
1193 if (f != null) {
1194 performPendingDeferredStart(f);
1195 }
1196 }
1197 }
1198
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001199 void makeActive(Fragment f) {
1200 if (f.mIndex >= 0) {
1201 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001202 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001203
1204 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
1205 if (mActive == null) {
1206 mActive = new ArrayList<Fragment>();
1207 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001208 f.setIndex(mActive.size(), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001209 mActive.add(f);
1210
1211 } else {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001212 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001213 mActive.set(f.mIndex, f);
1214 }
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001215 if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001216 }
1217
1218 void makeInactive(Fragment f) {
1219 if (f.mIndex < 0) {
1220 return;
1221 }
1222
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001223 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001224 mActive.set(f.mIndex, null);
1225 if (mAvailIndices == null) {
1226 mAvailIndices = new ArrayList<Integer>();
1227 }
1228 mAvailIndices.add(f.mIndex);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001229 mHost.inactivateFragment(f.mWho);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001230 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001231 }
1232
1233 public void addFragment(Fragment fragment, boolean moveToStateNow) {
1234 if (mAdded == null) {
1235 mAdded = new ArrayList<Fragment>();
1236 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001237 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001238 makeActive(fragment);
1239 if (!fragment.mDetached) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001240 if (mAdded.contains(fragment)) {
1241 throw new IllegalStateException("Fragment already added: " + fragment);
1242 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001243 mAdded.add(fragment);
1244 fragment.mAdded = true;
1245 fragment.mRemoving = false;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001246 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001247 mNeedMenuInvalidate = true;
1248 }
1249 if (moveToStateNow) {
1250 moveToState(fragment);
1251 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001252 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001253 }
1254
Dianne Hackbornf121be72010-05-06 14:10:32 -07001255 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001256 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001257 final boolean inactive = !fragment.isInBackStack();
1258 if (!fragment.mDetached || inactive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001259 if (false) {
1260 // Would be nice to catch a bad remove here, but we need
1261 // time to test this to make sure we aren't crashes cases
1262 // where it is not a problem.
1263 if (!mAdded.contains(fragment)) {
1264 throw new IllegalStateException("Fragment not added: " + fragment);
1265 }
1266 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001267 if (mAdded != null) {
1268 mAdded.remove(fragment);
1269 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001270 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001271 mNeedMenuInvalidate = true;
1272 }
1273 fragment.mAdded = false;
1274 fragment.mRemoving = true;
1275 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001276 transition, transitionStyle, false);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001277 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001278 }
1279
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001280 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1281 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1282 if (!fragment.mHidden) {
1283 fragment.mHidden = true;
1284 if (fragment.mView != null) {
Adam Powell27562932013-06-07 10:16:08 -07001285 Animator anim = loadAnimator(fragment, transition, false,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001286 transitionStyle);
1287 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001288 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001289 // Delay the actual hide operation until the animation finishes, otherwise
1290 // the fragment will just immediately disappear
1291 final Fragment finalFragment = fragment;
1292 anim.addListener(new AnimatorListenerAdapter() {
1293 @Override
1294 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001295 if (finalFragment.mView != null) {
1296 finalFragment.mView.setVisibility(View.GONE);
1297 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001298 }
1299 });
Doris Liude9284d2015-05-22 15:41:46 -07001300 setHWLayerAnimListenerIfAlpha(finalFragment.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -07001301 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001302 } else {
1303 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001304 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001305 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001306 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001307 mNeedMenuInvalidate = true;
1308 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001309 fragment.onHiddenChanged(true);
1310 }
1311 }
1312
1313 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1314 if (DEBUG) Log.v(TAG, "show: " + fragment);
1315 if (fragment.mHidden) {
1316 fragment.mHidden = false;
1317 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001318 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001319 transitionStyle);
1320 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001321 anim.setTarget(fragment.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001322 setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -07001323 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001324 }
1325 fragment.mView.setVisibility(View.VISIBLE);
1326 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001327 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001328 mNeedMenuInvalidate = true;
1329 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001330 fragment.onHiddenChanged(false);
1331 }
1332 }
1333
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001334 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1335 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1336 if (!fragment.mDetached) {
1337 fragment.mDetached = true;
1338 if (fragment.mAdded) {
1339 // We are not already in back stack, so need to remove the fragment.
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001340 if (mAdded != null) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001341 if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001342 mAdded.remove(fragment);
1343 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001344 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001345 mNeedMenuInvalidate = true;
1346 }
1347 fragment.mAdded = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001348 moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001349 }
1350 }
1351 }
1352
1353 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1354 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1355 if (fragment.mDetached) {
1356 fragment.mDetached = false;
1357 if (!fragment.mAdded) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001358 if (mAdded == null) {
1359 mAdded = new ArrayList<Fragment>();
1360 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001361 if (mAdded.contains(fragment)) {
1362 throw new IllegalStateException("Fragment already added: " + fragment);
1363 }
1364 if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001365 mAdded.add(fragment);
1366 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001367 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001368 mNeedMenuInvalidate = true;
1369 }
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001370 moveToState(fragment, mCurState, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001371 }
1372 }
1373 }
1374
Dianne Hackbornf121be72010-05-06 14:10:32 -07001375 public Fragment findFragmentById(int id) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001376 if (mAdded != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001377 // First look through added fragments.
1378 for (int i=mAdded.size()-1; i>=0; i--) {
1379 Fragment f = mAdded.get(i);
1380 if (f != null && f.mFragmentId == id) {
1381 return f;
1382 }
1383 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001384 }
1385 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001386 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001387 for (int i=mActive.size()-1; i>=0; i--) {
1388 Fragment f = mActive.get(i);
1389 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001390 return f;
1391 }
1392 }
1393 }
1394 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001395 }
1396
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001397 public Fragment findFragmentByTag(String tag) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001398 if (mAdded != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001399 // First look through added fragments.
1400 for (int i=mAdded.size()-1; i>=0; i--) {
1401 Fragment f = mAdded.get(i);
1402 if (f != null && tag.equals(f.mTag)) {
1403 return f;
1404 }
1405 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001406 }
1407 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001408 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001409 for (int i=mActive.size()-1; i>=0; i--) {
1410 Fragment f = mActive.get(i);
1411 if (f != null && tag.equals(f.mTag)) {
1412 return f;
1413 }
1414 }
1415 }
1416 return null;
1417 }
1418
1419 public Fragment findFragmentByWho(String who) {
1420 if (mActive != null && who != null) {
1421 for (int i=mActive.size()-1; i>=0; i--) {
1422 Fragment f = mActive.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001423 if (f != null && (f=f.findFragmentByWho(who)) != null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001424 return f;
1425 }
1426 }
1427 }
1428 return null;
1429 }
1430
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001431 private void checkStateLoss() {
1432 if (mStateSaved) {
1433 throw new IllegalStateException(
1434 "Can not perform this action after onSaveInstanceState");
1435 }
1436 if (mNoTransactionsBecause != null) {
1437 throw new IllegalStateException(
1438 "Can not perform this action inside of " + mNoTransactionsBecause);
1439 }
1440 }
1441
Alan Viverette95a46092013-08-14 11:17:25 -07001442 /**
1443 * Adds an action to the queue of pending actions.
1444 *
1445 * @param action the action to add
1446 * @param allowStateLoss whether to allow loss of state information
1447 * @throws IllegalStateException if the activity has been destroyed
1448 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001449 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001450 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001451 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001452 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001453 synchronized (this) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001454 if (mDestroyed || mHost == null) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001455 throw new IllegalStateException("Activity has been destroyed");
1456 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001457 if (mPendingActions == null) {
1458 mPendingActions = new ArrayList<Runnable>();
1459 }
1460 mPendingActions.add(action);
1461 if (mPendingActions.size() == 1) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001462 mHost.getHandler().removeCallbacks(mExecCommit);
1463 mHost.getHandler().post(mExecCommit);
Dianne Hackborn445646c2010-06-25 15:52:59 -07001464 }
1465 }
1466 }
1467
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001468 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001469 synchronized (this) {
1470 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1471 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001472 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001473 }
1474 int index = mBackStackIndices.size();
1475 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1476 mBackStackIndices.add(bse);
1477 return index;
1478
1479 } else {
1480 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1481 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1482 mBackStackIndices.set(index, bse);
1483 return index;
1484 }
1485 }
1486 }
1487
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001488 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001489 synchronized (this) {
1490 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001491 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001492 }
1493 int N = mBackStackIndices.size();
1494 if (index < N) {
1495 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1496 mBackStackIndices.set(index, bse);
1497 } else {
1498 while (N < index) {
1499 mBackStackIndices.add(null);
1500 if (mAvailBackStackIndices == null) {
1501 mAvailBackStackIndices = new ArrayList<Integer>();
1502 }
1503 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1504 mAvailBackStackIndices.add(N);
1505 N++;
1506 }
1507 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1508 mBackStackIndices.add(bse);
1509 }
1510 }
1511 }
1512
1513 public void freeBackStackIndex(int index) {
1514 synchronized (this) {
1515 mBackStackIndices.set(index, null);
1516 if (mAvailBackStackIndices == null) {
1517 mAvailBackStackIndices = new ArrayList<Integer>();
1518 }
1519 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1520 mAvailBackStackIndices.add(index);
1521 }
1522 }
1523
Adam Powell8585ed62016-02-04 15:38:20 -08001524 public void execSingleAction(Runnable action, boolean allowStateLoss) {
1525 if (mExecutingActions) {
1526 throw new IllegalStateException("FragmentManager is already executing transactions");
1527 }
1528
1529 if (Looper.myLooper() != mHost.getHandler().getLooper()) {
1530 throw new IllegalStateException("Must be called from main thread of fragment host");
1531 }
1532
Adam Powell3518fed2016-03-01 09:07:44 -08001533 if (!allowStateLoss) {
Adam Powell8585ed62016-02-04 15:38:20 -08001534 checkStateLoss();
1535 }
1536
1537 mExecutingActions = true;
1538 action.run();
1539 mExecutingActions = false;
1540
1541 doPendingDeferredStart();
1542 }
1543
Dianne Hackborn445646c2010-06-25 15:52:59 -07001544 /**
1545 * Only call from main thread!
1546 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001547 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001548 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001549 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001550 }
1551
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001552 if (Looper.myLooper() != mHost.getHandler().getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001553 throw new IllegalStateException("Must be called from main thread of process");
1554 }
1555
1556 boolean didSomething = false;
1557
Dianne Hackborn445646c2010-06-25 15:52:59 -07001558 while (true) {
1559 int numActions;
1560
1561 synchronized (this) {
1562 if (mPendingActions == null || mPendingActions.size() == 0) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001563 break;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001564 }
1565
1566 numActions = mPendingActions.size();
1567 if (mTmpActions == null || mTmpActions.length < numActions) {
1568 mTmpActions = new Runnable[numActions];
1569 }
1570 mPendingActions.toArray(mTmpActions);
1571 mPendingActions.clear();
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001572 mHost.getHandler().removeCallbacks(mExecCommit);
Dianne Hackborn445646c2010-06-25 15:52:59 -07001573 }
1574
1575 mExecutingActions = true;
1576 for (int i=0; i<numActions; i++) {
1577 mTmpActions[i].run();
Jeff Sharkey0d325282011-07-13 09:36:27 -07001578 mTmpActions[i] = null;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001579 }
1580 mExecutingActions = false;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001581 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001582 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001583
Adam Powell8585ed62016-02-04 15:38:20 -08001584 doPendingDeferredStart();
1585
1586 return didSomething;
1587 }
1588
1589 void doPendingDeferredStart() {
Adam Powell78fed9b2011-11-07 10:45:34 -08001590 if (mHavePendingDeferredStart) {
1591 boolean loadersRunning = false;
1592 for (int i=0; i<mActive.size(); i++) {
1593 Fragment f = mActive.get(i);
1594 if (f != null && f.mLoaderManager != null) {
1595 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1596 }
1597 }
1598 if (!loadersRunning) {
1599 mHavePendingDeferredStart = false;
1600 startPendingDeferredFragments();
1601 }
1602 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001603 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001604
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001605 void reportBackStackChanged() {
1606 if (mBackStackChangeListeners != null) {
1607 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1608 mBackStackChangeListeners.get(i).onBackStackChanged();
1609 }
1610 }
1611 }
1612
1613 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001614 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001615 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001616 }
1617 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001618 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001619 }
1620
Dianne Hackborndd913a52010-07-22 12:17:04 -07001621 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001622 if (mBackStack == null) {
1623 return false;
1624 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001625 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001626 int last = mBackStack.size()-1;
1627 if (last < 0) {
1628 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001629 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001630 final BackStackRecord bss = mBackStack.remove(last);
George Mountc03da0e2014-08-22 17:04:02 -07001631 SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
1632 SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
George Mounta7245b42016-02-10 17:03:32 -08001633 if (mCurState >= Fragment.CREATED) {
1634 bss.calculateBackFragments(firstOutFragments, lastInFragments);
1635 }
George Mountc03da0e2014-08-22 17:04:02 -07001636 bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001637 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001638 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001639 int index = -1;
1640 if (name != null || id >= 0) {
1641 // If a name or ID is specified, look for that place in
1642 // the stack.
1643 index = mBackStack.size()-1;
1644 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001645 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001646 if (name != null && name.equals(bss.getName())) {
1647 break;
1648 }
1649 if (id >= 0 && id == bss.mIndex) {
1650 break;
1651 }
1652 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001653 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001654 if (index < 0) {
1655 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001656 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001657 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001658 index--;
1659 // Consume all following entries that match.
1660 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001661 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001662 if ((name != null && name.equals(bss.getName()))
1663 || (id >= 0 && id == bss.mIndex)) {
1664 index--;
1665 continue;
1666 }
1667 break;
1668 }
1669 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001670 }
1671 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001672 return false;
1673 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001674 final ArrayList<BackStackRecord> states
1675 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001676 for (int i=mBackStack.size()-1; i>index; i--) {
1677 states.add(mBackStack.remove(i));
1678 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001679 final int LAST = states.size()-1;
George Mountc03da0e2014-08-22 17:04:02 -07001680 SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
1681 SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
George Mounta7245b42016-02-10 17:03:32 -08001682 if (mCurState >= Fragment.CREATED) {
1683 for (int i = 0; i <= LAST; i++) {
1684 states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
1685 }
George Mountc03da0e2014-08-22 17:04:02 -07001686 }
George Mountd4c3c912014-06-09 12:31:34 -07001687 BackStackRecord.TransitionState state = null;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001688 for (int i=0; i<=LAST; i++) {
1689 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
George Mountc03da0e2014-08-22 17:04:02 -07001690 state = states.get(i).popFromBackStack(i == LAST, state,
1691 firstOutFragments, lastInFragments);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001692 }
1693 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001694 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001695 return true;
1696 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001697
1698 FragmentManagerNonConfig retainNonConfig() {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001699 ArrayList<Fragment> fragments = null;
Adam Powell44ba79e2016-02-04 16:20:37 -08001700 ArrayList<FragmentManagerNonConfig> childFragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001701 if (mActive != null) {
1702 for (int i=0; i<mActive.size(); i++) {
1703 Fragment f = mActive.get(i);
Adam Powell44ba79e2016-02-04 16:20:37 -08001704 if (f != null) {
1705 if (f.mRetainInstance) {
1706 if (fragments == null) {
1707 fragments = new ArrayList<>();
1708 }
1709 fragments.add(f);
1710 f.mRetaining = true;
1711 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
1712 if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001713 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001714 boolean addedChild = false;
1715 if (f.mChildFragmentManager != null) {
1716 FragmentManagerNonConfig child = f.mChildFragmentManager.retainNonConfig();
1717 if (child != null) {
1718 if (childFragments == null) {
1719 childFragments = new ArrayList<>();
1720 for (int j = 0; j < i; j++) {
1721 childFragments.add(null);
1722 }
1723 }
1724 childFragments.add(child);
1725 addedChild = true;
1726 }
1727 }
1728 if (childFragments != null && !addedChild) {
1729 childFragments.add(null);
1730 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001731 }
1732 }
1733 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001734 if (fragments == null && childFragments == null) {
1735 return null;
1736 }
1737 return new FragmentManagerNonConfig(fragments, childFragments);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001738 }
1739
1740 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001741 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001742 return;
1743 }
1744 if (mStateArray == null) {
1745 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001746 } else {
1747 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001748 }
1749 f.mView.saveHierarchyState(mStateArray);
1750 if (mStateArray.size() > 0) {
1751 f.mSavedViewState = mStateArray;
1752 mStateArray = null;
1753 }
1754 }
1755
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001756 Bundle saveFragmentBasicState(Fragment f) {
1757 Bundle result = null;
1758
1759 if (mStateBundle == null) {
1760 mStateBundle = new Bundle();
1761 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001762 f.performSaveInstanceState(mStateBundle);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001763 if (!mStateBundle.isEmpty()) {
1764 result = mStateBundle;
1765 mStateBundle = null;
1766 }
1767
1768 if (f.mView != null) {
1769 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07001770 }
1771 if (f.mSavedViewState != null) {
1772 if (result == null) {
1773 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001774 }
Dianne Hackborn13332762011-06-03 17:34:45 -07001775 result.putSparseParcelableArray(
1776 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001777 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001778 if (!f.mUserVisibleHint) {
Jake Wharton258029e2012-04-22 17:17:01 -04001779 if (result == null) {
1780 result = new Bundle();
1781 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001782 // Only add this if it's not the default value
1783 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
1784 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001785
1786 return result;
1787 }
1788
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001789 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001790 // Make sure all pending operations have now been executed to get
1791 // our state update-to-date.
1792 execPendingActions();
1793
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001794 mStateSaved = true;
1795
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001796 if (mActive == null || mActive.size() <= 0) {
1797 return null;
1798 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001799
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001800 // First collect all active fragments.
1801 int N = mActive.size();
1802 FragmentState[] active = new FragmentState[N];
1803 boolean haveFragments = false;
1804 for (int i=0; i<N; i++) {
1805 Fragment f = mActive.get(i);
1806 if (f != null) {
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001807 if (f.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001808 throwException(new IllegalStateException(
1809 "Failure saving state: active " + f
1810 + " has cleared index: " + f.mIndex));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001811 }
1812
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001813 haveFragments = true;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001814
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001815 FragmentState fs = new FragmentState(f);
1816 active[i] = fs;
1817
Dianne Hackborn625ac272010-09-17 18:29:22 -07001818 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001819 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001820
1821 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001822 if (f.mTarget.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001823 throwException(new IllegalStateException(
1824 "Failure saving state: " + f
1825 + " has target not in fragment manager: " + f.mTarget));
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001826 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001827 if (fs.mSavedFragmentState == null) {
1828 fs.mSavedFragmentState = new Bundle();
1829 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001830 putFragment(fs.mSavedFragmentState,
1831 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1832 if (f.mTargetRequestCode != 0) {
1833 fs.mSavedFragmentState.putInt(
1834 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1835 f.mTargetRequestCode);
1836 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001837 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001838
Dianne Hackborn625ac272010-09-17 18:29:22 -07001839 } else {
1840 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001841 }
1842
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001843 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1844 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001845 }
1846 }
1847
1848 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001849 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001850 return null;
1851 }
1852
1853 int[] added = null;
1854 BackStackState[] backStack = null;
1855
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001856 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001857 if (mAdded != null) {
1858 N = mAdded.size();
1859 if (N > 0) {
1860 added = new int[N];
1861 for (int i=0; i<N; i++) {
1862 added[i] = mAdded.get(i).mIndex;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001863 if (added[i] < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001864 throwException(new IllegalStateException(
1865 "Failure saving state: active " + mAdded.get(i)
1866 + " has cleared index: " + added[i]));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001867 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001868 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1869 + ": " + mAdded.get(i));
1870 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001871 }
1872 }
1873
1874 // Now save back stack.
1875 if (mBackStack != null) {
1876 N = mBackStack.size();
1877 if (N > 0) {
1878 backStack = new BackStackState[N];
1879 for (int i=0; i<N; i++) {
1880 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001881 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1882 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001883 }
1884 }
1885 }
1886
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001887 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001888 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001889 fms.mAdded = added;
1890 fms.mBackStack = backStack;
1891 return fms;
1892 }
1893
Adam Powell44ba79e2016-02-04 16:20:37 -08001894 void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001895 // If there is no saved state at all, then there can not be
1896 // any nonConfig fragments either, so that is that.
1897 if (state == null) return;
1898 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001899 if (fms.mActive == null) return;
Adam Powell44ba79e2016-02-04 16:20:37 -08001900
1901 List<FragmentManagerNonConfig> childNonConfigs = null;
1902
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001903 // First re-attach any non-config instances we are retaining back
1904 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001905 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001906 List<Fragment> nonConfigFragments = nonConfig.getFragments();
1907 childNonConfigs = nonConfig.getChildNonConfigs();
1908 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
1909 for (int i = 0; i < count; i++) {
1910 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001911 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001912 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001913 fs.mInstance = f;
1914 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001915 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001916 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001917 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001918 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001919 if (fs.mSavedFragmentState != null) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001920 fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001921 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001922 FragmentManagerImpl.VIEW_STATE_TAG);
Craig Mautner33acfbe2014-06-28 14:00:53 -07001923 f.mSavedFragmentState = fs.mSavedFragmentState;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001924 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001925 }
1926 }
1927
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001928 // Build the full list of active fragments, instantiating them from
1929 // their saved state.
Adam Powell44ba79e2016-02-04 16:20:37 -08001930 mActive = new ArrayList<>(fms.mActive.length);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001931 if (mAvailIndices != null) {
1932 mAvailIndices.clear();
1933 }
1934 for (int i=0; i<fms.mActive.length; i++) {
1935 FragmentState fs = fms.mActive[i];
1936 if (fs != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001937 FragmentManagerNonConfig childNonConfig = null;
1938 if (childNonConfigs != null && i < childNonConfigs.size()) {
1939 childNonConfig = childNonConfigs.get(i);
1940 }
1941 Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001942 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001943 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001944 // Now that the fragment is instantiated (or came from being
1945 // retained above), clear mInstance in case we end up re-restoring
1946 // from this FragmentState again.
1947 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001948 } else {
1949 mActive.add(null);
1950 if (mAvailIndices == null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001951 mAvailIndices = new ArrayList<>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001952 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001953 if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001954 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001955 }
1956 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001957
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001958 // Update the target of all retained fragments.
1959 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001960 List<Fragment> nonConfigFragments = nonConfig.getFragments();
1961 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
1962 for (int i = 0; i < count; i++) {
1963 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001964 if (f.mTargetIndex >= 0) {
1965 if (f.mTargetIndex < mActive.size()) {
1966 f.mTarget = mActive.get(f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001967 } else {
1968 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07001969 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001970 f.mTarget = null;
1971 }
1972 }
1973 }
1974 }
1975
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001976 // Build the list of currently added fragments.
1977 if (fms.mAdded != null) {
1978 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1979 for (int i=0; i<fms.mAdded.length; i++) {
1980 Fragment f = mActive.get(fms.mAdded[i]);
1981 if (f == null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001982 throwException(new IllegalStateException(
1983 "No instantiated fragment for index #" + fms.mAdded[i]));
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001984 }
1985 f.mAdded = true;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001986 if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
1987 if (mAdded.contains(f)) {
1988 throw new IllegalStateException("Already added!");
1989 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001990 mAdded.add(f);
1991 }
1992 } else {
1993 mAdded = null;
1994 }
1995
1996 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001997 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001998 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001999 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002000 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002001 if (DEBUG) {
2002 Log.v(TAG, "restoreAllState: back stack #" + i
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002003 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002004 LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002005 PrintWriter pw = new FastPrintWriter(logw, false, 1024);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002006 bse.dump(" ", pw, false);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002007 pw.flush();
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002008 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002009 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07002010 if (bse.mIndex >= 0) {
2011 setBackStackIndex(bse.mIndex, bse);
2012 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002013 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002014 } else {
2015 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002016 }
2017 }
2018
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002019 public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
2020 Fragment parent) {
2021 if (mHost != null) throw new IllegalStateException("Already attached");
2022 mHost = host;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002023 mContainer = container;
2024 mParent = parent;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002025 }
2026
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07002027 public void noteStateNotSaved() {
2028 mStateSaved = false;
2029 }
2030
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002031 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002032 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002033 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002034 }
2035
Dianne Hackbornc8017682010-07-06 13:34:38 -07002036 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002037 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07002038 moveToState(Fragment.ACTIVITY_CREATED, false);
2039 }
2040
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002041 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002042 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002043 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002044 }
2045
2046 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002047 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002048 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002049 }
2050
2051 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002052 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002053 }
2054
2055 public void dispatchStop() {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07002056 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002057 }
2058
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002059 public void dispatchDestroyView() {
2060 moveToState(Fragment.CREATED, false);
2061 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07002062
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002063 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08002064 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07002065 execPendingActions();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002066 moveToState(Fragment.INITIALIZING, false);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002067 mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002068 mContainer = null;
2069 mParent = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002070 }
Wale Ogunwale7c796812016-01-29 21:13:50 -08002071
Andrii Kulian933076d2016-03-29 17:04:42 -07002072 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08002073 if (mAdded == null) {
2074 return;
2075 }
2076 for (int i = mAdded.size() - 1; i >= 0; --i) {
2077 final Fragment f = mAdded.get(i);
2078 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07002079 f.performMultiWindowModeChanged(isInMultiWindowMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08002080 }
2081 }
2082 }
2083
Andrii Kulian933076d2016-03-29 17:04:42 -07002084 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08002085 if (mAdded == null) {
2086 return;
2087 }
2088 for (int i = mAdded.size() - 1; i >= 0; --i) {
2089 final Fragment f = mAdded.get(i);
2090 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07002091 f.performPictureInPictureModeChanged(isInPictureInPictureMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08002092 }
2093 }
2094 }
2095
Dianne Hackborn9d071802010-12-08 14:49:15 -08002096 public void dispatchConfigurationChanged(Configuration newConfig) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002097 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08002098 for (int i=0; i<mAdded.size(); i++) {
2099 Fragment f = mAdded.get(i);
2100 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002101 f.performConfigurationChanged(newConfig);
Dianne Hackborn9d071802010-12-08 14:49:15 -08002102 }
2103 }
2104 }
2105 }
2106
2107 public void dispatchLowMemory() {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002108 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08002109 for (int i=0; i<mAdded.size(); i++) {
2110 Fragment f = mAdded.get(i);
2111 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002112 f.performLowMemory();
Dianne Hackborn9d071802010-12-08 14:49:15 -08002113 }
2114 }
2115 }
2116 }
2117
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002118 public void dispatchTrimMemory(int level) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002119 if (mAdded != null) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002120 for (int i=0; i<mAdded.size(); i++) {
2121 Fragment f = mAdded.get(i);
2122 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002123 f.performTrimMemory(level);
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002124 }
2125 }
2126 }
2127 }
2128
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002129 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
2130 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002131 ArrayList<Fragment> newMenus = null;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002132 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002133 for (int i=0; i<mAdded.size(); i++) {
2134 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002135 if (f != null) {
2136 if (f.performCreateOptionsMenu(menu, inflater)) {
2137 show = true;
2138 if (newMenus == null) {
2139 newMenus = new ArrayList<Fragment>();
2140 }
2141 newMenus.add(f);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002142 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002143 }
2144 }
2145 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002146
2147 if (mCreatedMenus != null) {
2148 for (int i=0; i<mCreatedMenus.size(); i++) {
2149 Fragment f = mCreatedMenus.get(i);
2150 if (newMenus == null || !newMenus.contains(f)) {
2151 f.onDestroyOptionsMenu();
2152 }
2153 }
2154 }
2155
2156 mCreatedMenus = newMenus;
2157
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002158 return show;
2159 }
2160
2161 public boolean dispatchPrepareOptionsMenu(Menu menu) {
2162 boolean show = false;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002163 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002164 for (int i=0; i<mAdded.size(); i++) {
2165 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002166 if (f != null) {
2167 if (f.performPrepareOptionsMenu(menu)) {
2168 show = true;
2169 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002170 }
2171 }
2172 }
2173 return show;
2174 }
2175
2176 public boolean dispatchOptionsItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002177 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002178 for (int i=0; i<mAdded.size(); i++) {
2179 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002180 if (f != null) {
2181 if (f.performOptionsItemSelected(item)) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002182 return true;
2183 }
2184 }
2185 }
2186 }
2187 return false;
2188 }
2189
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002190 public boolean dispatchContextItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002191 if (mAdded != null) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002192 for (int i=0; i<mAdded.size(); i++) {
2193 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002194 if (f != null) {
2195 if (f.performContextItemSelected(item)) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002196 return true;
2197 }
2198 }
2199 }
2200 }
2201 return false;
2202 }
2203
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002204 public void dispatchOptionsMenuClosed(Menu menu) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002205 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002206 for (int i=0; i<mAdded.size(); i++) {
2207 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002208 if (f != null) {
2209 f.performOptionsMenuClosed(menu);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002210 }
2211 }
2212 }
2213 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07002214
2215 @Override
2216 public void invalidateOptionsMenu() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002217 if (mHost != null && mCurState == Fragment.RESUMED) {
2218 mHost.onInvalidateOptionsMenu();
Adam Powellf0f5fff2011-08-01 13:42:50 -07002219 } else {
2220 mNeedMenuInvalidate = true;
2221 }
2222 }
2223
Dianne Hackbornf121be72010-05-06 14:10:32 -07002224 public static int reverseTransit(int transit) {
2225 int rev = 0;
2226 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002227 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
2228 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002229 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002230 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
2231 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002232 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002233 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
2234 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002235 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002236 }
2237 return rev;
2238
2239 }
2240
2241 public static int transitToStyleIndex(int transit, boolean enter) {
2242 int animAttr = -1;
2243 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002244 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002245 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002246 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
2247 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002248 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002249 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002250 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002251 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
2252 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002253 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002254 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07002255 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002256 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
2257 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002258 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002259 }
2260 return animAttr;
2261 }
Adam Powell371a8092014-06-20 12:51:12 -07002262
2263 @Override
2264 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
2265 if (!"fragment".equals(name)) {
2266 return null;
2267 }
2268
2269 String fname = attrs.getAttributeValue(null, "class");
2270 TypedArray a =
2271 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
2272 if (fname == null) {
2273 fname = a.getString(com.android.internal.R.styleable.Fragment_name);
2274 }
2275 int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID);
2276 String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);
2277 a.recycle();
2278
2279 int containerId = parent != null ? parent.getId() : 0;
2280 if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
2281 throw new IllegalArgumentException(attrs.getPositionDescription()
2282 + ": Must specify unique android:id, android:tag, or have a parent with"
2283 + " an id for " + fname);
2284 }
2285
2286 // If we restored from a previous state, we may already have
2287 // instantiated this fragment from the state and should use
2288 // that instance instead of making a new one.
2289 Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;
2290 if (fragment == null && tag != null) {
2291 fragment = findFragmentByTag(tag);
2292 }
2293 if (fragment == null && containerId != View.NO_ID) {
2294 fragment = findFragmentById(containerId);
2295 }
2296
2297 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"
2298 + Integer.toHexString(id) + " fname=" + fname
2299 + " existing=" + fragment);
2300 if (fragment == null) {
2301 fragment = Fragment.instantiate(context, fname);
2302 fragment.mFromLayout = true;
2303 fragment.mFragmentId = id != 0 ? id : containerId;
2304 fragment.mContainerId = containerId;
2305 fragment.mTag = tag;
2306 fragment.mInLayout = true;
2307 fragment.mFragmentManager = this;
Todd Kennedy0aa69b72015-08-31 14:10:04 -07002308 fragment.mHost = mHost;
Todd Kennedy434bd652015-05-04 12:29:50 -07002309 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07002310 addFragment(fragment, true);
2311 } else if (fragment.mInLayout) {
2312 // A fragment already exists and it is not one we restored from
2313 // previous state.
2314 throw new IllegalArgumentException(attrs.getPositionDescription()
2315 + ": Duplicate id 0x" + Integer.toHexString(id)
2316 + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)
2317 + " with another fragment for " + fname);
2318 } else {
2319 // This fragment was retained from a previous instance; get it
2320 // going now.
2321 fragment.mInLayout = true;
Todd Kennedyac0e6ca2015-10-19 12:48:55 -07002322 fragment.mHost = mHost;
Adam Powell371a8092014-06-20 12:51:12 -07002323 // If this fragment is newly instantiated (either right now, or
2324 // from last saved state), then give it the attributes to
2325 // initialize itself.
2326 if (!fragment.mRetaining) {
Todd Kennedy434bd652015-05-04 12:29:50 -07002327 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07002328 }
2329 }
2330
2331 // If we haven't finished entering the CREATED state ourselves yet,
2332 // push the inflated child fragment along.
2333 if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
2334 moveToState(fragment, Fragment.CREATED, 0, 0, false);
2335 } else {
2336 moveToState(fragment);
2337 }
2338
2339 if (fragment.mView == null) {
2340 throw new IllegalStateException("Fragment " + fname
2341 + " did not create a view.");
2342 }
2343 if (id != 0) {
2344 fragment.mView.setId(id);
2345 }
2346 if (fragment.mView.getTag() == null) {
2347 fragment.mView.setTag(tag);
2348 }
2349 return fragment.mView;
2350 }
2351
2352 @Override
2353 public View onCreateView(String name, Context context, AttributeSet attrs) {
2354 return null;
2355 }
2356
2357 LayoutInflater.Factory2 getLayoutInflaterFactory() {
2358 return this;
2359 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002360}