blob: 674c3f7166f14112b79ff5cad3c3262dd70fc6fd [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
Andrew Solovayf5396802016-08-26 15:46:38 -070062 * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
Joe Fernandezb54e7a32011-10-03 15:09:50 -070063 * </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
Adam Powell467cc6f2016-05-11 13:45:33 -0700873 boolean isStateAtLeast(int state) {
874 return mCurState >= state;
875 }
876
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700877 void moveToState(Fragment f, int newState, int transit, int transitionStyle,
878 boolean keepActive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -0700879 if (DEBUG && false) Log.v(TAG, "moveToState: " + f
880 + " oldState=" + f.mState + " newState=" + newState
881 + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
Craig Mautner1c437192012-08-01 10:01:16 -0700882
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700883 // Fragments that are not currently added will sit in the onCreate() state.
Dianne Hackborne181bd92012-09-25 14:15:15 -0700884 if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700885 newState = Fragment.CREATED;
886 }
Dianne Hackbornf9302322011-06-14 18:36:14 -0700887 if (f.mRemoving && newState > f.mState) {
888 // While removing a fragment, we can't change it to a higher state.
889 newState = f.mState;
890 }
Adam Powell2db4e4b2011-11-02 14:30:47 -0700891 // Defer start if requested; don't allow it to move to STARTED or higher
892 // if it's not already started.
893 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -0700894 newState = Fragment.STOPPED;
895 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700896 if (f.mState < newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -0800897 // For fragments that are created from a layout, when restoring from
898 // state we don't want to allow them to be created until they are
899 // being reloaded from the layout.
900 if (f.mFromLayout && !f.mInLayout) {
901 return;
902 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800903 if (f.mAnimatingAway != null) {
904 // The fragment is currently being animated... but! Now we
905 // want to move our state back up. Give up on waiting for the
906 // animation, move to whatever the final state should be once
907 // the animation is done, and then we can proceed from there.
908 f.mAnimatingAway = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -0700909 moveToState(f, f.mStateAfterAnimating, 0, 0, true);
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800910 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700911 switch (f.mState) {
912 case Fragment.INITIALIZING:
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700913 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
Dianne Hackborndef15372010-08-15 12:43:52 -0700914 if (f.mSavedFragmentState != null) {
915 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
916 FragmentManagerImpl.VIEW_STATE_TAG);
917 f.mTarget = getFragment(f.mSavedFragmentState,
918 FragmentManagerImpl.TARGET_STATE_TAG);
919 if (f.mTarget != null) {
920 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
921 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
922 }
Adam Powell78fed9b2011-11-07 10:45:34 -0800923 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
924 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
925 if (!f.mUserVisibleHint) {
926 f.mDeferStart = true;
927 if (newState > Fragment.STOPPED) {
928 newState = Fragment.STOPPED;
929 }
930 }
Dianne Hackborndef15372010-08-15 12:43:52 -0700931 }
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700932 f.mHost = mHost;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700933 f.mParentFragment = mParent;
934 f.mFragmentManager = mParent != null
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700935 ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700936 f.mCalled = false;
Todd Kennedy434bd652015-05-04 12:29:50 -0700937 f.onAttach(mHost.getContext());
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700938 if (!f.mCalled) {
939 throw new SuperNotCalledException("Fragment " + f
940 + " did not call through to super.onAttach()");
941 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700942 if (f.mParentFragment == null) {
Todd Kennedy434bd652015-05-04 12:29:50 -0700943 mHost.onAttachFragment(f);
Adam Powelle30299f2016-05-13 11:04:39 -0700944 } else {
945 f.mParentFragment.onAttachFragment(f);
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700946 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700947
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700948 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700949 f.performCreate(f.mSavedFragmentState);
Adam Powelleacacb52016-03-23 13:07:27 -0700950 } else {
951 f.restoreChildFragmentState(f.mSavedFragmentState, true);
952 f.mState = Fragment.CREATED;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700953 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700954 f.mRetaining = false;
955 if (f.mFromLayout) {
956 // For fragments that are part of the content view
957 // layout, we need to instantiate the view immediately
958 // and the inflater will take care of adding it.
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700959 f.mView = f.performCreateView(f.getLayoutInflater(
960 f.mSavedFragmentState), null, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700961 if (f.mView != null) {
962 f.mView.setSaveFromParentEnabled(false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700963 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700964 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700965 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700966 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700967 case Fragment.CREATED:
968 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -0700969 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700970 if (!f.mFromLayout) {
971 ViewGroup container = null;
972 if (f.mContainerId != 0) {
Adam Powelle01f5952016-02-23 15:25:42 -0800973 if (f.mContainerId == View.NO_ID) {
974 throwException(new IllegalArgumentException(
975 "Cannot create fragment "
976 + f
977 + " for a container view with no id"));
978 }
979 container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -0800980 if (container == null && !f.mRestored) {
Adam Powelle01f5952016-02-23 15:25:42 -0800981 String resName;
982 try {
983 resName = f.getResources().getResourceName(f.mContainerId);
984 } catch (NotFoundException e) {
985 resName = "unknown";
986 }
Dianne Hackborn4702a852012-08-17 15:18:29 -0700987 throwException(new IllegalArgumentException(
988 "No view found for id 0x"
989 + Integer.toHexString(f.mContainerId) + " ("
Adam Powelle01f5952016-02-23 15:25:42 -0800990 + resName
Dianne Hackborn4702a852012-08-17 15:18:29 -0700991 + ") for fragment " + f));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700992 }
993 }
994 f.mContainer = container;
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -0700995 f.mView = f.performCreateView(f.getLayoutInflater(
996 f.mSavedFragmentState), container, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700997 if (f.mView != null) {
998 f.mView.setSaveFromParentEnabled(false);
999 if (container != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001000 Animator anim = loadAnimator(f, transit, true,
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001001 transitionStyle);
1002 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001003 anim.setTarget(f.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001004 setHWLayerAnimListenerIfAlpha(f.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -07001005 anim.start();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001006 }
1007 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001008 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001009 if (f.mHidden) f.mView.setVisibility(View.GONE);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001010 f.onViewCreated(f.mView, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001011 }
1012 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07001013
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001014 f.performActivityCreated(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001015 if (f.mView != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001016 f.restoreViewState(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001017 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001018 f.mSavedFragmentState = null;
1019 }
Dianne Hackbornc8017682010-07-06 13:34:38 -07001020 case Fragment.ACTIVITY_CREATED:
Adam Powelleacacb52016-03-23 13:07:27 -07001021 if (newState > Fragment.ACTIVITY_CREATED) {
1022 f.mState = Fragment.STOPPED;
1023 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001024 case Fragment.STOPPED:
1025 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001026 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001027 f.performStart();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001028 }
1029 case Fragment.STARTED:
1030 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001031 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001032 f.performResume();
Adam Powell95202512011-08-07 17:20:17 -07001033 // Get rid of this in case we saved it and never needed it.
1034 f.mSavedFragmentState = null;
1035 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001036 }
1037 }
1038 } else if (f.mState > newState) {
1039 switch (f.mState) {
1040 case Fragment.RESUMED:
1041 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001042 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001043 f.performPause();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001044 }
1045 case Fragment.STARTED:
1046 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001047 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2707d602010-07-09 18:01:20 -07001048 f.performStop();
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001049 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001050 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -07001051 case Fragment.ACTIVITY_CREATED:
1052 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001053 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001054 if (f.mView != null) {
1055 // Need to save the current view state if not
1056 // done already.
Todd Kennedy46d168f2015-05-13 11:13:58 -07001057 if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001058 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001059 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001060 }
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001061 f.performDestroyView();
Dianne Hackborndef15372010-08-15 12:43:52 -07001062 if (f.mView != null && f.mContainer != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001063 Animator anim = null;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001064 if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001065 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -07001066 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001067 }
1068 if (anim != null) {
1069 final ViewGroup container = f.mContainer;
1070 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001071 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -07001072 container.startViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001073 f.mAnimatingAway = anim;
1074 f.mStateAfterAnimating = newState;
Chet Haaseb20db3e2010-09-10 13:07:30 -07001075 anim.addListener(new AnimatorListenerAdapter() {
1076 @Override
1077 public void onAnimationEnd(Animator anim) {
1078 container.endViewTransition(view);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001079 if (fragment.mAnimatingAway != null) {
1080 fragment.mAnimatingAway = null;
1081 moveToState(fragment, fragment.mStateAfterAnimating,
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001082 0, 0, false);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001083 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001084 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07001085 });
1086 anim.setTarget(f.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001087 setHWLayerAnimListenerIfAlpha(f.mView, anim);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001088 anim.start();
1089
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001090 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001091 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001092 }
1093 f.mContainer = null;
1094 f.mView = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001095 }
1096 case Fragment.CREATED:
1097 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001098 if (mDestroyed) {
1099 if (f.mAnimatingAway != null) {
1100 // The fragment's containing activity is
1101 // being destroyed, but this fragment is
1102 // currently animating away. Stop the
1103 // animation right now -- it is not needed,
1104 // and we can't wait any more on destroying
1105 // the fragment.
Dianne Hackborn1b39e222010-12-28 14:17:18 -08001106 Animator anim = f.mAnimatingAway;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001107 f.mAnimatingAway = null;
Dianne Hackborn1b39e222010-12-28 14:17:18 -08001108 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001109 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001110 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001111 if (f.mAnimatingAway != null) {
1112 // We are waiting for the fragment's view to finish
1113 // animating away. Just make a note of the state
1114 // the fragment now should move to once the animation
1115 // is done.
1116 f.mStateAfterAnimating = newState;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001117 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001118 } else {
1119 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
1120 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001121 f.performDestroy();
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001122 } else {
Adam Powellcbade7f2016-04-15 11:14:37 -07001123 f.mState = Fragment.INITIALIZING;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001124 }
1125
Adam Powella9bab982016-04-21 11:04:41 -07001126 f.performDetach();
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001127 if (!keepActive) {
1128 if (!f.mRetaining) {
1129 makeInactive(f);
1130 } else {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001131 f.mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001132 f.mParentFragment = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001133 f.mFragmentManager = null;
1134 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001135 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001136 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001137 }
1138 }
1139 }
1140
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001141 if (f.mState != newState) {
1142 Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
1143 + "expected state " + newState + " found " + f.mState);
1144 f.mState = newState;
1145 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001146 }
1147
Dianne Hackborn625ac272010-09-17 18:29:22 -07001148 void moveToState(Fragment f) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001149 moveToState(f, mCurState, 0, 0, false);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001150 }
1151
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001152 void moveToState(int newState, boolean always) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001153 moveToState(newState, 0, 0, always);
1154 }
1155
1156 void moveToState(int newState, int transit, int transitStyle, boolean always) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001157 if (mHost == null && newState != Fragment.INITIALIZING) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001158 throw new IllegalStateException("No activity");
1159 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001160
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001161 if (!always && mCurState == newState) {
1162 return;
1163 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001164
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001165 mCurState = newState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001166 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001167 boolean loadersRunning = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001168 for (int i=0; i<mActive.size(); i++) {
1169 Fragment f = mActive.get(i);
1170 if (f != null) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001171 moveToState(f, newState, transit, transitStyle, false);
Adam Powell635c60a2011-10-26 10:22:16 -07001172 if (f.mLoaderManager != null) {
1173 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1174 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001175 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001176 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001177
Adam Powell635c60a2011-10-26 10:22:16 -07001178 if (!loadersRunning) {
1179 startPendingDeferredFragments();
1180 }
1181
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001182 if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
1183 mHost.onInvalidateOptionsMenu();
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001184 mNeedMenuInvalidate = false;
1185 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001186 }
1187 }
1188
Adam Powell635c60a2011-10-26 10:22:16 -07001189 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001190 if (mActive == null) return;
1191
Adam Powell635c60a2011-10-26 10:22:16 -07001192 for (int i=0; i<mActive.size(); i++) {
1193 Fragment f = mActive.get(i);
1194 if (f != null) {
1195 performPendingDeferredStart(f);
1196 }
1197 }
1198 }
1199
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001200 void makeActive(Fragment f) {
1201 if (f.mIndex >= 0) {
1202 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001203 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001204
1205 if (mAvailIndices == null || mAvailIndices.size() <= 0) {
1206 if (mActive == null) {
1207 mActive = new ArrayList<Fragment>();
1208 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001209 f.setIndex(mActive.size(), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001210 mActive.add(f);
1211
1212 } else {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001213 f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001214 mActive.set(f.mIndex, f);
1215 }
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001216 if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001217 }
1218
1219 void makeInactive(Fragment f) {
1220 if (f.mIndex < 0) {
1221 return;
1222 }
1223
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001224 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001225 mActive.set(f.mIndex, null);
1226 if (mAvailIndices == null) {
1227 mAvailIndices = new ArrayList<Integer>();
1228 }
1229 mAvailIndices.add(f.mIndex);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001230 mHost.inactivateFragment(f.mWho);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001231 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001232 }
1233
1234 public void addFragment(Fragment fragment, boolean moveToStateNow) {
1235 if (mAdded == null) {
1236 mAdded = new ArrayList<Fragment>();
1237 }
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001238 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001239 makeActive(fragment);
1240 if (!fragment.mDetached) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001241 if (mAdded.contains(fragment)) {
1242 throw new IllegalStateException("Fragment already added: " + fragment);
1243 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001244 mAdded.add(fragment);
1245 fragment.mAdded = true;
1246 fragment.mRemoving = false;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001247 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001248 mNeedMenuInvalidate = true;
1249 }
1250 if (moveToStateNow) {
1251 moveToState(fragment);
1252 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001253 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001254 }
1255
Dianne Hackbornf121be72010-05-06 14:10:32 -07001256 public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001257 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001258 final boolean inactive = !fragment.isInBackStack();
1259 if (!fragment.mDetached || inactive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001260 if (false) {
1261 // Would be nice to catch a bad remove here, but we need
1262 // time to test this to make sure we aren't crashes cases
1263 // where it is not a problem.
1264 if (!mAdded.contains(fragment)) {
1265 throw new IllegalStateException("Fragment not added: " + fragment);
1266 }
1267 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001268 if (mAdded != null) {
1269 mAdded.remove(fragment);
1270 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001271 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001272 mNeedMenuInvalidate = true;
1273 }
1274 fragment.mAdded = false;
1275 fragment.mRemoving = true;
1276 moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001277 transition, transitionStyle, false);
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001278 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001279 }
1280
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001281 public void hideFragment(Fragment fragment, int transition, int transitionStyle) {
1282 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1283 if (!fragment.mHidden) {
1284 fragment.mHidden = true;
1285 if (fragment.mView != null) {
Adam Powell27562932013-06-07 10:16:08 -07001286 Animator anim = loadAnimator(fragment, transition, false,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001287 transitionStyle);
1288 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001289 anim.setTarget(fragment.mView);
Chet Haase61eb40d2010-12-28 13:59:17 -08001290 // Delay the actual hide operation until the animation finishes, otherwise
1291 // the fragment will just immediately disappear
1292 final Fragment finalFragment = fragment;
1293 anim.addListener(new AnimatorListenerAdapter() {
1294 @Override
1295 public void onAnimationEnd(Animator animation) {
Chet Haaseb29407f2011-01-11 14:09:34 -08001296 if (finalFragment.mView != null) {
1297 finalFragment.mView.setVisibility(View.GONE);
1298 }
Chet Haase61eb40d2010-12-28 13:59:17 -08001299 }
1300 });
Doris Liude9284d2015-05-22 15:41:46 -07001301 setHWLayerAnimListenerIfAlpha(finalFragment.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -07001302 anim.start();
Chet Haasee646b28c2010-12-28 14:48:32 -08001303 } else {
1304 fragment.mView.setVisibility(View.GONE);
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001305 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001306 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001307 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001308 mNeedMenuInvalidate = true;
1309 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001310 fragment.onHiddenChanged(true);
1311 }
1312 }
1313
1314 public void showFragment(Fragment fragment, int transition, int transitionStyle) {
1315 if (DEBUG) Log.v(TAG, "show: " + fragment);
1316 if (fragment.mHidden) {
1317 fragment.mHidden = false;
1318 if (fragment.mView != null) {
Chet Haasea18a86b2010-09-07 13:20:00 -07001319 Animator anim = loadAnimator(fragment, transition, true,
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001320 transitionStyle);
1321 if (anim != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001322 anim.setTarget(fragment.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001323 setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
Chet Haase811ed1062010-08-06 10:38:15 -07001324 anim.start();
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001325 }
1326 fragment.mView.setVisibility(View.VISIBLE);
1327 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001328 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07001329 mNeedMenuInvalidate = true;
1330 }
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001331 fragment.onHiddenChanged(false);
1332 }
1333 }
1334
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001335 public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
1336 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1337 if (!fragment.mDetached) {
1338 fragment.mDetached = true;
1339 if (fragment.mAdded) {
1340 // We are not already in back stack, so need to remove the fragment.
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001341 if (mAdded != null) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001342 if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001343 mAdded.remove(fragment);
1344 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001345 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001346 mNeedMenuInvalidate = true;
1347 }
1348 fragment.mAdded = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001349 moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001350 }
1351 }
1352 }
1353
1354 public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
1355 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1356 if (fragment.mDetached) {
1357 fragment.mDetached = false;
1358 if (!fragment.mAdded) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001359 if (mAdded == null) {
1360 mAdded = new ArrayList<Fragment>();
1361 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001362 if (mAdded.contains(fragment)) {
1363 throw new IllegalStateException("Fragment already added: " + fragment);
1364 }
1365 if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001366 mAdded.add(fragment);
1367 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001368 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001369 mNeedMenuInvalidate = true;
1370 }
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001371 moveToState(fragment, mCurState, transition, transitionStyle, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001372 }
1373 }
1374 }
1375
Dianne Hackbornf121be72010-05-06 14:10:32 -07001376 public Fragment findFragmentById(int id) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001377 if (mAdded != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001378 // First look through added fragments.
1379 for (int i=mAdded.size()-1; i>=0; i--) {
1380 Fragment f = mAdded.get(i);
1381 if (f != null && f.mFragmentId == id) {
1382 return f;
1383 }
1384 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001385 }
1386 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001387 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001388 for (int i=mActive.size()-1; i>=0; i--) {
1389 Fragment f = mActive.get(i);
1390 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001391 return f;
1392 }
1393 }
1394 }
1395 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001396 }
1397
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001398 public Fragment findFragmentByTag(String tag) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001399 if (mAdded != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001400 // First look through added fragments.
1401 for (int i=mAdded.size()-1; i>=0; i--) {
1402 Fragment f = mAdded.get(i);
1403 if (f != null && tag.equals(f.mTag)) {
1404 return f;
1405 }
1406 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001407 }
1408 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001409 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001410 for (int i=mActive.size()-1; i>=0; i--) {
1411 Fragment f = mActive.get(i);
1412 if (f != null && tag.equals(f.mTag)) {
1413 return f;
1414 }
1415 }
1416 }
1417 return null;
1418 }
1419
1420 public Fragment findFragmentByWho(String who) {
1421 if (mActive != null && who != null) {
1422 for (int i=mActive.size()-1; i>=0; i--) {
1423 Fragment f = mActive.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001424 if (f != null && (f=f.findFragmentByWho(who)) != null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001425 return f;
1426 }
1427 }
1428 }
1429 return null;
1430 }
1431
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001432 private void checkStateLoss() {
1433 if (mStateSaved) {
1434 throw new IllegalStateException(
1435 "Can not perform this action after onSaveInstanceState");
1436 }
1437 if (mNoTransactionsBecause != null) {
1438 throw new IllegalStateException(
1439 "Can not perform this action inside of " + mNoTransactionsBecause);
1440 }
1441 }
1442
Alan Viverette95a46092013-08-14 11:17:25 -07001443 /**
1444 * Adds an action to the queue of pending actions.
1445 *
1446 * @param action the action to add
1447 * @param allowStateLoss whether to allow loss of state information
1448 * @throws IllegalStateException if the activity has been destroyed
1449 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -07001450 public void enqueueAction(Runnable action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001451 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001452 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001453 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001454 synchronized (this) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001455 if (mDestroyed || mHost == null) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001456 throw new IllegalStateException("Activity has been destroyed");
1457 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001458 if (mPendingActions == null) {
1459 mPendingActions = new ArrayList<Runnable>();
1460 }
1461 mPendingActions.add(action);
1462 if (mPendingActions.size() == 1) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001463 mHost.getHandler().removeCallbacks(mExecCommit);
1464 mHost.getHandler().post(mExecCommit);
Dianne Hackborn445646c2010-06-25 15:52:59 -07001465 }
1466 }
1467 }
1468
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001469 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001470 synchronized (this) {
1471 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1472 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001473 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001474 }
1475 int index = mBackStackIndices.size();
1476 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1477 mBackStackIndices.add(bse);
1478 return index;
1479
1480 } else {
1481 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1482 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1483 mBackStackIndices.set(index, bse);
1484 return index;
1485 }
1486 }
1487 }
1488
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001489 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001490 synchronized (this) {
1491 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001492 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001493 }
1494 int N = mBackStackIndices.size();
1495 if (index < N) {
1496 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1497 mBackStackIndices.set(index, bse);
1498 } else {
1499 while (N < index) {
1500 mBackStackIndices.add(null);
1501 if (mAvailBackStackIndices == null) {
1502 mAvailBackStackIndices = new ArrayList<Integer>();
1503 }
1504 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1505 mAvailBackStackIndices.add(N);
1506 N++;
1507 }
1508 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1509 mBackStackIndices.add(bse);
1510 }
1511 }
1512 }
1513
1514 public void freeBackStackIndex(int index) {
1515 synchronized (this) {
1516 mBackStackIndices.set(index, null);
1517 if (mAvailBackStackIndices == null) {
1518 mAvailBackStackIndices = new ArrayList<Integer>();
1519 }
1520 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1521 mAvailBackStackIndices.add(index);
1522 }
1523 }
1524
Adam Powell8585ed62016-02-04 15:38:20 -08001525 public void execSingleAction(Runnable action, boolean allowStateLoss) {
1526 if (mExecutingActions) {
1527 throw new IllegalStateException("FragmentManager is already executing transactions");
1528 }
1529
1530 if (Looper.myLooper() != mHost.getHandler().getLooper()) {
1531 throw new IllegalStateException("Must be called from main thread of fragment host");
1532 }
1533
Adam Powell3518fed2016-03-01 09:07:44 -08001534 if (!allowStateLoss) {
Adam Powell8585ed62016-02-04 15:38:20 -08001535 checkStateLoss();
1536 }
1537
1538 mExecutingActions = true;
George Mountc8c2bdf2016-06-30 17:08:27 -07001539 try {
1540 action.run();
1541 } finally {
1542 mExecutingActions = false;
1543 }
Adam Powell8585ed62016-02-04 15:38:20 -08001544
1545 doPendingDeferredStart();
1546 }
1547
Dianne Hackborn445646c2010-06-25 15:52:59 -07001548 /**
1549 * Only call from main thread!
1550 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001551 public boolean execPendingActions() {
Dianne Hackborn445646c2010-06-25 15:52:59 -07001552 if (mExecutingActions) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001553 throw new IllegalStateException("Recursive entry to executePendingTransactions");
Dianne Hackborn445646c2010-06-25 15:52:59 -07001554 }
1555
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001556 if (Looper.myLooper() != mHost.getHandler().getLooper()) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001557 throw new IllegalStateException("Must be called from main thread of process");
1558 }
1559
1560 boolean didSomething = false;
1561
Dianne Hackborn445646c2010-06-25 15:52:59 -07001562 while (true) {
1563 int numActions;
1564
1565 synchronized (this) {
1566 if (mPendingActions == null || mPendingActions.size() == 0) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001567 break;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001568 }
1569
1570 numActions = mPendingActions.size();
1571 if (mTmpActions == null || mTmpActions.length < numActions) {
1572 mTmpActions = new Runnable[numActions];
1573 }
1574 mPendingActions.toArray(mTmpActions);
1575 mPendingActions.clear();
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001576 mHost.getHandler().removeCallbacks(mExecCommit);
Dianne Hackborn445646c2010-06-25 15:52:59 -07001577 }
1578
1579 mExecutingActions = true;
George Mountc8c2bdf2016-06-30 17:08:27 -07001580 try {
1581 for (int i = 0; i < numActions; i++) {
1582 mTmpActions[i].run();
1583 mTmpActions[i] = null;
1584 }
1585 } finally {
1586 mExecutingActions = false;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001587 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001588 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07001589 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001590
Adam Powell8585ed62016-02-04 15:38:20 -08001591 doPendingDeferredStart();
1592
1593 return didSomething;
1594 }
1595
1596 void doPendingDeferredStart() {
Adam Powell78fed9b2011-11-07 10:45:34 -08001597 if (mHavePendingDeferredStart) {
1598 boolean loadersRunning = false;
1599 for (int i=0; i<mActive.size(); i++) {
1600 Fragment f = mActive.get(i);
1601 if (f != null && f.mLoaderManager != null) {
1602 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1603 }
1604 }
1605 if (!loadersRunning) {
1606 mHavePendingDeferredStart = false;
1607 startPendingDeferredFragments();
1608 }
1609 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001610 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001611
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001612 void reportBackStackChanged() {
1613 if (mBackStackChangeListeners != null) {
1614 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
1615 mBackStackChangeListeners.get(i).onBackStackChanged();
1616 }
1617 }
1618 }
1619
1620 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001621 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001622 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001623 }
1624 mBackStack.add(state);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001625 reportBackStackChanged();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001626 }
1627
Dianne Hackborndd913a52010-07-22 12:17:04 -07001628 boolean popBackStackState(Handler handler, String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001629 if (mBackStack == null) {
1630 return false;
1631 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001632 if (name == null && id < 0 && (flags&POP_BACK_STACK_INCLUSIVE) == 0) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001633 int last = mBackStack.size()-1;
1634 if (last < 0) {
1635 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001636 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001637 final BackStackRecord bss = mBackStack.remove(last);
George Mount7fe44142016-08-22 15:49:00 -07001638 SparseArray<BackStackRecord.FragmentContainerTransition> transitioningFragments =
1639 new SparseArray<>();
George Mounta7245b42016-02-10 17:03:32 -08001640 if (mCurState >= Fragment.CREATED) {
George Mount7fe44142016-08-22 15:49:00 -07001641 bss.calculateBackFragments(transitioningFragments);
George Mounta7245b42016-02-10 17:03:32 -08001642 }
George Mount7fe44142016-08-22 15:49:00 -07001643 bss.popFromBackStack(true, null, transitioningFragments);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001644 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001645 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001646 int index = -1;
1647 if (name != null || id >= 0) {
1648 // If a name or ID is specified, look for that place in
1649 // the stack.
1650 index = mBackStack.size()-1;
1651 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001652 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001653 if (name != null && name.equals(bss.getName())) {
1654 break;
1655 }
1656 if (id >= 0 && id == bss.mIndex) {
1657 break;
1658 }
1659 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07001660 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001661 if (index < 0) {
1662 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07001663 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001664 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001665 index--;
1666 // Consume all following entries that match.
1667 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001668 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07001669 if ((name != null && name.equals(bss.getName()))
1670 || (id >= 0 && id == bss.mIndex)) {
1671 index--;
1672 continue;
1673 }
1674 break;
1675 }
1676 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07001677 }
1678 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001679 return false;
1680 }
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001681 final ArrayList<BackStackRecord> states
1682 = new ArrayList<BackStackRecord>();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001683 for (int i=mBackStack.size()-1; i>index; i--) {
1684 states.add(mBackStack.remove(i));
1685 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001686 final int LAST = states.size()-1;
George Mount7fe44142016-08-22 15:49:00 -07001687 SparseArray<BackStackRecord.FragmentContainerTransition> transitioningFragments =
1688 new SparseArray<>();
George Mounta7245b42016-02-10 17:03:32 -08001689 if (mCurState >= Fragment.CREATED) {
1690 for (int i = 0; i <= LAST; i++) {
George Mount7fe44142016-08-22 15:49:00 -07001691 states.get(i).calculateBackFragments(transitioningFragments);
George Mounta7245b42016-02-10 17:03:32 -08001692 }
George Mountc03da0e2014-08-22 17:04:02 -07001693 }
George Mountd4c3c912014-06-09 12:31:34 -07001694 BackStackRecord.TransitionState state = null;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001695 for (int i=0; i<=LAST; i++) {
1696 if (DEBUG) Log.v(TAG, "Popping back stack state: " + states.get(i));
George Mount7fe44142016-08-22 15:49:00 -07001697 state = states.get(i).popFromBackStack(i == LAST, state, transitioningFragments);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001698 }
1699 reportBackStackChanged();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001700 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001701 return true;
1702 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001703
1704 FragmentManagerNonConfig retainNonConfig() {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001705 ArrayList<Fragment> fragments = null;
Adam Powell44ba79e2016-02-04 16:20:37 -08001706 ArrayList<FragmentManagerNonConfig> childFragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001707 if (mActive != null) {
1708 for (int i=0; i<mActive.size(); i++) {
1709 Fragment f = mActive.get(i);
Adam Powell44ba79e2016-02-04 16:20:37 -08001710 if (f != null) {
1711 if (f.mRetainInstance) {
1712 if (fragments == null) {
1713 fragments = new ArrayList<>();
1714 }
1715 fragments.add(f);
1716 f.mRetaining = true;
1717 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
1718 if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001719 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001720 boolean addedChild = false;
1721 if (f.mChildFragmentManager != null) {
1722 FragmentManagerNonConfig child = f.mChildFragmentManager.retainNonConfig();
1723 if (child != null) {
1724 if (childFragments == null) {
1725 childFragments = new ArrayList<>();
1726 for (int j = 0; j < i; j++) {
1727 childFragments.add(null);
1728 }
1729 }
1730 childFragments.add(child);
1731 addedChild = true;
1732 }
1733 }
1734 if (childFragments != null && !addedChild) {
1735 childFragments.add(null);
1736 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001737 }
1738 }
1739 }
Adam Powell44ba79e2016-02-04 16:20:37 -08001740 if (fragments == null && childFragments == null) {
1741 return null;
1742 }
1743 return new FragmentManagerNonConfig(fragments, childFragments);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001744 }
1745
1746 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001747 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001748 return;
1749 }
1750 if (mStateArray == null) {
1751 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001752 } else {
1753 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001754 }
1755 f.mView.saveHierarchyState(mStateArray);
1756 if (mStateArray.size() > 0) {
1757 f.mSavedViewState = mStateArray;
1758 mStateArray = null;
1759 }
1760 }
1761
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001762 Bundle saveFragmentBasicState(Fragment f) {
1763 Bundle result = null;
1764
1765 if (mStateBundle == null) {
1766 mStateBundle = new Bundle();
1767 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001768 f.performSaveInstanceState(mStateBundle);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001769 if (!mStateBundle.isEmpty()) {
1770 result = mStateBundle;
1771 mStateBundle = null;
1772 }
1773
1774 if (f.mView != null) {
1775 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07001776 }
1777 if (f.mSavedViewState != null) {
1778 if (result == null) {
1779 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001780 }
Dianne Hackborn13332762011-06-03 17:34:45 -07001781 result.putSparseParcelableArray(
1782 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001783 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001784 if (!f.mUserVisibleHint) {
Jake Wharton258029e2012-04-22 17:17:01 -04001785 if (result == null) {
1786 result = new Bundle();
1787 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001788 // Only add this if it's not the default value
1789 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
1790 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001791
1792 return result;
1793 }
1794
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001795 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001796 // Make sure all pending operations have now been executed to get
1797 // our state update-to-date.
1798 execPendingActions();
1799
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001800 mStateSaved = true;
1801
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001802 if (mActive == null || mActive.size() <= 0) {
1803 return null;
1804 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001805
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001806 // First collect all active fragments.
1807 int N = mActive.size();
1808 FragmentState[] active = new FragmentState[N];
1809 boolean haveFragments = false;
1810 for (int i=0; i<N; i++) {
1811 Fragment f = mActive.get(i);
1812 if (f != null) {
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001813 if (f.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001814 throwException(new IllegalStateException(
1815 "Failure saving state: active " + f
1816 + " has cleared index: " + f.mIndex));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001817 }
1818
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001819 haveFragments = true;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001820
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001821 FragmentState fs = new FragmentState(f);
1822 active[i] = fs;
1823
Dianne Hackborn625ac272010-09-17 18:29:22 -07001824 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07001825 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001826
1827 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001828 if (f.mTarget.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001829 throwException(new IllegalStateException(
1830 "Failure saving state: " + f
1831 + " has target not in fragment manager: " + f.mTarget));
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08001832 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001833 if (fs.mSavedFragmentState == null) {
1834 fs.mSavedFragmentState = new Bundle();
1835 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001836 putFragment(fs.mSavedFragmentState,
1837 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
1838 if (f.mTargetRequestCode != 0) {
1839 fs.mSavedFragmentState.putInt(
1840 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
1841 f.mTargetRequestCode);
1842 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001843 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001844
Dianne Hackborn625ac272010-09-17 18:29:22 -07001845 } else {
1846 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001847 }
1848
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001849 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
1850 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001851 }
1852 }
1853
1854 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001855 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001856 return null;
1857 }
1858
1859 int[] added = null;
1860 BackStackState[] backStack = null;
1861
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001862 // Build list of currently added fragments.
Dianne Hackborn625ac272010-09-17 18:29:22 -07001863 if (mAdded != null) {
1864 N = mAdded.size();
1865 if (N > 0) {
1866 added = new int[N];
1867 for (int i=0; i<N; i++) {
1868 added[i] = mAdded.get(i).mIndex;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001869 if (added[i] < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001870 throwException(new IllegalStateException(
1871 "Failure saving state: active " + mAdded.get(i)
1872 + " has cleared index: " + added[i]));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07001873 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001874 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
1875 + ": " + mAdded.get(i));
1876 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001877 }
1878 }
1879
1880 // Now save back stack.
1881 if (mBackStack != null) {
1882 N = mBackStack.size();
1883 if (N > 0) {
1884 backStack = new BackStackState[N];
1885 for (int i=0; i<N; i++) {
1886 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001887 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
1888 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001889 }
1890 }
1891 }
1892
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001893 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001894 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001895 fms.mAdded = added;
1896 fms.mBackStack = backStack;
1897 return fms;
1898 }
1899
Adam Powell44ba79e2016-02-04 16:20:37 -08001900 void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001901 // If there is no saved state at all, then there can not be
1902 // any nonConfig fragments either, so that is that.
1903 if (state == null) return;
1904 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001905 if (fms.mActive == null) return;
Adam Powell44ba79e2016-02-04 16:20:37 -08001906
1907 List<FragmentManagerNonConfig> childNonConfigs = null;
1908
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001909 // First re-attach any non-config instances we are retaining back
1910 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001911 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001912 List<Fragment> nonConfigFragments = nonConfig.getFragments();
1913 childNonConfigs = nonConfig.getChildNonConfigs();
1914 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
1915 for (int i = 0; i < count; i++) {
1916 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001917 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001918 FragmentState fs = fms.mActive[f.mIndex];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001919 fs.mInstance = f;
1920 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001921 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07001922 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001923 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07001924 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001925 if (fs.mSavedFragmentState != null) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001926 fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001927 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07001928 FragmentManagerImpl.VIEW_STATE_TAG);
Craig Mautner33acfbe2014-06-28 14:00:53 -07001929 f.mSavedFragmentState = fs.mSavedFragmentState;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001930 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001931 }
1932 }
1933
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001934 // Build the full list of active fragments, instantiating them from
1935 // their saved state.
Adam Powell44ba79e2016-02-04 16:20:37 -08001936 mActive = new ArrayList<>(fms.mActive.length);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001937 if (mAvailIndices != null) {
1938 mAvailIndices.clear();
1939 }
1940 for (int i=0; i<fms.mActive.length; i++) {
1941 FragmentState fs = fms.mActive[i];
1942 if (fs != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001943 FragmentManagerNonConfig childNonConfig = null;
1944 if (childNonConfigs != null && i < childNonConfigs.size()) {
1945 childNonConfig = childNonConfigs.get(i);
1946 }
1947 Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001948 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07001949 mActive.add(f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08001950 // Now that the fragment is instantiated (or came from being
1951 // retained above), clear mInstance in case we end up re-restoring
1952 // from this FragmentState again.
1953 fs.mInstance = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001954 } else {
1955 mActive.add(null);
1956 if (mAvailIndices == null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001957 mAvailIndices = new ArrayList<>();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001958 }
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001959 if (DEBUG) Log.v(TAG, "restoreAllState: avail #" + i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001960 mAvailIndices.add(i);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001961 }
1962 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001963
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001964 // Update the target of all retained fragments.
1965 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08001966 List<Fragment> nonConfigFragments = nonConfig.getFragments();
1967 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
1968 for (int i = 0; i < count; i++) {
1969 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001970 if (f.mTargetIndex >= 0) {
1971 if (f.mTargetIndex < mActive.size()) {
1972 f.mTarget = mActive.get(f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001973 } else {
1974 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07001975 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07001976 f.mTarget = null;
1977 }
1978 }
1979 }
1980 }
1981
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001982 // Build the list of currently added fragments.
1983 if (fms.mAdded != null) {
1984 mAdded = new ArrayList<Fragment>(fms.mAdded.length);
1985 for (int i=0; i<fms.mAdded.length; i++) {
1986 Fragment f = mActive.get(fms.mAdded[i]);
1987 if (f == null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001988 throwException(new IllegalStateException(
1989 "No instantiated fragment for index #" + fms.mAdded[i]));
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001990 }
1991 f.mAdded = true;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001992 if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
1993 if (mAdded.contains(f)) {
1994 throw new IllegalStateException("Already added!");
1995 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001996 mAdded.add(f);
1997 }
1998 } else {
1999 mAdded = null;
2000 }
2001
2002 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002003 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002004 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002005 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002006 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002007 if (DEBUG) {
2008 Log.v(TAG, "restoreAllState: back stack #" + i
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002009 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002010 LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002011 PrintWriter pw = new FastPrintWriter(logw, false, 1024);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002012 bse.dump(" ", pw, false);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002013 pw.flush();
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002014 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002015 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07002016 if (bse.mIndex >= 0) {
2017 setBackStackIndex(bse.mIndex, bse);
2018 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002019 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002020 } else {
2021 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002022 }
2023 }
2024
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002025 public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
2026 Fragment parent) {
2027 if (mHost != null) throw new IllegalStateException("Already attached");
2028 mHost = host;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002029 mContainer = container;
2030 mParent = parent;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002031 }
2032
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07002033 public void noteStateNotSaved() {
2034 mStateSaved = false;
2035 }
2036
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002037 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002038 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002039 moveToState(Fragment.CREATED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002040 }
2041
Dianne Hackbornc8017682010-07-06 13:34:38 -07002042 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002043 mStateSaved = false;
Dianne Hackbornc8017682010-07-06 13:34:38 -07002044 moveToState(Fragment.ACTIVITY_CREATED, false);
2045 }
2046
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002047 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002048 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002049 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002050 }
2051
2052 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002053 mStateSaved = false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002054 moveToState(Fragment.RESUMED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002055 }
2056
2057 public void dispatchPause() {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002058 moveToState(Fragment.STARTED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002059 }
2060
2061 public void dispatchStop() {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07002062 moveToState(Fragment.STOPPED, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002063 }
2064
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002065 public void dispatchDestroyView() {
2066 moveToState(Fragment.CREATED, false);
2067 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07002068
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002069 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08002070 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07002071 execPendingActions();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002072 moveToState(Fragment.INITIALIZING, false);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002073 mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002074 mContainer = null;
2075 mParent = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002076 }
Wale Ogunwale7c796812016-01-29 21:13:50 -08002077
Andrii Kulian933076d2016-03-29 17:04:42 -07002078 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08002079 if (mAdded == null) {
2080 return;
2081 }
2082 for (int i = mAdded.size() - 1; i >= 0; --i) {
2083 final Fragment f = mAdded.get(i);
2084 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07002085 f.performMultiWindowModeChanged(isInMultiWindowMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08002086 }
2087 }
2088 }
2089
Andrii Kulian933076d2016-03-29 17:04:42 -07002090 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08002091 if (mAdded == null) {
2092 return;
2093 }
2094 for (int i = mAdded.size() - 1; i >= 0; --i) {
2095 final Fragment f = mAdded.get(i);
2096 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07002097 f.performPictureInPictureModeChanged(isInPictureInPictureMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08002098 }
2099 }
2100 }
2101
Dianne Hackborn9d071802010-12-08 14:49:15 -08002102 public void dispatchConfigurationChanged(Configuration newConfig) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002103 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08002104 for (int i=0; i<mAdded.size(); i++) {
2105 Fragment f = mAdded.get(i);
2106 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002107 f.performConfigurationChanged(newConfig);
Dianne Hackborn9d071802010-12-08 14:49:15 -08002108 }
2109 }
2110 }
2111 }
2112
2113 public void dispatchLowMemory() {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002114 if (mAdded != null) {
Dianne Hackborn9d071802010-12-08 14:49:15 -08002115 for (int i=0; i<mAdded.size(); i++) {
2116 Fragment f = mAdded.get(i);
2117 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002118 f.performLowMemory();
Dianne Hackborn9d071802010-12-08 14:49:15 -08002119 }
2120 }
2121 }
2122 }
2123
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002124 public void dispatchTrimMemory(int level) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002125 if (mAdded != null) {
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002126 for (int i=0; i<mAdded.size(); i++) {
2127 Fragment f = mAdded.get(i);
2128 if (f != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002129 f.performTrimMemory(level);
Dianne Hackbornc68c9132011-07-29 01:25:18 -07002130 }
2131 }
2132 }
2133 }
2134
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002135 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
2136 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002137 ArrayList<Fragment> newMenus = null;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002138 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002139 for (int i=0; i<mAdded.size(); i++) {
2140 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002141 if (f != null) {
2142 if (f.performCreateOptionsMenu(menu, inflater)) {
2143 show = true;
2144 if (newMenus == null) {
2145 newMenus = new ArrayList<Fragment>();
2146 }
2147 newMenus.add(f);
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002148 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002149 }
2150 }
2151 }
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07002152
2153 if (mCreatedMenus != null) {
2154 for (int i=0; i<mCreatedMenus.size(); i++) {
2155 Fragment f = mCreatedMenus.get(i);
2156 if (newMenus == null || !newMenus.contains(f)) {
2157 f.onDestroyOptionsMenu();
2158 }
2159 }
2160 }
2161
2162 mCreatedMenus = newMenus;
2163
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002164 return show;
2165 }
2166
2167 public boolean dispatchPrepareOptionsMenu(Menu menu) {
2168 boolean show = false;
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002169 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002170 for (int i=0; i<mAdded.size(); i++) {
2171 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002172 if (f != null) {
2173 if (f.performPrepareOptionsMenu(menu)) {
2174 show = true;
2175 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002176 }
2177 }
2178 }
2179 return show;
2180 }
2181
2182 public boolean dispatchOptionsItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002183 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002184 for (int i=0; i<mAdded.size(); i++) {
2185 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002186 if (f != null) {
2187 if (f.performOptionsItemSelected(item)) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002188 return true;
2189 }
2190 }
2191 }
2192 }
2193 return false;
2194 }
2195
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002196 public boolean dispatchContextItemSelected(MenuItem item) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002197 if (mAdded != null) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002198 for (int i=0; i<mAdded.size(); i++) {
2199 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002200 if (f != null) {
2201 if (f.performContextItemSelected(item)) {
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07002202 return true;
2203 }
2204 }
2205 }
2206 }
2207 return false;
2208 }
2209
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002210 public void dispatchOptionsMenuClosed(Menu menu) {
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07002211 if (mAdded != null) {
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002212 for (int i=0; i<mAdded.size(); i++) {
2213 Fragment f = mAdded.get(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002214 if (f != null) {
2215 f.performOptionsMenuClosed(menu);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07002216 }
2217 }
2218 }
2219 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07002220
2221 @Override
2222 public void invalidateOptionsMenu() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002223 if (mHost != null && mCurState == Fragment.RESUMED) {
2224 mHost.onInvalidateOptionsMenu();
Adam Powellf0f5fff2011-08-01 13:42:50 -07002225 } else {
2226 mNeedMenuInvalidate = true;
2227 }
2228 }
2229
Dianne Hackbornf121be72010-05-06 14:10:32 -07002230 public static int reverseTransit(int transit) {
2231 int rev = 0;
2232 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002233 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
2234 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002235 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002236 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
2237 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002238 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002239 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
2240 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002241 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002242 }
2243 return rev;
2244
2245 }
2246
2247 public static int transitToStyleIndex(int transit, boolean enter) {
2248 int animAttr = -1;
2249 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07002250 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002251 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002252 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
2253 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002254 break;
Chet Haase811ed1062010-08-06 10:38:15 -07002255 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07002256 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07002257 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
2258 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002259 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002260 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07002261 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08002262 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
2263 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07002264 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002265 }
2266 return animAttr;
2267 }
Adam Powell371a8092014-06-20 12:51:12 -07002268
2269 @Override
2270 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
2271 if (!"fragment".equals(name)) {
2272 return null;
2273 }
2274
2275 String fname = attrs.getAttributeValue(null, "class");
2276 TypedArray a =
2277 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
2278 if (fname == null) {
2279 fname = a.getString(com.android.internal.R.styleable.Fragment_name);
2280 }
2281 int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID);
2282 String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);
2283 a.recycle();
2284
2285 int containerId = parent != null ? parent.getId() : 0;
2286 if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
2287 throw new IllegalArgumentException(attrs.getPositionDescription()
2288 + ": Must specify unique android:id, android:tag, or have a parent with"
2289 + " an id for " + fname);
2290 }
2291
2292 // If we restored from a previous state, we may already have
2293 // instantiated this fragment from the state and should use
2294 // that instance instead of making a new one.
2295 Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;
2296 if (fragment == null && tag != null) {
2297 fragment = findFragmentByTag(tag);
2298 }
2299 if (fragment == null && containerId != View.NO_ID) {
2300 fragment = findFragmentById(containerId);
2301 }
2302
2303 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"
2304 + Integer.toHexString(id) + " fname=" + fname
2305 + " existing=" + fragment);
2306 if (fragment == null) {
2307 fragment = Fragment.instantiate(context, fname);
2308 fragment.mFromLayout = true;
2309 fragment.mFragmentId = id != 0 ? id : containerId;
2310 fragment.mContainerId = containerId;
2311 fragment.mTag = tag;
2312 fragment.mInLayout = true;
2313 fragment.mFragmentManager = this;
Todd Kennedy0aa69b72015-08-31 14:10:04 -07002314 fragment.mHost = mHost;
Todd Kennedy434bd652015-05-04 12:29:50 -07002315 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07002316 addFragment(fragment, true);
2317 } else if (fragment.mInLayout) {
2318 // A fragment already exists and it is not one we restored from
2319 // previous state.
2320 throw new IllegalArgumentException(attrs.getPositionDescription()
2321 + ": Duplicate id 0x" + Integer.toHexString(id)
2322 + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)
2323 + " with another fragment for " + fname);
2324 } else {
2325 // This fragment was retained from a previous instance; get it
2326 // going now.
2327 fragment.mInLayout = true;
Todd Kennedyac0e6ca2015-10-19 12:48:55 -07002328 fragment.mHost = mHost;
Adam Powell371a8092014-06-20 12:51:12 -07002329 // If this fragment is newly instantiated (either right now, or
2330 // from last saved state), then give it the attributes to
2331 // initialize itself.
2332 if (!fragment.mRetaining) {
Todd Kennedy434bd652015-05-04 12:29:50 -07002333 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07002334 }
2335 }
2336
2337 // If we haven't finished entering the CREATED state ourselves yet,
2338 // push the inflated child fragment along.
2339 if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
2340 moveToState(fragment, Fragment.CREATED, 0, 0, false);
2341 } else {
2342 moveToState(fragment);
2343 }
2344
2345 if (fragment.mView == null) {
2346 throw new IllegalStateException("Fragment " + fname
2347 + " did not create a view.");
2348 }
2349 if (id != 0) {
2350 fragment.mView.setId(id);
2351 }
2352 if (fragment.mView.getTag() == null) {
2353 fragment.mView.setTag(tag);
2354 }
2355 return fragment.mView;
2356 }
2357
2358 @Override
2359 public View onCreateView(String name, Context context, AttributeSet attrs) {
2360 return null;
2361 }
2362
2363 LayoutInflater.Factory2 getLayoutInflaterFactory() {
2364 return this;
2365 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002366}